evolclaw 3.1.2 → 3.1.4
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 +38 -0
- package/README.md +2 -6
- package/assets/.env.template +4 -0
- package/assets/config.json.template +6 -0
- package/assets/wechat-group-qr.jpeg +0 -0
- package/dist/agents/claude-runner.js +1 -1
- package/dist/agents/codex-runner.js +75 -19
- package/dist/agents/gemini-runner.js +0 -2
- package/dist/agents/kit-renderer.js +85 -22
- package/dist/aun/aid/agentmd.js +67 -74
- package/dist/aun/aid/client.js +22 -7
- package/dist/aun/aid/identity.js +314 -28
- package/dist/aun/aid/index.js +2 -2
- package/dist/aun/rpc/connection.js +8 -10
- package/dist/channels/aun.js +53 -41
- package/dist/cli/agent.js +28 -28
- package/dist/cli/bench.js +8 -14
- package/dist/cli/help.js +23 -0
- package/dist/cli/index.js +398 -73
- package/dist/cli/init-channel.js +2 -3
- package/dist/cli/init.js +13 -6
- package/dist/cli/link-rules.js +2 -1
- package/dist/cli/net-check.js +10 -11
- package/dist/core/command-handler.js +621 -541
- package/dist/core/evolagent.js +31 -0
- package/dist/core/message/im-renderer.js +10 -0
- package/dist/core/message/message-bridge.js +123 -24
- package/dist/core/message/message-processor.js +61 -31
- package/dist/core/relation/peer-identity.js +64 -21
- package/dist/core/session/session-manager.js +191 -44
- package/dist/core/trigger/manager.js +37 -0
- package/dist/index.js +4 -1
- package/dist/paths.js +87 -16
- package/dist/utils/npm-ops.js +18 -11
- package/kits/eck_manifest.json +9 -9
- package/kits/rules/02-navigation.md +1 -0
- package/kits/rules/05-venue.md +2 -2
- package/kits/rules/06-channel.md +2 -18
- package/kits/templates/system-fragments/baseagent.md +8 -2
- package/kits/templates/system-fragments/channel.md +20 -8
- package/kits/templates/system-fragments/identity.md +5 -6
- package/kits/templates/system-fragments/relation.md +10 -5
- package/kits/templates/system-fragments/session.md +20 -0
- package/kits/templates/system-fragments/venue.md +5 -3
- package/package.json +4 -2
- package/dist/net-check.js +0 -640
- package/dist/watch-msg.js +0 -544
- package/kits/templates/system-fragments/runtime.md +0 -19
package/dist/channels/aun.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GatewayDiscovery, E2EEError } from '@agentunion/fastaun';
|
|
2
2
|
import crypto from 'crypto';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
@@ -6,13 +6,14 @@ import os from 'os';
|
|
|
6
6
|
import { logger, localTimestamp } from '../utils/logger.js';
|
|
7
7
|
import { LogWriter } from '../utils/log-writer.js';
|
|
8
8
|
import { normalizeChannelInstances, getChannelShowActivities } from '../utils/channel-helpers.js';
|
|
9
|
-
import { resolvePaths, getPackageRoot, agentMdPath as agentMdPathFn, agentDir as agentDirPath } from '../paths.js';
|
|
9
|
+
import { resolvePaths, getPackageRoot, agentMdPath as agentMdPathFn, agentDir as agentDirPath, resolveRoot } from '../paths.js';
|
|
10
10
|
import { saveToUploads, sanitizeFileName } from '../utils/media-cache.js';
|
|
11
11
|
import { appendAidEvent } from '../utils/instance-registry.js';
|
|
12
12
|
import { appendMessageLog, buildOutboundEntry } from '../core/message/message-log.js';
|
|
13
13
|
import { chatDirPath } from '../core/session/session-fs-store.js';
|
|
14
14
|
import { appendAidLifecycle } from '../aun/aid/identity.js';
|
|
15
|
-
import {
|
|
15
|
+
import { createAunClient } from '../aun/aid/client.js';
|
|
16
|
+
import { loadAgent, saveAgent, loadProcessConfig } from '../config-store.js';
|
|
16
17
|
import { getProcessStartTime } from '../utils/process-introspect.js';
|
|
17
18
|
import * as outbox from '../aun/outbox.js';
|
|
18
19
|
import { guessMime, formatSize } from '../utils/media-cache.js';
|
|
@@ -445,6 +446,10 @@ export class AUNChannel {
|
|
|
445
446
|
'text', 'quote', 'image', 'video', 'voice', 'file', 'json',
|
|
446
447
|
'merge', 'link', 'location', 'personal_card',
|
|
447
448
|
]);
|
|
449
|
+
/** Menu protocol 请求类型:自定义消息快速路径,绕过白名单直接分发到 bridge */
|
|
450
|
+
static MENU_REQUEST_TYPES = new Set([
|
|
451
|
+
'menu.list', 'menu.query', 'menu.options', 'menu.update', 'menu.action',
|
|
452
|
+
]);
|
|
448
453
|
// Reconnect state
|
|
449
454
|
// SDK 自己跑无限指数退避(1s → 5min);TS 层只在 SDK 够不到的两类场景下接管:
|
|
450
455
|
// 1. flap:短命 connected 反复出现(SDK 不记忆跨轮 base delay,会从 1s 重新开始)
|
|
@@ -541,9 +546,12 @@ export class AUNChannel {
|
|
|
541
546
|
this.client = null;
|
|
542
547
|
}
|
|
543
548
|
this.connected = false;
|
|
544
|
-
const aunPath = this.config.keystorePath ||
|
|
549
|
+
const aunPath = this.config.keystorePath || resolveRoot();
|
|
545
550
|
const aidName = this.config.aid;
|
|
546
|
-
const encryptionSeed =
|
|
551
|
+
const encryptionSeed = loadProcessConfig().aun?.encryptionSeed
|
|
552
|
+
|| process.env.AUN_ENCRYPTION_SEED
|
|
553
|
+
|| 'evol';
|
|
554
|
+
// Migration from ~/.aun is handled by ensureDataDirs() at startup with a marker file.
|
|
547
555
|
// Gateway URL 解析:优先用配置的 gatewayUrl,否则通过 well-known 自动发现
|
|
548
556
|
let gateway = this.config.gatewayUrl || '';
|
|
549
557
|
if (!gateway) {
|
|
@@ -565,39 +573,39 @@ export class AUNChannel {
|
|
|
565
573
|
logger.info(`${this.logPrefix()} Initializing: aid=${aidName}, gateway=${gateway}, aun_path=${aunPath}`);
|
|
566
574
|
// Create client with FileSecretStore (AES-256-GCM)
|
|
567
575
|
// 不传 encryption_seed 时,SDK 自动从 {aun_path}/.seed 文件派生密钥(与 aun_cli.py 对齐)
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
576
|
+
const client = await createAunClient({
|
|
577
|
+
aunPath,
|
|
578
|
+
encryptionSeed,
|
|
579
|
+
aunSdkLog: this.config.aunSdkLog ?? true,
|
|
580
|
+
});
|
|
581
|
+
this.client = client;
|
|
574
582
|
// Set gateway URL (internal property, same as Python SDK)
|
|
575
|
-
|
|
583
|
+
client._gatewayUrl = gateway;
|
|
576
584
|
// Register event handlers before connecting
|
|
577
|
-
|
|
585
|
+
client.on('message.received', (data) => {
|
|
578
586
|
this.trace('IN', 'message.received', data);
|
|
579
587
|
const kind = (data && typeof data === 'object') ? data.kind ?? '' : '';
|
|
580
588
|
const keys = (data && typeof data === 'object') ? Object.keys(data).join(',') : typeof data;
|
|
581
589
|
logger.debug(`${this.logPrefix()}[DIAG] message.received: kind=${kind} keys=${keys}`);
|
|
582
590
|
this.handleIncomingPrivateMessage(data);
|
|
583
591
|
});
|
|
584
|
-
|
|
592
|
+
client.on('group.message_created', (data) => {
|
|
585
593
|
this.trace('IN', 'group.message_created', data);
|
|
586
594
|
const gid = (data && typeof data === 'object') ? data.group_id ?? '' : '';
|
|
587
595
|
const sender = (data && typeof data === 'object') ? data.sender_aid ?? '' : '';
|
|
588
596
|
logger.debug(`${this.logPrefix()}[DIAG] group.message_created: group_id=${gid} sender=${sender}`);
|
|
589
597
|
this.handleIncomingGroupMessage(data);
|
|
590
598
|
});
|
|
591
|
-
|
|
599
|
+
client.on('connection.state', (data) => {
|
|
592
600
|
// trace is handled inside handleConnectionState with throttling
|
|
593
601
|
this.handleConnectionState(data);
|
|
594
602
|
});
|
|
595
603
|
// gateway 被踢/服务端主动断开(含同槽位互踢的 self/new extra_info)
|
|
596
|
-
|
|
604
|
+
client.on('gateway.disconnect', (data) => {
|
|
597
605
|
this.trace('IN', 'gateway.disconnect', data);
|
|
598
606
|
this.handleGatewayDisconnect(data);
|
|
599
607
|
});
|
|
600
|
-
|
|
608
|
+
client.on('message.recalled', (data) => {
|
|
601
609
|
this.trace('IN', 'message.recalled', data);
|
|
602
610
|
if (data && typeof data === 'object') {
|
|
603
611
|
const ids = data.message_ids;
|
|
@@ -611,12 +619,12 @@ export class AUNChannel {
|
|
|
611
619
|
}
|
|
612
620
|
}
|
|
613
621
|
});
|
|
614
|
-
|
|
622
|
+
client.on('message.undecryptable', (data) => {
|
|
615
623
|
this.trace('IN', 'message.undecryptable', data);
|
|
616
624
|
const d = data;
|
|
617
625
|
logger.warn(`${this.logPrefix()} Message undecryptable: from=${d.from} mid=${d.message_id} err=${d._decrypt_error}`);
|
|
618
626
|
});
|
|
619
|
-
|
|
627
|
+
client.on('group.message_undecryptable', (data) => {
|
|
620
628
|
this.trace('IN', 'group.message_undecryptable', data);
|
|
621
629
|
const d = data;
|
|
622
630
|
logger.warn(`${this.logPrefix()} Group message undecryptable: group=${d.group_id} from=${d.from} mid=${d.message_id} err=${d._decrypt_error}`);
|
|
@@ -624,7 +632,7 @@ export class AUNChannel {
|
|
|
624
632
|
// Authenticate
|
|
625
633
|
// Workaround: SDK 0.3.x _loadIdentityOrRaise doesn't set identity.aid from requested aid,
|
|
626
634
|
// causing gateway "missing aid" error. Patch to backfill aid on loaded identity.
|
|
627
|
-
const authFlow =
|
|
635
|
+
const authFlow = client._auth;
|
|
628
636
|
if (authFlow && typeof authFlow._loadIdentityOrRaise === 'function') {
|
|
629
637
|
const origLoad = authFlow._loadIdentityOrRaise.bind(authFlow);
|
|
630
638
|
authFlow._loadIdentityOrRaise = (aid) => {
|
|
@@ -638,12 +646,12 @@ export class AUNChannel {
|
|
|
638
646
|
try {
|
|
639
647
|
logger.info(`${this.logPrefix()} Authenticating as ${aidName}...`);
|
|
640
648
|
this.trace('OUT', 'auth.authenticate', { aid: aidName });
|
|
641
|
-
const auth = await
|
|
649
|
+
const auth = await client.auth.authenticate(aidName ? { aid: aidName } : undefined);
|
|
642
650
|
this.trace('OUT', 'auth.authenticate.ok', { aid: auth.aid, gateway: auth.gateway, hasToken: !!auth.access_token });
|
|
643
651
|
this.trace('IN', 'auth.result', { aid: auth.aid, gateway: auth.gateway, hasToken: !!auth.access_token });
|
|
644
652
|
accessToken = auth.access_token;
|
|
645
653
|
const resolvedGateway = auth.gateway || gateway;
|
|
646
|
-
|
|
654
|
+
client._gatewayUrl = resolvedGateway;
|
|
647
655
|
logger.info(`${this.logPrefix()} Authenticated as ${auth.aid ?? '?'}, gateway=${resolvedGateway}`);
|
|
648
656
|
}
|
|
649
657
|
catch (e) {
|
|
@@ -670,12 +678,12 @@ export class AUNChannel {
|
|
|
670
678
|
agentName: this.config.agentName,
|
|
671
679
|
channelName: this.config.channelName,
|
|
672
680
|
});
|
|
673
|
-
this.trace('OUT', 'client.connect', { gateway:
|
|
674
|
-
await
|
|
681
|
+
this.trace('OUT', 'client.connect', { gateway: client._gatewayUrl, extra_info: extraInfo });
|
|
682
|
+
await client.connect({ access_token: accessToken, gateway: client._gatewayUrl, extra_info: extraInfo },
|
|
675
683
|
// max_attempts=0 = 无限重试(与 Go/Python 对齐),交由 SDK 自己跑指数退避
|
|
676
684
|
// initial_delay=1s,max_delay=300s(5min 封顶)
|
|
677
685
|
{ auto_reconnect: true, retry: { max_attempts: 0, initial_delay: 1.0, max_delay: 300.0 } });
|
|
678
|
-
this.trace('OUT', 'client.connect.ok', { aid:
|
|
686
|
+
this.trace('OUT', 'client.connect.ok', { aid: client.aid });
|
|
679
687
|
this._aid = this.client.aid ?? undefined;
|
|
680
688
|
const deviceId = this.client._device_id ?? '';
|
|
681
689
|
this._chatId = this._aid ? `${this._aid}:${deviceId}:` : '';
|
|
@@ -781,9 +789,9 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
781
789
|
fs.mkdirSync(path.dirname(agentMdLocalPath), { recursive: true });
|
|
782
790
|
fs.writeFileSync(agentMdLocalPath, newAgentMd, 'utf-8');
|
|
783
791
|
logger.info(`${this.logPrefix()} Updated agent.md for ${aidName}`);
|
|
784
|
-
// Publish to AUN network via
|
|
792
|
+
// Publish to AUN network via publishAgentMd (auto-sign)
|
|
785
793
|
try {
|
|
786
|
-
await this.client.
|
|
794
|
+
await this.client.publishAgentMd();
|
|
787
795
|
logger.info(`${this.logPrefix()} Published agent.md to AUN network`);
|
|
788
796
|
}
|
|
789
797
|
catch (e) {
|
|
@@ -800,8 +808,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
800
808
|
2. **查看帮助**:发送 \`/help\` 查看所有可用命令
|
|
801
809
|
3. **切换项目**:发送 \`/project <项目名>\` 切换到其他项目
|
|
802
810
|
4. **查看状态**:发送 \`/status\` 查看当前会话状态
|
|
803
|
-
5.
|
|
804
|
-
6. **会话管理**:发送 \`/session\` 查看和切换会话
|
|
811
|
+
5. **会话管理**:发送 \`/session\` 查看和切换会话
|
|
805
812
|
|
|
806
813
|
💡 **提示**:
|
|
807
814
|
- 直接发送消息即可与 Claude/Codex 对话
|
|
@@ -963,8 +970,8 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
963
970
|
// action_card_reply 已在 extractTextPayload 中消费,不分发给 agent
|
|
964
971
|
if (p2pPayloadType === 'action_card_reply')
|
|
965
972
|
return;
|
|
966
|
-
// menu
|
|
967
|
-
if (p2pPayloadType
|
|
973
|
+
// menu.* 协议:自定义消息快速路径,需要原始 payload JSON 传递给 bridge
|
|
974
|
+
if (AUNChannel.MENU_REQUEST_TYPES.has(p2pPayloadType)) {
|
|
968
975
|
this.acknowledgeImmediately(messageId, seq);
|
|
969
976
|
this.dispatchMessage({
|
|
970
977
|
channelId: chatId, userId: fromAid,
|
|
@@ -1069,8 +1076,8 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
1069
1076
|
{
|
|
1070
1077
|
const payloadObj = (payload && typeof payload === 'object') ? payload : null;
|
|
1071
1078
|
const payloadType = payloadObj?.type ?? '';
|
|
1072
|
-
// menu
|
|
1073
|
-
if (payloadType
|
|
1079
|
+
// menu.* 协议:自定义消息快速路径
|
|
1080
|
+
if (AUNChannel.MENU_REQUEST_TYPES.has(payloadType)) {
|
|
1074
1081
|
this.acknowledgeImmediately(messageId, seq);
|
|
1075
1082
|
this.dispatchMessage({
|
|
1076
1083
|
channelId: groupId, userId: senderAid,
|
|
@@ -2373,11 +2380,10 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
2373
2380
|
if (!this.client)
|
|
2374
2381
|
return { type: null };
|
|
2375
2382
|
try {
|
|
2376
|
-
const
|
|
2377
|
-
const
|
|
2378
|
-
const
|
|
2379
|
-
const
|
|
2380
|
-
const name = nameMatch?.[1]?.trim() || undefined;
|
|
2383
|
+
const selfAgentDir = path.join(resolvePaths().agentsDir, this.config.aid);
|
|
2384
|
+
const identity = await PeerIdentityCache.resolve('aun', aid, selfAgentDir, this.client, false);
|
|
2385
|
+
const type = identity.type === 'human' ? 'human' : 'ai';
|
|
2386
|
+
const name = identity.name || undefined;
|
|
2381
2387
|
const info = { type, name };
|
|
2382
2388
|
this.peerInfoCache.set(aid, info);
|
|
2383
2389
|
setTimeout(() => this.peerInfoCache.delete(aid), 30 * 60 * 1000);
|
|
@@ -2385,7 +2391,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
2385
2391
|
}
|
|
2386
2392
|
catch (e) {
|
|
2387
2393
|
logger.debug(`${this.logPrefix()} fetchPeerInfo failed for ${aid}: ${e}`);
|
|
2388
|
-
return { type: null };
|
|
2394
|
+
return { type: null };
|
|
2389
2395
|
}
|
|
2390
2396
|
}
|
|
2391
2397
|
/** 同步取 peerInfo 缓存,未命中返回 undefined,不发起任何网络请求。 */
|
|
@@ -2401,12 +2407,18 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
|
|
|
2401
2407
|
async uploadAgentMd(content) {
|
|
2402
2408
|
if (!this.client)
|
|
2403
2409
|
throw new Error('not connected');
|
|
2404
|
-
await
|
|
2410
|
+
const { agentMdPath } = await import('../paths.js');
|
|
2411
|
+
const localPath = agentMdPath(this.config.aid);
|
|
2412
|
+
fs.mkdirSync(path.dirname(localPath), { recursive: true });
|
|
2413
|
+
fs.writeFileSync(localPath, content, 'utf-8');
|
|
2414
|
+
await this.client.publishAgentMd();
|
|
2405
2415
|
}
|
|
2406
2416
|
async downloadAgentMd(aid) {
|
|
2407
2417
|
if (!this.client)
|
|
2408
2418
|
throw new Error('not connected');
|
|
2409
|
-
|
|
2419
|
+
const { agentmdSync } = await import('../aun/aid/agentmd.js');
|
|
2420
|
+
const result = await agentmdSync(aid, { client: this.client });
|
|
2421
|
+
return result.content ?? '';
|
|
2410
2422
|
}
|
|
2411
2423
|
}
|
|
2412
2424
|
// Plugin implementation
|
package/dist/cli/agent.js
CHANGED
|
@@ -2,12 +2,13 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import readline from 'readline';
|
|
5
|
-
import { resolvePaths } from '../paths.js';
|
|
5
|
+
import { resolvePaths, agentMdPath as getAgentMdPathFromPaths, aunPath as defaultAunPath } from '../paths.js';
|
|
6
6
|
import { loadDefaults, loadAllAgents, loadAgent, saveAgent, ensureAgentDirSkeleton } from '../config-store.js';
|
|
7
7
|
import { ipcQuery } from '../ipc.js';
|
|
8
8
|
import { CONFIG_SCHEMA_VERSION } from '../types.js';
|
|
9
9
|
import { isValidChannelName } from '../core/channel-loader.js';
|
|
10
10
|
import { commandExists } from '../utils/cross-platform.js';
|
|
11
|
+
import { isCodexSdkAvailable } from '../agents/codex-runner.js';
|
|
11
12
|
// ==================== Helpers ====================
|
|
12
13
|
const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
13
14
|
const BASEAGENT_ENV_KEY = {
|
|
@@ -15,8 +16,13 @@ const BASEAGENT_ENV_KEY = {
|
|
|
15
16
|
codex: 'OPENAI_API_KEY',
|
|
16
17
|
gemini: 'GEMINI_API_KEY',
|
|
17
18
|
};
|
|
19
|
+
function isBaseagentAvailable(baseagent) {
|
|
20
|
+
if (baseagent === 'codex')
|
|
21
|
+
return isCodexSdkAvailable();
|
|
22
|
+
return commandExists(baseagent);
|
|
23
|
+
}
|
|
18
24
|
function detectAvailableBaseagents() {
|
|
19
|
-
return BASEAGENT_CANDIDATES.filter(
|
|
25
|
+
return BASEAGENT_CANDIDATES.filter(isBaseagentAvailable);
|
|
20
26
|
}
|
|
21
27
|
function pickDefaultBaseagent(available) {
|
|
22
28
|
if (available.length === 0)
|
|
@@ -40,12 +46,11 @@ function deriveAgentProjectPath(rootPath, aid) {
|
|
|
40
46
|
return `${candidate}~${i}`;
|
|
41
47
|
}
|
|
42
48
|
function readAgentMdIdentity(aid) {
|
|
43
|
-
const
|
|
44
|
-
const agentMdPath = path.join(aunPath, 'AIDs', aid, 'agent.md');
|
|
49
|
+
const agentMdFilePath = getAgentMdPathFromPaths(aid);
|
|
45
50
|
try {
|
|
46
|
-
if (!fs.existsSync(
|
|
51
|
+
if (!fs.existsSync(agentMdFilePath))
|
|
47
52
|
return { name: null, description: null };
|
|
48
|
-
const content = fs.readFileSync(
|
|
53
|
+
const content = fs.readFileSync(agentMdFilePath, 'utf-8');
|
|
49
54
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
50
55
|
if (!fmMatch)
|
|
51
56
|
return { name: null, description: null };
|
|
@@ -62,8 +67,7 @@ function readAgentMdIdentity(aid) {
|
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
function getAgentMdPath(aid) {
|
|
65
|
-
|
|
66
|
-
return path.join(aunPath, 'AIDs', aid, 'agent.md');
|
|
70
|
+
return getAgentMdPathFromPaths(aid);
|
|
67
71
|
}
|
|
68
72
|
function getNestedValue(obj, keyPath) {
|
|
69
73
|
const keys = keyPath.split('.');
|
|
@@ -316,7 +320,7 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
316
320
|
// Baseagent
|
|
317
321
|
const available = detectAvailableBaseagents();
|
|
318
322
|
if (available.length === 0) {
|
|
319
|
-
return { ok: false, error: `No baseagent
|
|
323
|
+
return { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or optional dependency @openai/codex-sdk.` };
|
|
320
324
|
}
|
|
321
325
|
const defaultBa = pickDefaultBaseagent(available);
|
|
322
326
|
let baseagent;
|
|
@@ -333,7 +337,7 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
333
337
|
continue;
|
|
334
338
|
}
|
|
335
339
|
if (!available.includes(input)) {
|
|
336
|
-
console.log(` ${input} not
|
|
340
|
+
console.log(` ${input} is not available in the current environment. Available: ${available.join('/')}`);
|
|
337
341
|
continue;
|
|
338
342
|
}
|
|
339
343
|
chosen = input;
|
|
@@ -385,10 +389,8 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
385
389
|
if (agentDescription) {
|
|
386
390
|
content = content.replace(/^description:\s*".*?"$/m, `description: "${agentDescription}"`);
|
|
387
391
|
}
|
|
388
|
-
const aunPath = process.env.AUN_HOME ||
|
|
389
|
-
|
|
390
|
-
fs.mkdirSync(path.dirname(agentMdPath), { recursive: true });
|
|
391
|
-
fs.writeFileSync(agentMdPath, content, 'utf-8');
|
|
392
|
+
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
393
|
+
// agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
|
|
392
394
|
// Upload with retry (3 attempts, 2s delay between retries)
|
|
393
395
|
const MAX_ATTEMPTS = 3;
|
|
394
396
|
const RETRY_DELAY_MS = 2000;
|
|
@@ -463,7 +465,7 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
463
465
|
// Baseagent
|
|
464
466
|
const available = detectAvailableBaseagents();
|
|
465
467
|
if (available.length === 0) {
|
|
466
|
-
return { ok: false, error: `No baseagent
|
|
468
|
+
return { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or optional dependency @openai/codex-sdk.` };
|
|
467
469
|
}
|
|
468
470
|
let baseagent;
|
|
469
471
|
if (opts.baseagent) {
|
|
@@ -471,7 +473,7 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
471
473
|
return { ok: false, error: `Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})` };
|
|
472
474
|
}
|
|
473
475
|
if (!available.includes(opts.baseagent)) {
|
|
474
|
-
return { ok: false, error: `${opts.baseagent} not
|
|
476
|
+
return { ok: false, error: `${opts.baseagent} is not available in the current environment (available: ${available.join('/')})` };
|
|
475
477
|
}
|
|
476
478
|
baseagent = opts.baseagent;
|
|
477
479
|
}
|
|
@@ -541,10 +543,8 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
541
543
|
if (agentDescription) {
|
|
542
544
|
content = content.replace(/^description:\s*".*?"$/m, `description: "${agentDescription}"`);
|
|
543
545
|
}
|
|
544
|
-
const aunPath = process.env.AUN_HOME ||
|
|
545
|
-
|
|
546
|
-
fs.mkdirSync(path.dirname(agentMdPath), { recursive: true });
|
|
547
|
-
fs.writeFileSync(agentMdPath, content, 'utf-8');
|
|
546
|
+
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
547
|
+
// agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
|
|
548
548
|
const MAX_ATTEMPTS = 3;
|
|
549
549
|
const RETRY_DELAY_MS = 2000;
|
|
550
550
|
let lastError;
|
|
@@ -592,11 +592,12 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
592
592
|
hotLoadError,
|
|
593
593
|
};
|
|
594
594
|
}
|
|
595
|
-
// ==================== agentSyncAids ====================
|
|
595
|
+
// ==================== agentSyncAids (deprecated) ====================
|
|
596
|
+
/** @deprecated sync-aids 已废弃,不再从 CLI 调用 */
|
|
596
597
|
export async function agentSyncAids() {
|
|
597
598
|
const p = resolvePaths();
|
|
598
599
|
const { aidList } = await import('../aun/aid/index.js');
|
|
599
|
-
const aunPath = process.env.AUN_HOME ||
|
|
600
|
+
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
600
601
|
const allAids = aidList(aunPath);
|
|
601
602
|
const localAids = allAids.filter(a => a.hasPrivateKey).map(a => a.aid);
|
|
602
603
|
if (localAids.length === 0) {
|
|
@@ -862,12 +863,12 @@ export async function agentDelete(aid, purge = false) {
|
|
|
862
863
|
}
|
|
863
864
|
// ==================== agentRename ====================
|
|
864
865
|
export async function agentRename(aid, newName) {
|
|
865
|
-
const aunPath = process.env.AUN_HOME ||
|
|
866
|
-
const
|
|
867
|
-
if (!fs.existsSync(
|
|
866
|
+
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
867
|
+
const agentMdFilePath = getAgentMdPathFromPaths(aid);
|
|
868
|
+
if (!fs.existsSync(agentMdFilePath)) {
|
|
868
869
|
return { ok: false, error: `agent.md not found for ${aid}. Run: evolclaw aid agentmd put ${aid}` };
|
|
869
870
|
}
|
|
870
|
-
let content = fs.readFileSync(
|
|
871
|
+
let content = fs.readFileSync(agentMdFilePath, 'utf-8');
|
|
871
872
|
const fmMatch = content.match(/^(---\n)([\s\S]*?)(\n---)/);
|
|
872
873
|
if (!fmMatch) {
|
|
873
874
|
return { ok: false, error: `agent.md has no valid frontmatter for ${aid}` };
|
|
@@ -882,8 +883,7 @@ export async function agentRename(aid, newName) {
|
|
|
882
883
|
newFm = `name: "${newName}"\n${fm}`;
|
|
883
884
|
}
|
|
884
885
|
content = fmMatch[1] + newFm + fmMatch[3] + content.slice(fmMatch[0].length);
|
|
885
|
-
|
|
886
|
-
// Upload
|
|
886
|
+
// agentmdPut 会写本地文件并 publishAgentMd
|
|
887
887
|
let uploaded = false;
|
|
888
888
|
try {
|
|
889
889
|
const { agentmdPut } = await import('../aun/aid/index.js');
|
package/dist/cli/bench.js
CHANGED
|
@@ -6,7 +6,9 @@ import { execFile } from 'child_process';
|
|
|
6
6
|
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
|
-
import { getPackageRoot } from '../paths.js';
|
|
9
|
+
import { getPackageRoot, aunPath as defaultAunPath } from '../paths.js';
|
|
10
|
+
import { createAunClient } from '../aun/aid/client.js';
|
|
11
|
+
import { isHelpFlag } from './help.js';
|
|
10
12
|
const execFileAsync = promisify(execFile);
|
|
11
13
|
// ==================== ANSI ====================
|
|
12
14
|
const GREEN = '\x1b[32m';
|
|
@@ -247,19 +249,11 @@ function filterBySize(results, received, cls, durationSec) {
|
|
|
247
249
|
return computeMetrics(results.filter(r => r.sizeClass === cls), received.filter(r => r.sizeClass === cls), durationSec);
|
|
248
250
|
}
|
|
249
251
|
async function benchAuth(aids, concurrency, aunPath, slotId) {
|
|
250
|
-
const
|
|
251
|
-
const path = (await import('path')).default;
|
|
252
|
-
const fs = (await import('fs')).default;
|
|
253
|
-
const os = (await import('os')).default;
|
|
254
|
-
const resolvedAunPath = aunPath ?? path.join(os.homedir(), '.aun');
|
|
255
|
-
const caCertPath = path.join(resolvedAunPath, 'CA', 'root', 'root.crt');
|
|
252
|
+
const resolvedAunPath = aunPath ?? defaultAunPath();
|
|
256
253
|
const tasks = aids.map(aid => async () => {
|
|
257
254
|
const start = Date.now();
|
|
258
255
|
try {
|
|
259
|
-
const
|
|
260
|
-
if (fs.existsSync(caCertPath))
|
|
261
|
-
clientOpts.root_ca_path = caCertPath;
|
|
262
|
-
const client = new AUNClient(clientOpts);
|
|
256
|
+
const client = await createAunClient({ aunPath: resolvedAunPath });
|
|
263
257
|
await client.auth.createAid({ aid });
|
|
264
258
|
const authResult = await client.auth.authenticate({ aid });
|
|
265
259
|
const accessToken = authResult?.access_token ?? client._access_token;
|
|
@@ -363,7 +357,7 @@ async function cliAuth(aid, slotId) {
|
|
|
363
357
|
}
|
|
364
358
|
// ==================== Main Command ====================
|
|
365
359
|
export async function cmdBench(args) {
|
|
366
|
-
if (args[0]
|
|
360
|
+
if (isHelpFlag(args[0])) {
|
|
367
361
|
console.log(`用法: evolclaw bench [options]
|
|
368
362
|
|
|
369
363
|
AUN 消息系统性能基准测试。使用多个本地 AID 并发互发消息,
|
|
@@ -411,14 +405,14 @@ Options:
|
|
|
411
405
|
const aids = [];
|
|
412
406
|
// AID is usable if: has private key + cert not expired + key/cert public key match
|
|
413
407
|
const { aidShow } = await import('../aun/aid/identity.js');
|
|
414
|
-
const resolvedAunPath = aunPath ??
|
|
408
|
+
const resolvedAunPath = aunPath ?? defaultAunPath();
|
|
415
409
|
const usableAids = [];
|
|
416
410
|
const skippedAids = [];
|
|
417
411
|
for (const a of allAids) {
|
|
418
412
|
if (!a.hasPrivateKey)
|
|
419
413
|
continue;
|
|
420
414
|
try {
|
|
421
|
-
const info = aidShow(a.aid, { aunPath });
|
|
415
|
+
const info = await aidShow(a.aid, { aunPath });
|
|
422
416
|
if (!info.certExpiresAt) {
|
|
423
417
|
skippedAids.push({ aid: a.aid, reason: '无证书' });
|
|
424
418
|
continue;
|
package/dist/cli/help.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI help 检测 helper。
|
|
3
|
+
*
|
|
4
|
+
* 把 7 种历史写法统一为两个语义清晰的函数:
|
|
5
|
+
* - isHelpFlag(token):单 token 是否是 help 标记('help' / '--help' / '-h')
|
|
6
|
+
* - wantsHelp(args):args 任意位置出现 help 标记
|
|
7
|
+
*
|
|
8
|
+
* 两套 API 服务于不同语义:
|
|
9
|
+
* - 顶层路由(如 cmdAid 看到第一个 token 是子命令名时)必须用 isHelpFlag(sub),
|
|
10
|
+
* 否则 `ec aid delete --help` 会被顶层吞掉,永远到不了 delete 自己的 help。
|
|
11
|
+
* - 单层命令(如 cmdLinkRules、cmdAid 的具体 sub 处理块内)用 wantsHelp(args)
|
|
12
|
+
* 更宽松,任意位置都识别。
|
|
13
|
+
*/
|
|
14
|
+
const HELP_TOKENS = new Set(['help', '--help', '-h']);
|
|
15
|
+
export function isHelpFlag(token) {
|
|
16
|
+
return token !== undefined && HELP_TOKENS.has(token);
|
|
17
|
+
}
|
|
18
|
+
export function wantsHelp(args) {
|
|
19
|
+
for (const a of args)
|
|
20
|
+
if (HELP_TOKENS.has(a))
|
|
21
|
+
return true;
|
|
22
|
+
return false;
|
|
23
|
+
}
|