evolclaw 2.7.3 → 2.8.1
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/dist/agents/claude-runner.js +91 -48
- package/dist/channels/aun-ops.js +275 -0
- package/dist/channels/aun.js +285 -125
- package/dist/cli.js +360 -1
- package/dist/config.js +1 -1
- package/dist/core/agent-registry.js +164 -0
- package/dist/core/command-handler.js +147 -97
- package/dist/core/evolagent-schema.js +72 -0
- package/dist/core/evolagent.js +66 -0
- package/dist/core/message/message-bridge.js +14 -2
- package/dist/core/message/message-processor.js +24 -10
- package/dist/core/message/thought-emitter.js +4 -2
- package/dist/core/session/session-manager.js +22 -3
- package/dist/index.js +8 -12
- package/dist/paths.js +2 -0
- package/dist/templates/prompts.md +1 -0
- package/dist/utils/init-channel.js +91 -221
- package/dist/utils/init.js +18 -42
- package/dist/utils/logger.js +58 -2
- package/evolclaw-install-aun.md +48 -7
- package/package.json +2 -2
package/dist/utils/init.js
CHANGED
|
@@ -396,7 +396,7 @@ export async function cmdInit(options) {
|
|
|
396
396
|
// 非交互式模式
|
|
397
397
|
if (options?.nonInteractive) {
|
|
398
398
|
const config = JSON.parse(fs.readFileSync(sampleSrc, 'utf-8'));
|
|
399
|
-
const defaultPath = options.defaultPath || path.join(os.homedir(), '
|
|
399
|
+
const defaultPath = options.defaultPath || path.join(os.homedir(), 'projects', 'default');
|
|
400
400
|
if (!fs.existsSync(defaultPath))
|
|
401
401
|
fs.mkdirSync(defaultPath, { recursive: true });
|
|
402
402
|
config.projects.defaultPath = defaultPath;
|
|
@@ -405,56 +405,32 @@ export async function cmdInit(options) {
|
|
|
405
405
|
throw new Error('--aun-aid is required for AUN channel (e.g. --aun-aid mybot.agentid.pub)');
|
|
406
406
|
}
|
|
407
407
|
if (options.channel === 'aun' && options.aunAid) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (!resolveAunCoreSdkPkg()) {
|
|
411
|
-
console.log('正在安装 @agentunion/fastaun...');
|
|
412
|
-
await npmInstallGlobal('@agentunion/fastaun@latest');
|
|
413
|
-
}
|
|
414
|
-
// 创建 AID(如果本地不存在)
|
|
408
|
+
const { ensureAunSdk, aidCreate, agentmdPut, buildInitialAgentMd } = await import('../channels/aun-ops.js');
|
|
409
|
+
await ensureAunSdk();
|
|
415
410
|
const aunPath = path.join(os.homedir(), '.aun');
|
|
416
411
|
const aidDir = path.join(aunPath, 'AIDs', options.aunAid);
|
|
417
412
|
if (!fs.existsSync(path.join(aidDir, 'private'))) {
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const result = await client.auth.createAid({ aid: options.aunAid });
|
|
422
|
-
// 下载 CA 根证书(如果本地不存在),从 SDK 返回的实际网关 URL 派生
|
|
423
|
-
const caDownloaded = await downloadCaRoot(aunPath, result.gateway || '');
|
|
424
|
-
// 关键:SDK 默认 rootCaPath=null,只读取包内 bundled certs。
|
|
425
|
-
// 必须显式传 root_ca_path 指向刚下载的 root.crt,uploadAgentMd 才能验证 server cert。
|
|
426
|
-
// 同时传 aid,否则新 client 不知道该加载哪个身份,uploadAgentMd 会报
|
|
427
|
-
// "no local identity found, call auth.createAid() first"。
|
|
428
|
-
const caCertPath = path.join(aunPath, 'CA', 'root', 'root.crt');
|
|
429
|
-
if (caDownloaded && fs.existsSync(caCertPath)) {
|
|
413
|
+
const result = await aidCreate(options.aunAid);
|
|
414
|
+
try {
|
|
415
|
+
const content = buildInitialAgentMd({ aid: options.aunAid });
|
|
430
416
|
try {
|
|
431
|
-
await client.
|
|
417
|
+
await agentmdPut(content, { aid: options.aunAid, client: result.client });
|
|
418
|
+
}
|
|
419
|
+
catch (e) {
|
|
420
|
+
console.warn(`⚠ agent.md 网络发布失败(首次连接将自动重试): ${String(e?.message || e).slice(0, 100)}`);
|
|
421
|
+
fs.mkdirSync(aidDir, { recursive: true });
|
|
422
|
+
fs.writeFileSync(path.join(aidDir, 'agent.md'), content, 'utf-8');
|
|
423
|
+
}
|
|
424
|
+
if (!fs.existsSync(path.join(aidDir, 'agent.md'))) {
|
|
425
|
+
throw new Error(`agent.md 写入校验失败: ${path.join(aidDir, 'agent.md')}`);
|
|
432
426
|
}
|
|
433
|
-
catch { }
|
|
434
|
-
client = new AUNClient({ aun_path: aunPath, root_ca_path: caCertPath, aid: options.aunAid });
|
|
435
|
-
}
|
|
436
|
-
// 写入初始 agent.md(initialized: false)
|
|
437
|
-
const agentName = options.aunAid.split('.')[0];
|
|
438
|
-
const agentMd = `---\naid: "${options.aunAid}"\nname: "${agentName}"\ntype: "ai"\nversion: "1.0.0"\ndescription: ""\ntags:\n - evolclaw\ninitialized: false\n---\n`;
|
|
439
|
-
const agentMdPath = path.join(aidDir, 'agent.md');
|
|
440
|
-
try {
|
|
441
|
-
await client.auth.uploadAgentMd(agentMd);
|
|
442
|
-
}
|
|
443
|
-
catch (e) {
|
|
444
|
-
console.warn(`⚠ agent.md 网络发布失败(首次连接将自动重试): ${String(e?.message || e).slice(0, 100)}`);
|
|
445
427
|
}
|
|
446
|
-
|
|
447
|
-
if (!fs.existsSync(agentMdPath)) {
|
|
428
|
+
finally {
|
|
448
429
|
try {
|
|
449
|
-
await client.close();
|
|
430
|
+
await result.client.close();
|
|
450
431
|
}
|
|
451
432
|
catch { }
|
|
452
|
-
throw new Error(`agent.md 写入校验失败: ${agentMdPath}`);
|
|
453
|
-
}
|
|
454
|
-
try {
|
|
455
|
-
await client.close();
|
|
456
433
|
}
|
|
457
|
-
catch { }
|
|
458
434
|
}
|
|
459
435
|
config.channels.aun = {
|
|
460
436
|
enabled: true,
|
|
@@ -483,7 +459,7 @@ export async function cmdInit(options) {
|
|
|
483
459
|
}
|
|
484
460
|
console.log('📝 交互式配置\n');
|
|
485
461
|
// 通用配置
|
|
486
|
-
const defaultSuggestion = path.join(os.homedir(), '
|
|
462
|
+
const defaultSuggestion = path.join(os.homedir(), 'projects', 'default');
|
|
487
463
|
let defaultPath = (await ask(rl, ` 默认项目路径 [${defaultSuggestion}]: `)).trim();
|
|
488
464
|
if (!defaultPath)
|
|
489
465
|
defaultPath = defaultSuggestion;
|
package/dist/utils/logger.js
CHANGED
|
@@ -4,6 +4,9 @@ import { resolvePaths } from '../paths.js';
|
|
|
4
4
|
const LOG_DIR = resolvePaths().logs;
|
|
5
5
|
let currentLevel = process.env.LOG_LEVEL || 'INFO';
|
|
6
6
|
const LEVELS = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
|
|
7
|
+
const HOUR_MS = 60 * 60 * 1000;
|
|
8
|
+
const RETAIN_HOURS = 12;
|
|
9
|
+
const LOG_FILE_RE = /^evolclaw-\d{8}-\d{2}\.log$/;
|
|
7
10
|
const config = {
|
|
8
11
|
messageLog: process.env.MESSAGE_LOG === 'true',
|
|
9
12
|
eventLog: process.env.EVENT_LOG === 'true'
|
|
@@ -11,8 +14,60 @@ const config = {
|
|
|
11
14
|
if (!fs.existsSync(LOG_DIR)) {
|
|
12
15
|
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
13
16
|
}
|
|
17
|
+
/** 获取当前小时标识 YYYYMMDD-HH */
|
|
18
|
+
function currentHourTag() {
|
|
19
|
+
const d = new Date();
|
|
20
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
21
|
+
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}`;
|
|
22
|
+
}
|
|
23
|
+
/** 清理超过 RETAIN_HOURS 的旧日志文件 */
|
|
24
|
+
function cleanupOldLogs() {
|
|
25
|
+
const cutoff = Date.now() - RETAIN_HOURS * HOUR_MS;
|
|
26
|
+
try {
|
|
27
|
+
for (const name of fs.readdirSync(LOG_DIR)) {
|
|
28
|
+
if (!LOG_FILE_RE.test(name))
|
|
29
|
+
continue;
|
|
30
|
+
try {
|
|
31
|
+
const full = path.join(LOG_DIR, name);
|
|
32
|
+
if (fs.statSync(full).mtimeMs < cutoff)
|
|
33
|
+
fs.unlinkSync(full);
|
|
34
|
+
}
|
|
35
|
+
catch { }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch { }
|
|
39
|
+
}
|
|
40
|
+
let mainHourTag = currentHourTag();
|
|
41
|
+
let mainStream = fs.createWriteStream(path.join(LOG_DIR, `evolclaw-${mainHourTag}.log`), { flags: 'a' });
|
|
42
|
+
// 同时保留 evolclaw.log 软链接指向当前文件,方便 tail -f
|
|
43
|
+
function updateSymlink() {
|
|
44
|
+
const link = path.join(LOG_DIR, 'evolclaw.log');
|
|
45
|
+
const target = `evolclaw-${mainHourTag}.log`;
|
|
46
|
+
try {
|
|
47
|
+
fs.unlinkSync(link);
|
|
48
|
+
}
|
|
49
|
+
catch { }
|
|
50
|
+
try {
|
|
51
|
+
fs.symlinkSync(target, link);
|
|
52
|
+
}
|
|
53
|
+
catch { }
|
|
54
|
+
}
|
|
55
|
+
updateSymlink();
|
|
56
|
+
// 启动时清理一次,之后每小时清理
|
|
57
|
+
cleanupOldLogs();
|
|
58
|
+
const cleanupTimer = setInterval(cleanupOldLogs, HOUR_MS);
|
|
59
|
+
cleanupTimer.unref?.();
|
|
60
|
+
function rotateMainIfNeeded() {
|
|
61
|
+
const tag = currentHourTag();
|
|
62
|
+
if (tag === mainHourTag)
|
|
63
|
+
return;
|
|
64
|
+
mainStream.end();
|
|
65
|
+
mainHourTag = tag;
|
|
66
|
+
mainStream = fs.createWriteStream(path.join(LOG_DIR, `evolclaw-${mainHourTag}.log`), { flags: 'a' });
|
|
67
|
+
updateSymlink();
|
|
68
|
+
cleanupOldLogs();
|
|
69
|
+
}
|
|
14
70
|
const streams = {
|
|
15
|
-
main: fs.createWriteStream(path.join(LOG_DIR, 'evolclaw.log'), { flags: 'a' }),
|
|
16
71
|
message: config.messageLog ? fs.createWriteStream(path.join(LOG_DIR, 'messages.log'), { flags: 'a' }) : null,
|
|
17
72
|
event: config.eventLog ? fs.createWriteStream(path.join(LOG_DIR, 'events.log'), { flags: 'a' }) : null
|
|
18
73
|
};
|
|
@@ -33,9 +88,10 @@ export function localTimestamp() {
|
|
|
33
88
|
function log(level, ...args) {
|
|
34
89
|
if (!shouldLog(level))
|
|
35
90
|
return;
|
|
91
|
+
rotateMainIfNeeded();
|
|
36
92
|
const timestamp = localTimestamp();
|
|
37
93
|
const msg = `[${timestamp}] [${level}] ${args.join(' ')}`;
|
|
38
|
-
write(
|
|
94
|
+
mainStream.write(msg + '\n');
|
|
39
95
|
}
|
|
40
96
|
/**
|
|
41
97
|
* 设置日志级别(config 加载后调用,覆盖环境变量默认值)
|
package/evolclaw-install-aun.md
CHANGED
|
@@ -46,23 +46,64 @@ export PATH=~/.npm-global/bin:$PATH
|
|
|
46
46
|
npm install -g evolclaw
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
### 步骤 3
|
|
49
|
+
### 步骤 3:检查是否已在运行
|
|
50
|
+
|
|
51
|
+
npm 安装完成后,先检查是否有正在运行的 evolclaw 进程。升级或重装场景下,旧进程仍在使用旧版本代码,必须停止后才能让新版本生效。
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
evolclaw status
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
判断逻辑:
|
|
58
|
+
|
|
59
|
+
- 输出包含 `running` / `PID` / `已启动` 等表明服务在运行 → **询问用户**是否停止:
|
|
60
|
+
|
|
61
|
+
> 检测到 evolclaw 正在运行(PID: xxx)。继续安装需要停止当前服务以应用新版本,是否停止?(y/N)
|
|
62
|
+
|
|
63
|
+
用户确认后执行:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
evolclaw stop
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
用户拒绝则中止安装流程,提醒其手动 `evolclaw stop` 后重新发起。
|
|
70
|
+
|
|
71
|
+
- 输出表明未运行(`not running` / `stopped` / 无 PID)→ 直接进入下一步。
|
|
72
|
+
|
|
73
|
+
### 步骤 4:准备配置信息
|
|
50
74
|
|
|
51
75
|
| 参数 | 说明 | 示例 |
|
|
52
76
|
|------|------|------|
|
|
53
77
|
| `--aun-aid` | **必填**,Agent 自身的 AID,作为 bot 在 AUN 网络上的独立身份 | `mybot.agentid.pub` |
|
|
54
78
|
| `--aun-owner` | **必填**,Owner 的 AID,用于接收欢迎消息和管理权限 | `alice.agentid.pub` |
|
|
55
|
-
| `--default-path` |
|
|
79
|
+
| `--default-path` | 默认项目路径(bot 会话未显式 `/bind` 时使用的工作目录) | `/home/user/myproject` |
|
|
56
80
|
|
|
57
81
|
**注意**:`--aun-aid` 和 `--aun-owner` 必须是不同的 AID。Agent 需要独立身份,不能与 Owner 相同。
|
|
58
82
|
|
|
59
83
|
如果用户在触发安装时已提供 Owner AID(例如消息中包含"将 xxx 添加为 Owner ID"),直接使用该值,否则询问用户。Agent AID 必须单独询问用户,不能默认使用 Owner AID。
|
|
60
84
|
|
|
61
|
-
|
|
85
|
+
**默认项目路径必须询问用户,提供三个选项:**
|
|
86
|
+
|
|
87
|
+
1. **推荐默认**:`~/projects/default`(EvolClaw 约定的默认工作区;若不存在会自动创建)
|
|
88
|
+
2. **当前 Claude Code 运行目录**:即本次会话启动 `claude` 的工作目录(通过 `pwd` 获取)——适合希望 bot 直接在当前项目里工作的场景
|
|
89
|
+
3. **自定义路径**:用户指定绝对路径(须是已存在的目录,或接受后自动创建)
|
|
90
|
+
|
|
91
|
+
示例提问:
|
|
92
|
+
|
|
93
|
+
> 请选择默认项目目录(bot 未显式 `/bind` 时使用的工作目录):
|
|
94
|
+
> 1) `~/projects/default`(推荐,EvolClaw 默认工作区)
|
|
95
|
+
> 2) 当前目录:`<pwd 输出>`
|
|
96
|
+
> 3) 自定义路径(请提供绝对路径)
|
|
97
|
+
|
|
98
|
+
用户未选择时,默认取选项 1。选项 3 需校验路径是绝对路径;目录不存在则 `mkdir -p` 创建。
|
|
99
|
+
|
|
100
|
+
### 步骤 5:非交互式初始化
|
|
101
|
+
|
|
102
|
+
将用户选择的目录作为 `--default-path` 传入:
|
|
62
103
|
|
|
63
104
|
```bash
|
|
64
105
|
evolclaw init --non-interactive \
|
|
65
|
-
--default-path
|
|
106
|
+
--default-path <用户选择的绝对路径> \
|
|
66
107
|
--channel aun \
|
|
67
108
|
--aun-aid <AID> \
|
|
68
109
|
--aun-owner <Owner AID>
|
|
@@ -76,7 +117,7 @@ evolclaw init --non-interactive \
|
|
|
76
117
|
5. 写入初始 `agent.md`(`initialized: false`)
|
|
77
118
|
6. 写入配置(含 owner 字段)
|
|
78
119
|
|
|
79
|
-
### 步骤
|
|
120
|
+
### 步骤 6:启动前验证
|
|
80
121
|
|
|
81
122
|
读取配置文件确认关键字段:
|
|
82
123
|
|
|
@@ -92,13 +133,13 @@ cat ~/.evolclaw/data/evolclaw.json
|
|
|
92
133
|
|
|
93
134
|
如发现缺失或异常,向用户说明并提供修复方案。
|
|
94
135
|
|
|
95
|
-
### 步骤
|
|
136
|
+
### 步骤 7:启动服务
|
|
96
137
|
|
|
97
138
|
```bash
|
|
98
139
|
evolclaw start
|
|
99
140
|
```
|
|
100
141
|
|
|
101
|
-
### 步骤
|
|
142
|
+
### 步骤 8:验证运行状态
|
|
102
143
|
|
|
103
144
|
```bash
|
|
104
145
|
evolclaw status
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Lightweight AI Agent gateway connecting Claude Agent SDK to messaging channels (Feishu, ACP) with multi-project session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"prepublishOnly": "npm run build && npm test"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@agentunion/fastaun": "^0.2.
|
|
26
|
+
"@agentunion/fastaun": "^0.2.17",
|
|
27
27
|
"@anthropic-ai/claude-agent-sdk": "^0.2.100",
|
|
28
28
|
"image-type": "^6.0.0",
|
|
29
29
|
"qrcode-terminal": "^0.12.0"
|