evolclaw 3.1.11 → 3.3.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 +41 -0
- package/README.md +27 -2
- package/dist/agents/{resolve.js → baseagent.js} +34 -5
- package/dist/agents/claude-runner.js +120 -27
- package/dist/agents/codex-app-server-client.js +364 -0
- package/dist/agents/codex-runner.js +1069 -141
- package/dist/agents/gemini-runner.js +2 -2
- package/dist/agents/runner-types.js +28 -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/aun/storage/download.js +1 -1
- package/dist/aun/storage/upload.js +13 -1
- package/dist/channels/aun.js +538 -325
- package/dist/channels/dingtalk.js +77 -140
- package/dist/channels/feishu.js +98 -151
- package/dist/channels/qqbot.js +75 -138
- package/dist/channels/wechat.js +75 -136
- package/dist/channels/wecom.js +75 -138
- package/dist/cli/agent.js +44 -13
- package/dist/cli/index.js +207 -46
- package/dist/cli/init-channel.js +38 -148
- package/dist/cli/init.js +192 -85
- package/dist/cli/model.js +1 -1
- package/dist/cli/stats.js +558 -0
- package/dist/cli/version.js +87 -0
- package/dist/cli/watch-msg.js +5 -2
- package/dist/config-store.js +48 -11
- package/dist/core/channel-loader.js +84 -82
- package/dist/core/command-handler.js +754 -172
- package/dist/core/daemon-file-cache.js +216 -0
- package/dist/core/evolagent-registry.js +4 -0
- package/dist/core/evolagent.js +28 -23
- package/dist/core/interaction-router.js +8 -0
- package/dist/core/message/command-handler-agent-control.js +215 -0
- package/dist/core/message/create-status.js +67 -0
- package/dist/core/message/im-renderer.js +35 -13
- package/dist/core/message/items-formatter.js +9 -1
- package/dist/core/message/message-bridge.js +52 -22
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-processor.js +336 -68
- package/dist/core/message/message-queue.js +15 -8
- package/dist/core/message/pending-hints.js +232 -0
- package/dist/core/message/response-depth.js +56 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-scope.js +40 -7
- package/dist/core/permission.js +9 -12
- package/dist/core/relation/peer-identity.js +16 -1
- package/dist/core/session/adapters/claude-session-file-adapter.js +48 -5
- package/dist/core/session/adapters/codex-session-file-adapter.js +4 -2
- package/dist/core/session/session-manager.js +27 -13
- package/dist/core/session/session-title.js +26 -0
- package/dist/core/stats/billing.js +151 -0
- package/dist/core/stats/budget.js +93 -0
- package/dist/core/stats/db.js +314 -0
- package/dist/core/stats/eck-vars.js +84 -0
- package/dist/core/stats/index.js +10 -0
- package/dist/core/stats/normalizer.js +78 -0
- package/dist/core/stats/query.js +760 -0
- package/dist/core/stats/writer.js +115 -0
- package/dist/core/trigger/manager.js +34 -0
- package/dist/core/trigger/parser.js +9 -3
- package/dist/core/trigger/scheduler.js +20 -17
- package/dist/{agents → eck}/kit-renderer.js +5 -1
- package/dist/{agents → eck}/manifest-engine.js +127 -35
- package/dist/{agents → eck}/message-renderer.js +26 -1
- package/dist/index.js +185 -8
- package/dist/ipc.js +22 -0
- package/dist/paths.js +7 -3
- package/dist/utils/cross-platform.js +23 -5
- package/dist/utils/ecweb-pair.js +20 -0
- package/dist/utils/stats.js +14 -0
- package/kits/docs/evolclaw/INDEX.md +3 -1
- package/kits/docs/evolclaw/fs-architecture.md +1215 -0
- package/kits/docs/evolclaw/fs.md +131 -0
- package/kits/docs/evolclaw/group-fs.md +209 -0
- package/kits/docs/evolclaw/stats.md +70 -0
- package/kits/docs/venues/aun-group.md +29 -6
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +12 -0
- package/kits/eck_message_manifest.json +30 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/templates/message-fragments/inject-default.md +2 -0
- package/kits/templates/message-fragments/item.md +1 -1
- package/kits/templates/system-fragments/response-depth.md +16 -0
- package/package.json +4 -4
- package/dist/agents/baseagent-normalize.js +0 -19
- package/dist/core/relation/peer-key.js +0 -16
- package/dist/utils/channel-helpers.js +0 -46
package/dist/cli/index.js
CHANGED
|
@@ -5,18 +5,21 @@ import os from 'os';
|
|
|
5
5
|
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
|
-
import { loadDefaults, loadAllAgents, mergeForAgent } from '../config-store.js';
|
|
9
|
-
import { resolveAnthropicConfig } from '../agents/
|
|
8
|
+
import { loadDefaults, loadAllAgents, mergeForAgent, loadEvolclawConfig, saveEvolclawConfig } from '../config-store.js';
|
|
9
|
+
import { resolveAnthropicConfig } from '../agents/baseagent.js';
|
|
10
10
|
import { migrateProject } from '../config-store.js';
|
|
11
|
-
import
|
|
11
|
+
import readline from 'readline';
|
|
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';
|
|
17
18
|
import { tryUpgrade, tryUpgradeAunSdk } from '../utils/npm-ops.js';
|
|
19
|
+
import { fetchEcwebPairCode } from '../utils/ecweb-pair.js';
|
|
18
20
|
import { resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG } from '../aun/aid/client.js';
|
|
19
21
|
import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
|
|
22
|
+
import { displaySessionTitle } from '../core/session/session-title.js';
|
|
20
23
|
// Suppress Node.js ExperimentalWarning (e.g. SQLite) from cluttering CLI output
|
|
21
24
|
process.removeAllListeners('warning');
|
|
22
25
|
process.on('warning', (w) => { if (w.name === 'ExperimentalWarning')
|
|
@@ -299,6 +302,40 @@ async function cmdStart() {
|
|
|
299
302
|
await cmdInit();
|
|
300
303
|
return;
|
|
301
304
|
}
|
|
305
|
+
// 控制 AID 门禁:缺 aid 且交互式 → 只补全控制 AID + owners(不重走 baseagent 向导)。
|
|
306
|
+
// 非 TTY(restart-monitor/systemd/管道)不补全(无法交互),只提示后继续启动,daemon 侧 warn 兜底。
|
|
307
|
+
const evolclawCfgStart = loadEvolclawConfig();
|
|
308
|
+
if (needsControlAidInit(evolclawCfgStart.aid, !!process.stdin.isTTY)) {
|
|
309
|
+
console.log('⚡ 控制 AID 未配置,自动补全...\n');
|
|
310
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
311
|
+
suppressSdkLogs();
|
|
312
|
+
await initTail();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (!evolclawCfgStart.aid) {
|
|
316
|
+
console.log('⚠ 控制 AID 未配置(非交互式启动,跳过补全)。如需进程身份/远程管理,请运行 evolclaw init');
|
|
317
|
+
}
|
|
318
|
+
else if (process.stdin.isTTY) {
|
|
319
|
+
// 证书缺失时在 CLI 侧提示,daemon 是后台进程无终端不做交互
|
|
320
|
+
const certKey = path.join(resolvePaths().root, 'AIDs', evolclawCfgStart.aid, 'private', 'key.json');
|
|
321
|
+
if (!fs.existsSync(certKey)) {
|
|
322
|
+
console.log(`⚠ 控制 AID 证书缺失:${evolclawCfgStart.aid}`);
|
|
323
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
324
|
+
const ans = await new Promise(res => rl.question(' [1] 继续启动 [2] 重新生成 AID [3] 退出 [1/2/3]: ', res));
|
|
325
|
+
rl.close();
|
|
326
|
+
if (ans.trim() === '3') {
|
|
327
|
+
process.exit(0);
|
|
328
|
+
}
|
|
329
|
+
if (ans.trim() === '2') {
|
|
330
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
331
|
+
suppressSdkLogs();
|
|
332
|
+
const { generateControlAid } = await import('../aun/aid/control-aid.js');
|
|
333
|
+
const result = await generateControlAid();
|
|
334
|
+
saveEvolclawConfig({ ...loadEvolclawConfig(), aid: result.aid });
|
|
335
|
+
console.log(`✓ 新控制 AID: ${result.aid}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
302
339
|
// 检查至少有一个 self-agent
|
|
303
340
|
const { agents, skipped } = loadAllAgents();
|
|
304
341
|
if (agents.length === 0) {
|
|
@@ -422,6 +459,8 @@ async function cmdStart() {
|
|
|
422
459
|
countLines(getPackageRoot(), p.logs);
|
|
423
460
|
}
|
|
424
461
|
console.log(`⏱ done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
|
|
462
|
+
// ECWeb 自动后台启动
|
|
463
|
+
startEcwebIfEnabled(p);
|
|
425
464
|
return;
|
|
426
465
|
}
|
|
427
466
|
// 超时
|
|
@@ -900,7 +939,7 @@ async function cmdStatus() {
|
|
|
900
939
|
const projectName = path.basename(s.projectPath);
|
|
901
940
|
const sessionType = s.threadId ? '话题会话' : '主会话';
|
|
902
941
|
const chatType = s.chatType === 'group' ? '群聊' : '单聊';
|
|
903
|
-
const sessionName = s.name
|
|
942
|
+
const sessionName = displaySessionTitle(s.name);
|
|
904
943
|
const timeAgo = formatTimeAgo(Date.now() - s.updatedAt);
|
|
905
944
|
const dot = s.isActive ? '•' : '○';
|
|
906
945
|
const agentSidLabel = s.agentSessionId ? ` [${s.agentSessionId}]` : '';
|
|
@@ -968,6 +1007,14 @@ async function cmdStatus() {
|
|
|
968
1007
|
}
|
|
969
1008
|
}
|
|
970
1009
|
catch { /* ignore */ }
|
|
1010
|
+
// 控制 AID(daemon 进程身份)状态
|
|
1011
|
+
if (status.controlAid) {
|
|
1012
|
+
const state = status.controlAid.connected ? 'connected' : 'disconnected';
|
|
1013
|
+
console.log(`control: ${status.controlAid.aid} [${state}]`);
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
console.log('control: not configured');
|
|
1017
|
+
}
|
|
971
1018
|
if (status.stats) {
|
|
972
1019
|
console.log('');
|
|
973
1020
|
console.log('📊 Last hour:');
|
|
@@ -2101,54 +2148,129 @@ async function cmdWatchAid() {
|
|
|
2101
2148
|
}
|
|
2102
2149
|
platform.onShutdown(cleanup);
|
|
2103
2150
|
}
|
|
2151
|
+
/** 扫描 instance/ 目录,返回存活的 ecweb 实例(ecweb-<pid>.json)。 */
|
|
2152
|
+
function findAliveEcweb(p) {
|
|
2153
|
+
if (!fs.existsSync(p.instanceDir))
|
|
2154
|
+
return null;
|
|
2155
|
+
for (const file of fs.readdirSync(p.instanceDir)) {
|
|
2156
|
+
if (!file.startsWith('ecweb-') || !file.endsWith('.json'))
|
|
2157
|
+
continue;
|
|
2158
|
+
try {
|
|
2159
|
+
const rec = JSON.parse(fs.readFileSync(path.join(p.instanceDir, file), 'utf-8'));
|
|
2160
|
+
if (rec.pid && platform.isProcessRunning(rec.pid))
|
|
2161
|
+
return { pid: rec.pid, port: rec.port ?? 42705 };
|
|
2162
|
+
fs.unlinkSync(path.join(p.instanceDir, file));
|
|
2163
|
+
}
|
|
2164
|
+
catch { }
|
|
2165
|
+
}
|
|
2166
|
+
return null;
|
|
2167
|
+
}
|
|
2168
|
+
/** 若 ecweb 在运行则杀掉并清理 pid 文件,返回是否成功 kill。 */
|
|
2169
|
+
function stopEcwebIfRunning(p) {
|
|
2170
|
+
const alive = findAliveEcweb(p);
|
|
2171
|
+
if (!alive)
|
|
2172
|
+
return false;
|
|
2173
|
+
try {
|
|
2174
|
+
platform.killProcess(alive.pid);
|
|
2175
|
+
}
|
|
2176
|
+
catch { }
|
|
2177
|
+
// 清理 pid 文件
|
|
2178
|
+
try {
|
|
2179
|
+
for (const file of fs.readdirSync(p.instanceDir)) {
|
|
2180
|
+
if (file.startsWith('ecweb-') && file.endsWith('.json')) {
|
|
2181
|
+
fs.unlinkSync(path.join(p.instanceDir, file));
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
catch { }
|
|
2186
|
+
return true;
|
|
2187
|
+
}
|
|
2188
|
+
/** 后台 detached 启动 ecweb;若已运行则先停再启(确保加载最新代码)。 */
|
|
2189
|
+
function startEcwebIfEnabled(p) {
|
|
2190
|
+
const cfg = loadEvolclawConfig();
|
|
2191
|
+
if (!cfg.ecweb?.enabled)
|
|
2192
|
+
return;
|
|
2193
|
+
stopEcwebIfRunning(p); // 先停旧进程(有则停),保证加载最新代码
|
|
2194
|
+
const exe = platform.resolveCommandPath('evolclaw-web');
|
|
2195
|
+
if (!exe)
|
|
2196
|
+
return; // 未安装,静默跳过
|
|
2197
|
+
const port = cfg.ecweb.port ?? 42705;
|
|
2198
|
+
const isBatch = /\.(cmd|bat)$/i.test(exe);
|
|
2199
|
+
const args = ['--home', p.root, '--port', String(port)];
|
|
2200
|
+
const child = isBatch
|
|
2201
|
+
? spawn(`"${exe}"`, args.map(a => `"${a}"`), { detached: true, stdio: 'ignore', shell: true, windowsHide: true })
|
|
2202
|
+
: spawn(exe, args, { detached: true, stdio: 'ignore', windowsHide: true });
|
|
2203
|
+
child.unref();
|
|
2204
|
+
const pid = child.pid;
|
|
2205
|
+
if (!pid)
|
|
2206
|
+
return;
|
|
2207
|
+
fs.mkdirSync(p.instanceDir, { recursive: true });
|
|
2208
|
+
fs.writeFileSync(path.join(p.instanceDir, `ecweb-${pid}.json`), JSON.stringify({ pid, port, startedAt: Date.now() }, null, 2));
|
|
2209
|
+
console.log(`🔭 ECWeb 已在后台启动 (PID: ${pid}) http://localhost:${port}`);
|
|
2210
|
+
console.log(` 运行 ec watch web 查看配对码`);
|
|
2211
|
+
}
|
|
2212
|
+
/** 显示 ecweb 访问信息 + 配对码(启动后 ecweb 需要一点时间起 HTTP,故重试几次)。 */
|
|
2213
|
+
async function printEcwebAccess(port) {
|
|
2214
|
+
console.log(`🔭 ECWeb http://localhost:${port}`);
|
|
2215
|
+
let pair = null;
|
|
2216
|
+
for (let i = 0; i < 10 && !pair; i++) {
|
|
2217
|
+
pair = await fetchEcwebPairCode(port);
|
|
2218
|
+
if (!pair)
|
|
2219
|
+
await sleep(300);
|
|
2220
|
+
}
|
|
2221
|
+
if (pair) {
|
|
2222
|
+
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
2223
|
+
console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,配对后 token 缓存 24h)`);
|
|
2224
|
+
}
|
|
2225
|
+
else {
|
|
2226
|
+
console.log(' 配对码: 暂不可用(稍后重试 ec watch web,或查看 logs/watch-web.log)');
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2104
2229
|
async function cmdWatchWeb() {
|
|
2105
|
-
|
|
2106
|
-
//
|
|
2107
|
-
const { execFileSync } = await import('child_process');
|
|
2108
|
-
const home = resolvePaths().root;
|
|
2230
|
+
const p = resolvePaths();
|
|
2231
|
+
// 1. 检查安装
|
|
2109
2232
|
if (!platform.commandExists('evolclaw-web')) {
|
|
2110
|
-
process.stdout.write('📦 evolclaw-web
|
|
2233
|
+
process.stdout.write('📦 evolclaw-web 未安装。');
|
|
2234
|
+
if (!process.stdin.isTTY) {
|
|
2235
|
+
process.stdout.write(' 请手动安装: npm install -g evolclaw-web\n');
|
|
2236
|
+
process.exit(1);
|
|
2237
|
+
}
|
|
2238
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2239
|
+
const ans = await new Promise(res => rl.question(' 立即安装?[Y/n] ', res));
|
|
2240
|
+
rl.close();
|
|
2241
|
+
if (ans.trim().toLowerCase() === 'n') {
|
|
2242
|
+
process.exit(0);
|
|
2243
|
+
}
|
|
2244
|
+
process.stdout.write('\n');
|
|
2111
2245
|
const { npmInstallGlobal } = await import('../utils/npm-ops.js');
|
|
2112
2246
|
try {
|
|
2113
2247
|
await npmInstallGlobal('evolclaw-web');
|
|
2114
2248
|
}
|
|
2115
2249
|
catch (e) {
|
|
2116
|
-
process.stderr.write(`❌
|
|
2250
|
+
process.stderr.write(`❌ 安装失败: ${e?.stderr || e?.message || e}\n`);
|
|
2117
2251
|
process.exit(1);
|
|
2118
2252
|
}
|
|
2119
2253
|
}
|
|
2120
|
-
//
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
process.stderr.write('❌ 已安装 evolclaw-web 但无法定位可执行文件。\n 请重新打开终端后再次运行,或手动执行: evolclaw-web --home ' + home + '\n');
|
|
2126
|
-
process.exit(1);
|
|
2127
|
-
}
|
|
2128
|
-
// Node 18.20+/20+/22 起,execFile 拒绝直接 spawn .cmd/.bat(CVE-2024-27980),必须 shell:true。
|
|
2129
|
-
// shell 模式下含空格的路径/参数需加引号。
|
|
2130
|
-
// evolclaw-web 是前台长驻服务:用户 Ctrl-C、被新实例的单实例保护 SIGKILL、或正常退出,
|
|
2131
|
-
// execFileSync 都会抛错(signal 终止时 status=null)。这些都是正常生命周期,
|
|
2132
|
-
// 不应让父进程 evolclaw 带堆栈崩溃。只有真正的非信号失败才提示。
|
|
2133
|
-
const isBatch = /\.(cmd|bat)$/i.test(exe);
|
|
2134
|
-
try {
|
|
2135
|
-
if (isBatch) {
|
|
2136
|
-
const q = (s) => `"${s}"`;
|
|
2137
|
-
execFileSync(q(exe), ['--home', q(home)], { stdio: 'inherit', shell: true });
|
|
2138
|
-
}
|
|
2139
|
-
else {
|
|
2140
|
-
execFileSync(exe, ['--home', home], { stdio: 'inherit' });
|
|
2141
|
-
}
|
|
2254
|
+
// 2. 检查是否已运行
|
|
2255
|
+
const alive = findAliveEcweb(p);
|
|
2256
|
+
if (alive) {
|
|
2257
|
+
await printEcwebAccess(alive.port);
|
|
2258
|
+
return;
|
|
2142
2259
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
//
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2260
|
+
// 3. 启动(后台)并同步配置
|
|
2261
|
+
const cfg = loadEvolclawConfig();
|
|
2262
|
+
const port = cfg.ecweb?.port ?? 42705;
|
|
2263
|
+
if (cfg.ecweb?.enabled === undefined) {
|
|
2264
|
+
// 首次手动启动时自动写入 enabled:true
|
|
2265
|
+
saveEvolclawConfig({ ...cfg, ecweb: { enabled: true, port } });
|
|
2266
|
+
}
|
|
2267
|
+
startEcwebIfEnabled(p);
|
|
2268
|
+
const started = findAliveEcweb(p);
|
|
2269
|
+
if (!started) {
|
|
2270
|
+
process.stderr.write('❌ 启动失败,请检查 evolclaw-web 是否正确安装\n');
|
|
2271
|
+
process.exit(1);
|
|
2151
2272
|
}
|
|
2273
|
+
await printEcwebAccess(started.port);
|
|
2152
2274
|
}
|
|
2153
2275
|
async function cmdRestartMonitor() {
|
|
2154
2276
|
const p = resolvePaths();
|
|
@@ -2805,13 +2927,23 @@ async function cmdCtl(args) {
|
|
|
2805
2927
|
Agent:
|
|
2806
2928
|
agent <subcommand> EvolAgent 管理(list/show/new/enable/disable/reload/delete)
|
|
2807
2929
|
|
|
2930
|
+
触发器:
|
|
2931
|
+
trigger 查看活跃触发器
|
|
2932
|
+
trigger list 查看所有触发器(含历史)
|
|
2933
|
+
trigger set --delay <时长> --prompt <内容> 延迟触发(如 15m、2h)
|
|
2934
|
+
trigger set --at <ISO时间> --prompt <内容> 定时触发(如 2026-06-10T09:00)
|
|
2935
|
+
trigger set --cron '<表达式>' --prompt <内容> 周期触发(如 '*/15 * * * *')
|
|
2936
|
+
trigger cancel <名称> 取消触发器
|
|
2937
|
+
trigger update <名称> ... 修改触发器参数
|
|
2938
|
+
|
|
2808
2939
|
运维:
|
|
2809
2940
|
restart [channel] 重启服务或重连指定渠道
|
|
2810
2941
|
|
|
2811
2942
|
示例:
|
|
2812
2943
|
evolclaw ctl model sonnet
|
|
2813
2944
|
evolclaw ctl effort high
|
|
2814
|
-
evolclaw ctl compact
|
|
2945
|
+
evolclaw ctl compact
|
|
2946
|
+
evolclaw ctl "trigger set --cron '*/15 * * * *' --prompt '现在时间?'"`);
|
|
2815
2947
|
process.exit(1);
|
|
2816
2948
|
}
|
|
2817
2949
|
// help 不需要连接服务,直接复用无参数时的帮助输出
|
|
@@ -4053,11 +4185,16 @@ Commands:
|
|
|
4053
4185
|
process.exit(1);
|
|
4054
4186
|
}
|
|
4055
4187
|
if (formatJson) {
|
|
4056
|
-
console.log(JSON.stringify({ ok: true, objectKey: remotePath, isPublic, ref: `${aid}/${remotePath}
|
|
4188
|
+
console.log(JSON.stringify({ ok: true, objectKey: remotePath, isPublic, ref: `${aid}/${remotePath}`, publicUrl: result.publicUrl ?? null }));
|
|
4057
4189
|
}
|
|
4058
4190
|
else {
|
|
4059
4191
|
console.log(`✓ 已上传: ${remotePath}${isPublic ? ' (公开)' : ''}`);
|
|
4060
|
-
|
|
4192
|
+
if (result.publicUrl) {
|
|
4193
|
+
console.log(` 🔗 访问: ${result.publicUrl}`);
|
|
4194
|
+
}
|
|
4195
|
+
else {
|
|
4196
|
+
console.log(` 引用: ${aid}/${remotePath}`);
|
|
4197
|
+
}
|
|
4061
4198
|
console.log(` 下载: evolclaw storage download ${aid} ${aid}/${remotePath}`);
|
|
4062
4199
|
}
|
|
4063
4200
|
return;
|
|
@@ -4870,12 +5007,18 @@ export async function main(args) {
|
|
|
4870
5007
|
--force 已存在 defaults.json 时覆盖
|
|
4871
5008
|
|
|
4872
5009
|
配置渠道(先 evolclaw agent new 创建 agent):
|
|
5010
|
+
evolclaw init aun AUN 渠道配置(AID 创建/绑定)
|
|
4873
5011
|
evolclaw init feishu 飞书扫码登录
|
|
4874
5012
|
evolclaw init wechat 微信扫码登录
|
|
4875
5013
|
evolclaw init dingtalk 钉钉扫码登录
|
|
4876
5014
|
evolclaw init qqbot QQ 机器人扫码绑定
|
|
4877
5015
|
evolclaw init wecom 企业微信 AI Bot 配置(手动输入)`);
|
|
4878
5016
|
}
|
|
5017
|
+
else if (args[1] === 'aun') {
|
|
5018
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
5019
|
+
suppressSdkLogs();
|
|
5020
|
+
await cmdInitAun();
|
|
5021
|
+
}
|
|
4879
5022
|
else if (args[1] === 'wechat') {
|
|
4880
5023
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
4881
5024
|
suppressSdkLogs();
|
|
@@ -4900,7 +5043,7 @@ export async function main(args) {
|
|
|
4900
5043
|
await cmdInitWecom();
|
|
4901
5044
|
}
|
|
4902
5045
|
else if (args[1] && !args[1].startsWith('-')) {
|
|
4903
|
-
const supported = ['feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom'];
|
|
5046
|
+
const supported = ['feishu', 'wechat', 'aun', 'dingtalk', 'qqbot', 'wecom'];
|
|
4904
5047
|
console.error(`❌ 不支持的渠道: ${args[1]}`);
|
|
4905
5048
|
console.error(` 支持的渠道: ${supported.join(', ')}`);
|
|
4906
5049
|
process.exit(1);
|
|
@@ -4931,7 +5074,12 @@ export async function main(args) {
|
|
|
4931
5074
|
case 'logs':
|
|
4932
5075
|
cmdLogs(args.slice(1));
|
|
4933
5076
|
break;
|
|
4934
|
-
case 'watch':
|
|
5077
|
+
case 'watch': {
|
|
5078
|
+
// watch 子命令(aid/msg)会调 AUN SDK(aidLookup 刷名片、对端探测等),
|
|
5079
|
+
// 与 aid/msg/group 等命令一致:进 case 先关掉 SDK 的 [aun_core] 日志,
|
|
5080
|
+
// 否则 SDK debug 日志会直喷终端、糊住 watch 的 TUI 面板。
|
|
5081
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
5082
|
+
suppressSdkLogs();
|
|
4935
5083
|
if (args[1] === 'aid') {
|
|
4936
5084
|
await cmdWatchAid();
|
|
4937
5085
|
}
|
|
@@ -4971,6 +5119,7 @@ export async function main(args) {
|
|
|
4971
5119
|
cmdWatch();
|
|
4972
5120
|
}
|
|
4973
5121
|
break;
|
|
5122
|
+
}
|
|
4974
5123
|
case 'restart-monitor':
|
|
4975
5124
|
await cmdRestartMonitor();
|
|
4976
5125
|
break;
|
|
@@ -5032,6 +5181,18 @@ export async function main(args) {
|
|
|
5032
5181
|
await cmdModel(args.slice(1));
|
|
5033
5182
|
break;
|
|
5034
5183
|
}
|
|
5184
|
+
case 'stats': {
|
|
5185
|
+
const { handleStats } = await import('./stats.js');
|
|
5186
|
+
await handleStats(args.slice(1));
|
|
5187
|
+
break;
|
|
5188
|
+
}
|
|
5189
|
+
case 'version':
|
|
5190
|
+
case '-v':
|
|
5191
|
+
case '--version': {
|
|
5192
|
+
const { handleVersion } = await import('./version.js');
|
|
5193
|
+
handleVersion(args.slice(1));
|
|
5194
|
+
break;
|
|
5195
|
+
}
|
|
5035
5196
|
case 'bench': {
|
|
5036
5197
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
5037
5198
|
suppressSdkLogs();
|
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';
|