evolclaw 3.1.3 → 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.
Files changed (38) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/assets/.env.template +4 -0
  3. package/assets/config.json.template +6 -0
  4. package/assets/wechat-group-qr.jpeg +0 -0
  5. package/dist/agents/kit-renderer.js +35 -21
  6. package/dist/aun/aid/agentmd.js +25 -54
  7. package/dist/aun/aid/client.js +22 -7
  8. package/dist/aun/aid/identity.js +314 -28
  9. package/dist/aun/aid/index.js +1 -1
  10. package/dist/aun/rpc/connection.js +8 -13
  11. package/dist/channels/aun.js +31 -72
  12. package/dist/cli/agent.js +15 -22
  13. package/dist/cli/bench.js +8 -14
  14. package/dist/cli/help.js +23 -0
  15. package/dist/cli/index.js +371 -36
  16. package/dist/cli/init-channel.js +2 -3
  17. package/dist/cli/link-rules.js +2 -1
  18. package/dist/cli/net-check.js +10 -11
  19. package/dist/core/command-handler.js +6 -7
  20. package/dist/core/message/message-processor.js +19 -18
  21. package/dist/core/relation/peer-identity.js +64 -21
  22. package/dist/core/session/session-manager.js +6 -2
  23. package/dist/core/trigger/manager.js +37 -0
  24. package/dist/index.js +4 -1
  25. package/dist/paths.js +87 -16
  26. package/dist/utils/npm-ops.js +18 -11
  27. package/kits/eck_manifest.json +8 -8
  28. package/kits/rules/05-venue.md +2 -2
  29. package/kits/templates/system-fragments/baseagent.md +7 -1
  30. package/kits/templates/system-fragments/channel.md +4 -1
  31. package/kits/templates/system-fragments/identity.md +4 -4
  32. package/kits/templates/system-fragments/relation.md +8 -5
  33. package/kits/templates/system-fragments/session.md +20 -0
  34. package/kits/templates/system-fragments/venue.md +4 -1
  35. package/package.json +4 -2
  36. package/dist/net-check.js +0 -640
  37. package/dist/watch-msg.js +0 -544
  38. package/kits/templates/system-fragments/eckruntime.md +0 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## v3.1.4 (2026-05-27)
4
+
5
+ ### New Features
6
+
7
+ - **CLI help 系统重构 + ECK 注入** — 全新 help 子命令体系,ECK(EvolClaw Kit)注入机制重构,AID identity 管理命令
8
+ - **Menu 协议五动词拆分** — menu 协议拆分为 list/query/options/update/action 五个动词,命令收敛至 baseagent/session
9
+
10
+ ### Improvements
11
+
12
+ - **npm-ops 去 CLI 依赖** — checkLatestVersion 改用 HTTP fetch 直接查 registry API,去除对 npm CLI 的运行时依赖
13
+ - **agent.md 适配 SDK 0.3.3** — 统一 aun_path 到 EVOLCLAW_HOME,适配最新 SDK 版本
14
+
15
+ ### Bug Fixes
16
+
17
+ - **Session channelType 缺失修复** — 修复 channelType 缺失导致 chat dir 无法解析 + isBackgroundSession 同步化
18
+ - **SessionManager 查询路径 NPE** — 修复缺失 channelType 时的空指针异常
19
+
3
20
  ## v3.1.3 (2026-05-26)
4
21
 
5
22
  ### New Features
@@ -0,0 +1,4 @@
1
+ # AUN 环境变量
2
+ # 取消注释并填入值即可生效(进程已有的同名变量不会被覆盖)
3
+
4
+ # AUN_ENCRYPTION_SEED=your-seed-here
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema_version": 1,
3
+ "aun": {
4
+ "encryptionSeed": null
5
+ }
6
+ }
Binary file
@@ -14,20 +14,24 @@ const PARAM_DESCRIPTIONS = {
14
14
  peerId: '对端在该渠道的原生 ID',
15
15
  peerKey: '对端跨渠道唯一标识(channel#urlEncode(peerId))',
16
16
  peerName: '对端显示名',
17
- peerRole: '对端角色',
17
+ peerRole: '对端角色(owner/admin/guest/anonymous)',
18
+ peerType: '对端类型(human/agent)',
18
19
  groupId: '群组 ID(群聊时)',
19
- scene: '场景类型',
20
- chatType: '聊天类型',
21
- channel: '当前渠道',
22
- venueUid: 'venue 唯一标识',
23
- project: '当前项目目录名(由 CURRENT_PROJECT 派生)',
20
+ chatType: '聊天类型(private=私聊 / group=群聊 / null=本地开发)',
21
+ channel: '渠道类型(aun/feishu/wechat/dingtalk/qqbot/wecom)',
22
+ venueUid: '场所唯一标识(预留)',
23
+ capabilities: '当前渠道支持的能力列表',
24
+ project: '当前项目目录名',
25
+ sessionId: 'evolclaw 会话 ID',
24
26
  sessionName: '会话名称',
25
- chatmode: '会话模式(interactive/proactive)',
27
+ sessionCreatedAt: '会话创建时间(ISO)',
28
+ threadId: '话题 ID(多话题路由时)',
29
+ chatMode: '会话模式(interactive=同步交互 / proactive=主动推送)',
26
30
  readonly: '是否只读模式',
27
- canSendFile: '当前渠道是否支持发文件',
28
- capabilities: '渠道能力列表',
29
- baseAgent: '当前 base agent 规范值(claude/codex/gemini/hermes)',
30
- baseAgentName: '当前 base agent 显示名',
31
+ baseAgent: 'base agent 规范值(claude/codex/gemini/hermes)',
32
+ baseAgentName: 'base agent 显示名',
33
+ baseAgentModel: 'base agent 使用的模型',
34
+ agentSessionId: 'base agent 会话 ID',
31
35
  };
32
36
  function buildPathMappings(vars) {
33
37
  const pkgRoot = getPackageRoot();
@@ -276,17 +280,27 @@ function isTruthy(val) {
276
280
  }
277
281
  // CHUNK_CONTINUE_6
278
282
  // ── Template rendering ──
283
+ function resolveConditions(template, vars) {
284
+ // Find innermost {{?...}}...{{/}} block (no nested {{? inside) and resolve it.
285
+ // Repeat until no blocks remain.
286
+ const inner = /\{\{\?(\w+)(?:(!=|=)([^}]*))?\}\}([^]*?)\{\{\/\}\}/;
287
+ let result = template;
288
+ let prev;
289
+ do {
290
+ prev = result;
291
+ result = result.replace(inner, (_match, key, op, value, body) => {
292
+ if (op === '=')
293
+ return String(vars[key]) === value ? body : '';
294
+ if (op === '!=')
295
+ return String(vars[key]) !== value ? body : '';
296
+ return isTruthy(vars[key]) ? body : '';
297
+ });
298
+ } while (result !== prev);
299
+ return result;
300
+ }
279
301
  function renderTemplate(template, vars) {
280
- // Pass 1: conditional sections {{?key=value}}, {{?key!=value}}, {{?key}}...{{/}}
281
- let result = template.replace(/\{\{\?(\w+)(!=|=)([^}]*)?\}\}([\s\S]*?)\{\{\/\}\}/g, (_match, key, op, value, body) => {
282
- if (op === '!=')
283
- return String(vars[key]) !== value ? body : '';
284
- return String(vars[key]) === value ? body : '';
285
- });
286
- // Pass 1b: truthy-only {{?key}}...{{/}}
287
- result = result.replace(/\{\{\?(\w+)\}\}([\s\S]*?)\{\{\/\}\}/g, (_match, key, body) => {
288
- return isTruthy(vars[key]) ? body : '';
289
- });
302
+ // Pass 1: resolve nested conditionals inside-out
303
+ let result = resolveConditions(template, vars);
290
304
  // Pass 2: variable substitution {{key}}
291
305
  result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
292
306
  const val = vars[key];
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { getAunClient } from './client.js';
3
+ import { getAunClient, createAunClient } from './client.js';
4
4
  import { agentMdPath, aidLocalDir, resolveRoot } from '../../paths.js';
5
5
  export function buildInitialAgentMd(opts) {
6
6
  const agentName = opts.aid.split('.')[0];
@@ -82,66 +82,37 @@ async function verifyContent(content, aid, certPem, client) {
82
82
  * Create a bare AUNClient (no createAid) for read-only operations.
83
83
  */
84
84
  async function createBareClient(aunPath) {
85
- const p = aunPath ?? resolveRoot();
86
- const { AUNClient } = await import('@agentunion/fastaun');
87
- const caCertPath = path.join(p, 'CA', 'root', 'root.crt');
88
- const clientOpts = { aun_path: p, debug: false };
89
- if (fs.existsSync(caCertPath))
90
- clientOpts.root_ca_path = caCertPath;
91
- return new AUNClient(clientOpts);
85
+ return createAunClient({ aunPath });
92
86
  }
93
87
  export async function agentmdGet(aid, opts) {
94
88
  const aunPath = opts?.aunPath ?? resolveRoot();
95
- const localPath = agentMdPath(aid);
96
- // === Path A: local agent.md exists ===
97
- if (fs.existsSync(localPath)) {
98
- const content = fs.readFileSync(localPath, 'utf-8');
99
- if (!opts?.withVerification)
100
- return content;
101
- // Verify local content
102
- const client = opts?.client ?? await createBareClient(aunPath);
103
- const ownClient = !opts?.client;
104
- try {
105
- const certPem = await obtainCertPem(aid, aunPath, client);
106
- const verification = await verifyContent(content, aid, certPem, client);
107
- if (verification.status !== 'invalid') {
108
- return { content, verification };
109
- }
110
- // Fallback: local invalid → try remote
111
- try {
112
- const info = await client.fetchAgentMd(aid);
113
- const remote = info.content;
114
- if (remote) {
115
- const remoteVerification = await verifyContent(remote, aid, certPem, client);
116
- if (remoteVerification.status === 'verified') {
117
- fs.writeFileSync(localPath, remote, 'utf-8');
118
- return { content: remote, verification: remoteVerification };
119
- }
120
- }
121
- }
122
- catch { /* remote fetch failed, return local invalid result */ }
123
- return { content, verification };
124
- }
125
- finally {
126
- if (ownClient)
127
- try {
128
- await client.close();
129
- }
130
- catch { /* ignore */ }
131
- }
132
- }
133
- // === Path B: no local agent.md → download from remote ===
134
89
  const client = opts?.client ?? await createBareClient(aunPath);
135
90
  const ownClient = !opts?.client;
91
+ const localPath = agentMdPath(aid);
136
92
  try {
137
- const info = await client.fetchAgentMd(aid);
138
- const raw = info.content;
139
- if (!opts?.withVerification) {
140
- return raw;
93
+ // Try SDK fetch (auto-saves locally + verifies signature)
94
+ let content;
95
+ let verification;
96
+ try {
97
+ const info = await client.fetchAgentMd(aid);
98
+ content = info.content;
99
+ const sig = info.signature ?? {};
100
+ const status = sig.status === 'verified' ? 'verified' : sig.status === 'unsigned' ? 'unsigned' : 'invalid';
101
+ verification = { status, ...(sig.reason ? { reason: String(sig.reason) } : {}) };
141
102
  }
142
- const certPem = await obtainCertPem(aid, aunPath, client);
143
- const verification = await verifyContent(raw, aid, certPem, client);
144
- return { content: raw, verification };
103
+ catch (err) {
104
+ // Network failed fall back to local file (verify signature via SDK if requested)
105
+ if (!fs.existsSync(localPath))
106
+ throw err;
107
+ content = fs.readFileSync(localPath, 'utf-8');
108
+ if (opts?.withVerification) {
109
+ const certPem = await obtainCertPem(aid, aunPath, client);
110
+ verification = await verifyContent(content, aid, certPem, client);
111
+ }
112
+ }
113
+ if (!opts?.withVerification)
114
+ return content;
115
+ return { content: content, verification: verification ?? { status: 'unsigned' } };
145
116
  }
146
117
  finally {
147
118
  if (ownClient)
@@ -1,6 +1,5 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import os from 'os';
4
3
  import { fileURLToPath } from 'url';
5
4
  import { execFileSync } from 'child_process';
6
5
  import { isWindows } from '../../utils/cross-platform.js';
@@ -25,7 +24,7 @@ export function suppressSdkLogs() {
25
24
  return; process.stderr.write(args.map(String).join(' ') + '\n'); };
26
25
  }
27
26
  // ==================== Constants ====================
28
- export const MIN_AUN_CORE_SDK = [0, 2, 17];
27
+ export const MIN_AUN_CORE_SDK = [0, 3, 3];
29
28
  export const AUN_CORE_SDK_PKG = '@agentunion/fastaun';
30
29
  // ==================== SDK & Environment ====================
31
30
  function compareVersion(a, min) {
@@ -114,15 +113,31 @@ export async function downloadCaRoot(aunPath, gatewayUrl, indent = '') {
114
113
  return false;
115
114
  }
116
115
  }
117
- // ==================== AUNClient Factory ====================
118
- export async function getAunClient(aid, opts) {
119
- const aunPath = opts?.aunPath ?? path.join(os.homedir(), '.aun');
116
+ /**
117
+ * 统一构造 AUNClient:自动绑 root_ca_path + setAgentMdPath(aidsDir())。
118
+ * 不做 createAid / authenticate / connect,调用方按需续作。
119
+ *
120
+ * 所有 new AUNClient 调用都应走此工厂,避免 SDK 默认把 agent.md 写到
121
+ * {aun_path}/AgentMDs(默认目录)。
122
+ */
123
+ export async function createAunClient(opts = {}) {
124
+ const { aunPath: defaultAunPath, aidsDir } = await import('../../paths.js');
125
+ const aunPath = opts.aunPath ?? defaultAunPath();
120
126
  const caCertPath = path.join(aunPath, 'CA', 'root', 'root.crt');
121
127
  const { AUNClient } = await import('@agentunion/fastaun');
122
- const clientOpts = { aun_path: aunPath, debug: false };
128
+ const clientOpts = { aun_path: aunPath, debug: opts.debug ?? false };
123
129
  if (fs.existsSync(caCertPath))
124
130
  clientOpts.root_ca_path = caCertPath;
125
- const client = new AUNClient(clientOpts);
131
+ if (opts.encryptionSeed)
132
+ clientOpts.encryption_seed = opts.encryptionSeed;
133
+ const client = opts.aunSdkLog !== undefined
134
+ ? new AUNClient(clientOpts, opts.aunSdkLog)
135
+ : new AUNClient(clientOpts);
136
+ client.setAgentMdPath(aidsDir());
137
+ return client;
138
+ }
139
+ export async function getAunClient(aid, opts) {
140
+ const client = await createAunClient({ aunPath: opts?.aunPath });
126
141
  await client.auth.createAid({ aid });
127
142
  return client;
128
143
  }