evolclaw 3.1.4 → 3.1.5
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 +10 -0
- package/dist/agents/claude-runner.js +348 -156
- package/dist/agents/kit-renderer.js +176 -21
- package/dist/aun/aid/agentmd.js +68 -103
- package/dist/aun/aid/client.js +1 -29
- package/dist/aun/aid/identity.js +105 -64
- package/dist/aun/aid/index.js +2 -1
- package/dist/aun/aid/store.js +74 -0
- package/dist/aun/msg/p2p.js +26 -2
- package/dist/aun/rpc/connection.js +23 -30
- package/dist/channels/aun.js +77 -88
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +270 -190
- package/dist/channels/qqbot.js +1 -0
- package/dist/channels/wechat.js +1 -0
- package/dist/channels/wecom.js +1 -0
- package/dist/cli/agent.js +11 -5
- package/dist/cli/bench.js +40 -23
- package/dist/cli/index.js +170 -44
- package/dist/cli/init-channel.js +5 -1
- package/dist/cli/model.js +324 -0
- package/dist/cli/net-check.js +133 -50
- package/dist/cli/watch-msg.js +7 -7
- package/dist/cli/watch-web/debug-log.js +18 -0
- package/dist/cli/watch-web/server.js +306 -0
- package/dist/cli/watch-web/sources/aid.js +63 -0
- package/dist/cli/watch-web/sources/msg.js +70 -0
- package/dist/cli/watch-web/sources/session.js +638 -0
- package/dist/cli/watch-web/sources/types.js +10 -0
- package/dist/cli/watch-web/static/app.js +546 -0
- package/dist/cli/watch-web/static/index.html +54 -0
- package/dist/cli/watch-web/static/style.css +247 -0
- package/dist/core/channel-loader.js +7 -4
- package/dist/core/command-handler.js +81 -86
- package/dist/core/evolagent-registry.js +1 -1
- package/dist/core/evolagent.js +4 -4
- package/dist/core/interaction-router.js +59 -0
- package/dist/core/message/message-bridge.js +6 -6
- package/dist/core/message/message-log.js +2 -2
- package/dist/core/message/message-processor.js +86 -101
- package/dist/core/message/stream-idle-monitor.js +21 -0
- package/dist/core/model/model-catalog.js +215 -0
- package/dist/core/model/model-scope.js +250 -0
- package/dist/core/relation/peer-identity.js +40 -49
- package/dist/core/relation/peer-key.js +16 -0
- package/dist/core/session/session-fs-store.js +34 -55
- package/dist/core/session/session-key.js +24 -0
- package/dist/core/session/session-manager.js +308 -251
- package/dist/core/session/session-mapper.js +9 -4
- package/dist/core/trigger/manager.js +3 -3
- package/dist/core/trigger/scheduler.js +2 -1
- package/dist/index.js +6 -2
- package/dist/ipc.js +22 -0
- package/kits/docs/GUIDE.md +2 -2
- package/kits/docs/INDEX.md +11 -7
- package/kits/docs/channels/aun.md +56 -17
- package/kits/docs/channels/feishu.md +41 -12
- package/kits/docs/context-assembly.md +181 -0
- package/kits/docs/evolclaw/agent.md +49 -0
- package/kits/docs/evolclaw/aid.md +49 -0
- package/kits/docs/evolclaw/ctl.md +46 -0
- package/kits/docs/evolclaw/group.md +82 -0
- package/kits/docs/evolclaw/msg.md +86 -0
- package/kits/docs/evolclaw/rpc.md +35 -0
- package/kits/docs/evolclaw/storage.md +49 -0
- package/kits/docs/venues/aun-group.md +10 -0
- package/kits/docs/venues/aun-private.md +10 -0
- package/kits/docs/venues/client-desktop.md +10 -0
- package/kits/docs/venues/client-mobile.md +10 -0
- package/kits/docs/venues/feishu-group.md +13 -0
- package/kits/docs/venues/feishu-private.md +9 -0
- package/kits/docs/venues/group.md +11 -0
- package/kits/docs/venues/private.md +10 -0
- package/kits/eck_manifest.json +72 -36
- package/kits/rules/01-overview.md +20 -10
- package/kits/rules/06-channel.md +30 -27
- package/kits/templates/system-fragments/session.md +10 -3
- package/kits/templates/system-fragments/venue.md +9 -0
- package/package.json +11 -6
- package/dist/aun/aid/lifecycle-log.js +0 -33
- package/dist/utils/aid-lifecycle-log.js +0 -33
- package/kits/docs/evolclaw/AGENT_CMD.md +0 -31
- package/kits/docs/evolclaw/MSG_GROUP.md +0 -30
- package/kits/docs/evolclaw/MSG_PRIVATE.md +0 -72
- package/kits/docs/evolclaw/tools.md +0 -25
package/dist/cli/agent.js
CHANGED
|
@@ -419,11 +419,14 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
419
419
|
catch (e) {
|
|
420
420
|
console.warn(` ⚠ agent.md generation failed: ${e?.message || e}`);
|
|
421
421
|
}
|
|
422
|
-
// Attempt hot-load via IPC (if daemon is running)
|
|
422
|
+
// Attempt hot-load via IPC (if daemon is running).
|
|
423
|
+
// Cold-starting a new agent (connecting AUN WebSocket) routinely takes
|
|
424
|
+
// >3s, so use a generous timeout to avoid a false "service not running"
|
|
425
|
+
// report while the daemon actually finishes bringing the agent online.
|
|
423
426
|
let hotLoaded = false;
|
|
424
427
|
let hotLoadError;
|
|
425
428
|
try {
|
|
426
|
-
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid });
|
|
429
|
+
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid }, 30_000);
|
|
427
430
|
if (ipcResult?.ok) {
|
|
428
431
|
hotLoaded = true;
|
|
429
432
|
}
|
|
@@ -569,11 +572,14 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
569
572
|
catch (e) {
|
|
570
573
|
console.warn(`⚠ agent.md generation failed: ${e?.message || e}`);
|
|
571
574
|
}
|
|
572
|
-
// Attempt hot-load via IPC (if daemon is running)
|
|
575
|
+
// Attempt hot-load via IPC (if daemon is running).
|
|
576
|
+
// Cold-starting a new agent (connecting AUN WebSocket) routinely takes
|
|
577
|
+
// >3s, so use a generous timeout to avoid a false "service not running"
|
|
578
|
+
// report while the daemon actually finishes bringing the agent online.
|
|
573
579
|
let hotLoaded = false;
|
|
574
580
|
let hotLoadError;
|
|
575
581
|
try {
|
|
576
|
-
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid });
|
|
582
|
+
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid }, 30_000);
|
|
577
583
|
if (ipcResult?.ok) {
|
|
578
584
|
hotLoaded = true;
|
|
579
585
|
}
|
|
@@ -829,7 +835,7 @@ export async function agentChannelUpsert(opts) {
|
|
|
829
835
|
return {
|
|
830
836
|
ok: true,
|
|
831
837
|
aid: opts.aid,
|
|
832
|
-
channelKey: `${opts.channel.type}#${
|
|
838
|
+
channelKey: `${opts.channel.type}#${opts.aid}#${opts.channel.name}`,
|
|
833
839
|
reloaded,
|
|
834
840
|
};
|
|
835
841
|
}
|
package/dist/cli/bench.js
CHANGED
|
@@ -7,7 +7,7 @@ import { promisify } from 'util';
|
|
|
7
7
|
import { aidList, aidCreate } from '../aun/aid/identity.js';
|
|
8
8
|
import { msgSend, msgPull } from '../aun/msg/index.js';
|
|
9
9
|
import { getPackageRoot, aunPath as defaultAunPath } from '../paths.js';
|
|
10
|
-
import {
|
|
10
|
+
import { getAidStore, loadClient, SLOT } from '../aun/aid/store.js';
|
|
11
11
|
import { isHelpFlag } from './help.js';
|
|
12
12
|
const execFileAsync = promisify(execFile);
|
|
13
13
|
// ==================== ANSI ====================
|
|
@@ -248,34 +248,48 @@ function computeMetrics(results, received, durationSec) {
|
|
|
248
248
|
function filterBySize(results, received, cls, durationSec) {
|
|
249
249
|
return computeMetrics(results.filter(r => r.sizeClass === cls), received.filter(r => r.sizeClass === cls), durationSec);
|
|
250
250
|
}
|
|
251
|
-
async function benchAuth(aids, concurrency, aunPath
|
|
252
|
-
const
|
|
253
|
-
const tasks = aids.map(aid => async () => {
|
|
251
|
+
async function benchAuth(aids, concurrency, aunPath) {
|
|
252
|
+
const tasks = aids.map((aid, index) => async () => {
|
|
254
253
|
const start = Date.now();
|
|
254
|
+
const slotId = `${SLOT.bench}-${index}`;
|
|
255
|
+
let store = null;
|
|
256
|
+
let client = null;
|
|
255
257
|
try {
|
|
256
|
-
|
|
257
|
-
await
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
await client.connect({ access_token: accessToken, gateway, slot_id: slotId ?? '', connection_kind: 'short' }, { auto_reconnect: false });
|
|
258
|
+
store = await getAidStore({ slotId, aunPath });
|
|
259
|
+
client = await loadClient(store, aid);
|
|
260
|
+
await client.connect({ auto_reconnect: false });
|
|
261
|
+
const gateway = ''; // Gateway URL not exposed in 0.4.3
|
|
262
|
+
const authMs = Date.now() - start;
|
|
262
263
|
try {
|
|
263
264
|
await client.close();
|
|
264
265
|
}
|
|
265
266
|
catch { }
|
|
266
|
-
|
|
267
|
+
try {
|
|
268
|
+
store.close();
|
|
269
|
+
}
|
|
270
|
+
catch { }
|
|
271
|
+
return { aid, ok: true, authMs, gateway };
|
|
267
272
|
}
|
|
268
273
|
catch (e) {
|
|
274
|
+
if (client)
|
|
275
|
+
try {
|
|
276
|
+
await client.close();
|
|
277
|
+
}
|
|
278
|
+
catch { }
|
|
279
|
+
if (store)
|
|
280
|
+
try {
|
|
281
|
+
store.close();
|
|
282
|
+
}
|
|
283
|
+
catch { }
|
|
269
284
|
return { aid, ok: false, authMs: Date.now() - start, error: e.message };
|
|
270
285
|
}
|
|
271
286
|
});
|
|
272
287
|
return runPool(tasks, concurrency);
|
|
273
288
|
}
|
|
274
|
-
async function benchSwitch(aids, rounds, aunPath, useCli,
|
|
289
|
+
async function benchSwitch(aids, rounds, aunPath, useCli, encrypt) {
|
|
275
290
|
const results = [];
|
|
276
291
|
const start = Date.now();
|
|
277
292
|
let seq = 0;
|
|
278
|
-
const slot = slotId ?? 'bench';
|
|
279
293
|
for (let round = 0; round < rounds; round++) {
|
|
280
294
|
for (let i = 0; i < aids.length; i++) {
|
|
281
295
|
const from = aids[i];
|
|
@@ -286,8 +300,9 @@ async function benchSwitch(aids, rounds, aunPath, useCli, slotId, encrypt) {
|
|
|
286
300
|
let ok = false;
|
|
287
301
|
let serverTimestamp;
|
|
288
302
|
if (useCli) {
|
|
303
|
+
const slotId = `${SLOT.bench}-${i}`;
|
|
289
304
|
try {
|
|
290
|
-
const res = await withTimeout(cliSend(from, to, text,
|
|
305
|
+
const res = await withTimeout(cliSend(from, to, text, slotId, encrypt), 10000, `${from.split('.')[0]}→${to.split('.')[0]}`);
|
|
291
306
|
ok = res.ok;
|
|
292
307
|
serverTimestamp = res.timestamp;
|
|
293
308
|
}
|
|
@@ -296,8 +311,9 @@ async function benchSwitch(aids, rounds, aunPath, useCli, slotId, encrypt) {
|
|
|
296
311
|
}
|
|
297
312
|
}
|
|
298
313
|
else {
|
|
314
|
+
const slotId = `${SLOT.bench}-${i}`;
|
|
299
315
|
try {
|
|
300
|
-
const res = await withTimeout(msgSend({ from, to, body: { mode: 'text', text }, slotId
|
|
316
|
+
const res = await withTimeout(msgSend({ from, to, body: { mode: 'text', text }, slotId, aunPath, encrypt }), 10000, `${from.split('.')[0]}→${to.split('.')[0]}`);
|
|
301
317
|
ok = res.ok;
|
|
302
318
|
serverTimestamp = res.ok ? res.timestamp : undefined;
|
|
303
319
|
}
|
|
@@ -392,7 +408,6 @@ Options:
|
|
|
392
408
|
const defaultWait = encrypt ? '10' : '3';
|
|
393
409
|
const waitSec = Math.max(1, parseInt(getArgValue(args, '--wait') || defaultWait, 10));
|
|
394
410
|
const sessionId = crypto.randomBytes(4).toString('hex');
|
|
395
|
-
const benchSlot = `bench-${sessionId}`;
|
|
396
411
|
if (!formatJson) {
|
|
397
412
|
console.log(`\n${BOLD} evolclaw bench${RST} — AUN 消息性能基准测试`);
|
|
398
413
|
console.log(` ${'━'.repeat(50)}`);
|
|
@@ -495,14 +510,15 @@ Options:
|
|
|
495
510
|
authTasks.push(...aids);
|
|
496
511
|
let authResults;
|
|
497
512
|
if (cliMode) {
|
|
498
|
-
const cliAuthTasks = authTasks.map(aid => async () => {
|
|
499
|
-
const
|
|
513
|
+
const cliAuthTasks = authTasks.map((aid, index) => async () => {
|
|
514
|
+
const slotId = `${SLOT.bench}-${index}`;
|
|
515
|
+
const r = await cliAuth(aid, slotId);
|
|
500
516
|
return { aid, ok: r.ok, authMs: r.authMs };
|
|
501
517
|
});
|
|
502
518
|
authResults = await runPool(cliAuthTasks, concurrency);
|
|
503
519
|
}
|
|
504
520
|
else {
|
|
505
|
-
authResults = await benchAuth(authTasks, concurrency, aunPath
|
|
521
|
+
authResults = await benchAuth(authTasks, concurrency, aunPath);
|
|
506
522
|
}
|
|
507
523
|
const authOk = authResults.filter(r => r.ok);
|
|
508
524
|
const authFail = authResults.filter(r => !r.ok);
|
|
@@ -592,7 +608,7 @@ Options:
|
|
|
592
608
|
// Suppress SDK error logs during send phase (we track errors ourselves)
|
|
593
609
|
const origError2 = console.error;
|
|
594
610
|
console.error = () => { };
|
|
595
|
-
const sendFns = tasks.map(t => async () => {
|
|
611
|
+
const sendFns = tasks.map((t, taskIndex) => async () => {
|
|
596
612
|
let lastError;
|
|
597
613
|
let retries = 0;
|
|
598
614
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -605,10 +621,11 @@ Options:
|
|
|
605
621
|
? buildFileChunkText(t.seq, fileChunks.length, sendTs, sessionId, fileChunks[t.seq]?.toString('base64') ?? '')
|
|
606
622
|
: buildMessageText(t.seq, t.sizeClass, sendTs, sessionId);
|
|
607
623
|
const t0 = Date.now();
|
|
624
|
+
const slotId = `${SLOT.bench}-${taskIndex % concurrency}`;
|
|
608
625
|
try {
|
|
609
626
|
const sendPromise = cliMode
|
|
610
|
-
? cliSend(t.from, t.to, text,
|
|
611
|
-
: msgSend({ from: t.from, to: t.to, body: { mode: 'text', text }, slotId
|
|
627
|
+
? cliSend(t.from, t.to, text, slotId, encrypt)
|
|
628
|
+
: msgSend({ from: t.from, to: t.to, body: { mode: 'text', text }, slotId, aunPath, encrypt });
|
|
612
629
|
const res = await withTimeout(sendPromise, SEND_TIMEOUT_MS, `${t.from.split('.')[0]}→${t.to.split('.')[0]}`);
|
|
613
630
|
if (cliMode) {
|
|
614
631
|
const cliRes = res;
|
|
@@ -922,7 +939,7 @@ Options:
|
|
|
922
939
|
if (!formatJson)
|
|
923
940
|
console.log(`${DIM} Phase 5: 频繁切换账号收发测试${RST}`);
|
|
924
941
|
const switchRounds = Math.max(2, Math.min(rounds, 5));
|
|
925
|
-
const switchOut = await benchSwitch(aids, switchRounds, aunPath, cliMode,
|
|
942
|
+
const switchOut = await benchSwitch(aids, switchRounds, aunPath, cliMode, encrypt);
|
|
926
943
|
const switchOkResults = switchOut.results.filter(r => r.ok);
|
|
927
944
|
const switchLatencies = switchOkResults
|
|
928
945
|
.filter(r => r.serverTimestamp !== undefined)
|
package/dist/cli/index.js
CHANGED
|
@@ -884,8 +884,8 @@ async function cmdStatus() {
|
|
|
884
884
|
const configChannelNames = new Set();
|
|
885
885
|
for (const cfg of agents) {
|
|
886
886
|
for (const inst of cfg.channels) {
|
|
887
|
-
// effective key: <type>#<
|
|
888
|
-
configChannelNames.add(`${inst.type}#${
|
|
887
|
+
// effective key: <type>#<selfAID>#<name>
|
|
888
|
+
configChannelNames.add(`${inst.type}#${cfg.aid}#${inst.name}`);
|
|
889
889
|
}
|
|
890
890
|
}
|
|
891
891
|
for (const s of allSessions) {
|
|
@@ -1014,7 +1014,7 @@ async function cmdStatus() {
|
|
|
1014
1014
|
}
|
|
1015
1015
|
}
|
|
1016
1016
|
/**
|
|
1017
|
-
* 把 channel fingerprint 列表(`<type>#<
|
|
1017
|
+
* 把 channel fingerprint 列表(`<type>#<selfAID>#<name>`)折叠成展示用摘要。
|
|
1018
1018
|
*
|
|
1019
1019
|
* 聚合规则:
|
|
1020
1020
|
* - 按 type 分组
|
|
@@ -1414,6 +1414,7 @@ async function cmdWatchMenu() {
|
|
|
1414
1414
|
{ key: 'log', label: 'log', desc: 'real-time log tail' },
|
|
1415
1415
|
{ key: 'aid', label: 'aid', desc: 'AID connection stats' },
|
|
1416
1416
|
{ key: 'msg', label: 'msg', desc: 'message inspector' },
|
|
1417
|
+
{ key: 'web', label: 'web', desc: 'browser dashboard (aid/msg/session)' },
|
|
1417
1418
|
];
|
|
1418
1419
|
let index = 0;
|
|
1419
1420
|
const useColor = !!process.stdout.isTTY;
|
|
@@ -1477,6 +1478,9 @@ async function cmdWatchMenu() {
|
|
|
1477
1478
|
const { cmdWatchMsg } = await import('./watch-msg.js');
|
|
1478
1479
|
await cmdWatchMsg();
|
|
1479
1480
|
}
|
|
1481
|
+
else if (chosen === 'web') {
|
|
1482
|
+
await cmdWatchWeb();
|
|
1483
|
+
}
|
|
1480
1484
|
resolve();
|
|
1481
1485
|
}
|
|
1482
1486
|
};
|
|
@@ -2098,6 +2102,97 @@ async function cmdWatchAid() {
|
|
|
2098
2102
|
}
|
|
2099
2103
|
platform.onShutdown(cleanup);
|
|
2100
2104
|
}
|
|
2105
|
+
async function cmdWatchWeb() {
|
|
2106
|
+
const p = resolvePaths();
|
|
2107
|
+
fs.mkdirSync(p.instanceDir, { recursive: true });
|
|
2108
|
+
const useColor = !!process.stdout.isTTY;
|
|
2109
|
+
const RST = useColor ? '\x1b[0m' : '';
|
|
2110
|
+
const DIM = useColor ? '\x1b[2m' : '';
|
|
2111
|
+
const BOLD = useColor ? '\x1b[1m' : '';
|
|
2112
|
+
const CYAN = useColor ? '\x1b[36m' : '';
|
|
2113
|
+
const GREEN = useColor ? '\x1b[32m' : '';
|
|
2114
|
+
const YELLOW = useColor ? '\x1b[33m' : '';
|
|
2115
|
+
const logLine = (line) => {
|
|
2116
|
+
const t = new Date();
|
|
2117
|
+
const ts = `${String(t.getHours()).padStart(2, '0')}:${String(t.getMinutes()).padStart(2, '0')}:${String(t.getSeconds()).padStart(2, '0')}`;
|
|
2118
|
+
process.stdout.write(`${DIM}${ts}${RST} ${line}\n`);
|
|
2119
|
+
};
|
|
2120
|
+
// 调试日志文件:每次运行 watch web 时清空,便于建立调试闭环
|
|
2121
|
+
// 查看 sessions 调试日志 → 读这个文件
|
|
2122
|
+
const logFile = path.join(p.logs, 'watch-web.log');
|
|
2123
|
+
try {
|
|
2124
|
+
fs.mkdirSync(p.logs, { recursive: true });
|
|
2125
|
+
fs.writeFileSync(logFile, `# watch-web debug log\n# started ${new Date().toISOString()} pid=${process.pid}\n`);
|
|
2126
|
+
}
|
|
2127
|
+
catch { /* best effort */ }
|
|
2128
|
+
const fileLog = (line) => {
|
|
2129
|
+
const t = new Date();
|
|
2130
|
+
const ts = `${String(t.getHours()).padStart(2, '0')}:${String(t.getMinutes()).padStart(2, '0')}:${String(t.getSeconds()).padStart(2, '0')}.${String(t.getMilliseconds()).padStart(3, '0')}`;
|
|
2131
|
+
try {
|
|
2132
|
+
fs.appendFileSync(logFile, `${ts} ${line.replace(/\x1b\[[0-9;]*m/g, '')}\n`);
|
|
2133
|
+
}
|
|
2134
|
+
catch { /* ignore */ }
|
|
2135
|
+
};
|
|
2136
|
+
// 同时输出到终端和日志文件
|
|
2137
|
+
const log = (line) => { logLine(line); fileLog(line); };
|
|
2138
|
+
const { startWatchWebServer } = await import('./watch-web/server.js');
|
|
2139
|
+
let handle;
|
|
2140
|
+
try {
|
|
2141
|
+
handle = await startWatchWebServer({ log });
|
|
2142
|
+
}
|
|
2143
|
+
catch (e) {
|
|
2144
|
+
console.error(`❌ 启动 Web 服务失败: ${e?.message || e}`);
|
|
2145
|
+
process.exit(1);
|
|
2146
|
+
}
|
|
2147
|
+
// 注册 instance 文件
|
|
2148
|
+
const instanceFile = path.join(p.instanceDir, `watch-web-${process.pid}.json`);
|
|
2149
|
+
fs.writeFileSync(instanceFile, JSON.stringify({
|
|
2150
|
+
pid: process.pid, startedAt: Date.now(), startedAtIso: new Date().toISOString(),
|
|
2151
|
+
type: 'watch-web', port: handle.port,
|
|
2152
|
+
}, null, 2));
|
|
2153
|
+
// 列出本机访问地址
|
|
2154
|
+
const os = await import('os');
|
|
2155
|
+
const ifaces = os.networkInterfaces();
|
|
2156
|
+
const lanIps = [];
|
|
2157
|
+
for (const list of Object.values(ifaces)) {
|
|
2158
|
+
for (const ni of list || []) {
|
|
2159
|
+
if (ni.family === 'IPv4' && !ni.internal)
|
|
2160
|
+
lanIps.push(ni.address);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
process.stdout.write(`\n${BOLD}${CYAN}🔭 EvolClaw Watch Web${RST}\n\n`);
|
|
2164
|
+
process.stdout.write(` ${BOLD}配对码:${RST} ${GREEN}${BOLD}${handle.pairingCode}${RST} ${DIM}(5 分钟内有效,配对后 token 缓存 24h 自动续期)${RST}\n\n`);
|
|
2165
|
+
process.stdout.write(` ${BOLD}本机:${RST} http://localhost:${handle.port}\n`);
|
|
2166
|
+
for (const ip of lanIps) {
|
|
2167
|
+
process.stdout.write(` ${BOLD}局域网:${RST} http://${ip}:${handle.port}\n`);
|
|
2168
|
+
}
|
|
2169
|
+
process.stdout.write(`\n ${DIM}绑定 0.0.0.0,远程可访问。按任意键退出。${RST}\n`);
|
|
2170
|
+
process.stdout.write(` ${DIM}调试日志: ${logFile}${RST}\n\n`);
|
|
2171
|
+
const cleanup = () => {
|
|
2172
|
+
try {
|
|
2173
|
+
fs.unlinkSync(instanceFile);
|
|
2174
|
+
}
|
|
2175
|
+
catch { }
|
|
2176
|
+
handle.close().finally(() => process.exit(0));
|
|
2177
|
+
};
|
|
2178
|
+
process.on('exit', () => { try {
|
|
2179
|
+
fs.unlinkSync(instanceFile);
|
|
2180
|
+
}
|
|
2181
|
+
catch { } });
|
|
2182
|
+
process.on('SIGINT', cleanup);
|
|
2183
|
+
process.on('SIGTERM', cleanup);
|
|
2184
|
+
platform.onShutdown(cleanup);
|
|
2185
|
+
// 按任意键退出
|
|
2186
|
+
if (process.stdin.isTTY) {
|
|
2187
|
+
process.stdin.setRawMode(true);
|
|
2188
|
+
process.stdin.resume();
|
|
2189
|
+
process.stdin.on('data', (key) => {
|
|
2190
|
+
logLine(`${YELLOW}收到退出指令,关闭服务…${RST}`);
|
|
2191
|
+
cleanup();
|
|
2192
|
+
});
|
|
2193
|
+
}
|
|
2194
|
+
await new Promise(() => { });
|
|
2195
|
+
}
|
|
2101
2196
|
async function cmdRestartMonitor() {
|
|
2102
2197
|
const p = resolvePaths();
|
|
2103
2198
|
const restartLog = path.join(p.logs, 'restart.log');
|
|
@@ -2472,14 +2567,13 @@ function archiveSelfHealLog(p, log) {
|
|
|
2472
2567
|
* Searches across all channel types (feishu, wechat, aun) for a matching instance.
|
|
2473
2568
|
*/
|
|
2474
2569
|
function resolveInstanceConfig(instanceName) {
|
|
2475
|
-
// 新结构:channel key 是 <type>#<
|
|
2570
|
+
// 新结构:channel key 是 <type>#<selfAID>#<name>,解析后从对应 agent 的 channels[] 找
|
|
2476
2571
|
const parts = instanceName.split('#');
|
|
2477
2572
|
if (parts.length === 3) {
|
|
2478
|
-
const [type,
|
|
2479
|
-
const selfPeerId = decodeURIComponent(encodedSelfPeerId);
|
|
2573
|
+
const [type, selfAID, name] = parts;
|
|
2480
2574
|
const { agents } = loadAllAgents();
|
|
2481
|
-
// AUN channel 的
|
|
2482
|
-
const agent = agents.find(a => a.aid ===
|
|
2575
|
+
// AUN channel 的 selfAID 就是 agent.aid
|
|
2576
|
+
const agent = agents.find(a => a.aid === selfAID);
|
|
2483
2577
|
if (!agent)
|
|
2484
2578
|
return null;
|
|
2485
2579
|
const inst = agent.channels.find((c) => c.type === type && c.name === name);
|
|
@@ -3467,7 +3561,7 @@ Options:
|
|
|
3467
3561
|
console.log('无匹配 AID');
|
|
3468
3562
|
return;
|
|
3469
3563
|
}
|
|
3470
|
-
console.log(`本地 AID${noVerify ? '(静态扫描,未实测)' : ''}
|
|
3564
|
+
console.log(`本地 AID${noVerify ? '(静态扫描,未实测)' : ''}(${aunPath ?? resolveRoot()}):`);
|
|
3471
3565
|
for (const a of aids) {
|
|
3472
3566
|
const keyIcon = a.hasPrivateKey ? '🔑' : ' ';
|
|
3473
3567
|
let signIcon = ' ';
|
|
@@ -3533,40 +3627,63 @@ Options:
|
|
|
3533
3627
|
}
|
|
3534
3628
|
if (sub === 'new') {
|
|
3535
3629
|
if (wantsHelp(args)) {
|
|
3536
|
-
console.log(`用法: evolclaw aid new <完整AID>
|
|
3630
|
+
console.log(`用法: evolclaw aid new <完整AID> [--force]
|
|
3537
3631
|
|
|
3538
3632
|
创建新 AID 身份:生成 ECDSA 密钥对、向 Issuer 申请证书、构建并上传初始 agent.md。
|
|
3539
3633
|
|
|
3540
|
-
|
|
3634
|
+
选项:
|
|
3635
|
+
--force 强制重新注册,覆盖已存在的身份(即使签名验证失败)
|
|
3636
|
+
|
|
3637
|
+
例: evolclaw aid new reviewer.agentid.pub
|
|
3638
|
+
evolclaw aid new reviewer.agentid.pub --force`);
|
|
3541
3639
|
return;
|
|
3542
3640
|
}
|
|
3543
3641
|
const aid = args[1];
|
|
3642
|
+
const force = args.includes('--force');
|
|
3544
3643
|
if (!aid) {
|
|
3545
|
-
console.error('用法: evolclaw aid new <完整AID
|
|
3644
|
+
console.error('用法: evolclaw aid new <完整AID> [--force]\n例: evolclaw aid new reviewer.agentid.pub');
|
|
3546
3645
|
process.exit(1);
|
|
3547
3646
|
}
|
|
3548
3647
|
if (!isValidAid(aid)) {
|
|
3549
3648
|
console.error(`❌ 无效 AID 格式: ${aid}`);
|
|
3550
3649
|
process.exit(1);
|
|
3551
3650
|
}
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3651
|
+
try {
|
|
3652
|
+
const result = await aidCreate(aid, { aunPath, force });
|
|
3653
|
+
if (!result.alreadyExisted) {
|
|
3654
|
+
const content = buildInitialAgentMd({ aid });
|
|
3655
|
+
try {
|
|
3656
|
+
await agentmdPut(content, { aid, aunPath });
|
|
3657
|
+
console.log('✓ agent.md 已发布');
|
|
3658
|
+
}
|
|
3659
|
+
catch (e) {
|
|
3660
|
+
console.warn(`⚠ agent.md 发布失败(首次连接将自动重试): ${String(e.message || e).slice(0, 100)}`);
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3555
3663
|
try {
|
|
3556
|
-
await
|
|
3557
|
-
console.log('✓ agent.md 已发布');
|
|
3664
|
+
await result.client.close();
|
|
3558
3665
|
}
|
|
3559
|
-
catch
|
|
3560
|
-
|
|
3666
|
+
catch { }
|
|
3667
|
+
try {
|
|
3668
|
+
result.store?.close();
|
|
3561
3669
|
}
|
|
3670
|
+
catch { }
|
|
3671
|
+
const verb = result.alreadyExisted ? '已存在且有效' : (force ? '已重新创建' : '已创建');
|
|
3672
|
+
console.log(`✓ ${aid} ${verb}`);
|
|
3673
|
+
console.log(' 如需上线 AUN 通道,运行 evolclaw agent new ' + aid);
|
|
3562
3674
|
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3675
|
+
catch (e) {
|
|
3676
|
+
if (e.code === 'AID_INVALID') {
|
|
3677
|
+
console.error(`❌ ${e.message}`);
|
|
3678
|
+
process.exit(1);
|
|
3679
|
+
}
|
|
3680
|
+
if (e.code === -32052 || e.constructor?.name === 'IdentityConflictError') {
|
|
3681
|
+
console.error(`❌ AID ${aid} 已在服务端注册,但本地密钥无法匹配。\n` +
|
|
3682
|
+
`该 AID 可能由其他设备创建,无法在本地恢复。请选择其他名称。`);
|
|
3683
|
+
process.exit(1);
|
|
3684
|
+
}
|
|
3685
|
+
throw e;
|
|
3565
3686
|
}
|
|
3566
|
-
catch { }
|
|
3567
|
-
const verb = result.alreadyExisted ? '已存在' : '已创建';
|
|
3568
|
-
console.log(`✓ ${aid} ${verb}`);
|
|
3569
|
-
console.log(' 如需上线 AUN 通道,运行 evolclaw agent new ' + aid);
|
|
3570
3687
|
return;
|
|
3571
3688
|
}
|
|
3572
3689
|
if (sub === 'delete') {
|
|
@@ -4069,7 +4186,6 @@ async function cmdMsg(args) {
|
|
|
4069
4186
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
4070
4187
|
const appIdx = args.indexOf('--app');
|
|
4071
4188
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
4072
|
-
const asDaemon = args.includes('--as-daemon');
|
|
4073
4189
|
if (!sub || isHelpFlag(sub)) {
|
|
4074
4190
|
console.log(`用法: evolclaw msg <command> <from-aid> [args...] [options]
|
|
4075
4191
|
|
|
@@ -4079,13 +4195,12 @@ Commands:
|
|
|
4079
4195
|
send <from> <to> --link <url> [--title T] 发送链接卡片
|
|
4080
4196
|
send <from> <to> --payload <json> 发送自定义 payload
|
|
4081
4197
|
pull <from> [--after-seq N] [--limit N] 拉取收件箱
|
|
4082
|
-
ack <from> <seq> --app <name>
|
|
4198
|
+
ack <from> <seq> [--app <name>] 确认已读
|
|
4083
4199
|
recall <from> <message-id> [<message-id>...] 撤回消息
|
|
4084
4200
|
online <from> <target-aid> [<target-aid>...] 查询在线状态
|
|
4085
4201
|
|
|
4086
4202
|
Options:
|
|
4087
|
-
--app <name> 指定应用 slot
|
|
4088
|
-
--as-daemon ack 时显式以 daemon 身份(高危,会污染 daemon 游标)
|
|
4203
|
+
--app <name> 指定应用 slot(独立消费通道,不影响 daemon)
|
|
4089
4204
|
--format json 输出 JSON 格式
|
|
4090
4205
|
--encrypt 启用端到端加密
|
|
4091
4206
|
--thread <id> 指定话题 ID(用于多话题路由)
|
|
@@ -4211,7 +4326,7 @@ Options:
|
|
|
4211
4326
|
}
|
|
4212
4327
|
if (sub === 'pull') {
|
|
4213
4328
|
if (!appSlot) {
|
|
4214
|
-
console.
|
|
4329
|
+
console.warn('⚠ 警告: 未传 --app,当前与 daemon 共享 evolclaw 消费通道。pull 会看到/影响 daemon 的消息消费;如需独立消费请用 --app <name>');
|
|
4215
4330
|
}
|
|
4216
4331
|
const afterSeqStr = getArgValue(args, '--after-seq');
|
|
4217
4332
|
const limitStr = getArgValue(args, '--limit');
|
|
@@ -4253,7 +4368,7 @@ Options:
|
|
|
4253
4368
|
if (sub === 'ack') {
|
|
4254
4369
|
const seqStr = args[2];
|
|
4255
4370
|
if (!seqStr) {
|
|
4256
|
-
console.error('用法: evolclaw msg ack <from> <seq> --app <name>');
|
|
4371
|
+
console.error('用法: evolclaw msg ack <from> <seq> [--app <name>]');
|
|
4257
4372
|
process.exit(1);
|
|
4258
4373
|
}
|
|
4259
4374
|
const seq = Number(seqStr);
|
|
@@ -4261,10 +4376,8 @@ Options:
|
|
|
4261
4376
|
console.error(`❌ seq 必须是数字: ${seqStr}`);
|
|
4262
4377
|
process.exit(1);
|
|
4263
4378
|
}
|
|
4264
|
-
if (!appSlot
|
|
4265
|
-
console.
|
|
4266
|
-
console.error(' 理由: 不传 --app 会推进 daemon 共享的 ack 游标,导致 daemon 丢消息');
|
|
4267
|
-
process.exit(1);
|
|
4379
|
+
if (!appSlot) {
|
|
4380
|
+
console.warn('⚠ 警告: 未传 --app,ack 将推进与 daemon 共享的 evolclaw 消费游标,可能影响 daemon 收消息;如需独立请用 --app <name>');
|
|
4268
4381
|
}
|
|
4269
4382
|
const result = await msgAck({ from, seq, ...commonOpts });
|
|
4270
4383
|
if (!result.ok) {
|
|
@@ -4355,7 +4468,6 @@ async function cmdGroup(args) {
|
|
|
4355
4468
|
const formatJson = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
4356
4469
|
const appIdx = args.indexOf('--app');
|
|
4357
4470
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
4358
|
-
const asDaemon = args.includes('--as-daemon');
|
|
4359
4471
|
if (!sub || isHelpFlag(sub)) {
|
|
4360
4472
|
console.log(`用法: evolclaw group <command> <from-aid> [args...] [options]
|
|
4361
4473
|
|
|
@@ -4364,7 +4476,7 @@ async function cmdGroup(args) {
|
|
|
4364
4476
|
send <from> <group-id> --file <path> [--as <type>] 发送群文件
|
|
4365
4477
|
send <from> <group-id> --payload <json> 发送自定义 payload
|
|
4366
4478
|
pull <from> <group-id> [--after-seq N] [--limit N] 拉取群消息
|
|
4367
|
-
ack <from> <group-id> <seq> --app <name>
|
|
4479
|
+
ack <from> <group-id> <seq> [--app <name>] 确认已读
|
|
4368
4480
|
|
|
4369
4481
|
群管理:
|
|
4370
4482
|
create <from> <name> [--visibility public|private] [--description D] [--join-mode M] 创建群
|
|
@@ -4382,8 +4494,7 @@ async function cmdGroup(args) {
|
|
|
4382
4494
|
online <from> <group-id> 查看在线成员
|
|
4383
4495
|
|
|
4384
4496
|
Options:
|
|
4385
|
-
--app <name> 指定应用 slot
|
|
4386
|
-
--as-daemon ack 时显式以 daemon 身份(高危)
|
|
4497
|
+
--app <name> 指定应用 slot(独立消费通道,不影响 daemon)
|
|
4387
4498
|
--format json 输出 JSON 格式
|
|
4388
4499
|
--mention <aid> 发送时 @ 某个成员(可多次)
|
|
4389
4500
|
--mention-all 发送时 @ 所有人
|
|
@@ -4496,7 +4607,7 @@ Options:
|
|
|
4496
4607
|
if (sub === 'pull') {
|
|
4497
4608
|
const groupId = requireGroupId();
|
|
4498
4609
|
if (!appSlot) {
|
|
4499
|
-
console.
|
|
4610
|
+
console.warn('⚠ 警告: 未传 --app,当前与 daemon 共享 evolclaw 消费通道。pull 会看到/影响 daemon 的消息消费;如需独立消费请用 --app <name>');
|
|
4500
4611
|
}
|
|
4501
4612
|
const afterSeqStr = getArgValue(args, '--after-seq');
|
|
4502
4613
|
const limitStr = getArgValue(args, '--limit');
|
|
@@ -4517,7 +4628,7 @@ Options:
|
|
|
4517
4628
|
const groupId = requireGroupId();
|
|
4518
4629
|
const seqStr = args[3];
|
|
4519
4630
|
if (!seqStr) {
|
|
4520
|
-
console.error('用法: evolclaw group ack <from> <group-id> <seq> --app <name>');
|
|
4631
|
+
console.error('用法: evolclaw group ack <from> <group-id> <seq> [--app <name>]');
|
|
4521
4632
|
process.exit(1);
|
|
4522
4633
|
}
|
|
4523
4634
|
const seq = Number(seqStr);
|
|
@@ -4525,9 +4636,8 @@ Options:
|
|
|
4525
4636
|
console.error(`❌ seq 必须是数字: ${seqStr}`);
|
|
4526
4637
|
process.exit(1);
|
|
4527
4638
|
}
|
|
4528
|
-
if (!appSlot
|
|
4529
|
-
console.
|
|
4530
|
-
process.exit(1);
|
|
4639
|
+
if (!appSlot) {
|
|
4640
|
+
console.warn('⚠ 警告: 未传 --app,ack 将推进与 daemon 共享的 evolclaw 消费游标,可能影响 daemon 收消息;如需独立请用 --app <name>');
|
|
4531
4641
|
}
|
|
4532
4642
|
const result = await groupAck({ from, groupId, seq, ...commonOpts });
|
|
4533
4643
|
outputResult(result, () => {
|
|
@@ -4857,6 +4967,9 @@ export async function main(args) {
|
|
|
4857
4967
|
else if (args[1] === 'log') {
|
|
4858
4968
|
cmdWatch();
|
|
4859
4969
|
}
|
|
4970
|
+
else if (args[1] === 'web' || args[1] === 'session') {
|
|
4971
|
+
await cmdWatchWeb();
|
|
4972
|
+
}
|
|
4860
4973
|
else if (!args[1]) {
|
|
4861
4974
|
await cmdWatchMenu();
|
|
4862
4975
|
}
|
|
@@ -4920,6 +5033,11 @@ export async function main(args) {
|
|
|
4920
5033
|
await cmdGroup(args.slice(1));
|
|
4921
5034
|
break;
|
|
4922
5035
|
}
|
|
5036
|
+
case 'model': {
|
|
5037
|
+
const { cmdModel } = await import('./model.js');
|
|
5038
|
+
await cmdModel(args.slice(1));
|
|
5039
|
+
break;
|
|
5040
|
+
}
|
|
4923
5041
|
case 'bench': {
|
|
4924
5042
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
4925
5043
|
suppressSdkLogs();
|
|
@@ -4970,6 +5088,14 @@ Commands:
|
|
|
4970
5088
|
--force (覆盖已有 config.json)
|
|
4971
5089
|
agent reload 全量 resync(扫磁盘,新增上线、删除下线、修改热更新)
|
|
4972
5090
|
agent reload <n> 热重载指定 agent 配置
|
|
5091
|
+
model 模型管理(查看/切换,作用域:全局/agent/关系/会话)
|
|
5092
|
+
model list 列出可用模型,标注各作用域命中
|
|
5093
|
+
model current 显示实际生效的模型 + 来源
|
|
5094
|
+
model info <id> 查看单个模型详情(价格/上下文/模态等)
|
|
5095
|
+
model use <id> 切换模型(--self/--peer/--session 决定作用域)
|
|
5096
|
+
model effort <lv> 设置推理强度
|
|
5097
|
+
model reset 清除指定作用域设置,回落上一级
|
|
5098
|
+
model help 查看完整用法
|
|
4973
5099
|
aid AID 身份管理
|
|
4974
5100
|
aid list 列出本地所有 AID
|
|
4975
5101
|
aid show <aid> 查看本地 AID 详情(证书有效期、私钥状态)
|
package/dist/cli/init-channel.js
CHANGED
|
@@ -463,7 +463,7 @@ export async function setupAunAid(rl, _config) {
|
|
|
463
463
|
const agentType = typeInput === 'human' ? 'human' : 'ai';
|
|
464
464
|
const content = buildInitialAgentMd({ aid, type: agentType });
|
|
465
465
|
try {
|
|
466
|
-
await agentmdPut(content, { aid
|
|
466
|
+
await agentmdPut(content, { aid });
|
|
467
467
|
console.log(' ✓ agent.md 已发布并写入本地');
|
|
468
468
|
}
|
|
469
469
|
catch (e) {
|
|
@@ -484,6 +484,10 @@ export async function setupAunAid(rl, _config) {
|
|
|
484
484
|
await result.client.close();
|
|
485
485
|
}
|
|
486
486
|
catch { /* ignore */ }
|
|
487
|
+
try {
|
|
488
|
+
result.store?.close();
|
|
489
|
+
}
|
|
490
|
+
catch { /* ignore */ }
|
|
487
491
|
}
|
|
488
492
|
catch (e) {
|
|
489
493
|
const msg = e.message || String(e);
|