evolclaw 3.2.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 +53 -0
- package/README.md +7 -4
- package/dist/agents/{resolve.js → baseagent.js} +34 -5
- package/dist/agents/claude-runner.js +120 -31
- package/dist/agents/codex-app-server-client.js +364 -0
- package/dist/agents/codex-runner.js +1152 -140
- package/dist/agents/gemini-runner.js +2 -2
- package/dist/agents/runner-types.js +58 -0
- package/dist/aun/aid/store.js +1 -1
- package/dist/aun/outbox.js +14 -2
- package/dist/aun/storage/download.js +1 -1
- package/dist/aun/storage/upload.js +13 -1
- package/dist/channels/aun.js +869 -358
- package/dist/channels/dingtalk.js +77 -140
- package/dist/channels/feishu.js +125 -154
- package/dist/channels/qqbot.js +75 -138
- package/dist/channels/wechat.js +75 -136
- package/dist/channels/wecom.js +75 -138
- package/dist/cli/agent-command.js +591 -0
- package/dist/cli/agent.js +23 -8
- 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 +23 -4905
- package/dist/cli/init.js +33 -6
- package/dist/cli/model.js +1 -1
- package/dist/cli/restart-monitor.js +539 -0
- package/dist/cli/stats.js +558 -0
- package/dist/cli/version.js +87 -0
- package/dist/cli/watch-logs.js +33 -0
- package/dist/cli/watch-msg.js +5 -2
- package/dist/config-store.js +12 -6
- package/dist/core/channel-loader.js +88 -83
- 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 +82 -0
- package/dist/core/evolagent.js +17 -1
- package/dist/core/interaction-router.js +8 -0
- package/dist/core/message/command-handler-agent-control.js +63 -1
- package/dist/core/message/im-renderer.js +91 -51
- package/dist/core/message/items-formatter.js +9 -1
- package/dist/core/message/message-bridge.js +73 -24
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-processor.js +432 -94
- package/dist/core/message/message-queue.js +70 -2
- package/dist/core/message/pending-hints.js +232 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-scope.js +2 -2
- package/dist/core/permission.js +25 -12
- package/dist/core/relation/peer-identity.js +16 -1
- package/dist/core/session/adapters/codex-session-file-adapter.js +4 -2
- package/dist/core/session/session-manager.js +86 -26
- package/dist/core/session/session-title.js +26 -0
- package/dist/core/stats/billing.js +151 -0
- package/dist/core/stats/budget.js +93 -0
- package/dist/core/stats/db.js +334 -0
- package/dist/core/stats/eck-vars.js +84 -0
- package/dist/core/stats/index.js +10 -0
- package/dist/core/stats/normalizer.js +78 -0
- package/dist/core/stats/query.js +760 -0
- package/dist/core/stats/writer.js +115 -0
- package/dist/core/trigger/manager.js +34 -0
- package/dist/core/trigger/parser.js +9 -3
- package/dist/core/trigger/scheduler.js +20 -17
- package/dist/data/error-dict.json +7 -0
- package/dist/{agents → eck}/manifest-engine.js +20 -1
- package/dist/{agents → eck}/message-renderer.js +24 -1
- package/dist/index.js +174 -9
- package/dist/ipc.js +116 -1
- package/dist/utils/cross-platform.js +58 -5
- package/dist/utils/ecweb-launch.js +49 -0
- package/dist/utils/ecweb-pair.js +20 -0
- package/dist/utils/error-utils.js +18 -5
- package/dist/utils/npm-ops.js +38 -8
- package/dist/utils/stats.js +77 -6
- package/kits/docs/evolclaw/INDEX.md +3 -1
- package/kits/docs/evolclaw/fs-architecture.md +1215 -0
- package/kits/docs/evolclaw/fs.md +131 -0
- package/kits/docs/evolclaw/group-fs.md +209 -0
- package/kits/docs/evolclaw/stats.md +70 -0
- package/kits/docs/venues/aun-group.md +29 -6
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_message_manifest.json +30 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/templates/message-fragments/inject-default.md +2 -0
- package/package.json +5 -6
- package/dist/agents/baseagent-normalize.js +0 -19
- package/dist/core/command-handler.js +0 -3876
- package/dist/core/relation/peer-key.js +0 -16
- package/dist/evolclaw-config.js +0 -11
- package/dist/utils/channel-helpers.js +0 -46
- /package/dist/core/{cache/file-cache.js → daemon-file-cache.js} +0 -0
- /package/dist/{agents → eck}/kit-renderer.js +0 -0
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
|
}
|
|
@@ -104,6 +132,8 @@ export class AidStatsCollector {
|
|
|
104
132
|
queueStatsProvider;
|
|
105
133
|
/** sessionId → 当前正在跑该 session 的 agent,task:started 写入,task:completed/error 清除 */
|
|
106
134
|
sessionToAgent = new Map();
|
|
135
|
+
/** 外部注入的持久化回调(写入 message_events 表) */
|
|
136
|
+
onMessage;
|
|
107
137
|
constructor(eventBus) {
|
|
108
138
|
if (!eventBus)
|
|
109
139
|
return;
|
|
@@ -128,6 +158,14 @@ export class AidStatsCollector {
|
|
|
128
158
|
if (e.sessionId)
|
|
129
159
|
this.sessionToAgent.delete(e.sessionId);
|
|
130
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
|
+
});
|
|
131
169
|
// thought.put 次数 + 最后一次 thought 文本
|
|
132
170
|
// 注意:thought.put 是 fire-and-forget async,可能在 task:completed 之后才到达,
|
|
133
171
|
// 所以同时累加到 currentTask(task 进行中)或 lastTaskEnd(task 已结束但 thought 属于它)
|
|
@@ -192,7 +230,10 @@ export class AidStatsCollector {
|
|
|
192
230
|
lastSentTo: null,
|
|
193
231
|
lastSentEncrypt: null,
|
|
194
232
|
lastSentChatmode: null,
|
|
233
|
+
lastReceivedKind: null,
|
|
234
|
+
lastSentKind: null,
|
|
195
235
|
uniquePeers: new Set(),
|
|
236
|
+
recentMessages: [],
|
|
196
237
|
currentTaskStartAt: null,
|
|
197
238
|
currentTaskReplyCount: 0,
|
|
198
239
|
currentTaskThoughtPutCount: 0,
|
|
@@ -324,7 +365,7 @@ export class AidStatsCollector {
|
|
|
324
365
|
const entry = this.getOrCreate(aid);
|
|
325
366
|
entry.selfName = name;
|
|
326
367
|
}
|
|
327
|
-
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode) {
|
|
368
|
+
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
328
369
|
const entry = this.getOrCreate(aid);
|
|
329
370
|
if (isSystem) {
|
|
330
371
|
entry.systemReceived++;
|
|
@@ -339,11 +380,24 @@ export class AidStatsCollector {
|
|
|
339
380
|
entry.lastReceivedEncrypt = encrypt;
|
|
340
381
|
if (chatmode)
|
|
341
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
|
+
}
|
|
342
390
|
}
|
|
343
391
|
entry.bytesReceived += byteLength;
|
|
344
392
|
entry.uniquePeers.add(fromPeer);
|
|
393
|
+
// 持久化
|
|
394
|
+
this.onMessage?.({
|
|
395
|
+
ts: Date.now(), agent_aid: aid, peer_key: `aun#${fromPeer}`,
|
|
396
|
+
direction: 'in', msg_type: isSystem ? 'system' : 'private',
|
|
397
|
+
bytes: byteLength, encrypted: encrypt, chatmode,
|
|
398
|
+
});
|
|
345
399
|
}
|
|
346
|
-
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode) {
|
|
400
|
+
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
347
401
|
const entry = this.getOrCreate(aid);
|
|
348
402
|
if (isSystem) {
|
|
349
403
|
entry.systemSent++;
|
|
@@ -358,6 +412,13 @@ export class AidStatsCollector {
|
|
|
358
412
|
entry.lastSentEncrypt = encrypt;
|
|
359
413
|
if (chatmode)
|
|
360
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
|
+
}
|
|
361
422
|
// 累计当前 task 的回复数
|
|
362
423
|
if (entry.currentTaskStartAt != null) {
|
|
363
424
|
entry.currentTaskReplyCount++;
|
|
@@ -369,13 +430,19 @@ export class AidStatsCollector {
|
|
|
369
430
|
}
|
|
370
431
|
entry.bytesSent += byteLength;
|
|
371
432
|
entry.uniquePeers.add(toPeer);
|
|
433
|
+
// 持久化
|
|
434
|
+
this.onMessage?.({
|
|
435
|
+
ts: Date.now(), agent_aid: aid, peer_key: `aun#${toPeer}`,
|
|
436
|
+
direction: 'out', msg_type: isSystem ? 'system' : 'private',
|
|
437
|
+
bytes: byteLength, encrypted: encrypt, chatmode,
|
|
438
|
+
});
|
|
372
439
|
}
|
|
373
440
|
getAllSnapshots() {
|
|
374
441
|
const out = [];
|
|
375
442
|
for (const entry of this.entries.values()) {
|
|
376
443
|
const queueStats = this.queueStatsProvider
|
|
377
444
|
? this.queueStatsProvider(entry.aid)
|
|
378
|
-
: { processing: 0, queued: 0 };
|
|
445
|
+
: { processing: 0, queued: 0, muted: false };
|
|
379
446
|
out.push({
|
|
380
447
|
aid: entry.aid,
|
|
381
448
|
selfName: entry.selfName,
|
|
@@ -395,9 +462,13 @@ export class AidStatsCollector {
|
|
|
395
462
|
lastSentTo: entry.lastSentTo,
|
|
396
463
|
lastSentEncrypt: entry.lastSentEncrypt,
|
|
397
464
|
lastSentChatmode: entry.lastSentChatmode,
|
|
465
|
+
lastReceivedKind: entry.lastReceivedKind,
|
|
466
|
+
lastSentKind: entry.lastSentKind,
|
|
398
467
|
uniquePeerCount: entry.uniquePeers.size,
|
|
399
468
|
processing: queueStats.processing,
|
|
400
469
|
queued: queueStats.queued,
|
|
470
|
+
muted: queueStats.muted,
|
|
471
|
+
recentMessages: entry.recentMessages,
|
|
401
472
|
lastTaskEnd: entry.lastTaskEnd,
|
|
402
473
|
});
|
|
403
474
|
}
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
| `ec msg` | 私聊收发消息 | 回复/发消息/拉取/撤回/查在线 | 有对端(peerId) | `msg.md` |
|
|
15
15
|
| `ec group` | 群聊收发与群管理 | 群发/建群/邀请/踢人/退群/群成员 | 群聊(groupId) | `group.md` |
|
|
16
16
|
| `ec aid` | AID 身份管理 | 身份/证书/名片/探测对端 | 任意有渠道场景 | `aid.md` |
|
|
17
|
-
| `ec
|
|
17
|
+
| `ec fs` | 网络文件系统(统一前端) | 上传/下载/看文件/列目录/分享/共享/挂载/配额 | 任意有渠道场景 | `fs.md`(架构全景 `fs-architecture.md`) |
|
|
18
|
+
| `ec storage` | 文件存储(底层调试) | 上传/下载/配额 | 任意有渠道场景 | `storage.md` |
|
|
18
19
|
| `ec agent` | EvolAgent 生命周期 | 创建/启停/热重载/改配置 | 管理员(owner/admin) | `agent.md` |
|
|
19
20
|
| `ec rpc` | 底层 AUN RPC(逃生通道) | 直接调协议方法 | 高级/兜底 | `rpc.md` |
|
|
20
21
|
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
| 命令集 | 用途 | 触发词 | 文档 |
|
|
30
31
|
|--------|------|--------|------|
|
|
31
32
|
| `ec model` | 模型管理(按作用域持久化) | 切模型/列模型/看当前/改强度 | `model.md` |
|
|
33
|
+
| `ec stats` | Token 用量与费用统计 | 用量/费用/统计/预算/token/cost | `stats.md` |
|
|
32
34
|
|
|
33
35
|
## 开发者工具(非 agent 会话能力)
|
|
34
36
|
|