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.
@@ -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
- images.push({ data: buf.toString('base64'), mimeType: 'image/jpeg' });
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 { ok: false, error: `Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)` };
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 { ok: false, error: `Agent "${opts.aid}" already exists: ${agentDirPath}/config.json (use --force to overwrite)` };
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 { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or optional dependency @openai/codex-sdk.` };
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 { ok: false, error: `Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})` };
475
+ return failValidating(`Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`);
470
476
  }
471
477
  if (!available.includes(opts.baseagent)) {
472
- return { ok: false, error: `${opts.baseagent} is not available in the current environment (available: ${available.join('/')})` };
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 { ok: false, error: `--project must be absolute: ${opts.project}` };
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 { ok: false, error: `Failed to create ${opts.project}: ${e?.message || e}` };
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 { ok: false, error: `Invalid owner: ${opts.owner}` };
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
- return { ok: false, error: `AID creation failed: ${e?.message || e}` };
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 { /* daemon not running */ }
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
- if (isBatch) {
2132
- const q = (s) => `"${s}"`;
2133
- execFileSync(q(exe), ['--home', q(home)], { stdio: 'inherit', shell: true });
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
- else {
2136
- execFileSync(exe, ['--home', home], { stdio: 'inherit' });
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);
@@ -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 { npmInstallGlobal } from '../utils/npm-ops.js';
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 { AUN_CORE_SDK_PKG, MIN_AUN_CORE_SDK, resolveAunCoreSdkPkg, isAunSdkVersionOk, isValidAid, aidCreate, agentmdPut, buildInitialAgentMd, } from '../aun/aid/index.js';
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 原子操作(aidCreate, agentmdPut, downloadCaRoot, isValidAid, ...)
377
- // 已迁移至 src/channels/aun-ops.ts。本节仅保留交互式 UI 编排。
378
- export async function checkAunEnvironment(rl) {
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 npmInstallGlobal(`${AUN_CORE_SDK_PKG}@latest`);
415
- console.log(` ✓ ${AUN_CORE_SDK_PKG} 升级完成`);
416
- }
417
- catch (e) {
418
- console.log(` ✗ 升级失败: ${e.message?.slice(0, 200) || e}`);
419
- return false;
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
- // Create AID + agent.md via atomic ops
456
- console.log(' 正在创建 AID...');
457
- let failed = false;
458
- try {
459
- const result = await aidCreate(aid);
460
- console.log(` ✓ AID ${result.aid} 创建成功`);
461
- // Collect agent.md type and upload
462
- const typeInput = (await ask(rl, ' Agent 类型 human/ai [ai]: ')).trim().toLowerCase();
463
- const agentType = typeInput === 'human' ? 'human' : 'ai';
464
- const content = buildInitialAgentMd({ aid, type: agentType });
465
- try {
466
- await agentmdPut(content, { aid });
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
- catch (we) {
479
- console.log(` ✗ agent.md 本地写入失败: ${String(we.message || we).slice(0, 100)}`);
480
- failed = true;
481
- }
482
- }
483
- try {
484
- await result.client.close();
397
+ console.log(' ⚠ Owner AID 不能为空');
398
+ continue;
485
399
  }
486
- catch { /* ignore */ }
487
- try {
488
- result.store?.close();
400
+ if (!isValidAid(input)) {
401
+ console.log(' ⚠ Owner AID 格式无效(需合法多级域名,如 alice.agentid.pub)');
402
+ continue;
489
403
  }
490
- catch { /* ignore */ }
404
+ owner = input;
491
405
  }
492
- catch (e) {
493
- const msg = e.message || String(e);
494
- console.log(` ✗ AID 创建失败: ${msg.slice(0, 200)}`);
495
- failed = true;
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
- // Owner 必填
508
- console.log('\n📋 Owner 配置');
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';