evolclaw 3.3.0 → 3.4.0
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/CHANGELOG.md +36 -0
- package/README.md +7 -3
- package/dist/agents/claude-runner.js +23 -27
- package/dist/agents/codex-runner.js +90 -6
- package/dist/agents/runner-types.js +30 -0
- package/dist/aun/outbox.js +14 -2
- package/dist/channels/aun.js +506 -108
- package/dist/channels/feishu.js +29 -5
- package/dist/cli/agent-command.js +591 -0
- package/dist/cli/agent.js +15 -3
- package/dist/cli/aun-commands.js +1444 -0
- package/dist/cli/ctl-command.js +78 -0
- package/dist/cli/daemon-commands.js +2707 -0
- package/dist/cli/index.js +12 -5027
- package/dist/cli/restart-monitor.js +539 -0
- package/dist/cli/watch-logs.js +33 -0
- package/dist/core/channel-loader.js +4 -1
- package/dist/core/command/command-handler.js +1189 -0
- package/dist/core/command/menu-handler.js +1478 -0
- package/dist/core/command/slash-gate.js +142 -0
- package/dist/core/command/slash-handler.js +2090 -0
- package/dist/core/evolagent-registry.js +81 -0
- package/dist/core/evolagent.js +16 -0
- package/dist/core/message/im-renderer.js +67 -49
- package/dist/core/message/message-bridge.js +30 -9
- package/dist/core/message/message-processor.js +200 -122
- package/dist/core/message/message-queue.js +68 -0
- package/dist/core/permission.js +16 -0
- package/dist/core/session/session-manager.js +59 -13
- package/dist/core/stats/db.js +20 -0
- package/dist/core/stats/writer.js +3 -3
- package/dist/data/error-dict.json +7 -0
- package/dist/index.js +49 -6
- package/dist/ipc.js +99 -0
- package/dist/utils/cross-platform.js +35 -0
- package/dist/utils/ecweb-launch.js +49 -0
- package/dist/utils/error-utils.js +18 -5
- package/dist/utils/npm-ops.js +38 -8
- package/dist/utils/stats.js +63 -6
- package/kits/eck_manifest.json +0 -12
- package/package.json +2 -3
- package/dist/core/command-handler.js +0 -4235
- package/dist/core/message/response-depth.js +0 -56
- package/kits/templates/system-fragments/response-depth.md +0 -16
package/dist/utils/npm-ops.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import path from 'path';
|
|
11
|
-
import { execFile } from 'child_process';
|
|
11
|
+
import { execFile, execSync } from 'child_process';
|
|
12
12
|
import { promisify } from 'util';
|
|
13
13
|
import { getPackageRoot } from '../paths.js';
|
|
14
14
|
import { isWindows } from './cross-platform.js';
|
|
@@ -92,6 +92,28 @@ export function getLocalVersion() {
|
|
|
92
92
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
93
93
|
return pkg.version;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* 解析全局安装包的已装版本(通过 `npm root -g` 定位全局 node_modules)。
|
|
97
|
+
* 用于 evolclaw-web 这类独立全局命令包——它们不在 evolclaw 的依赖树里。
|
|
98
|
+
* 未安装或查询失败返回 null。
|
|
99
|
+
*/
|
|
100
|
+
export function resolveGlobalPkg(pkgName) {
|
|
101
|
+
try {
|
|
102
|
+
// 命令完全静态(npm root -g,无用户输入),用 execSync 传完整命令字符串,
|
|
103
|
+
// 避免 "args 数组 + shell:true" 组合触发 Node DeprecationWarning,且无注入风险。
|
|
104
|
+
const npmCmd = isWindows ? 'npm.cmd' : 'npm';
|
|
105
|
+
const globalRoot = execSync(`${npmCmd} root -g`, {
|
|
106
|
+
encoding: 'utf-8', timeout: 10000,
|
|
107
|
+
}).trim();
|
|
108
|
+
const pkgPath = path.join(globalRoot, ...pkgName.split('/'), 'package.json');
|
|
109
|
+
if (fs.existsSync(pkgPath)) {
|
|
110
|
+
const data = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
111
|
+
return { version: data.version, path: pkgPath };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch { /* not found */ }
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
95
117
|
/**
|
|
96
118
|
* 查询 npm registry 上指定包的最新版本。
|
|
97
119
|
* 使用 HTTP fetch 直接查 registry API,不依赖 npm CLI。
|
|
@@ -147,19 +169,20 @@ export async function tryUpgrade() {
|
|
|
147
169
|
return { status: 'failed', from: localVer, to: remoteVer, error: lastError };
|
|
148
170
|
}
|
|
149
171
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
172
|
+
* 通用全局包升级流程:检查 → 比较 → 安装(失败重试一次)。
|
|
173
|
+
* 仅在包已安装时检查升级,未安装则跳过(resolveFn 返回 null)。
|
|
174
|
+
* fastaun / evolclaw-web 等独立全局包共用此逻辑。
|
|
152
175
|
*/
|
|
153
|
-
export async function
|
|
176
|
+
export async function tryUpgradeGlobalPkg(resolveInstalled, pkgName) {
|
|
154
177
|
if (isLinkedInstall()) {
|
|
155
178
|
return { status: 'skipped' };
|
|
156
179
|
}
|
|
157
|
-
const installed =
|
|
180
|
+
const installed = resolveInstalled();
|
|
158
181
|
if (!installed) {
|
|
159
|
-
return { status: 'skipped' }; //
|
|
182
|
+
return { status: 'skipped' }; // not installed, skip
|
|
160
183
|
}
|
|
161
184
|
const localVer = installed.version;
|
|
162
|
-
const remoteVer = await checkLatestVersion(
|
|
185
|
+
const remoteVer = await checkLatestVersion(pkgName);
|
|
163
186
|
if (!remoteVer) {
|
|
164
187
|
return { status: 'skipped', error: 'Failed to check remote version' };
|
|
165
188
|
}
|
|
@@ -169,7 +192,7 @@ export async function tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG) {
|
|
|
169
192
|
let lastError;
|
|
170
193
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
171
194
|
try {
|
|
172
|
-
await npmInstallGlobal(`${
|
|
195
|
+
await npmInstallGlobal(`${pkgName}@latest`);
|
|
173
196
|
return { status: 'upgraded', from: localVer, to: remoteVer };
|
|
174
197
|
}
|
|
175
198
|
catch (e) {
|
|
@@ -178,3 +201,10 @@ export async function tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG) {
|
|
|
178
201
|
}
|
|
179
202
|
return { status: 'failed', from: localVer, to: remoteVer, error: lastError };
|
|
180
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* AUN SDK 升级流程:检查 → 比较 → 安装
|
|
206
|
+
* 仅在 SDK 已安装时检查升级,未安装则跳过。
|
|
207
|
+
*/
|
|
208
|
+
export async function tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG) {
|
|
209
|
+
return tryUpgradeGlobalPkg(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG);
|
|
210
|
+
}
|
package/dist/utils/stats.js
CHANGED
|
@@ -2,6 +2,8 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
export class StatsCollector {
|
|
4
4
|
events = [];
|
|
5
|
+
recentErrors = [];
|
|
6
|
+
MAX_RECENT_ERRORS = 50;
|
|
5
7
|
startTime;
|
|
6
8
|
HOUR_MS = 3_600_000;
|
|
7
9
|
constructor(eventBus) {
|
|
@@ -17,7 +19,12 @@ export class StatsCollector {
|
|
|
17
19
|
});
|
|
18
20
|
eventBus.subscribe('task:error', (event) => {
|
|
19
21
|
const e = event;
|
|
20
|
-
|
|
22
|
+
const ts = Date.now();
|
|
23
|
+
this.recordEvent({ type: 'error', timestamp: ts, errorType: e.errorType, agentName: e.agentName });
|
|
24
|
+
this.recordRecentError({
|
|
25
|
+
ts, kind: 'task', agentName: e.agentName, errorType: e.errorType,
|
|
26
|
+
message: this.truncate(e.error),
|
|
27
|
+
});
|
|
21
28
|
});
|
|
22
29
|
eventBus.subscribe('task:interrupted', (event) => {
|
|
23
30
|
const e = event;
|
|
@@ -26,10 +33,26 @@ export class StatsCollector {
|
|
|
26
33
|
eventBus.subscribe('tool:result', (event) => {
|
|
27
34
|
const e = event;
|
|
28
35
|
if (e.isError) {
|
|
29
|
-
|
|
36
|
+
const ts = Date.now();
|
|
37
|
+
this.recordEvent({ type: 'tool-error', timestamp: ts, toolName: e.toolName, agentName: e.agentName });
|
|
38
|
+
this.recordRecentError({
|
|
39
|
+
ts, kind: 'tool', agentName: e.agentName, toolName: e.toolName,
|
|
40
|
+
});
|
|
30
41
|
}
|
|
31
42
|
});
|
|
32
43
|
}
|
|
44
|
+
truncate(s) {
|
|
45
|
+
if (!s)
|
|
46
|
+
return undefined;
|
|
47
|
+
const oneLine = String(s).replace(/\s+/g, ' ').trim();
|
|
48
|
+
return oneLine.length > 200 ? oneLine.slice(0, 200) + '…' : oneLine;
|
|
49
|
+
}
|
|
50
|
+
recordRecentError(err) {
|
|
51
|
+
this.recentErrors.unshift(err); // 新在前
|
|
52
|
+
if (this.recentErrors.length > this.MAX_RECENT_ERRORS) {
|
|
53
|
+
this.recentErrors.length = this.MAX_RECENT_ERRORS;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
33
56
|
recordEvent(record) {
|
|
34
57
|
this.events.push(record);
|
|
35
58
|
}
|
|
@@ -84,6 +107,10 @@ export class StatsCollector {
|
|
|
84
107
|
break;
|
|
85
108
|
}
|
|
86
109
|
}
|
|
110
|
+
// 最近错误:按 agent 过滤(与上面一致),取前 20 条
|
|
111
|
+
const recentErrors = (agentName === undefined
|
|
112
|
+
? this.recentErrors
|
|
113
|
+
: this.recentErrors.filter(e => (e.agentName ?? '<unknown>') === agentName)).slice(0, 20);
|
|
87
114
|
return {
|
|
88
115
|
uptimeMs: now - this.startTime,
|
|
89
116
|
lastHour: {
|
|
@@ -95,7 +122,8 @@ export class StatsCollector {
|
|
|
95
122
|
toolErrorsByName,
|
|
96
123
|
interrupts,
|
|
97
124
|
avgResponseMs: durationCount > 0 ? totalDuration / durationCount : 0
|
|
98
|
-
}
|
|
125
|
+
},
|
|
126
|
+
recentErrors,
|
|
99
127
|
};
|
|
100
128
|
}
|
|
101
129
|
}
|
|
@@ -130,6 +158,14 @@ export class AidStatsCollector {
|
|
|
130
158
|
if (e.sessionId)
|
|
131
159
|
this.sessionToAgent.delete(e.sessionId);
|
|
132
160
|
});
|
|
161
|
+
// 用户主动打断(新消息//stop/撤回):任务有自己的生命周期收尾,不计为 error
|
|
162
|
+
eventBus.subscribe('task:interrupted', (event) => {
|
|
163
|
+
const e = event;
|
|
164
|
+
if (e.agentName)
|
|
165
|
+
this.onTaskEnd(e.agentName, 'interrupted');
|
|
166
|
+
if (e.sessionId)
|
|
167
|
+
this.sessionToAgent.delete(e.sessionId);
|
|
168
|
+
});
|
|
133
169
|
// thought.put 次数 + 最后一次 thought 文本
|
|
134
170
|
// 注意:thought.put 是 fire-and-forget async,可能在 task:completed 之后才到达,
|
|
135
171
|
// 所以同时累加到 currentTask(task 进行中)或 lastTaskEnd(task 已结束但 thought 属于它)
|
|
@@ -194,7 +230,10 @@ export class AidStatsCollector {
|
|
|
194
230
|
lastSentTo: null,
|
|
195
231
|
lastSentEncrypt: null,
|
|
196
232
|
lastSentChatmode: null,
|
|
233
|
+
lastReceivedKind: null,
|
|
234
|
+
lastSentKind: null,
|
|
197
235
|
uniquePeers: new Set(),
|
|
236
|
+
recentMessages: [],
|
|
198
237
|
currentTaskStartAt: null,
|
|
199
238
|
currentTaskReplyCount: 0,
|
|
200
239
|
currentTaskThoughtPutCount: 0,
|
|
@@ -326,7 +365,7 @@ export class AidStatsCollector {
|
|
|
326
365
|
const entry = this.getOrCreate(aid);
|
|
327
366
|
entry.selfName = name;
|
|
328
367
|
}
|
|
329
|
-
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode) {
|
|
368
|
+
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
330
369
|
const entry = this.getOrCreate(aid);
|
|
331
370
|
if (isSystem) {
|
|
332
371
|
entry.systemReceived++;
|
|
@@ -341,6 +380,13 @@ export class AidStatsCollector {
|
|
|
341
380
|
entry.lastReceivedEncrypt = encrypt;
|
|
342
381
|
if (chatmode)
|
|
343
382
|
entry.lastReceivedChatmode = chatmode;
|
|
383
|
+
entry.lastReceivedKind = kind;
|
|
384
|
+
// ring buffer:最近 10 轮
|
|
385
|
+
if (text) {
|
|
386
|
+
entry.recentMessages.unshift({ dir: 'in', peer: fromPeer, text: text.slice(0, 100), ts: Date.now(), kind, encrypt: encrypt ?? null, chatmode: chatmode ?? null });
|
|
387
|
+
if (entry.recentMessages.length > 10)
|
|
388
|
+
entry.recentMessages.pop();
|
|
389
|
+
}
|
|
344
390
|
}
|
|
345
391
|
entry.bytesReceived += byteLength;
|
|
346
392
|
entry.uniquePeers.add(fromPeer);
|
|
@@ -351,7 +397,7 @@ export class AidStatsCollector {
|
|
|
351
397
|
bytes: byteLength, encrypted: encrypt, chatmode,
|
|
352
398
|
});
|
|
353
399
|
}
|
|
354
|
-
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode) {
|
|
400
|
+
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
355
401
|
const entry = this.getOrCreate(aid);
|
|
356
402
|
if (isSystem) {
|
|
357
403
|
entry.systemSent++;
|
|
@@ -366,6 +412,13 @@ export class AidStatsCollector {
|
|
|
366
412
|
entry.lastSentEncrypt = encrypt;
|
|
367
413
|
if (chatmode)
|
|
368
414
|
entry.lastSentChatmode = chatmode;
|
|
415
|
+
entry.lastSentKind = kind;
|
|
416
|
+
// ring buffer:最近 10 轮
|
|
417
|
+
if (text) {
|
|
418
|
+
entry.recentMessages.unshift({ dir: 'out', peer: toPeer, text: text.slice(0, 100), ts: Date.now(), kind, encrypt: encrypt ?? null, chatmode: chatmode ?? null });
|
|
419
|
+
if (entry.recentMessages.length > 10)
|
|
420
|
+
entry.recentMessages.pop();
|
|
421
|
+
}
|
|
369
422
|
// 累计当前 task 的回复数
|
|
370
423
|
if (entry.currentTaskStartAt != null) {
|
|
371
424
|
entry.currentTaskReplyCount++;
|
|
@@ -389,7 +442,7 @@ export class AidStatsCollector {
|
|
|
389
442
|
for (const entry of this.entries.values()) {
|
|
390
443
|
const queueStats = this.queueStatsProvider
|
|
391
444
|
? this.queueStatsProvider(entry.aid)
|
|
392
|
-
: { processing: 0, queued: 0 };
|
|
445
|
+
: { processing: 0, queued: 0, muted: false };
|
|
393
446
|
out.push({
|
|
394
447
|
aid: entry.aid,
|
|
395
448
|
selfName: entry.selfName,
|
|
@@ -409,9 +462,13 @@ export class AidStatsCollector {
|
|
|
409
462
|
lastSentTo: entry.lastSentTo,
|
|
410
463
|
lastSentEncrypt: entry.lastSentEncrypt,
|
|
411
464
|
lastSentChatmode: entry.lastSentChatmode,
|
|
465
|
+
lastReceivedKind: entry.lastReceivedKind,
|
|
466
|
+
lastSentKind: entry.lastSentKind,
|
|
412
467
|
uniquePeerCount: entry.uniquePeers.size,
|
|
413
468
|
processing: queueStats.processing,
|
|
414
469
|
queued: queueStats.queued,
|
|
470
|
+
muted: queueStats.muted,
|
|
471
|
+
recentMessages: entry.recentMessages,
|
|
415
472
|
lastTaskEnd: entry.lastTaskEnd,
|
|
416
473
|
});
|
|
417
474
|
}
|
package/kits/eck_manifest.json
CHANGED
|
@@ -100,18 +100,6 @@
|
|
|
100
100
|
"when": { "var": "clientType", "neq": null },
|
|
101
101
|
"description": "客户端环境文档"
|
|
102
102
|
},
|
|
103
|
-
{
|
|
104
|
-
"id": "response-depth",
|
|
105
|
-
"type": "file",
|
|
106
|
-
"file": "$KITS_FRAGMENTS/response-depth.md",
|
|
107
|
-
"order": 45,
|
|
108
|
-
"needsInjection": true,
|
|
109
|
-
"when": { "and": [
|
|
110
|
-
{ "var": "chatType", "eq": "group" },
|
|
111
|
-
{ "var": "responseDepth", "in": ["lightweight", "deep"] }
|
|
112
|
-
]},
|
|
113
|
-
"description": "群聊响应深度指引(lightweight/deep 时注入)"
|
|
114
|
-
},
|
|
115
103
|
{
|
|
116
104
|
"id": "channel-layer",
|
|
117
105
|
"type": "file",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolclaw",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
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",
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@agentunion/fastaun": "^0.4.13",
|
|
36
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
37
|
-
"@anthropic-ai/sdk": "^0.100.1",
|
|
36
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.170",
|
|
38
37
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
39
38
|
"cron-parser": "^5.5.0",
|
|
40
39
|
"dotenv": "^17.4.2",
|