evolclaw 2.0.1 → 2.0.3
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/data/evolclaw.sample.json +31 -26
- package/dist/channels/wechat.js +451 -0
- package/dist/cli.js +205 -149
- package/dist/config.js +32 -17
- package/dist/core/agent-runner.js +27 -41
- package/dist/core/command-handler.js +72 -54
- package/dist/core/message-processor.js +36 -10
- package/dist/core/message-queue.js +9 -3
- package/dist/core/session-manager.js +81 -238
- package/dist/index.js +189 -115
- package/dist/utils/init-feishu.js +261 -0
- package/dist/utils/init-wechat.js +170 -0
- package/dist/utils/init.js +98 -69
- package/dist/utils/stream-flusher.js +3 -2
- package/package.json +8 -7
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import readline from 'readline';
|
|
3
|
+
import { resolvePaths } from '../paths.js';
|
|
4
|
+
const DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
|
|
5
|
+
const BOT_TYPE = '3';
|
|
6
|
+
const QR_POLL_TIMEOUT_MS = 35_000;
|
|
7
|
+
const LOGIN_TIMEOUT_MS = 480_000;
|
|
8
|
+
function ask(rl, question) {
|
|
9
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
10
|
+
}
|
|
11
|
+
async function fetchQRCode(baseUrl) {
|
|
12
|
+
const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
13
|
+
const url = `${base}ilink/bot/get_bot_qrcode?bot_type=${BOT_TYPE}`;
|
|
14
|
+
const res = await fetch(url);
|
|
15
|
+
if (!res.ok)
|
|
16
|
+
throw new Error(`QR fetch failed: ${res.status}`);
|
|
17
|
+
return (await res.json());
|
|
18
|
+
}
|
|
19
|
+
async function pollQRStatus(baseUrl, qrcode) {
|
|
20
|
+
const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
21
|
+
const url = `${base}ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`;
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const timer = setTimeout(() => controller.abort(), QR_POLL_TIMEOUT_MS);
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(url, {
|
|
26
|
+
headers: { 'iLink-App-ClientVersion': '1' },
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
});
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
throw new Error(`QR status failed: ${res.status}`);
|
|
32
|
+
return (await res.json());
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
37
|
+
return { status: 'wait' };
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function runWechatQrFlow() {
|
|
43
|
+
const qrResp = await fetchQRCode(DEFAULT_BASE_URL);
|
|
44
|
+
try {
|
|
45
|
+
const qrterm = await import('qrcode-terminal');
|
|
46
|
+
await new Promise(resolve => {
|
|
47
|
+
qrterm.default.generate(qrResp.qrcode_img_content, { small: true }, (qr) => {
|
|
48
|
+
console.log(qr);
|
|
49
|
+
resolve();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
console.log(`请在浏览器中打开此链接扫码: ${qrResp.qrcode_img_content}\n`);
|
|
55
|
+
}
|
|
56
|
+
console.log('请用微信扫描上方二维码...\n');
|
|
57
|
+
const deadline = Date.now() + LOGIN_TIMEOUT_MS;
|
|
58
|
+
let scannedPrinted = false;
|
|
59
|
+
while (Date.now() < deadline) {
|
|
60
|
+
const status = await pollQRStatus(DEFAULT_BASE_URL, qrResp.qrcode);
|
|
61
|
+
switch (status.status) {
|
|
62
|
+
case 'wait':
|
|
63
|
+
process.stdout.write('.');
|
|
64
|
+
break;
|
|
65
|
+
case 'scaned':
|
|
66
|
+
if (!scannedPrinted) {
|
|
67
|
+
console.log('\n👀 已扫码,请在微信中确认...');
|
|
68
|
+
scannedPrinted = true;
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'expired':
|
|
72
|
+
console.error('\n二维码已过期');
|
|
73
|
+
return null;
|
|
74
|
+
case 'confirmed':
|
|
75
|
+
if (!status.ilink_bot_id || !status.bot_token) {
|
|
76
|
+
console.error('\n登录失败:服务器未返回完整信息');
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
baseUrl: status.baseurl || DEFAULT_BASE_URL,
|
|
81
|
+
token: status.bot_token,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
85
|
+
}
|
|
86
|
+
console.log('\n登录超时');
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
export async function cmdInitWechat() {
|
|
90
|
+
const p = resolvePaths();
|
|
91
|
+
if (!fs.existsSync(p.config)) {
|
|
92
|
+
console.log(`❌ 配置文件不存在,请先运行 evolclaw init`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const config = JSON.parse(fs.readFileSync(p.config, 'utf-8'));
|
|
96
|
+
// 检查已有配置
|
|
97
|
+
if (config.channels?.wechat?.token) {
|
|
98
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
99
|
+
try {
|
|
100
|
+
const answer = (await ask(rl, '已有微信配置,是否重新登录?[y/N] ')).trim().toLowerCase();
|
|
101
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
102
|
+
console.log('已取消');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
rl.close();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
console.log('正在获取微信登录二维码...\n');
|
|
111
|
+
const qrResp = await fetchQRCode(DEFAULT_BASE_URL);
|
|
112
|
+
// 终端显示二维码
|
|
113
|
+
try {
|
|
114
|
+
const qrterm = await import('qrcode-terminal');
|
|
115
|
+
await new Promise(resolve => {
|
|
116
|
+
qrterm.default.generate(qrResp.qrcode_img_content, { small: true }, (qr) => {
|
|
117
|
+
console.log(qr);
|
|
118
|
+
resolve();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
console.log(`请在浏览器中打开此链接扫码: ${qrResp.qrcode_img_content}\n`);
|
|
124
|
+
}
|
|
125
|
+
console.log('请用微信扫描上方二维码...\n');
|
|
126
|
+
const deadline = Date.now() + LOGIN_TIMEOUT_MS;
|
|
127
|
+
let scannedPrinted = false;
|
|
128
|
+
while (Date.now() < deadline) {
|
|
129
|
+
const status = await pollQRStatus(DEFAULT_BASE_URL, qrResp.qrcode);
|
|
130
|
+
switch (status.status) {
|
|
131
|
+
case 'wait':
|
|
132
|
+
process.stdout.write('.');
|
|
133
|
+
break;
|
|
134
|
+
case 'scaned':
|
|
135
|
+
if (!scannedPrinted) {
|
|
136
|
+
console.log('\n👀 已扫码,请在微信中确认...');
|
|
137
|
+
scannedPrinted = true;
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
case 'expired':
|
|
141
|
+
console.log('\n二维码已过期,请重新运行 evolclaw init wechat');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
break;
|
|
144
|
+
case 'confirmed': {
|
|
145
|
+
if (!status.ilink_bot_id || !status.bot_token) {
|
|
146
|
+
console.error('\n登录失败:服务器未返回完整信息');
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
// 写入配置
|
|
150
|
+
if (!config.channels)
|
|
151
|
+
config.channels = {};
|
|
152
|
+
config.channels.wechat = {
|
|
153
|
+
enabled: true,
|
|
154
|
+
baseUrl: status.baseurl || DEFAULT_BASE_URL,
|
|
155
|
+
token: status.bot_token,
|
|
156
|
+
};
|
|
157
|
+
fs.writeFileSync(p.config, JSON.stringify(config, null, 2) + '\n');
|
|
158
|
+
console.log(`\n✅ 微信连接成功!`);
|
|
159
|
+
console.log(` Bot ID: ${status.ilink_bot_id}`);
|
|
160
|
+
console.log(` User ID: ${status.ilink_user_id}`);
|
|
161
|
+
console.log(` 配置已写入: ${p.config}`);
|
|
162
|
+
console.log(`\n现在可以启动服务: evolclaw restart`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
167
|
+
}
|
|
168
|
+
console.log('\n登录超时,请重新运行');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
package/dist/utils/init.js
CHANGED
|
@@ -29,12 +29,9 @@ async function sudoExec(cmd, args) {
|
|
|
29
29
|
// 让 n 安装到当前 node 所在的 prefix 目录
|
|
30
30
|
const env = { ...process.env };
|
|
31
31
|
if (cmd === 'n' && !env.N_PREFIX) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
env.N_PREFIX = nodePrefix;
|
|
36
|
-
}
|
|
37
|
-
catch { }
|
|
32
|
+
const nodePrefix = process.config.variables?.node_prefix;
|
|
33
|
+
if (nodePrefix)
|
|
34
|
+
env.N_PREFIX = nodePrefix;
|
|
38
35
|
}
|
|
39
36
|
try {
|
|
40
37
|
await execFileAsync(cmd, args, { timeout: 120000, env });
|
|
@@ -129,7 +126,8 @@ async function checkEnvironment(rl) {
|
|
|
129
126
|
await npmInstallGlobal('n');
|
|
130
127
|
console.log(' 正在升级 Node.js...');
|
|
131
128
|
await sudoExec('n', ['22']);
|
|
132
|
-
console.log(' ✓ Node.js
|
|
129
|
+
console.log(' ✓ Node.js 升级完成');
|
|
130
|
+
console.log(' → 请打开新终端后重新运行 evolclaw init');
|
|
133
131
|
return false;
|
|
134
132
|
}
|
|
135
133
|
catch (e) {
|
|
@@ -186,22 +184,10 @@ async function checkEnvironment(rl) {
|
|
|
186
184
|
// @anthropic-ai/claude-agent-sdk >= 0.2.75
|
|
187
185
|
let sdkAction = 'ok';
|
|
188
186
|
try {
|
|
189
|
-
|
|
187
|
+
// 用 require.resolve 找到 SDK 入口,推导 package.json 路径
|
|
190
188
|
const esmRequire = createRequire(import.meta.url);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
try {
|
|
196
|
-
const globalRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf-8' }).trim();
|
|
197
|
-
const globalPath = path.join(globalRoot, '@anthropic-ai', 'claude-agent-sdk', 'package.json');
|
|
198
|
-
if (fs.existsSync(globalPath))
|
|
199
|
-
sdkPkgPath = globalPath;
|
|
200
|
-
}
|
|
201
|
-
catch { }
|
|
202
|
-
}
|
|
203
|
-
if (!sdkPkgPath)
|
|
204
|
-
throw new Error('not found');
|
|
189
|
+
const sdkEntry = esmRequire.resolve('@anthropic-ai/claude-agent-sdk');
|
|
190
|
+
const sdkPkgPath = path.join(path.dirname(sdkEntry), 'package.json');
|
|
205
191
|
const sdkPkg = JSON.parse(fs.readFileSync(sdkPkgPath, 'utf-8'));
|
|
206
192
|
const sdkVer = sdkPkg.version;
|
|
207
193
|
const parts = sdkVer.split('.').map(Number);
|
|
@@ -270,11 +256,50 @@ function setupEnvVar(home) {
|
|
|
270
256
|
}
|
|
271
257
|
console.log(' ⚠ 请重新打开终端或执行 source 使其生效');
|
|
272
258
|
}
|
|
259
|
+
// ==================== Feishu Manual Input ====================
|
|
260
|
+
async function initFeishuManual(rl, config) {
|
|
261
|
+
let appId = '';
|
|
262
|
+
while (!appId) {
|
|
263
|
+
appId = (await ask(rl, ' 飞书 App ID: ')).trim();
|
|
264
|
+
if (!appId)
|
|
265
|
+
console.log(' ⚠ 不能为空');
|
|
266
|
+
}
|
|
267
|
+
let appSecret = '';
|
|
268
|
+
while (!appSecret) {
|
|
269
|
+
appSecret = (await ask(rl, ' 飞书 App Secret: ')).trim();
|
|
270
|
+
if (!appSecret)
|
|
271
|
+
console.log(' ⚠ 不能为空');
|
|
272
|
+
}
|
|
273
|
+
console.log(' 正在验证飞书凭证...');
|
|
274
|
+
try {
|
|
275
|
+
const lark = await import('@larksuiteoapi/node-sdk');
|
|
276
|
+
const client = new lark.Client({ appId, appSecret });
|
|
277
|
+
const res = await client.auth.tenantAccessToken.internal({
|
|
278
|
+
data: { app_id: appId, app_secret: appSecret },
|
|
279
|
+
});
|
|
280
|
+
if (res.code === 0) {
|
|
281
|
+
console.log(' ✓ 飞书凭证验证通过');
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
console.log(` ✗ 飞书凭证验证失败: ${res.msg}`);
|
|
285
|
+
const answer = (await ask(rl, ' → 是否继续?[y/N] ')).trim().toLowerCase();
|
|
286
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (e) {
|
|
292
|
+
console.log(` ⚠ 飞书凭证验证跳过: ${e.message?.slice(0, 100) || e}`);
|
|
293
|
+
}
|
|
294
|
+
config.channels.feishu.appId = appId;
|
|
295
|
+
config.channels.feishu.appSecret = appSecret;
|
|
296
|
+
config.channels.feishu.enabled = true;
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
273
299
|
// ==================== Main ====================
|
|
274
300
|
export async function cmdInit() {
|
|
275
301
|
const p = resolvePaths();
|
|
276
302
|
ensureDataDirs();
|
|
277
|
-
// 检查服务是否在运行
|
|
278
303
|
if (fs.existsSync(p.pid)) {
|
|
279
304
|
const pid = parseInt(fs.readFileSync(p.pid, 'utf-8').trim(), 10);
|
|
280
305
|
try {
|
|
@@ -302,49 +327,11 @@ export async function cmdInit() {
|
|
|
302
327
|
return;
|
|
303
328
|
}
|
|
304
329
|
console.log('📝 交互式配置\n');
|
|
305
|
-
//
|
|
306
|
-
let appId = '';
|
|
307
|
-
while (!appId) {
|
|
308
|
-
appId = (await ask(rl, ' 飞书 App ID: ')).trim();
|
|
309
|
-
if (!appId)
|
|
310
|
-
console.log(' ⚠ 不能为空');
|
|
311
|
-
}
|
|
312
|
-
// feishu.appSecret
|
|
313
|
-
let appSecret = '';
|
|
314
|
-
while (!appSecret) {
|
|
315
|
-
appSecret = (await ask(rl, ' 飞书 App Secret: ')).trim();
|
|
316
|
-
if (!appSecret)
|
|
317
|
-
console.log(' ⚠ 不能为空');
|
|
318
|
-
}
|
|
319
|
-
// 验证飞书凭证
|
|
320
|
-
console.log(' 正在验证飞书凭证...');
|
|
321
|
-
try {
|
|
322
|
-
const lark = await import('@larksuiteoapi/node-sdk');
|
|
323
|
-
const client = new lark.Client({ appId, appSecret });
|
|
324
|
-
const res = await client.auth.tenantAccessToken.internal({
|
|
325
|
-
data: { app_id: appId, app_secret: appSecret },
|
|
326
|
-
});
|
|
327
|
-
if (res.code === 0) {
|
|
328
|
-
console.log(' ✓ 飞书凭证验证通过');
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
console.log(` ✗ 飞书凭证验证失败: ${res.msg}`);
|
|
332
|
-
const answer = (await ask(rl, ' → 是否继续?[y/N] ')).trim().toLowerCase();
|
|
333
|
-
if (answer !== 'y' && answer !== 'yes') {
|
|
334
|
-
console.log(' 已取消');
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
catch (e) {
|
|
340
|
-
console.log(` ⚠ 飞书凭证验证跳过: ${e.message?.slice(0, 100) || e}`);
|
|
341
|
-
}
|
|
342
|
-
// projects.defaultPath
|
|
330
|
+
// 通用配置
|
|
343
331
|
const defaultSuggestion = path.join(os.homedir(), 'evolclaw-project');
|
|
344
332
|
let defaultPath = (await ask(rl, ` 默认项目路径 [${defaultSuggestion}]: `)).trim();
|
|
345
|
-
if (!defaultPath)
|
|
333
|
+
if (!defaultPath)
|
|
346
334
|
defaultPath = defaultSuggestion;
|
|
347
|
-
}
|
|
348
335
|
if (defaultPath.startsWith('~/')) {
|
|
349
336
|
defaultPath = path.join(os.homedir(), defaultPath.slice(2));
|
|
350
337
|
}
|
|
@@ -355,19 +342,61 @@ export async function cmdInit() {
|
|
|
355
342
|
fs.mkdirSync(defaultPath, { recursive: true });
|
|
356
343
|
console.log(` ✓ 已创建目录: ${defaultPath}`);
|
|
357
344
|
}
|
|
358
|
-
// anthropic.model
|
|
359
345
|
const modelInput = (await ask(rl, ' 模型 [sonnet(默认)/opus/haiku]: ')).trim().toLowerCase();
|
|
360
346
|
const model = ['opus', 'haiku'].includes(modelInput) ? modelInput : 'sonnet';
|
|
361
|
-
//
|
|
347
|
+
// 渠道选择
|
|
348
|
+
console.log('\n选择消息渠道:');
|
|
349
|
+
console.log(' 1. 飞书 (Feishu)');
|
|
350
|
+
console.log(' 2. 微信 (WeChat)');
|
|
351
|
+
const channelChoice = (await ask(rl, '请选择 [1]: ')).trim() || '1';
|
|
362
352
|
const config = JSON.parse(fs.readFileSync(sampleSrc, 'utf-8'));
|
|
363
|
-
config.feishu.appId = appId;
|
|
364
|
-
config.feishu.appSecret = appSecret;
|
|
365
353
|
config.projects.defaultPath = defaultPath;
|
|
366
354
|
config.projects.list = { [path.basename(defaultPath)]: defaultPath };
|
|
367
|
-
config.anthropic.model = model;
|
|
355
|
+
config.agents.anthropic.model = model;
|
|
356
|
+
if (channelChoice === '1') {
|
|
357
|
+
console.log('\n飞书配置方式:');
|
|
358
|
+
console.log(' 1. 扫码自动注册(推荐)');
|
|
359
|
+
console.log(' 2. 手动输入 App ID/Secret');
|
|
360
|
+
const feishuMethod = (await ask(rl, '请选择 [1]: ')).trim() || '1';
|
|
361
|
+
if (feishuMethod === '1') {
|
|
362
|
+
const { runFeishuQrFlow } = await import('./init-feishu.js');
|
|
363
|
+
const result = await runFeishuQrFlow();
|
|
364
|
+
if (!result) {
|
|
365
|
+
console.log('已取消');
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
config.channels.feishu.appId = result.appId;
|
|
369
|
+
config.channels.feishu.appSecret = result.appSecret;
|
|
370
|
+
config.channels.feishu.enabled = true;
|
|
371
|
+
if (result.openId)
|
|
372
|
+
config.channels.feishu.owner = result.openId;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
if (!await initFeishuManual(rl, config)) {
|
|
376
|
+
console.log('已取消');
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else if (channelChoice === '2') {
|
|
382
|
+
const { runWechatQrFlow } = await import('./init-wechat.js');
|
|
383
|
+
const result = await runWechatQrFlow();
|
|
384
|
+
if (!result) {
|
|
385
|
+
console.log('已取消');
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
config.channels.wechat = {
|
|
389
|
+
enabled: true,
|
|
390
|
+
baseUrl: result.baseUrl,
|
|
391
|
+
token: result.token,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
console.log('无效选择');
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
368
398
|
fs.writeFileSync(p.config, JSON.stringify(config, null, 2) + '\n');
|
|
369
399
|
console.log(`\n✓ 已创建配置文件: ${p.config}`);
|
|
370
|
-
// Setup EVOLCLAW_HOME in shell profile
|
|
371
400
|
setupEnvVar(resolveRoot());
|
|
372
401
|
}
|
|
373
402
|
finally {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
1
2
|
/**
|
|
2
3
|
* 流式输出缓冲器
|
|
3
4
|
* 按时间窗口批量推送文本和活动事件
|
|
@@ -137,10 +138,10 @@ export class StreamFlusher {
|
|
|
137
138
|
const before = output;
|
|
138
139
|
output = output.replace(this.fileMarkerPattern, '').trim();
|
|
139
140
|
if (before !== output) {
|
|
140
|
-
|
|
141
|
+
logger.debug('[StreamFlusher] Removed file markers, before length:', before.length, 'after:', output.length);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
+
logger.debug('[StreamFlusher] flush called, output length:', output.length, 'isEmpty:', !output, 'preview:', output.substring(0, 100));
|
|
144
145
|
if (output) {
|
|
145
146
|
await this.send(output, isFinal);
|
|
146
147
|
this.sentContent = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolclaw",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Lightweight AI Agent gateway connecting Claude Agent SDK to messaging channels (Feishu, ACP) with multi-project session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,16 +23,17 @@
|
|
|
23
23
|
"prepublishOnly": "npm run build && npm test"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@anthropic-ai/claude-agent-sdk": "^0.2.
|
|
26
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.75",
|
|
27
27
|
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
28
|
+
"image-type": "^6.0.0",
|
|
29
|
+
"qrcode-terminal": "^0.12.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/node": "^
|
|
33
|
-
"@
|
|
32
|
+
"@types/node": "^25.5.0",
|
|
33
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
34
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
34
35
|
"tsx": "^4.19.0",
|
|
35
36
|
"typescript": "^5.6.0",
|
|
36
|
-
"vitest": "^
|
|
37
|
+
"vitest": "^4.1.0"
|
|
37
38
|
}
|
|
38
39
|
}
|