evolcore 0.0.7 → 0.0.8

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 CHANGED
@@ -3,6 +3,25 @@
3
3
  本文件记录 EvolCore 的重要变更。EvolClaw 版本线的历史记录已归档至
4
4
  [`docs/_archive/CHANGELOG-evolclaw.md`](docs/_archive/CHANGELOG-evolclaw.md)。
5
5
 
6
+ ## 0.0.8 (2026-08-04)
7
+
8
+ ### AID 与域名管理
9
+
10
+ - 支持通过配置控制 AID 所属域名,并可在变更后自动迁移已有身份记录。
11
+
12
+ ### 运行稳定性
13
+
14
+ - 完善数据迁移的归档与收尾清理逻辑,降低目录结构演进带来的遗留数据风险。
15
+ - 增强 daemon 启停流程与运行状态诊断,异常时定位信息更准确。
16
+ - 完善 Agent 运行时在失败场景下的状态标记与回退行为。
17
+ - 修复 Windows 下 Codex CLI 的命令解析与进程启动兼容问题。
18
+
19
+ ### 交互体验
20
+
21
+ - AUN 交互卡片有效期延长至 24 小时,与实际使用节奏匹配。
22
+ - 修复 Web 控制台触发器视图中 daemon 控制触发器无处归属的问题,升级检查触发器包名一并修正。
23
+ - 优化 EC Web 网关状态展示。
24
+
6
25
  ## 0.0.7 (2026-08-03)
7
26
 
8
27
  ### 运行可靠性
package/README.md CHANGED
@@ -86,13 +86,13 @@ ResponseEngine.processMessage()
86
86
  **一行安装(macOS / Linux)**:
87
87
 
88
88
  ```bash
89
- curl -fsSL https://aun-network.oss-cn-hangzhou.aliyuncs.com/evolcore/install.sh | bash
89
+ curl -fsSL https://download.evolai.cn/install.sh | bash
90
90
  ```
91
91
 
92
92
  **Windows PowerShell**:
93
93
 
94
94
  ```powershell
95
- irm https://aun-network.oss-cn-hangzhou.aliyuncs.com/evolcore/install.ps1 | iex
95
+ irm https://download.evolai.cn/install.ps1 | iex
96
96
  ```
97
97
 
98
98
  安装器会自动进入 `ec init` 交互向导;只有已有配置同时包含控制 AID 和 Owner 时才跳过。绑定完成后运行 `ec start` 和 `ec status`。安装器不会停止或重启服务,详细流程见 [一键安装脚本说明](docs/evolcore-install-script.md)。
@@ -169,7 +169,7 @@ ec init aun
169
169
  ```
170
170
 
171
171
  **API 继承机制**:`agents.claude` 整个 section 可省略,系统自动按以下优先级继承:
172
- - `apiKey`:配置文件 → `ANTHROPIC_AUTH_TOKEN` 环境变量 → `~/.claude/settings.json`
172
+ - `apiKey`:配置文件 → `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_API_KEY` 环境变量 → `~/.claude/settings.json` 中对应变量
173
173
  - `baseUrl`:配置文件 → `ANTHROPIC_BASE_URL` 环境变量 → `~/.claude/settings.json`
174
174
  - `model`:配置文件 → `~/.claude/settings.json` → 默认 `sonnet`
175
175
  - `effort`:配置文件 → `~/.claude/settings.json` → SDK 默认值(`auto`)
@@ -50,6 +50,10 @@ function directInferenceValue(...values) {
50
50
  }
51
51
  return undefined;
52
52
  }
53
+ /** Claude Code accepts both names; AUTH_TOKEN is kept first for compatibility. */
54
+ function resolveAnthropicApiKey(...values) {
55
+ return directInferenceValue(...values);
56
+ }
53
57
  function loadClaudeSettings() {
54
58
  try {
55
59
  const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
@@ -80,12 +84,9 @@ export function resolveAnthropicConfig(config, override) {
80
84
  const isPlaceholder = (v) => !v || v.includes('your-') || v.includes('placeholder');
81
85
  const overrideApiKey = isPlaceholder(override?.apiKey) ? undefined : override?.apiKey;
82
86
  const globalApiKey = isPlaceholder(config.agents?.claude?.apiKey) ? undefined : config.agents?.claude?.apiKey;
83
- const apiKey = overrideApiKey
84
- || globalApiKey
85
- || process.env.ANTHROPIC_AUTH_TOKEN
86
- || settings.env?.ANTHROPIC_AUTH_TOKEN;
87
+ const apiKey = resolveAnthropicApiKey(overrideApiKey, globalApiKey, process.env.ANTHROPIC_AUTH_TOKEN, process.env.ANTHROPIC_API_KEY, settings.env?.ANTHROPIC_AUTH_TOKEN, settings.env?.ANTHROPIC_API_KEY);
87
88
  if (!apiKey) {
88
- throw new Error('No API key found. Set one of: baseagents.claude.apiKey (per-agent or defaults), env ANTHROPIC_AUTH_TOKEN, or ~/.claude/settings.json env.ANTHROPIC_AUTH_TOKEN');
89
+ throw new Error('No API key found for Claude. Set baseagents.claude.apiKey, env ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY, or the corresponding variable in ~/.claude/settings.json');
89
90
  }
90
91
  const isPlaceholderUrl = (v) => !v || v.includes('api.anthropic.com');
91
92
  const overrideBaseUrl = isPlaceholderUrl(override?.baseUrl) ? undefined : override?.baseUrl;
@@ -562,6 +562,7 @@ export class AgentRunner {
562
562
  const env = {
563
563
  ...process.env,
564
564
  ANTHROPIC_AUTH_TOKEN: this.apiKey,
565
+ ANTHROPIC_API_KEY: this.apiKey,
565
566
  PATH: process.env.PATH,
566
567
  DISABLE_AUTOUPDATER: '1',
567
568
  ...(this.baseUrl ? { ANTHROPIC_BASE_URL: this.baseUrl } : {}),
@@ -2,6 +2,7 @@ import { spawn } from 'child_process';
2
2
  import readline from 'readline';
3
3
  import { logger } from '../utils/logger.js';
4
4
  import { buildHClassGuardCommand } from '../core/permission/sandbox-runtime.js';
5
+ import { resolveCodexLaunchCommand } from '../utils/codex-cli.js';
5
6
  function hasPermissionProfile(config) {
6
7
  if (!config || typeof config.default_permissions !== 'string' || !config.default_permissions)
7
8
  return false;
@@ -330,11 +331,14 @@ export class CodexAppServerClient {
330
331
  env.OPENAI_BASE_URL = this.options.baseUrl;
331
332
  }
332
333
  const args = this.buildProcessArgs();
333
- const guardedCommand = buildHClassGuardCommand('codex', args);
334
+ const launchCommand = resolveCodexLaunchCommand(args);
335
+ if (!launchCommand)
336
+ throw new Error('Codex CLI not found');
337
+ const guardedCommand = buildHClassGuardCommand(launchCommand.command, launchCommand.args);
334
338
  if (process.platform === 'linux' && !guardedCommand) {
335
339
  throw new Error('Codex 缺少 EvolCore H 类路径隔离运行时,已拒绝启动 app-server');
336
340
  }
337
- this.proc = spawn(guardedCommand?.command ?? 'codex', guardedCommand?.args ?? args, {
341
+ this.proc = spawn(guardedCommand?.command ?? launchCommand.command, guardedCommand?.args ?? launchCommand.args, {
338
342
  cwd: this.options.cwd,
339
343
  env,
340
344
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -23,6 +23,7 @@ import { compareVersions } from '../utils/npm-ops.js';
23
23
  import { resolvePaths, resolveRoot } from '../paths.js';
24
24
  import { buildSessionTurnList } from '../core/session/session-turns.js';
25
25
  import { execFileSync } from 'child_process';
26
+ import { execCodexCliSync, resolveCodexCliPath } from '../utils/codex-cli.js';
26
27
  import { createHash, randomBytes } from 'crypto';
27
28
  import fs from 'fs';
28
29
  import path from 'path';
@@ -128,7 +129,7 @@ export function isCodexCliVersionSupported(version) {
128
129
  }
129
130
  export function getCodexCliVersion() {
130
131
  try {
131
- const output = execFileSync('codex', ['--version'], {
132
+ const output = execCodexCliSync(['--version'], {
132
133
  encoding: 'utf-8',
133
134
  timeout: 3000,
134
135
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -140,6 +141,10 @@ export function getCodexCliVersion() {
140
141
  }
141
142
  }
142
143
  export function getCodexAppServerAvailability() {
144
+ if (!resolveCodexCliPath()) {
145
+ const upgradeHint = '请升级 Codex CLI:npm install -g @openai/codex@latest';
146
+ return { available: false, reason: `未检测到可用 Codex CLI。${upgradeHint}` };
147
+ }
143
148
  const version = getCodexCliVersion();
144
149
  const upgradeHint = '请升级 Codex CLI:npm install -g @openai/codex@latest';
145
150
  if (!version) {
@@ -153,7 +158,7 @@ export function getCodexAppServerAvailability() {
153
158
  };
154
159
  }
155
160
  try {
156
- execFileSync('codex', ['app-server', '--help'], {
161
+ execCodexCliSync(['app-server', '--help'], {
157
162
  encoding: 'utf-8',
158
163
  timeout: 3000,
159
164
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -171,7 +176,7 @@ function fetchCodexCatalog() {
171
176
  if (codexCatalogCache)
172
177
  return codexCatalogCache;
173
178
  try {
174
- const output = execFileSync('codex', ['debug', 'models'], {
179
+ const output = execCodexCliSync(['debug', 'models'], {
175
180
  encoding: 'utf-8',
176
181
  timeout: 5000,
177
182
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -1,35 +1,46 @@
1
1
  import crypto from 'crypto';
2
2
  import { aidCreate } from './index.js';
3
+ import { DEFAULT_AID_DOMAIN, normalizeAidDomain } from './domain.js';
3
4
  import { getAidStore, SLOT } from './store.js';
4
5
  import { logger } from '../../utils/logger.js';
5
6
  const MAX_ATTEMPTS = 5;
6
- /** 解析控制 AID issuer:环境变量 EVOLCORE_ISSUER → 兜底 agentid.pub */
7
- export function resolveControlIssuer() {
8
- const env = process.env.EVOLCORE_ISSUER?.trim();
9
- if (env) {
10
- // Validate issuer format: must be valid domain-like structure
11
- if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(env)) {
12
- logger.error(`[control-aid] Invalid EVOLCORE_ISSUER format: ${env}, using default`);
13
- return 'agentid.pub';
14
- }
15
- // Prevent localhost/local domains
16
- if (env === 'localhost' || env.endsWith('.localhost') || env.startsWith('127.') || env.startsWith('0.')) {
17
- logger.error(`[control-aid] EVOLCORE_ISSUER cannot be localhost/local: ${env}, using default`);
18
- return 'agentid.pub';
19
- }
20
- // Length limit
21
- if (env.length > 253) {
22
- logger.error(`[control-aid] EVOLCORE_ISSUER too long: ${env.length} chars, using default`);
23
- return 'agentid.pub';
24
- }
7
+ export { DEFAULT_AID_DOMAIN } from './domain.js';
8
+ function environmentValue(name) {
9
+ if (!Object.prototype.hasOwnProperty.call(process.env, name))
10
+ return undefined;
11
+ return process.env[name]?.trim() ?? '';
12
+ }
13
+ /**
14
+ * Resolve the AID domain for automatically generated control identities.
15
+ *
16
+ * Explicit values fail closed. This avoids silently registering an identity
17
+ * under a different domain when deployment configuration is malformed.
18
+ */
19
+ export function resolveControlAidDomain(configuredAidDomain) {
20
+ const environmentDomain = environmentValue('EVOLCORE_AID_DOMAIN');
21
+ if (environmentDomain !== undefined)
22
+ return normalizeAidDomain(environmentDomain, 'EVOLCORE_AID_DOMAIN');
23
+ const legacyEnvironmentDomain = environmentValue('EVOLCORE_ISSUER');
24
+ if (legacyEnvironmentDomain !== undefined) {
25
+ logger.warn('[control-aid] EVOLCORE_ISSUER is deprecated; use EVOLCORE_AID_DOMAIN instead');
26
+ return normalizeAidDomain(legacyEnvironmentDomain, 'EVOLCORE_ISSUER');
25
27
  }
26
- return env || 'agentid.pub';
28
+ if (configuredAidDomain !== undefined) {
29
+ return normalizeAidDomain(configuredAidDomain, 'daemon.json.aun.defaultAidDomain');
30
+ }
31
+ return DEFAULT_AID_DOMAIN;
32
+ }
33
+ /** @deprecated Use resolveControlAidDomain(). */
34
+ export function resolveControlIssuer(configuredAidDomain) {
35
+ return resolveControlAidDomain(configuredAidDomain);
27
36
  }
28
- /** 生成候选控制 AID:ec + 5位随机数字 + .{issuer} */
29
- export function candidateAid(issuer) {
37
+ /** 生成候选控制 AID:ec + 5位随机数字 + .{aidDomain} */
38
+ export function candidateAid(aidDomain) {
30
39
  const n = crypto.randomInt(10000, 100000); // 5 位:10000-99999
31
- const finalIssuer = issuer || resolveControlIssuer();
32
- return `ec${n}.${finalIssuer}`;
40
+ const finalAidDomain = aidDomain === undefined
41
+ ? resolveControlAidDomain()
42
+ : normalizeAidDomain(aidDomain, 'aidDomain');
43
+ return `ec${n}.${finalAidDomain}`;
33
44
  }
34
45
  /**
35
46
  * 候选 AID 是否已在 PKI 注册。
@@ -56,12 +67,14 @@ async function candidateExists(store, candidate) {
56
67
  * - fail-fast:查重探测失败(网关不可达)立即抛错,不掩盖成"均冲突"
57
68
  * - agent.md 不上传:aidCreate 仅注册身份 + 写私钥,不调 agentmdPut
58
69
  */
59
- export async function generateControlAid() {
60
- const issuer = resolveControlIssuer();
70
+ export async function generateControlAid(aidDomain) {
71
+ const finalAidDomain = aidDomain === undefined
72
+ ? resolveControlAidDomain()
73
+ : normalizeAidDomain(aidDomain, 'aidDomain');
61
74
  const store = await getAidStore({ slotId: SLOT.cli });
62
75
  try {
63
76
  for (let i = 0; i < MAX_ATTEMPTS; i++) {
64
- const candidate = candidateAid(issuer);
77
+ const candidate = candidateAid(finalAidDomain);
65
78
  if (await candidateExists(store, candidate)) {
66
79
  logger.info(`[control-aid] ${candidate} 已注册,重试 (${i + 1}/${MAX_ATTEMPTS})`);
67
80
  continue;
@@ -0,0 +1,23 @@
1
+ export const DEFAULT_AID_DOMAIN = 'agentid.cn';
2
+ const DOMAIN_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;
3
+ const IPV4_RE = /^(?:\d{1,3}\.){3}\d{1,3}$/;
4
+ /** Normalize and validate the suffix domain used to construct an AID. */
5
+ export function normalizeAidDomain(value, source) {
6
+ if (typeof value !== 'string') {
7
+ throw new Error(`[aid-domain] ${source} must be a string`);
8
+ }
9
+ const aidDomain = value.trim().toLowerCase();
10
+ if (!DOMAIN_RE.test(aidDomain)) {
11
+ throw new Error(`[aid-domain] ${source} must be a valid multi-level domain: ${value}`);
12
+ }
13
+ if (IPV4_RE.test(aidDomain)) {
14
+ throw new Error(`[aid-domain] ${source} cannot be an IP address: ${value}`);
15
+ }
16
+ if (aidDomain.endsWith('.localhost')) {
17
+ throw new Error(`[aid-domain] ${source} cannot be a localhost/local domain: ${value}`);
18
+ }
19
+ if (aidDomain.length > 253) {
20
+ throw new Error(`[aid-domain] ${source} is too long: ${aidDomain.length} chars`);
21
+ }
22
+ return aidDomain;
23
+ }
@@ -35,6 +35,7 @@ import { isExplicitGroupId } from '../aun/group-identity.js';
35
35
  import { refreshAgentDisplayName, resolveAgentDisplayName } from '../aun/aid/agentmd.js';
36
36
  import { readInstalledEvolcoreVersion } from '../utils/evolcore-version.js';
37
37
  export const AUN_HANDOFF_MARKER_FIELD = '_evolcore_handoff_id';
38
+ const AUN_INTERACTION_CARD_TTL_MS = 24 * 60 * 60 * 1000;
38
39
  /**
39
40
  * 构造 connect extra_info:自描述本进程身份。
40
41
  *
@@ -275,8 +276,8 @@ export class AUNChannel {
275
276
  }
276
277
  }
277
278
  /** 判断 channelId 是否为群组 ID
278
- * - 新格式:group.{issuer}/{group_no|group_name}
279
- * - 数字群号:{group_no}.{issuer}(如 11117.agentid.pub
279
+ * - 新格式:group.{aidDomain}/{group_no|group_name}
280
+ * - 数字群号:{group_no}.{aidDomain}(如 11117.example.com
280
281
  * - 兼容旧格式:grp_xxx、g-xxx.agentid.pub
281
282
  */
282
283
  /** 判断 channelId 是否群组 ID(public:plugin adapter 闭包需调用) */
@@ -495,7 +496,7 @@ export class AUNChannel {
495
496
  }
496
497
  }
497
498
  else if (this.ownedCardMsgIds.has(cardMsgId)) {
498
- // 本 agent 发出的卡片,但 entry 已过期(20min TTL)
499
+ // 本 agent 发出的卡片,但 entry 已过期(24h TTL)
499
500
  logger.debug(`${this.logPrefix()} action_card_reply expired: cardMsgId=${cardMsgId}`);
500
501
  this.notifyCardActionFailure(channelId, '⚠️ 卡片已失效,请重新发起');
501
502
  }
@@ -884,8 +885,12 @@ export class AUNChannel {
884
885
  this.store = store;
885
886
  const client = await loadClient(store, aidName);
886
887
  this.client = client;
887
- // 仅作为配置/状态展示。当前 SDK public API 不接受 authenticate gateway override;
888
- // 实际 gateway SDK discovery + token-store metadata cache 解析。
888
+ // fastaun gives a preset in-memory gateway precedence over its metadata
889
+ // cache and AID discovery. authenticate({ gateway }) is deliberately
890
+ // rejected by its public API, so set the documented client preset before
891
+ // authentication instead.
892
+ if (configuredGateway)
893
+ client._gatewayUrl = configuredGateway;
889
894
  this.gatewayUrl = configuredGateway;
890
895
  // Register event handlers before connecting
891
896
  client.on('message.received', (data) => {
@@ -1364,24 +1369,24 @@ EvolCore AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1364
1369
  return null;
1365
1370
  }
1366
1371
  isTrustedStorageHost(host, normalizedOwner) {
1367
- const trustedIssuers = new Set();
1368
- // 对端 issuer(文件所有者 owner_aid)
1369
- const peerIssuer = this.extractIssuer(normalizedOwner);
1370
- if (peerIssuer)
1371
- trustedIssuers.add(peerIssuer);
1372
- // 本端 issuer(自己的 AID)
1373
- const selfIssuer = this.extractIssuer((this.getAid() || '').toLowerCase());
1374
- if (selfIssuer)
1375
- trustedIssuers.add(selfIssuer);
1376
- // 校验 host 是否为任一可信 issuer 的存储域名
1377
- for (const issuer of trustedIssuers) {
1378
- if (host === `storage.${issuer}`)
1372
+ const trustedAidDomains = new Set();
1373
+ // 对端 AID domain(文件所有者 owner_aid)
1374
+ const peerAidDomain = this.extractAidDomain(normalizedOwner);
1375
+ if (peerAidDomain)
1376
+ trustedAidDomains.add(peerAidDomain);
1377
+ // 本端 AID domain(自己的 AID)
1378
+ const selfAidDomain = this.extractAidDomain((this.getAid() || '').toLowerCase());
1379
+ if (selfAidDomain)
1380
+ trustedAidDomains.add(selfAidDomain);
1381
+ // 校验 host 是否为任一可信 AID domain 的存储域名
1382
+ for (const aidDomain of trustedAidDomains) {
1383
+ if (host === `storage.${aidDomain}`)
1379
1384
  return true;
1380
1385
  }
1381
1386
  return false;
1382
1387
  }
1383
- /** 从 AID 提取 issuer(去掉首段 label)。`mybot.agentid.pub` → `agentid.pub` */
1384
- extractIssuer(aid) {
1388
+ /** 从 AID 提取后缀 domain(去掉首段 label)。`mybot.example.com` → `example.com` */
1389
+ extractAidDomain(aid) {
1385
1390
  if (!aid || !aid.includes('.'))
1386
1391
  return '';
1387
1392
  return aid.split('.').slice(1).join('.');
@@ -2595,7 +2600,7 @@ EvolCore AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
2595
2600
  const now = Date.now();
2596
2601
  const mapTtl = action.expiresAt && action.expiresAt > now
2597
2602
  ? action.expiresAt - now
2598
- : 20 * 60 * 1000;
2603
+ : AUN_INTERACTION_CARD_TTL_MS;
2599
2604
  const mapTimer = setTimeout(() => {
2600
2605
  this.cardMessageIdMap.delete(messageId);
2601
2606
  const ids = this.interactionCardMessageIds.get(action.requestId);
@@ -4147,7 +4152,7 @@ export class AUNChannelPlugin {
4147
4152
  return;
4148
4153
  case 'interaction': {
4149
4154
  const req = payload.interaction;
4150
- const cardTtlMs = 20 * 60 * 1000;
4155
+ const cardTtlMs = AUN_INTERACTION_CARD_TTL_MS;
4151
4156
  if (req.kind.kind === 'action') {
4152
4157
  const action = req.kind;
4153
4158
  const aunCard = {
package/dist/cli/bench.js CHANGED
@@ -5,9 +5,10 @@ import os from 'os';
5
5
  import { execFile } from 'child_process';
6
6
  import { promisify } from 'util';
7
7
  import { aidList, aidCreate } from '../aun/aid/identity.js';
8
- import { resolveControlIssuer } from '../aun/aid/control-aid.js';
8
+ import { resolveControlAidDomain } from '../aun/aid/control-aid.js';
9
9
  import { msgSend, msgPull } from '../aun/msg/index.js';
10
10
  import { getPackageRoot, aunPath as defaultAunPath } from '../paths.js';
11
+ import { loadDaemonConfig } from '../config-store.js';
11
12
  import { getAidStore, loadClient, SLOT } from '../aun/aid/store.js';
12
13
  import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
13
14
  const execFileAsync = promisify(execFile);
@@ -476,10 +477,10 @@ Options:
476
477
  const need = numAids - usableAids.length;
477
478
  if (!formatJson)
478
479
  console.log(warn(`仅 ${usableAids.length} 个可用,需创建 ${need} 个新 AID`));
479
- const issuer = resolveControlIssuer();
480
+ const aidDomain = resolveControlAidDomain(loadDaemonConfig().aun?.defaultAidDomain);
480
481
  for (let i = 0; i < need; i++) {
481
482
  const hex = crypto.randomBytes(4).toString('hex');
482
- const newAid = `bench-${hex}.${issuer}`;
483
+ const newAid = `bench-${hex}.${aidDomain}`;
483
484
  try {
484
485
  await aidCreate(newAid, { aunPath });
485
486
  aids.push(newAid);