evolclaw 3.1.5 → 3.1.7
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 +68 -3
- package/dist/agents/claude-runner.js +69 -24
- package/dist/agents/kit-renderer.js +78 -321
- package/dist/agents/manifest-engine.js +243 -0
- package/dist/agents/message-renderer.js +112 -0
- package/dist/aun/aid/agentmd.js +10 -3
- package/dist/aun/msg/group.js +2 -2
- package/dist/channels/aun.js +154 -18
- package/dist/channels/dingtalk.js +1 -1
- package/dist/channels/feishu.js +31 -9
- package/dist/channels/qqbot.js +1 -1
- package/dist/channels/wechat.js +1 -1
- package/dist/channels/wecom.js +1 -1
- package/dist/cli/agent.js +10 -11
- package/dist/cli/bench.js +1 -5
- package/dist/cli/help.js +8 -0
- package/dist/cli/index.js +91 -128
- package/dist/cli/init.js +37 -21
- package/dist/cli/link-rules.js +1 -7
- package/dist/cli/model.js +231 -6
- package/dist/config-store.js +1 -22
- package/dist/core/command-handler.js +181 -48
- package/dist/core/evolagent.js +0 -18
- package/dist/core/message/im-renderer.js +9 -20
- package/dist/core/message/message-bridge.js +9 -10
- package/dist/core/message/message-processor.js +188 -39
- package/dist/core/message/message-queue.js +15 -1
- package/dist/core/relation/peer-identity.js +23 -11
- package/dist/core/trigger/parser.js +4 -4
- package/dist/core/trigger/scheduler.js +43 -13
- package/dist/index.js +102 -52
- package/dist/ipc.js +1 -1
- package/dist/utils/error-utils.js +6 -0
- package/dist/utils/process-introspect.js +7 -5
- package/kits/docs/INDEX.md +4 -8
- package/kits/docs/context-assembly.md +1 -0
- package/kits/docs/evolclaw/INDEX.md +43 -0
- package/kits/docs/evolclaw/group.md +13 -6
- package/kits/docs/evolclaw/model.md +51 -0
- package/kits/docs/evolclaw/msg.md +5 -0
- package/kits/docs/venues/group.md +13 -1
- package/kits/eck_manifest.json +9 -0
- package/kits/eck_message_manifest.json +14 -0
- package/kits/rules/06-channel.md +5 -1
- package/kits/templates/message-fragments/item.md +2 -0
- package/kits/templates/system-fragments/baseagent.md +7 -1
- package/kits/templates/system-fragments/channel.md +7 -5
- package/kits/templates/system-fragments/commands.md +19 -0
- package/kits/templates/system-fragments/session.md +12 -0
- package/kits/templates/system-fragments/venue.md +15 -0
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { migrateProject } from '../config-store.js';
|
|
|
11
11
|
import { cmdInit } from './init.js';
|
|
12
12
|
import { ipcQuery } from '../ipc.js';
|
|
13
13
|
import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom } from './init-channel.js';
|
|
14
|
-
import { isHelpFlag, wantsHelp } from './help.js';
|
|
14
|
+
import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
|
|
15
15
|
import * as platform from '../utils/cross-platform.js';
|
|
16
16
|
import { EventBus } from '../core/event-bus.js';
|
|
17
17
|
import { tryUpgrade, tryUpgradeAunSdk } from '../utils/npm-ops.js';
|
|
@@ -292,6 +292,13 @@ async function cmdStart() {
|
|
|
292
292
|
// 旧配置自动迁移(evolclaw.json → 新结构)
|
|
293
293
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
294
294
|
autoMigrateIfNeeded();
|
|
295
|
+
// 未初始化时自动引导
|
|
296
|
+
const defaults = loadDefaults();
|
|
297
|
+
if (!defaults || !defaults.baseagents || Object.keys(defaults.baseagents).length === 0) {
|
|
298
|
+
console.log('⚡ 未检测到初始化配置,自动启动初始化向导...\n');
|
|
299
|
+
await cmdInit();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
295
302
|
// 检查至少有一个 self-agent
|
|
296
303
|
const { agents, skipped } = loadAllAgents();
|
|
297
304
|
if (agents.length === 0) {
|
|
@@ -313,7 +320,7 @@ async function cmdStart() {
|
|
|
313
320
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
314
321
|
if (aliveMains.length > 0) {
|
|
315
322
|
const first = aliveMains[0];
|
|
316
|
-
console.log(
|
|
323
|
+
console.log(` EvolClaw is already running (PID: ${aliveMains.map(m => m.record.pid).join(', ')})`);
|
|
317
324
|
console.log(` 启动于: ${new Date(first.record.startedAtIso).toLocaleString()}`);
|
|
318
325
|
console.log(` 启动方式: ${first.record.launchedBy}`);
|
|
319
326
|
// 报告 AID 状态
|
|
@@ -371,14 +378,7 @@ async function cmdStart() {
|
|
|
371
378
|
const checkReady = () => {
|
|
372
379
|
// ready signal 出现(优先检查,避免 Windows 上误判进程状态)
|
|
373
380
|
if (fs.existsSync(p.readySignal)) {
|
|
374
|
-
|
|
375
|
-
let aunVer = 'unknown';
|
|
376
|
-
try {
|
|
377
|
-
const aunPkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'node_modules', '@agentunion', 'fastaun', 'package.json'), 'utf-8'));
|
|
378
|
-
aunVer = aunPkg.version;
|
|
379
|
-
}
|
|
380
|
-
catch { /* ignore */ }
|
|
381
|
-
console.log(`✓ EvolClaw v${pkg.version} started successfully (PID: ${childPid}) fastaun v${aunVer}`);
|
|
381
|
+
console.log(`✓ EvolClaw started successfully (PID: ${childPid})`);
|
|
382
382
|
console.log(` EVOLCLAW_HOME: ${resolveRoot()}`);
|
|
383
383
|
console.log(` Logs: ${p.logs}/`);
|
|
384
384
|
// 从主日志提取渠道连接摘要
|
|
@@ -495,7 +495,6 @@ async function cmdStop() {
|
|
|
495
495
|
}
|
|
496
496
|
async function cmdRestart(opts = {}) {
|
|
497
497
|
const cmdStartedAt = Date.now();
|
|
498
|
-
printStartupInfo();
|
|
499
498
|
console.log('🔄 Restarting EvolClaw...');
|
|
500
499
|
// 版本检查与自动升级
|
|
501
500
|
console.log('📦 Checking for updates...');
|
|
@@ -2103,95 +2102,22 @@ async function cmdWatchAid() {
|
|
|
2103
2102
|
platform.onShutdown(cleanup);
|
|
2104
2103
|
}
|
|
2105
2104
|
async function cmdWatchWeb() {
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
const
|
|
2109
|
-
const
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
const GREEN = useColor ? '\x1b[32m' : '';
|
|
2114
|
-
const YELLOW = useColor ? '\x1b[33m' : '';
|
|
2115
|
-
const logLine = (line) => {
|
|
2116
|
-
const t = new Date();
|
|
2117
|
-
const ts = `${String(t.getHours()).padStart(2, '0')}:${String(t.getMinutes()).padStart(2, '0')}:${String(t.getSeconds()).padStart(2, '0')}`;
|
|
2118
|
-
process.stdout.write(`${DIM}${ts}${RST} ${line}\n`);
|
|
2119
|
-
};
|
|
2120
|
-
// 调试日志文件:每次运行 watch web 时清空,便于建立调试闭环
|
|
2121
|
-
// 查看 sessions 调试日志 → 读这个文件
|
|
2122
|
-
const logFile = path.join(p.logs, 'watch-web.log');
|
|
2123
|
-
try {
|
|
2124
|
-
fs.mkdirSync(p.logs, { recursive: true });
|
|
2125
|
-
fs.writeFileSync(logFile, `# watch-web debug log\n# started ${new Date().toISOString()} pid=${process.pid}\n`);
|
|
2126
|
-
}
|
|
2127
|
-
catch { /* best effort */ }
|
|
2128
|
-
const fileLog = (line) => {
|
|
2129
|
-
const t = new Date();
|
|
2130
|
-
const ts = `${String(t.getHours()).padStart(2, '0')}:${String(t.getMinutes()).padStart(2, '0')}:${String(t.getSeconds()).padStart(2, '0')}.${String(t.getMilliseconds()).padStart(3, '0')}`;
|
|
2105
|
+
// evolclaw-web 是独立插件包(可执行命令),按需安装。
|
|
2106
|
+
// 复用 npm-ops.npmInstallGlobal(含 EACCES→sudo 回退、Windows npm.cmd、超时)。
|
|
2107
|
+
const { execFileSync } = await import('child_process');
|
|
2108
|
+
const home = resolvePaths().root;
|
|
2109
|
+
if (!platform.commandExists('evolclaw-web')) {
|
|
2110
|
+
process.stdout.write('📦 evolclaw-web 未安装,正在从 npm 安装...\n');
|
|
2111
|
+
const { npmInstallGlobal } = await import('../utils/npm-ops.js');
|
|
2131
2112
|
try {
|
|
2132
|
-
|
|
2113
|
+
await npmInstallGlobal('evolclaw-web');
|
|
2133
2114
|
}
|
|
2134
|
-
catch {
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
const log = (line) => { logLine(line); fileLog(line); };
|
|
2138
|
-
const { startWatchWebServer } = await import('./watch-web/server.js');
|
|
2139
|
-
let handle;
|
|
2140
|
-
try {
|
|
2141
|
-
handle = await startWatchWebServer({ log });
|
|
2142
|
-
}
|
|
2143
|
-
catch (e) {
|
|
2144
|
-
console.error(`❌ 启动 Web 服务失败: ${e?.message || e}`);
|
|
2145
|
-
process.exit(1);
|
|
2146
|
-
}
|
|
2147
|
-
// 注册 instance 文件
|
|
2148
|
-
const instanceFile = path.join(p.instanceDir, `watch-web-${process.pid}.json`);
|
|
2149
|
-
fs.writeFileSync(instanceFile, JSON.stringify({
|
|
2150
|
-
pid: process.pid, startedAt: Date.now(), startedAtIso: new Date().toISOString(),
|
|
2151
|
-
type: 'watch-web', port: handle.port,
|
|
2152
|
-
}, null, 2));
|
|
2153
|
-
// 列出本机访问地址
|
|
2154
|
-
const os = await import('os');
|
|
2155
|
-
const ifaces = os.networkInterfaces();
|
|
2156
|
-
const lanIps = [];
|
|
2157
|
-
for (const list of Object.values(ifaces)) {
|
|
2158
|
-
for (const ni of list || []) {
|
|
2159
|
-
if (ni.family === 'IPv4' && !ni.internal)
|
|
2160
|
-
lanIps.push(ni.address);
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
process.stdout.write(`\n${BOLD}${CYAN}🔭 EvolClaw Watch Web${RST}\n\n`);
|
|
2164
|
-
process.stdout.write(` ${BOLD}配对码:${RST} ${GREEN}${BOLD}${handle.pairingCode}${RST} ${DIM}(5 分钟内有效,配对后 token 缓存 24h 自动续期)${RST}\n\n`);
|
|
2165
|
-
process.stdout.write(` ${BOLD}本机:${RST} http://localhost:${handle.port}\n`);
|
|
2166
|
-
for (const ip of lanIps) {
|
|
2167
|
-
process.stdout.write(` ${BOLD}局域网:${RST} http://${ip}:${handle.port}\n`);
|
|
2168
|
-
}
|
|
2169
|
-
process.stdout.write(`\n ${DIM}绑定 0.0.0.0,远程可访问。按任意键退出。${RST}\n`);
|
|
2170
|
-
process.stdout.write(` ${DIM}调试日志: ${logFile}${RST}\n\n`);
|
|
2171
|
-
const cleanup = () => {
|
|
2172
|
-
try {
|
|
2173
|
-
fs.unlinkSync(instanceFile);
|
|
2115
|
+
catch (e) {
|
|
2116
|
+
process.stderr.write(`❌ 安装 evolclaw-web 失败: ${e?.stderr || e?.message || e}\n 可手动安装: npm install -g evolclaw-web\n`);
|
|
2117
|
+
process.exit(1);
|
|
2174
2118
|
}
|
|
2175
|
-
catch { }
|
|
2176
|
-
handle.close().finally(() => process.exit(0));
|
|
2177
|
-
};
|
|
2178
|
-
process.on('exit', () => { try {
|
|
2179
|
-
fs.unlinkSync(instanceFile);
|
|
2180
|
-
}
|
|
2181
|
-
catch { } });
|
|
2182
|
-
process.on('SIGINT', cleanup);
|
|
2183
|
-
process.on('SIGTERM', cleanup);
|
|
2184
|
-
platform.onShutdown(cleanup);
|
|
2185
|
-
// 按任意键退出
|
|
2186
|
-
if (process.stdin.isTTY) {
|
|
2187
|
-
process.stdin.setRawMode(true);
|
|
2188
|
-
process.stdin.resume();
|
|
2189
|
-
process.stdin.on('data', (key) => {
|
|
2190
|
-
logLine(`${YELLOW}收到退出指令,关闭服务…${RST}`);
|
|
2191
|
-
cleanup();
|
|
2192
|
-
});
|
|
2193
2119
|
}
|
|
2194
|
-
|
|
2120
|
+
execFileSync('evolclaw-web', ['--home', home], { stdio: 'inherit' });
|
|
2195
2121
|
}
|
|
2196
2122
|
async function cmdRestartMonitor() {
|
|
2197
2123
|
const p = resolvePaths();
|
|
@@ -2719,8 +2645,6 @@ async function cmdMv(oldDir, newDir) {
|
|
|
2719
2645
|
console.log('✓ 项目目录已移动');
|
|
2720
2646
|
if (r.evolclawDbUpdated > 0)
|
|
2721
2647
|
console.log(`✓ EvolClaw 会话存储已更新 (${r.evolclawDbUpdated} 条记录)`);
|
|
2722
|
-
if (r.evolclawConfigUpdated)
|
|
2723
|
-
console.log('✓ agent config projects.list 已更新');
|
|
2724
2648
|
console.log('\n迁移完成!');
|
|
2725
2649
|
}
|
|
2726
2650
|
catch (e) {
|
|
@@ -2894,7 +2818,7 @@ Agent:
|
|
|
2894
2818
|
// ==================== Agent ====================
|
|
2895
2819
|
async function cmdAgent(args) {
|
|
2896
2820
|
const sub = args[0];
|
|
2897
|
-
const formatJson = args
|
|
2821
|
+
const formatJson = getArgValue(args, '--format') === 'json';
|
|
2898
2822
|
if (!sub || isHelpFlag(sub)) {
|
|
2899
2823
|
console.log(`用法: evolclaw agent <command>
|
|
2900
2824
|
|
|
@@ -3469,7 +3393,7 @@ function resolveAunPath(args) {
|
|
|
3469
3393
|
}
|
|
3470
3394
|
async function cmdAid(args) {
|
|
3471
3395
|
const sub = args[0];
|
|
3472
|
-
const formatJson = args
|
|
3396
|
+
const formatJson = getArgValue(args, '--format') === 'json';
|
|
3473
3397
|
const aunPath = resolveAunPath(args);
|
|
3474
3398
|
if (!sub || isHelpFlag(sub)) {
|
|
3475
3399
|
console.log(`用法: evolclaw aid <command>
|
|
@@ -3970,6 +3894,10 @@ async function cmdRpc(args) {
|
|
|
3970
3894
|
|
|
3971
3895
|
每行 JSON 格式: {"method":"<namespace.method>","params":{...}}
|
|
3972
3896
|
|
|
3897
|
+
Options:
|
|
3898
|
+
--app <name> 指定应用 slot(独立消费通道)。仅对 message.pull / group.pull
|
|
3899
|
+
等消费类方法有意义——隔离 seq 游标与消息过滤;默认与 daemon 共享通道。
|
|
3900
|
+
|
|
3973
3901
|
示例:
|
|
3974
3902
|
evolclaw rpc --as alice.agentid.pub --params '{"method":"message.send","params":{"to":"bob.agentid.pub","payload":{"type":"text","text":"hello"}}}'
|
|
3975
3903
|
evolclaw rpc --as alice.agentid.pub --params calls.jsonl`);
|
|
@@ -3978,6 +3906,7 @@ async function cmdRpc(args) {
|
|
|
3978
3906
|
const asIdx = args.indexOf('--as');
|
|
3979
3907
|
const paramsIdx = args.indexOf('--params');
|
|
3980
3908
|
const aunPath = resolveAunPath(args);
|
|
3909
|
+
const appSlot = getArgValue(args, '--app');
|
|
3981
3910
|
if (asIdx === -1 || asIdx + 1 >= args.length) {
|
|
3982
3911
|
console.error('❌ 缺少 --as <aid>');
|
|
3983
3912
|
process.exit(1);
|
|
@@ -4022,11 +3951,11 @@ async function cmdRpc(args) {
|
|
|
4022
3951
|
}
|
|
4023
3952
|
const { rpcCall, rpcBatch } = await import('../aun/rpc/index.js');
|
|
4024
3953
|
if (calls.length === 1) {
|
|
4025
|
-
const result = await rpcCall(aid, calls[0].method, calls[0].params, { aunPath });
|
|
3954
|
+
const result = await rpcCall(aid, calls[0].method, calls[0].params, { aunPath, slotId: appSlot });
|
|
4026
3955
|
console.log(JSON.stringify(result));
|
|
4027
3956
|
}
|
|
4028
3957
|
else {
|
|
4029
|
-
const results = await rpcBatch(aid, calls, { aunPath });
|
|
3958
|
+
const results = await rpcBatch(aid, calls, { aunPath, slotId: appSlot });
|
|
4030
3959
|
for (const r of results) {
|
|
4031
3960
|
console.log(JSON.stringify(r));
|
|
4032
3961
|
}
|
|
@@ -4036,7 +3965,7 @@ async function cmdRpc(args) {
|
|
|
4036
3965
|
async function cmdStorage(args) {
|
|
4037
3966
|
const sub = args[0];
|
|
4038
3967
|
const aunPath = resolveAunPath(args);
|
|
4039
|
-
const formatJson = args
|
|
3968
|
+
const formatJson = getArgValue(args, '--format') === 'json';
|
|
4040
3969
|
if (!sub || isHelpFlag(sub)) {
|
|
4041
3970
|
console.log(`用法: evolclaw storage <command> <aid> [options]
|
|
4042
3971
|
|
|
@@ -4183,7 +4112,7 @@ Commands:
|
|
|
4183
4112
|
async function cmdMsg(args) {
|
|
4184
4113
|
const sub = args[0];
|
|
4185
4114
|
const aunPath = resolveAunPath(args);
|
|
4186
|
-
const formatJson = args
|
|
4115
|
+
const formatJson = getArgValue(args, '--format') === 'json';
|
|
4187
4116
|
const appIdx = args.indexOf('--app');
|
|
4188
4117
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
4189
4118
|
if (!sub || isHelpFlag(sub)) {
|
|
@@ -4207,6 +4136,8 @@ Options:
|
|
|
4207
4136
|
--content-type <mime> 显式覆盖 MIME(仅 --file 模式)
|
|
4208
4137
|
--text <说明> 附件说明文字(仅 --file 模式)
|
|
4209
4138
|
--transcript <text> 语音转写(仅 --as voice)
|
|
4139
|
+
-- end-of-options:其后所有参数按正文处理
|
|
4140
|
+
(用于发送恰好等于某 flag 的文本,如 send a b -- --encrypt)
|
|
4210
4141
|
|
|
4211
4142
|
示例:
|
|
4212
4143
|
evolclaw msg send alice.agentid.pub bob.agentid.pub "hello"
|
|
@@ -4465,7 +4396,7 @@ Options:
|
|
|
4465
4396
|
async function cmdGroup(args) {
|
|
4466
4397
|
const sub = args[0];
|
|
4467
4398
|
const aunPath = resolveAunPath(args);
|
|
4468
|
-
const formatJson = args
|
|
4399
|
+
const formatJson = getArgValue(args, '--format') === 'json';
|
|
4469
4400
|
const appIdx = args.indexOf('--app');
|
|
4470
4401
|
const appSlot = appIdx >= 0 ? args[appIdx + 1] : undefined;
|
|
4471
4402
|
if (!sub || isHelpFlag(sub)) {
|
|
@@ -4496,8 +4427,11 @@ async function cmdGroup(args) {
|
|
|
4496
4427
|
Options:
|
|
4497
4428
|
--app <name> 指定应用 slot(独立消费通道,不影响 daemon)
|
|
4498
4429
|
--format json 输出 JSON 格式
|
|
4499
|
-
--
|
|
4430
|
+
--encrypt 启用端到端加密(仅 send)
|
|
4431
|
+
--mention <aid> 发送时 @ 某个成员(可多次,或用逗号分隔多个 aid)
|
|
4500
4432
|
--mention-all 发送时 @ 所有人
|
|
4433
|
+
-- end-of-options:其后所有参数按正文处理
|
|
4434
|
+
(用于发送恰好等于某 flag 的文本,如 send a g -- --encrypt)
|
|
4501
4435
|
|
|
4502
4436
|
示例:
|
|
4503
4437
|
evolclaw group create alice.agentid.pub "Dev Team" --visibility private
|
|
@@ -4529,12 +4463,23 @@ Options:
|
|
|
4529
4463
|
}
|
|
4530
4464
|
return gid;
|
|
4531
4465
|
};
|
|
4532
|
-
// 收集 --mention
|
|
4466
|
+
// 收集 --mention(可多次;每次的值支持逗号分隔多个 aid)
|
|
4533
4467
|
const collectMentions = () => {
|
|
4534
4468
|
const mentions = [];
|
|
4535
|
-
for (let i = 0; i < args.length
|
|
4536
|
-
if (args[i]
|
|
4537
|
-
|
|
4469
|
+
for (let i = 0; i < args.length; i++) {
|
|
4470
|
+
if (args[i] !== '--mention')
|
|
4471
|
+
continue;
|
|
4472
|
+
const val = args[i + 1];
|
|
4473
|
+
if (val === undefined || val.startsWith('--')) {
|
|
4474
|
+
console.error(`❌ --mention 后面缺少 <aid>`);
|
|
4475
|
+
process.exit(1);
|
|
4476
|
+
}
|
|
4477
|
+
for (const aid of val.split(',').map(s => s.trim()).filter(Boolean)) {
|
|
4478
|
+
if (!isValidAid(aid)) {
|
|
4479
|
+
console.error(`❌ --mention 的 aid 无效: ${aid}`);
|
|
4480
|
+
process.exit(1);
|
|
4481
|
+
}
|
|
4482
|
+
mentions.push({ aid });
|
|
4538
4483
|
}
|
|
4539
4484
|
}
|
|
4540
4485
|
if (args.includes('--mention-all')) {
|
|
@@ -4828,32 +4773,50 @@ Options:
|
|
|
4828
4773
|
process.exit(1);
|
|
4829
4774
|
}
|
|
4830
4775
|
// ==================== Main ====================
|
|
4831
|
-
function getArgValue(args, flag) {
|
|
4832
|
-
const idx = args.indexOf(flag);
|
|
4833
|
-
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
|
|
4834
|
-
}
|
|
4835
4776
|
/**
|
|
4836
|
-
* 收集位置参数(从 startIdx
|
|
4837
|
-
*
|
|
4777
|
+
* 收集位置参数(从 startIdx 开始)。
|
|
4778
|
+
*
|
|
4779
|
+
* flag 判定采用**精确匹配已知 flag 集合**,而非 `startsWith('--')`——
|
|
4780
|
+
* 这样"正文恰好以 -- 开头"(如消息文本 `--file 坏了`)不会被误当 flag 吞掉。
|
|
4781
|
+
* 仅当 token 精确等于某个已知 flag 时才按 flag 处理:
|
|
4782
|
+
* - VALUE_FLAGS:消耗自身 + 下一个 arg(flag 的值)
|
|
4783
|
+
* - BOOLEAN_FLAGS:仅消耗自身
|
|
4784
|
+
* 其余以 -- 开头但不在集合中的 token,一律视为正文。
|
|
4785
|
+
*
|
|
4786
|
+
* 另支持 POSIX `--` end-of-options 分隔符:遇到单独的 `--` 后,
|
|
4787
|
+
* 其后所有 token 无条件按正文处理(用于发送精确等于某 flag 的文本,如 `-- --encrypt`)。
|
|
4838
4788
|
*/
|
|
4789
|
+
const VALUE_FLAGS = new Set([
|
|
4790
|
+
'--format', '--app', '--after-seq', '--limit', '--file', '--link',
|
|
4791
|
+
'--payload', '--title', '--description', '--text', '--transcript',
|
|
4792
|
+
'--as', '--content-type', '--mention', '--visibility', '--join-mode',
|
|
4793
|
+
'--group-id', '--name', '--message', '--answer', '--page', '--size',
|
|
4794
|
+
'--aun-path', '--thread',
|
|
4795
|
+
]);
|
|
4796
|
+
const BOOLEAN_FLAGS = new Set([
|
|
4797
|
+
'--encrypt', '--mention-all',
|
|
4798
|
+
]);
|
|
4839
4799
|
function collectPositional(args, startIdx) {
|
|
4840
|
-
const VALUE_FLAGS = new Set([
|
|
4841
|
-
'--format', '--app', '--after-seq', '--limit', '--file', '--link',
|
|
4842
|
-
'--payload', '--title', '--description', '--text', '--transcript',
|
|
4843
|
-
'--as', '--content-type', '--mention', '--visibility', '--join-mode',
|
|
4844
|
-
'--group-id', '--name', '--message', '--answer', '--page', '--size',
|
|
4845
|
-
'--aun-path',
|
|
4846
|
-
]);
|
|
4847
4800
|
const out = [];
|
|
4801
|
+
let endOfFlags = false;
|
|
4848
4802
|
for (let i = startIdx; i < args.length; i++) {
|
|
4849
4803
|
const a = args[i];
|
|
4850
|
-
if (
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4804
|
+
if (endOfFlags) {
|
|
4805
|
+
out.push(a);
|
|
4806
|
+
continue;
|
|
4807
|
+
}
|
|
4808
|
+
if (a === '--') {
|
|
4809
|
+
endOfFlags = true;
|
|
4854
4810
|
continue;
|
|
4855
4811
|
}
|
|
4856
|
-
|
|
4812
|
+
if (VALUE_FLAGS.has(a)) {
|
|
4813
|
+
i++;
|
|
4814
|
+
continue;
|
|
4815
|
+
} // 精确匹配取值 flag:跳过其值
|
|
4816
|
+
if (BOOLEAN_FLAGS.has(a)) {
|
|
4817
|
+
continue;
|
|
4818
|
+
} // 精确匹配开关 flag:仅跳过自身
|
|
4819
|
+
out.push(a); // 其余(含以 -- 开头的未知 token)= 正文
|
|
4857
4820
|
}
|
|
4858
4821
|
return out;
|
|
4859
4822
|
}
|
package/dist/cli/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
import readline from 'readline';
|
|
3
4
|
import { resolvePaths, ensureDataDirs } from '../paths.js';
|
|
4
5
|
import { commandExists } from '../utils/cross-platform.js';
|
|
@@ -10,11 +11,6 @@ function ask(rl, question) {
|
|
|
10
11
|
return new Promise(resolve => rl.question(question, resolve));
|
|
11
12
|
}
|
|
12
13
|
const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
13
|
-
const BASEAGENT_ENV_KEY = {
|
|
14
|
-
claude: 'ANTHROPIC_API_KEY',
|
|
15
|
-
codex: 'OPENAI_API_KEY',
|
|
16
|
-
gemini: 'GEMINI_API_KEY',
|
|
17
|
-
};
|
|
18
14
|
function isBaseagentAvailable(baseagent) {
|
|
19
15
|
if (baseagent === 'codex')
|
|
20
16
|
return isCodexSdkAvailable();
|
|
@@ -26,16 +22,19 @@ function detectAvailable() {
|
|
|
26
22
|
function pickDefault(available) {
|
|
27
23
|
return (available.includes('claude') ? 'claude' : available[0]);
|
|
28
24
|
}
|
|
29
|
-
function buildDefaults(chosen) {
|
|
30
|
-
const
|
|
25
|
+
function buildDefaults(chosen, available, projectsDefaultPath) {
|
|
26
|
+
const baseagents = {};
|
|
27
|
+
for (const b of available)
|
|
28
|
+
baseagents[b] = {};
|
|
31
29
|
return {
|
|
32
30
|
$schema_version: 1,
|
|
33
31
|
active_baseagent: chosen,
|
|
34
|
-
baseagents
|
|
32
|
+
baseagents,
|
|
33
|
+
...(projectsDefaultPath ? { projects: { defaultPath: projectsDefaultPath } } : {}),
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
|
-
function writeDefaults(
|
|
38
|
-
saveDefaultsSafe(buildDefaults(chosen));
|
|
36
|
+
function writeDefaults(chosen, available, projectsDefaultPath) {
|
|
37
|
+
saveDefaultsSafe(buildDefaults(chosen, available, projectsDefaultPath));
|
|
39
38
|
}
|
|
40
39
|
// ==================== Main ====================
|
|
41
40
|
export async function cmdInit(options) {
|
|
@@ -85,7 +84,7 @@ export async function cmdInit(options) {
|
|
|
85
84
|
else {
|
|
86
85
|
chosen = pickDefault(available);
|
|
87
86
|
}
|
|
88
|
-
writeDefaults(
|
|
87
|
+
writeDefaults(chosen, available);
|
|
89
88
|
console.log(`✓ 已${exists ? '覆盖' : '创建'}: ${defaultsPath}`);
|
|
90
89
|
console.log(` active_baseagent: ${chosen}`);
|
|
91
90
|
const { agents } = loadAllAgents();
|
|
@@ -118,12 +117,33 @@ export async function cmdInit(options) {
|
|
|
118
117
|
}
|
|
119
118
|
return chosen;
|
|
120
119
|
}
|
|
120
|
+
async function askProjectsDefaultPath() {
|
|
121
|
+
const defaultDir = path.join(p.root, 'projects', 'default');
|
|
122
|
+
const input = (await ask(rl, `项目默认目录 [${defaultDir}]: `)).trim();
|
|
123
|
+
const resolved = input || defaultDir;
|
|
124
|
+
if (!path.isAbsolute(resolved)) {
|
|
125
|
+
console.log(' ⚠ 需要绝对路径,已跳过');
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
if (!fs.existsSync(resolved)) {
|
|
129
|
+
const create = (await ask(rl, ` 目录不存在,是否创建?[Y/n]: `)).trim().toLowerCase();
|
|
130
|
+
if (create === '' || create === 'y' || create === 'yes') {
|
|
131
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
132
|
+
console.log(` ✓ 已创建 ${resolved}`);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return resolved;
|
|
139
|
+
}
|
|
121
140
|
try {
|
|
122
141
|
if (exists) {
|
|
123
142
|
const ans = (await ask(rl, `配置文件已存在: ${defaultsPath}\n 是否覆盖?[y/N] `)).trim().toLowerCase();
|
|
124
143
|
if (ans === 'y' || ans === 'yes') {
|
|
125
144
|
const chosen = await askBaseagent();
|
|
126
|
-
|
|
145
|
+
const projectsDefaultPath = await askProjectsDefaultPath();
|
|
146
|
+
writeDefaults(chosen, available, projectsDefaultPath);
|
|
127
147
|
console.log(`\n✓ 已覆盖: ${defaultsPath}`);
|
|
128
148
|
console.log(` active_baseagent: ${chosen}\n`);
|
|
129
149
|
}
|
|
@@ -133,20 +153,16 @@ export async function cmdInit(options) {
|
|
|
133
153
|
}
|
|
134
154
|
else {
|
|
135
155
|
const chosen = await askBaseagent();
|
|
136
|
-
|
|
156
|
+
const projectsDefaultPath = await askProjectsDefaultPath();
|
|
157
|
+
writeDefaults(chosen, available, projectsDefaultPath);
|
|
137
158
|
console.log(`\n✓ 已创建: ${defaultsPath}`);
|
|
138
159
|
console.log(` active_baseagent: ${chosen}\n`);
|
|
139
160
|
}
|
|
140
|
-
// ── 5.
|
|
161
|
+
// ── 5. 提示创建 agent ──
|
|
141
162
|
const { agents } = loadAllAgents();
|
|
142
163
|
if (agents.length === 0) {
|
|
143
|
-
console.log('
|
|
144
|
-
console.log('
|
|
145
|
-
const { agentCreateInteractive } = await import('./agent.js');
|
|
146
|
-
const result = await agentCreateInteractive({ rl });
|
|
147
|
-
if (!result.ok) {
|
|
148
|
-
console.error(`❌ ${result.error}`);
|
|
149
|
-
}
|
|
164
|
+
console.log('提示:尚无 agent,运行以下命令创建:');
|
|
165
|
+
console.log(' evolclaw agent new <aid>.agentid.pub');
|
|
150
166
|
}
|
|
151
167
|
}
|
|
152
168
|
finally {
|
package/dist/cli/link-rules.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { kitsRulesDir, resolvePaths } from '../paths.js';
|
|
4
4
|
import { atomicWriteJson, atomicReadJson } from '../utils/atomic-write.js';
|
|
5
|
-
import { wantsHelp } from './help.js';
|
|
5
|
+
import { wantsHelp, getArgValue } from './help.js';
|
|
6
6
|
const isWindows = process.platform === 'win32';
|
|
7
7
|
const KNOWN_BASEAGENTS = ['cc', 'codex', 'gemini'];
|
|
8
8
|
function statePath() {
|
|
@@ -232,12 +232,6 @@ function resolveBaseAgent(input) {
|
|
|
232
232
|
console.error(` Supported: ${KNOWN_BASEAGENTS.join(', ')}`);
|
|
233
233
|
process.exit(1);
|
|
234
234
|
}
|
|
235
|
-
function getArgValue(args, flag) {
|
|
236
|
-
const idx = args.indexOf(flag);
|
|
237
|
-
if (idx === -1 || idx + 1 >= args.length)
|
|
238
|
-
return undefined;
|
|
239
|
-
return args[idx + 1];
|
|
240
|
-
}
|
|
241
235
|
function pathEquals(a, b) {
|
|
242
236
|
if (isWindows) {
|
|
243
237
|
return path.resolve(a).toLowerCase() === path.resolve(b).toLowerCase();
|