evolclaw 3.1.10 → 3.2.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 +38 -0
- package/README.md +26 -4
- package/dist/agents/kit-renderer.js +5 -1
- package/dist/agents/manifest-engine.js +108 -35
- package/dist/agents/message-renderer.js +2 -0
- package/dist/aun/aid/control-aid.js +67 -0
- package/dist/aun/aid/identity.js +20 -7
- package/dist/aun/aid/store.js +2 -2
- package/dist/channels/aun.js +212 -158
- package/dist/channels/feishu.js +10 -14
- package/dist/channels/wechat.js +8 -2
- package/dist/cli/agent.js +38 -10
- package/dist/cli/index.js +50 -8
- package/dist/cli/init-channel.js +38 -148
- package/dist/cli/init.js +162 -82
- package/dist/config-store.js +38 -7
- package/dist/core/cache/file-cache.js +216 -0
- package/dist/core/command-handler.js +291 -68
- package/dist/core/evolagent-registry.js +3 -0
- package/dist/core/evolagent.js +28 -23
- package/dist/core/message/command-handler-agent-control.js +153 -0
- package/dist/core/message/create-status.js +67 -0
- package/dist/core/message/message-bridge.js +5 -3
- package/dist/core/message/message-processor.js +44 -36
- package/dist/core/message/message-queue.js +13 -6
- package/dist/core/model/model-scope.js +39 -6
- package/dist/core/session/adapters/claude-session-file-adapter.js +48 -5
- package/dist/evolclaw-config.js +11 -0
- package/dist/index.js +57 -2
- package/dist/ipc.js +6 -0
- package/dist/paths.js +7 -3
- package/dist/utils/media-cache.js +40 -1
- package/dist/utils/npm-ops.js +13 -3
- package/kits/templates/message-fragments/item.md +1 -1
- package/package.json +1 -1
package/dist/channels/wechat.js
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { resolvePaths } from '../paths.js';
|
|
5
5
|
import { logger } from '../utils/logger.js';
|
|
6
|
-
import { sanitizeFileName, saveToUploads, safeFetch } from '../utils/media-cache.js';
|
|
6
|
+
import { sanitizeFileName, saveToUploads, safeFetch, bufferToInboundImage } from '../utils/media-cache.js';
|
|
7
7
|
import { markdownToPlainText } from '../utils/rich-content-renderer.js';
|
|
8
8
|
import { formatItemsAsText } from '../core/message/items-formatter.js';
|
|
9
9
|
const CHANNEL_VERSION = '1.0.0';
|
|
@@ -527,7 +527,13 @@ export class WechatChannel {
|
|
|
527
527
|
try {
|
|
528
528
|
if (item.type === MSG_ITEM_IMAGE && item.image_item?.media) {
|
|
529
529
|
const buf = await downloadMedia(item.image_item.media, item.image_item.aeskey);
|
|
530
|
-
|
|
530
|
+
// 统一图片识别:magic bytes 优先正确区分 jpeg/png/gif/webp;
|
|
531
|
+
// 检测失败时回退到 image/jpeg(微信入站图片实际均为 jpeg,保留历史行为)。
|
|
532
|
+
const img = await bufferToInboundImage(buf, { contentType: 'image/jpeg' });
|
|
533
|
+
if (img)
|
|
534
|
+
images.push(img);
|
|
535
|
+
else
|
|
536
|
+
logger.warn('[WeChat] Image validation failed (not a supported image)');
|
|
531
537
|
}
|
|
532
538
|
else if (item.type === MSG_ITEM_FILE && item.file_item?.media) {
|
|
533
539
|
const buf = await downloadMedia(item.file_item.media);
|
package/dist/cli/agent.js
CHANGED
|
@@ -450,26 +450,32 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
450
450
|
export async function agentCreateNonInteractive(opts) {
|
|
451
451
|
const p = resolvePaths();
|
|
452
452
|
const { isValidAid, aidCreate } = await import('../aun/aid/index.js');
|
|
453
|
+
opts.onPhase?.('validating', 'begin');
|
|
454
|
+
/** 校验失败:透出 failed 进度并返回原结构(控制流不变)。 */
|
|
455
|
+
const failValidating = (error) => {
|
|
456
|
+
opts.onPhase?.('validating', 'failed', error);
|
|
457
|
+
return { ok: false, error };
|
|
458
|
+
};
|
|
453
459
|
if (!isValidAid(opts.aid)) {
|
|
454
|
-
return
|
|
460
|
+
return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
|
|
455
461
|
}
|
|
456
462
|
const agentDirPath = path.join(p.agentsDir, opts.aid);
|
|
457
463
|
const configExists = fs.existsSync(path.join(agentDirPath, 'config.json'));
|
|
458
464
|
if (configExists && !opts.force) {
|
|
459
|
-
return
|
|
465
|
+
return failValidating(`Agent "${opts.aid}" already exists: ${agentDirPath}/config.json (use --force to overwrite)`);
|
|
460
466
|
}
|
|
461
467
|
// Baseagent
|
|
462
468
|
const available = detectAvailableBaseagents();
|
|
463
469
|
if (available.length === 0) {
|
|
464
|
-
return
|
|
470
|
+
return failValidating(`No usable baseagent detected. Install claude/gemini CLI or optional dependency @openai/codex-sdk.`);
|
|
465
471
|
}
|
|
466
472
|
let baseagent;
|
|
467
473
|
if (opts.baseagent) {
|
|
468
474
|
if (!BASEAGENT_CANDIDATES.includes(opts.baseagent)) {
|
|
469
|
-
return
|
|
475
|
+
return failValidating(`Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`);
|
|
470
476
|
}
|
|
471
477
|
if (!available.includes(opts.baseagent)) {
|
|
472
|
-
return
|
|
478
|
+
return failValidating(`${opts.baseagent} is not available in the current environment (available: ${available.join('/')})`);
|
|
473
479
|
}
|
|
474
480
|
baseagent = opts.baseagent;
|
|
475
481
|
}
|
|
@@ -477,20 +483,22 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
477
483
|
baseagent = pickDefaultBaseagent(available);
|
|
478
484
|
}
|
|
479
485
|
if (!path.isAbsolute(opts.project)) {
|
|
480
|
-
return
|
|
486
|
+
return failValidating(`--project must be absolute: ${opts.project}`);
|
|
481
487
|
}
|
|
482
488
|
if (!fs.existsSync(opts.project)) {
|
|
483
489
|
try {
|
|
484
490
|
fs.mkdirSync(opts.project, { recursive: true });
|
|
485
491
|
}
|
|
486
492
|
catch (e) {
|
|
487
|
-
return
|
|
493
|
+
return failValidating(`Failed to create ${opts.project}: ${e?.message || e}`);
|
|
488
494
|
}
|
|
489
495
|
}
|
|
490
496
|
if (opts.owner && !isValidAid(opts.owner)) {
|
|
491
|
-
return
|
|
497
|
+
return failValidating(`Invalid owner: ${opts.owner}`);
|
|
492
498
|
}
|
|
499
|
+
opts.onPhase?.('validating', 'done');
|
|
493
500
|
// Register AID
|
|
501
|
+
opts.onPhase?.('registering_aid', 'begin');
|
|
494
502
|
let aidCreated = false;
|
|
495
503
|
try {
|
|
496
504
|
const result = await aidCreate(opts.aid);
|
|
@@ -499,9 +507,12 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
499
507
|
}
|
|
500
508
|
catch { /* ignore */ }
|
|
501
509
|
aidCreated = !result.alreadyExisted;
|
|
510
|
+
opts.onPhase?.('registering_aid', 'done', aidCreated ? 'created' : 'existed');
|
|
502
511
|
}
|
|
503
512
|
catch (e) {
|
|
504
|
-
|
|
513
|
+
const error = `AID creation failed: ${e?.message || e}`;
|
|
514
|
+
opts.onPhase?.('registering_aid', 'failed', error);
|
|
515
|
+
return { ok: false, error };
|
|
505
516
|
}
|
|
506
517
|
// Force 模式下若 agent 已存在且已 initialized,保留该状态(避免重复发欢迎)
|
|
507
518
|
let preservedInitialized = false;
|
|
@@ -526,9 +537,12 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
526
537
|
chatmode: { ...DEFAULT_CHATMODE },
|
|
527
538
|
dispatch: DEFAULT_DISPATCH,
|
|
528
539
|
};
|
|
540
|
+
opts.onPhase?.('config_saved', 'begin');
|
|
529
541
|
saveAgent(agentConfig);
|
|
530
542
|
ensureAgentDirSkeleton(opts.aid);
|
|
543
|
+
opts.onPhase?.('config_saved', 'done');
|
|
531
544
|
// Generate and upload agent.md
|
|
545
|
+
opts.onPhase?.('uploading_agentmd', 'begin');
|
|
532
546
|
let agentmdUploaded = false;
|
|
533
547
|
try {
|
|
534
548
|
const { buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
|
|
@@ -550,6 +564,7 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
550
564
|
await new Promise(r => setTimeout(r, RETRY_DELAY_MS));
|
|
551
565
|
await agentmdPut(content, { aid: opts.aid, aunPath });
|
|
552
566
|
agentmdUploaded = true;
|
|
567
|
+
opts.onPhase?.('uploading_agentmd', 'done');
|
|
553
568
|
break;
|
|
554
569
|
}
|
|
555
570
|
catch (e) {
|
|
@@ -559,11 +574,13 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
559
574
|
if (!agentmdUploaded) {
|
|
560
575
|
console.warn(`⚠ agent.md upload failed: ${lastError?.message || lastError}`);
|
|
561
576
|
console.warn(` Retry later with: evolclaw aid agentmd put ${opts.aid}`);
|
|
577
|
+
opts.onPhase?.('uploading_agentmd', 'warn', `upload failed: ${lastError?.message || lastError}`);
|
|
562
578
|
}
|
|
563
579
|
await new Promise(r => setTimeout(r, 0));
|
|
564
580
|
}
|
|
565
581
|
catch (e) {
|
|
566
582
|
console.warn(`⚠ agent.md generation failed: ${e?.message || e}`);
|
|
583
|
+
opts.onPhase?.('uploading_agentmd', 'warn', `generation failed: ${e?.message || e}`);
|
|
567
584
|
}
|
|
568
585
|
// Attempt hot-load via IPC (if daemon is running).
|
|
569
586
|
// Cold-starting a new agent (connecting AUN WebSocket) routinely takes
|
|
@@ -571,16 +588,24 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
571
588
|
// report while the daemon actually finishes bringing the agent online.
|
|
572
589
|
let hotLoaded = false;
|
|
573
590
|
let hotLoadError;
|
|
591
|
+
opts.onPhase?.('hot_loading', 'begin');
|
|
574
592
|
try {
|
|
575
593
|
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid }, 30_000);
|
|
576
594
|
if (ipcResult?.ok) {
|
|
577
595
|
hotLoaded = true;
|
|
596
|
+
opts.onPhase?.('hot_loading', 'done');
|
|
578
597
|
}
|
|
579
598
|
else if (ipcResult) {
|
|
580
599
|
hotLoadError = ipcResult.error;
|
|
600
|
+
opts.onPhase?.('hot_loading', 'warn', hotLoadError);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
opts.onPhase?.('hot_loading', 'warn', 'daemon not running');
|
|
581
604
|
}
|
|
582
605
|
}
|
|
583
|
-
catch {
|
|
606
|
+
catch {
|
|
607
|
+
opts.onPhase?.('hot_loading', 'warn', 'daemon not running'); /* daemon not running */
|
|
608
|
+
}
|
|
584
609
|
return {
|
|
585
610
|
ok: true,
|
|
586
611
|
aid: opts.aid,
|
|
@@ -858,6 +883,9 @@ export async function agentDelete(aid, purge = false) {
|
|
|
858
883
|
}
|
|
859
884
|
else {
|
|
860
885
|
fs.unlinkSync(configPath);
|
|
886
|
+
// 清理构建进度文件(非 purge 删除只移除 config.json,需显式清理 create-status.json)
|
|
887
|
+
const { removeCreateStatus } = await import('../core/message/create-status.js');
|
|
888
|
+
removeCreateStatus(agentDir);
|
|
861
889
|
}
|
|
862
890
|
// Trigger resync so daemon drops the agent
|
|
863
891
|
try {
|
package/dist/cli/index.js
CHANGED
|
@@ -6,11 +6,12 @@ import { spawn, execFileSync, execFile } from 'child_process';
|
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { resolveRoot, resolvePaths, ensureDataDirs, getPackageRoot, agentMdPath } from '../paths.js';
|
|
8
8
|
import { loadDefaults, loadAllAgents, mergeForAgent } from '../config-store.js';
|
|
9
|
+
import { loadEvolclawConfig } from '../evolclaw-config.js';
|
|
9
10
|
import { resolveAnthropicConfig } from '../agents/resolve.js';
|
|
10
11
|
import { migrateProject } from '../config-store.js';
|
|
11
|
-
import { cmdInit } from './init.js';
|
|
12
|
+
import { cmdInit, needsControlAidInit, initTail } from './init.js';
|
|
12
13
|
import { ipcQuery } from '../ipc.js';
|
|
13
|
-
import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom } from './init-channel.js';
|
|
14
|
+
import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom, cmdInitAun } from './init-channel.js';
|
|
14
15
|
import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
|
|
15
16
|
import * as platform from '../utils/cross-platform.js';
|
|
16
17
|
import { EventBus } from '../core/event-bus.js';
|
|
@@ -299,6 +300,19 @@ async function cmdStart() {
|
|
|
299
300
|
await cmdInit();
|
|
300
301
|
return;
|
|
301
302
|
}
|
|
303
|
+
// 控制 AID 门禁:缺 aid 且交互式 → 只补全控制 AID + owners(不重走 baseagent 向导)。
|
|
304
|
+
// 非 TTY(restart-monitor/systemd/管道)不补全(无法交互),只提示后继续启动,daemon 侧 warn 兜底。
|
|
305
|
+
const evolclawCfgStart = loadEvolclawConfig();
|
|
306
|
+
if (needsControlAidInit(evolclawCfgStart.aid, !!process.stdin.isTTY)) {
|
|
307
|
+
console.log('⚡ 控制 AID 未配置,自动补全...\n');
|
|
308
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
309
|
+
suppressSdkLogs();
|
|
310
|
+
await initTail();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (!evolclawCfgStart.aid) {
|
|
314
|
+
console.log('⚠ 控制 AID 未配置(非交互式启动,跳过补全)。如需进程身份/远程管理,请运行 evolclaw init');
|
|
315
|
+
}
|
|
302
316
|
// 检查至少有一个 self-agent
|
|
303
317
|
const { agents, skipped } = loadAllAgents();
|
|
304
318
|
if (agents.length === 0) {
|
|
@@ -968,6 +982,14 @@ async function cmdStatus() {
|
|
|
968
982
|
}
|
|
969
983
|
}
|
|
970
984
|
catch { /* ignore */ }
|
|
985
|
+
// 控制 AID(daemon 进程身份)状态
|
|
986
|
+
if (status.controlAid) {
|
|
987
|
+
const state = status.controlAid.connected ? 'connected' : 'disconnected';
|
|
988
|
+
console.log(`control: ${status.controlAid.aid} [${state}]`);
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
console.log('control: not configured');
|
|
992
|
+
}
|
|
971
993
|
if (status.stats) {
|
|
972
994
|
console.log('');
|
|
973
995
|
console.log('📊 Last hour:');
|
|
@@ -2127,13 +2149,27 @@ async function cmdWatchWeb() {
|
|
|
2127
2149
|
}
|
|
2128
2150
|
// Node 18.20+/20+/22 起,execFile 拒绝直接 spawn .cmd/.bat(CVE-2024-27980),必须 shell:true。
|
|
2129
2151
|
// shell 模式下含空格的路径/参数需加引号。
|
|
2152
|
+
// evolclaw-web 是前台长驻服务:用户 Ctrl-C、被新实例的单实例保护 SIGKILL、或正常退出,
|
|
2153
|
+
// execFileSync 都会抛错(signal 终止时 status=null)。这些都是正常生命周期,
|
|
2154
|
+
// 不应让父进程 evolclaw 带堆栈崩溃。只有真正的非信号失败才提示。
|
|
2130
2155
|
const isBatch = /\.(cmd|bat)$/i.test(exe);
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2156
|
+
try {
|
|
2157
|
+
if (isBatch) {
|
|
2158
|
+
const q = (s) => `"${s}"`;
|
|
2159
|
+
execFileSync(q(exe), ['--home', q(home)], { stdio: 'inherit', shell: true });
|
|
2160
|
+
}
|
|
2161
|
+
else {
|
|
2162
|
+
execFileSync(exe, ['--home', home], { stdio: 'inherit' });
|
|
2163
|
+
}
|
|
2134
2164
|
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2165
|
+
catch (e) {
|
|
2166
|
+
// 信号终止(SIGINT/SIGTERM/SIGKILL)= 用户主动退出或被新实例顶替,静默返回
|
|
2167
|
+
if (e?.signal)
|
|
2168
|
+
return;
|
|
2169
|
+
// 退出码非 0 但非信号:可能是启动失败,提示但不崩溃
|
|
2170
|
+
if (typeof e?.status === 'number' && e.status !== 0) {
|
|
2171
|
+
process.stderr.write(`⚠ evolclaw-web 退出(code ${e.status})\n`);
|
|
2172
|
+
}
|
|
2137
2173
|
}
|
|
2138
2174
|
}
|
|
2139
2175
|
async function cmdRestartMonitor() {
|
|
@@ -4856,12 +4892,18 @@ export async function main(args) {
|
|
|
4856
4892
|
--force 已存在 defaults.json 时覆盖
|
|
4857
4893
|
|
|
4858
4894
|
配置渠道(先 evolclaw agent new 创建 agent):
|
|
4895
|
+
evolclaw init aun AUN 渠道配置(AID 创建/绑定)
|
|
4859
4896
|
evolclaw init feishu 飞书扫码登录
|
|
4860
4897
|
evolclaw init wechat 微信扫码登录
|
|
4861
4898
|
evolclaw init dingtalk 钉钉扫码登录
|
|
4862
4899
|
evolclaw init qqbot QQ 机器人扫码绑定
|
|
4863
4900
|
evolclaw init wecom 企业微信 AI Bot 配置(手动输入)`);
|
|
4864
4901
|
}
|
|
4902
|
+
else if (args[1] === 'aun') {
|
|
4903
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
4904
|
+
suppressSdkLogs();
|
|
4905
|
+
await cmdInitAun();
|
|
4906
|
+
}
|
|
4865
4907
|
else if (args[1] === 'wechat') {
|
|
4866
4908
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
4867
4909
|
suppressSdkLogs();
|
|
@@ -4886,7 +4928,7 @@ export async function main(args) {
|
|
|
4886
4928
|
await cmdInitWecom();
|
|
4887
4929
|
}
|
|
4888
4930
|
else if (args[1] && !args[1].startsWith('-')) {
|
|
4889
|
-
const supported = ['feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom'];
|
|
4931
|
+
const supported = ['feishu', 'wechat', 'aun', 'dingtalk', 'qqbot', 'wecom'];
|
|
4890
4932
|
console.error(`❌ 不支持的渠道: ${args[1]}`);
|
|
4891
4933
|
console.error(` 支持的渠道: ${supported.join(', ')}`);
|
|
4892
4934
|
process.exit(1);
|
package/dist/cli/init-channel.js
CHANGED
|
@@ -5,16 +5,12 @@
|
|
|
5
5
|
* - cmdInit<Channel>() — standalone `evolclaw init <channel>` entry
|
|
6
6
|
* - run<Channel>QrFlow() or setupAun*() — reusable primitives for the main init wizard
|
|
7
7
|
*/
|
|
8
|
-
import fs from 'fs';
|
|
9
8
|
import readline from 'readline';
|
|
10
|
-
import path from 'path';
|
|
11
9
|
import crypto from 'crypto';
|
|
12
|
-
import { aidLocalDir, aunPath as defaultAunPath } from '../paths.js';
|
|
13
10
|
import { selectInstance } from './init.js';
|
|
14
|
-
import {
|
|
15
|
-
import { loadAllAgents, loadAgent } from '../config-store.js';
|
|
11
|
+
import { loadAllAgents, loadAgent, saveAgent } from '../config-store.js';
|
|
16
12
|
import { agentChannelUpsert } from './agent.js';
|
|
17
|
-
import {
|
|
13
|
+
import { isValidAid } from '../aun/aid/index.js';
|
|
18
14
|
function ask(rl, question) {
|
|
19
15
|
return new Promise(resolve => rl.question(question, resolve));
|
|
20
16
|
}
|
|
@@ -372,156 +368,50 @@ export async function cmdInitWechat() {
|
|
|
372
368
|
await commitChannel(aid, channel, choice.action);
|
|
373
369
|
}
|
|
374
370
|
// ==================== AUN ====================
|
|
375
|
-
|
|
376
|
-
// AUN
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
console.log('\n🔍 AUN 环境检查...\n');
|
|
380
|
-
const minVer = MIN_AUN_CORE_SDK.join('.');
|
|
381
|
-
const installed = resolveAunCoreSdkPkg();
|
|
382
|
-
if (!installed) {
|
|
383
|
-
console.log(` ✗ ${AUN_CORE_SDK_PKG} 未安装`);
|
|
384
|
-
const answer = (await ask(rl, ` → 是否安装 ${AUN_CORE_SDK_PKG}@latest?[Y/n] `)).trim().toLowerCase();
|
|
385
|
-
if (answer === 'n' || answer === 'no') {
|
|
386
|
-
console.log(' 已取消');
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
console.log(` 正在安装 ${AUN_CORE_SDK_PKG}...`);
|
|
390
|
-
try {
|
|
391
|
-
await npmInstallGlobal(`${AUN_CORE_SDK_PKG}@latest`);
|
|
392
|
-
console.log(` ✓ ${AUN_CORE_SDK_PKG} 安装完成`);
|
|
393
|
-
}
|
|
394
|
-
catch (e) {
|
|
395
|
-
console.log(` ✗ 安装失败: ${e.message?.slice(0, 200) || e}`);
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
console.log('');
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
if (isAunSdkVersionOk(installed.version)) {
|
|
402
|
-
console.log(` ✓ ${AUN_CORE_SDK_PKG} v${installed.version}`);
|
|
403
|
-
console.log('');
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
console.log(` ✗ ${AUN_CORE_SDK_PKG} v${installed.version} — 需要 >= ${minVer}`);
|
|
407
|
-
const answer = (await ask(rl, ` → 是否升级 ${AUN_CORE_SDK_PKG}?[Y/n] `)).trim().toLowerCase();
|
|
408
|
-
if (answer === 'n' || answer === 'no') {
|
|
409
|
-
console.log(' 已取消');
|
|
410
|
-
return false;
|
|
411
|
-
}
|
|
412
|
-
console.log(` 正在升级 ${AUN_CORE_SDK_PKG}...`);
|
|
371
|
+
export async function cmdInitAun() {
|
|
372
|
+
// AUN channel 从 agent.aid 隐式派生,AID 密钥在 `agent new` 时已创建就绪——本命令不碰 aid。
|
|
373
|
+
// 与其他渠道一致,职责是配置 owner;AUN 的 owner 存于 agent 顶层 owners[](见 evolagent.ts)。
|
|
374
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
413
375
|
try {
|
|
414
|
-
await
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
console.log('');
|
|
422
|
-
return true;
|
|
423
|
-
}
|
|
424
|
-
// isValidAid, createAidSilent → 已迁移至 src/channels/aun-ops.ts
|
|
425
|
-
// appendAunInstance → 已迁移至 src/channels/aun-ops.ts
|
|
426
|
-
export async function setupAunAid(rl, _config) {
|
|
427
|
-
let aid = '';
|
|
428
|
-
// Outer loop: allows retrying with a different AID
|
|
429
|
-
while (true) {
|
|
430
|
-
// Ask AID with format validation
|
|
431
|
-
aid = '';
|
|
432
|
-
while (!aid) {
|
|
433
|
-
aid = (await ask(rl, ' AUN Agent ID (例: mybot.agentid.pub): ')).trim();
|
|
434
|
-
if (!aid) {
|
|
435
|
-
console.log(' ⚠ 不能为空');
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
if (!isValidAid(aid)) {
|
|
439
|
-
console.log(' ⚠ 无效 AID 格式(需要合法域名,至少三级,如 alice.agentid.pub)');
|
|
440
|
-
aid = '';
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
// Check if AID exists locally
|
|
444
|
-
const aunPath = defaultAunPath();
|
|
445
|
-
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
446
|
-
if (fs.existsSync(aidDir) && fs.existsSync(path.join(aidDir, 'private'))) {
|
|
447
|
-
console.log(` ✓ AID ${aid} 已存在`);
|
|
448
|
-
break;
|
|
449
|
-
}
|
|
450
|
-
const answer = (await ask(rl, ` ⚠ AID ${aid} 本地不存在,是否创建?[Y/n] `)).trim().toLowerCase();
|
|
451
|
-
if (answer === 'n' || answer === 'no') {
|
|
452
|
-
console.log(' 已跳过 AID 创建(启动时可能连接失败)');
|
|
453
|
-
break;
|
|
376
|
+
const agentId = await pickAgentForChannel(rl);
|
|
377
|
+
if (!agentId)
|
|
378
|
+
return;
|
|
379
|
+
const agentConfig = loadAgent(agentId);
|
|
380
|
+
if (!agentConfig) {
|
|
381
|
+
console.error(`❌ 无法加载 agent ${agentId} 的配置`);
|
|
382
|
+
return;
|
|
454
383
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
console.log(' ✓ agent.md 已发布并写入本地');
|
|
468
|
-
}
|
|
469
|
-
catch (e) {
|
|
470
|
-
console.log(` ⚠ agent.md 发布失败(首次连接将自动重试): ${String(e.message || e).slice(0, 100)}`);
|
|
471
|
-
// Still write local copy as fallback
|
|
472
|
-
try {
|
|
473
|
-
const localDir = aidLocalDir(aid);
|
|
474
|
-
fs.mkdirSync(localDir, { recursive: true });
|
|
475
|
-
fs.writeFileSync(path.join(localDir, 'agent.md'), content, 'utf-8');
|
|
476
|
-
console.log(' ✓ agent.md 已写入本地');
|
|
384
|
+
console.log(`\n📡 AUN 渠道配置 — agent ${agentConfig.aid}`);
|
|
385
|
+
const current = agentConfig.owners?.[0];
|
|
386
|
+
if (current)
|
|
387
|
+
console.log(` 当前 Owner: ${current}`);
|
|
388
|
+
console.log(' Owner 将接收欢迎消息并拥有管理权限\n');
|
|
389
|
+
let owner = '';
|
|
390
|
+
while (!owner) {
|
|
391
|
+
const input = (await ask(rl, ` Owner AID${current ? ` [${current}]` : ''}: `)).trim();
|
|
392
|
+
if (!input) {
|
|
393
|
+
if (current) {
|
|
394
|
+
owner = current;
|
|
395
|
+
break;
|
|
477
396
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
failed = true;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
try {
|
|
484
|
-
await result.client.close();
|
|
397
|
+
console.log(' ⚠ Owner AID 不能为空');
|
|
398
|
+
continue;
|
|
485
399
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
400
|
+
if (!isValidAid(input)) {
|
|
401
|
+
console.log(' ⚠ Owner AID 格式无效(需合法多级域名,如 alice.agentid.pub)');
|
|
402
|
+
continue;
|
|
489
403
|
}
|
|
490
|
-
|
|
404
|
+
owner = input;
|
|
491
405
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (!failed)
|
|
498
|
-
break;
|
|
499
|
-
// Creation failed — retry or give up
|
|
500
|
-
const retry = (await ask(rl, ' → 重新输入 (r) / 跳过 (s) / 取消 (c)?[r/s/c] ')).trim().toLowerCase();
|
|
501
|
-
if (retry === 'c')
|
|
502
|
-
return null;
|
|
503
|
-
if (retry === 's')
|
|
504
|
-
break;
|
|
505
|
-
// default: retry with new AID
|
|
406
|
+
// 写入顶层 owners:新 owner 置首位(getOwner 取 owners[0]),保留其余去重
|
|
407
|
+
agentConfig.owners = [owner, ...(agentConfig.owners || []).filter(o => o !== owner)];
|
|
408
|
+
saveAgent(agentConfig);
|
|
409
|
+
console.log(`\n✅ AUN 渠道 Owner 已设置: ${owner}`);
|
|
410
|
+
console.log(`\n重启生效: evolclaw restart`);
|
|
506
411
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
console.log(' Owner 将接收欢迎消息并拥有管理权限');
|
|
510
|
-
let owner = '';
|
|
511
|
-
while (!owner) {
|
|
512
|
-
const ownerInput = (await ask(rl, ' Owner AID (必填): ')).trim();
|
|
513
|
-
if (!ownerInput) {
|
|
514
|
-
console.log(' ⚠ Owner AID 不能为空');
|
|
515
|
-
continue;
|
|
516
|
-
}
|
|
517
|
-
if (!isValidAid(ownerInput)) {
|
|
518
|
-
console.log(' ⚠ Owner AID 格式无效');
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
owner = ownerInput;
|
|
522
|
-
console.log(` ✓ Owner 已设置: ${owner}`);
|
|
412
|
+
finally {
|
|
413
|
+
rl.close();
|
|
523
414
|
}
|
|
524
|
-
return { aid, owner };
|
|
525
415
|
}
|
|
526
416
|
// ==================== DingTalk ====================
|
|
527
417
|
const DINGTALK_BASE_URL = 'https://oapi.dingtalk.com';
|