evolcore 0.0.2 → 0.0.3
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 +44 -793
- package/dist/agents/claude-runner.js +197 -17
- package/dist/agents/codex-runner.js +46 -3
- package/dist/aun/outbox.js +8 -0
- package/dist/channels/aun.js +21 -4
- package/dist/channels/contact-bind-code.js +134 -0
- package/dist/channels/dingtalk.js +979 -149
- package/dist/channels/feishu.js +130 -54
- package/dist/channels/wecom-card.js +101 -0
- package/dist/channels/wecom-onboarding.js +82 -0
- package/dist/channels/wecom-state.js +191 -0
- package/dist/channels/wecom.js +755 -163
- package/dist/cli/agent-command.js +2 -1
- package/dist/cli/aun-commands.js +88 -33
- package/dist/cli/bench.js +2 -2
- package/dist/cli/contact.js +71 -0
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +77 -214
- package/dist/cli/handoff-command.js +2 -2
- package/dist/cli/help.js +9 -5
- package/dist/cli/index.js +132 -116
- package/dist/cli/init-channel.js +92 -97
- package/dist/cli/init.js +63 -26
- package/dist/cli/model.js +2 -1
- package/dist/cli/net-check.js +2 -2
- package/dist/cli/queue-command.js +30 -6
- package/dist/cli/raw-key-input.js +25 -0
- package/dist/cli/response.js +5 -6
- package/dist/cli/restart-monitor.js +25 -1
- package/dist/cli/stats.js +6 -4
- package/dist/cli/trigger-command.js +55 -15
- package/dist/cli/version.js +6 -1
- package/dist/config/builtin-role-templates.js +22 -10
- package/dist/config/builtin-roles.js +7 -1
- package/dist/config/config-manager.js +221 -17
- package/dist/config/contact-alias.js +68 -0
- package/dist/config/contact-book-store.js +454 -0
- package/dist/config/contact-book-v2-startup.js +35 -0
- package/dist/config/contact-book.js +156 -303
- package/dist/config/contact-operation-service.js +110 -0
- package/dist/config/peer-role-resolver.js +133 -54
- package/dist/config/role-ranks.js +18 -0
- package/dist/config/role-service.js +16 -19
- package/dist/config/role-store.js +16 -5
- package/dist/config/roles.js +10 -1
- package/dist/config-store.js +0 -2
- package/dist/core/auth/authorization-audit.js +10 -1
- package/dist/core/auth/operation-authorizer.js +2 -0
- package/dist/core/auth/operation-catalog.js +56 -0
- package/dist/core/command/command-handler.js +105 -10
- package/dist/core/command/connect-menu.js +374 -0
- package/dist/core/command/menu-handler.js +114 -16
- package/dist/core/command/role-menu.js +128 -29
- package/dist/core/command/slash-handler.js +28 -18
- package/dist/core/daemon-file-cache.js +12 -6
- package/dist/core/event-catalog.js +70 -0
- package/dist/core/evolagent-registry.js +0 -1
- package/dist/core/evolagent.js +20 -9
- package/dist/core/message/im-renderer.js +2 -0
- package/dist/core/message/message-bridge.js +79 -8
- package/dist/core/message/message-queue.js +10 -0
- package/dist/core/message/message-utils.js +8 -2
- package/dist/core/message/response-engine.js +269 -25
- package/dist/core/message/send-receipt.js +24 -0
- package/dist/core/message/stream-debouncer.js +11 -2
- package/dist/core/permission/tool-policy.js +47 -15
- package/dist/core/protected-paths.js +2 -0
- package/dist/core/session/session-fs-store.js +44 -3
- package/dist/core/session/session-manager.js +61 -5
- package/dist/index.js +62 -6
- package/dist/ipc.js +34 -5
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/manager.js +3 -0
- package/dist/trigger/parser.js +77 -2
- package/dist/trigger/patch.js +8 -1
- package/dist/trigger/scheduler.js +3 -1
- package/dist/trigger/validation.js +13 -0
- package/dist/utils/aid-bind.js +43 -29
- package/dist/utils/instance-registry.js +14 -7
- package/dist/utils/log-writer.js +46 -0
- package/dist/utils/media-cache.js +4 -1
- package/dist/utils/model-prices.jsonl +6 -3
- package/dist/utils/restart-safety.js +31 -0
- package/dist/utils/system-memory.js +62 -0
- package/kits/docs/INDEX.md +2 -1
- package/kits/docs/evolcore/INDEX.md +5 -3
- package/kits/docs/evolcore/agent.md +9 -1
- package/kits/docs/evolcore/aid.md +5 -2
- package/kits/docs/evolcore/contact.md +57 -0
- package/kits/docs/evolcore/fs.md +9 -0
- package/kits/docs/evolcore/group.md +12 -3
- package/kits/docs/evolcore/model.md +4 -1
- package/kits/docs/evolcore/msg.md +9 -3
- package/kits/docs/evolcore/response.md +16 -21
- package/kits/docs/evolcore/rpc.md +2 -0
- package/kits/docs/evolcore/stats.md +15 -2
- package/kits/docs/evolcore/storage.md +1 -0
- package/kits/docs/evolcore/trigger.md +17 -2
- package/kits/eck_manifest.json +12 -0
- package/kits/migrations/migrate-contact-book-v2.mjs +747 -0
- package/kits/schemas/_meta.json +7 -4
- package/kits/schemas/agent-config.schema.6.json +322 -0
- package/kits/schemas/contact-book.schema.2.json +43 -0
- package/kits/schemas/relation-config.schema.5.json +47 -0
- package/kits/schemas/role-config.schema.1.json +1 -0
- package/kits/schemas/role-registry.schema.1.json +2 -2
- package/kits/templates/roles/admin.json +1 -0
- package/kits/templates/roles/member.json +1 -0
- package/kits/templates/roles/owner.json +1 -0
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/commands.md +3 -1
- package/package.json +4 -4
- package/assets/brand/evolcore/README.md +0 -19
- package/assets/brand/evolcore/evolcore-app-icon.png +0 -0
- package/assets/brand/evolcore/evolcore-app-icon.svg +0 -13
- package/assets/brand/evolcore/evolcore-brand-board.png +0 -0
- package/assets/brand/evolcore/evolcore-brand-board.svg +0 -126
- package/assets/brand/evolcore/evolcore-logo-kit.zip +0 -0
- package/assets/brand/evolcore/evolcore-logo-reverse.png +0 -0
- package/assets/brand/evolcore/evolcore-logo-reverse.svg +0 -14
- package/assets/brand/evolcore/evolcore-logo.png +0 -0
- package/assets/brand/evolcore/evolcore-logo.svg +0 -14
- package/assets/brand/evolcore/evolcore-mark.png +0 -0
- package/assets/brand/evolcore/evolcore-mark.svg +0 -10
package/dist/cli/init.js
CHANGED
|
@@ -64,27 +64,36 @@ export function parseOwnerAids(raw, isValid) {
|
|
|
64
64
|
function installErrorMessage(e) {
|
|
65
65
|
return String(e?.stderr || e?.message || e).trim();
|
|
66
66
|
}
|
|
67
|
-
async function ensureEcwebInstalledForInit() {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
export async function ensureEcwebInstalledForInit(options = {}) {
|
|
68
|
+
const isInstalled = options.isInstalled ?? (() => commandExists(WEB_CLI_BIN));
|
|
69
|
+
if (isInstalled())
|
|
70
|
+
return { ok: true, installedNow: false };
|
|
71
|
+
if (!options.quiet)
|
|
72
|
+
console.log(` 📦 EC Web 组件未安装,正在安装 ${WEB_PACKAGE_LATEST}...`);
|
|
71
73
|
try {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const install = options.install ?? (async (pkg) => {
|
|
75
|
+
const { npmInstallGlobal } = await import('../utils/npm-ops.js');
|
|
76
|
+
await npmInstallGlobal(pkg);
|
|
77
|
+
});
|
|
78
|
+
await install(WEB_PACKAGE_LATEST);
|
|
79
|
+
if (!options.quiet)
|
|
80
|
+
console.log(' ✓ EC Web 组件安装完成');
|
|
81
|
+
return { ok: true, installedNow: true };
|
|
76
82
|
}
|
|
77
83
|
catch (e) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
const error = installErrorMessage(e);
|
|
85
|
+
if (!options.quiet) {
|
|
86
|
+
console.log(` ⚠ EC Web 组件安装失败: ${error}`);
|
|
87
|
+
console.log(` 可稍后运行 ec watch web 自动安装并启动,或手动运行 npm install -g ${WEB_PACKAGE_LATEST}`);
|
|
88
|
+
}
|
|
89
|
+
return { ok: false, error };
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
// ==================== Main ====================
|
|
84
93
|
export async function cmdInit(options) {
|
|
85
94
|
// 云部署非交互式路径:当带 --owner 或 --format json 时走结构化分支,与交互式 tail 完全隔离。
|
|
86
95
|
// 预留方案 B:当 daemon 支持 Control Plane 无 agent 启动时,可在此分支跳过 agent new 预创建。
|
|
87
|
-
if (options?.nonInteractive && (options.owner || options.format === 'json')) {
|
|
96
|
+
if (options?.nonInteractive && (options.owner || options.format === 'json' || options.projectpath || options.ecweb)) {
|
|
88
97
|
return cmdInitNonInteractive({
|
|
89
98
|
owner: options.owner,
|
|
90
99
|
baseagent: options.baseagent,
|
|
@@ -339,16 +348,22 @@ export async function initTail() {
|
|
|
339
348
|
if (daemonConfigForEcweb.ecweb?.enabled === undefined) {
|
|
340
349
|
const ans = (await ask(rl, '\n是否在 ec start 时自动启动 ECWeb 控制台?[y/N] ')).trim().toLowerCase();
|
|
341
350
|
if (ans === 'y' || ans === 'yes') {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
351
|
+
const installResult = await ensureEcwebInstalledForInit();
|
|
352
|
+
if (installResult.ok) {
|
|
353
|
+
const cfg = loadDaemonConfig();
|
|
354
|
+
saveDaemonConfig({ ...cfg, ecweb: { ...(cfg.ecweb ?? {}), enabled: true } });
|
|
355
|
+
console.log(' ✓ 已启用 ECWeb(ec start 将自动在后台启动)');
|
|
356
|
+
console.log(' 提示:首次访问运行 ec watch web 查看配对码和 URL');
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
const cfg = loadDaemonConfig();
|
|
360
|
+
saveDaemonConfig({ ...cfg, ecweb: { ...(cfg.ecweb ?? {}), enabled: false } });
|
|
361
|
+
console.log(' 提示:安装完成后运行 ec start;如需立即打开控制台,运行 ec watch web');
|
|
362
|
+
}
|
|
349
363
|
}
|
|
350
364
|
else {
|
|
351
|
-
|
|
365
|
+
const cfg = loadDaemonConfig();
|
|
366
|
+
saveDaemonConfig({ ...cfg, ecweb: { ...(cfg.ecweb ?? {}), enabled: false } });
|
|
352
367
|
console.log(' 已跳过(可日后运行 ec watch web 手动启动,或编辑 daemon.json)');
|
|
353
368
|
}
|
|
354
369
|
}
|
|
@@ -436,10 +451,13 @@ function fail(code, message, exitCode, format) {
|
|
|
436
451
|
emitResult({ type: 'init.result', success: false, error: { code, message } }, format);
|
|
437
452
|
process.exit(exitCode);
|
|
438
453
|
}
|
|
439
|
-
export async function cmdInitNonInteractive(opts) {
|
|
454
|
+
export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
440
455
|
const format = opts.format;
|
|
441
456
|
const p = resolvePaths();
|
|
442
457
|
ensureDataDirs();
|
|
458
|
+
if (format !== undefined && format !== 'json') {
|
|
459
|
+
fail('INVALID_FORMAT', `--format only supports json: ${format}`, EXIT_USAGE, format);
|
|
460
|
+
}
|
|
443
461
|
// ── 1. owner 校验 ──
|
|
444
462
|
if (!opts.owner) {
|
|
445
463
|
fail('MISSING_OWNER', '--owner is required in non-interactive mode', EXIT_USAGE, format);
|
|
@@ -459,7 +477,7 @@ export async function cmdInitNonInteractive(opts) {
|
|
|
459
477
|
fail('DAEMON_RUNNING', `EvolCore daemon is running (PID: ${pids}); run 'ec stop' first`, EXIT_USAGE, format);
|
|
460
478
|
}
|
|
461
479
|
// ── 3. baseagent 探测 + 校验 ──
|
|
462
|
-
const available = detectAvailable();
|
|
480
|
+
const available = dependencies.availableBaseagents ?? detectAvailable();
|
|
463
481
|
if (available.length === 0) {
|
|
464
482
|
fail('BASEAGENT_UNAVAILABLE', 'no baseagent CLI detected (install claude/codex/gemini)', EXIT_USAGE, format);
|
|
465
483
|
}
|
|
@@ -503,14 +521,33 @@ export async function cmdInitNonInteractive(opts) {
|
|
|
503
521
|
}
|
|
504
522
|
const forced = differentOwner && !!opts.force;
|
|
505
523
|
const previousOwners = forced ? [...existingOwners] : undefined;
|
|
506
|
-
// ── 6.
|
|
524
|
+
// ── 6. EC Web 安装(先安装成功,再写 enabled 配置)──
|
|
525
|
+
if (opts.ecweb === true) {
|
|
526
|
+
const ensureEcweb = dependencies.ensureEcweb ?? (() => ensureEcwebInstalledForInit({ quiet: true }));
|
|
527
|
+
const installResult = await ensureEcweb();
|
|
528
|
+
if (!installResult.ok) {
|
|
529
|
+
if (existingCfg.ecweb?.enabled === true) {
|
|
530
|
+
try {
|
|
531
|
+
saveDaemonConfig({
|
|
532
|
+
...existingCfg,
|
|
533
|
+
ecweb: { ...(existingCfg.ecweb ?? {}), enabled: false },
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
catch (e) {
|
|
537
|
+
fail('ECWEB_INSTALL_FAILED', `failed to install ${WEB_PACKAGE_LATEST}: ${installResult.error}; failed to disable ecweb: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
fail('ECWEB_INSTALL_FAILED', `failed to install ${WEB_PACKAGE_LATEST}: ${installResult.error}`, EXIT_RUNTIME, format);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// ── 7. 写 defaults.json ──
|
|
507
544
|
try {
|
|
508
545
|
saveDefaultsSafe(buildDefaults(chosenBaseagent, available, projectsDefaultPath));
|
|
509
546
|
}
|
|
510
547
|
catch (e) {
|
|
511
548
|
fail('IO_ERROR', `failed to write defaults.json: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
512
549
|
}
|
|
513
|
-
// ──
|
|
550
|
+
// ── 8. 控制 AID:缺失则生成 ──
|
|
514
551
|
let controlAid = existingCfg.aid;
|
|
515
552
|
if (!controlAid) {
|
|
516
553
|
try {
|
|
@@ -521,7 +558,7 @@ export async function cmdInitNonInteractive(opts) {
|
|
|
521
558
|
fail('CONTROL_AID_CREATE_FAILED', `gateway unreachable: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
522
559
|
}
|
|
523
560
|
}
|
|
524
|
-
// ──
|
|
561
|
+
// ── 9. 写 daemon.json(aid + owners + ecweb)──
|
|
525
562
|
try {
|
|
526
563
|
const next = {
|
|
527
564
|
...existingCfg,
|
|
@@ -535,7 +572,7 @@ export async function cmdInitNonInteractive(opts) {
|
|
|
535
572
|
catch (e) {
|
|
536
573
|
fail('IO_ERROR', `failed to write daemon.json: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
537
574
|
}
|
|
538
|
-
// ──
|
|
575
|
+
// ── 10. 输出 init.result ──
|
|
539
576
|
const result = {
|
|
540
577
|
type: 'init.result',
|
|
541
578
|
success: true,
|
package/dist/cli/model.js
CHANGED
|
@@ -243,13 +243,14 @@ Commands:
|
|
|
243
243
|
check 诊断网关连通性与模型可用性(分阶段输出进度)
|
|
244
244
|
|
|
245
245
|
作用域(越具体越优先:关系 > 角色 > agent > defaults):
|
|
246
|
-
(无参数) 只读 catalog/defaults,不允许写入
|
|
246
|
+
(无参数) 本机 CLI 只读 catalog/defaults,不允许写入
|
|
247
247
|
--self <aid> agent级 → config.json
|
|
248
248
|
--self <aid> --role <role> 角色策略预览(只读)
|
|
249
249
|
--self <aid> --peer <X> 关系级 → relations/<peerKey>/config.json
|
|
250
250
|
|
|
251
251
|
修改 agent/关系作用域后,对应范围所有会话的下一条消息即时生效。
|
|
252
252
|
角色策略请通过角色策略编辑器修改。
|
|
253
|
+
托管会话内省略 --self/--peer/--role 时,命令作用于当前会话。
|
|
253
254
|
|
|
254
255
|
Options:
|
|
255
256
|
--self <aid> 本端 AID
|
package/dist/cli/net-check.js
CHANGED
|
@@ -10,7 +10,7 @@ import { WebSocket } from 'ws';
|
|
|
10
10
|
import { aunPath as defaultAunPath } from '../paths.js';
|
|
11
11
|
import { isHostChinese } from '../utils/locale.js';
|
|
12
12
|
import { getAidStore, loadClient, SLOT } from '../aun/aid/store.js';
|
|
13
|
-
import { isHelpFlag } from './help.js';
|
|
13
|
+
import { isHelpFlag, wantsHelp } from './help.js';
|
|
14
14
|
const GREEN = '\x1b[32m';
|
|
15
15
|
const RED = '\x1b[31m';
|
|
16
16
|
const YELLOW = '\x1b[33m';
|
|
@@ -645,7 +645,7 @@ export async function cmdNet(args) {
|
|
|
645
645
|
const sub = args[0];
|
|
646
646
|
const formatJson = args.includes('--format') && args.includes('json');
|
|
647
647
|
const kickTest = args.includes('--kick-test');
|
|
648
|
-
if (isHelpFlag(sub)) {
|
|
648
|
+
if (isHelpFlag(sub) || wantsHelp(args)) {
|
|
649
649
|
console.log(`用法: ec net check [<aid>] [--format json] [--kick-test]
|
|
650
650
|
|
|
651
651
|
检查 AUN 网络链路连通性(11 步逐层诊断)。
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolvePaths } from '../paths.js';
|
|
2
2
|
import { ipcQuery } from '../ipc.js';
|
|
3
|
-
import { isHelpFlag } from './help.js';
|
|
3
|
+
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
4
4
|
export async function cmdQueue(args) {
|
|
5
|
-
if (args.length === 0 || isHelpFlag(args[0])) {
|
|
5
|
+
if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
|
|
6
6
|
console.log(`用法: ec queue --agent <aid> [选项]
|
|
7
7
|
|
|
8
8
|
查询与操作 EvolAgent 的消息队列。
|
|
@@ -24,7 +24,7 @@ export async function cmdQueue(args) {
|
|
|
24
24
|
ec queue --agent mybot.agentid.pub --clear
|
|
25
25
|
ec queue --agent mybot.agentid.pub --cancel msg_d4e5f6
|
|
26
26
|
ec queue --agent mybot.agentid.pub --interrupt --sessionkey feishu#oc_abc123#main`);
|
|
27
|
-
|
|
27
|
+
return;
|
|
28
28
|
}
|
|
29
29
|
// 解析参数
|
|
30
30
|
const agentIdx = args.indexOf('--agent');
|
|
@@ -33,15 +33,39 @@ export async function cmdQueue(args) {
|
|
|
33
33
|
process.exit(1);
|
|
34
34
|
}
|
|
35
35
|
const agent = args[agentIdx + 1];
|
|
36
|
+
if (agent.startsWith('--')) {
|
|
37
|
+
console.error('❌ --agent 缺少 <aid> 参数');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
36
40
|
const showId = args.includes('--showid');
|
|
37
41
|
const full = args.includes('--full');
|
|
38
|
-
const
|
|
42
|
+
const formatValue = getArgValue(args, '--format');
|
|
43
|
+
if (formatValue !== undefined && formatValue !== 'json') {
|
|
44
|
+
console.error(`❌ --format 仅支持 json: ${formatValue}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const formatJson = formatValue === 'json';
|
|
39
48
|
const clear = args.includes('--clear');
|
|
40
49
|
const cancelIdx = args.indexOf('--cancel');
|
|
41
|
-
const
|
|
50
|
+
const cancelCandidate = cancelIdx >= 0 && cancelIdx + 1 < args.length ? args[cancelIdx + 1] : undefined;
|
|
51
|
+
const cancelMsgId = cancelCandidate && !cancelCandidate.startsWith('--') ? cancelCandidate : undefined;
|
|
42
52
|
const interrupt = args.includes('--interrupt');
|
|
43
53
|
const sessionKeyIdx = args.indexOf('--sessionkey');
|
|
44
|
-
const
|
|
54
|
+
const sessionCandidate = sessionKeyIdx >= 0 && sessionKeyIdx + 1 < args.length ? args[sessionKeyIdx + 1] : undefined;
|
|
55
|
+
const sessionKey = sessionCandidate && !sessionCandidate.startsWith('--') ? sessionCandidate : undefined;
|
|
56
|
+
const actionCount = [clear, cancelIdx >= 0, interrupt].filter(Boolean).length;
|
|
57
|
+
if (actionCount > 1) {
|
|
58
|
+
console.error('❌ --clear、--cancel、--interrupt 互斥,只能指定一个');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
if (cancelIdx >= 0 && !cancelMsgId) {
|
|
62
|
+
console.error('❌ --cancel 缺少 <messageId>');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
if (interrupt && !sessionKey) {
|
|
66
|
+
console.error('❌ --interrupt 必须配合 --sessionkey <key>');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
45
69
|
// 构建 IPC 请求
|
|
46
70
|
const action = clear ? 'clear'
|
|
47
71
|
: cancelMsgId ? 'cancel'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporarily listen for single-key input and restore stdin's previous state.
|
|
3
|
+
*
|
|
4
|
+
* Standalone init commands enter this flow after closing readline, so stdin is
|
|
5
|
+
* paused and must be paused again during cleanup or Node will stay alive. Some
|
|
6
|
+
* parent wizards keep readline active, so an already-flowing stdin must remain
|
|
7
|
+
* flowing for their next prompt.
|
|
8
|
+
*/
|
|
9
|
+
export function setupRawKeyListener(onKey, input = process.stdin) {
|
|
10
|
+
if (!input.isTTY)
|
|
11
|
+
return () => { };
|
|
12
|
+
const wasPaused = input.isPaused();
|
|
13
|
+
const wasRaw = Boolean(input.isRaw);
|
|
14
|
+
input.setRawMode(true);
|
|
15
|
+
input.resume();
|
|
16
|
+
input.setEncoding('utf8');
|
|
17
|
+
const handler = (chunk) => onKey(String(chunk));
|
|
18
|
+
input.on('data', handler);
|
|
19
|
+
return () => {
|
|
20
|
+
input.removeListener('data', handler);
|
|
21
|
+
input.setRawMode(wasRaw);
|
|
22
|
+
if (wasPaused)
|
|
23
|
+
input.pause();
|
|
24
|
+
};
|
|
25
|
+
}
|
package/dist/cli/response.js
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 查看/切换/配置会话的响应模式。作用域由 --self/--peer 决定。
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* (无) → 全局 defaults.json
|
|
6
|
+
* 读取解析链(越具体越优先:关系 > agent > defaults):
|
|
8
7
|
* --self → agent config.json
|
|
9
8
|
* --self --peer → 关系 relations/<peerKey>/config.json
|
|
10
9
|
*
|
|
@@ -149,11 +148,11 @@ Options:
|
|
|
149
148
|
示例:
|
|
150
149
|
ec response list
|
|
151
150
|
ec response current --self bot.agentid.pub
|
|
152
|
-
ec response info
|
|
151
|
+
ec response info single-session
|
|
153
152
|
ec response set single-session --self bot.agentid.pub
|
|
154
|
-
ec response set
|
|
155
|
-
ec response config
|
|
156
|
-
ec response config set
|
|
153
|
+
ec response set single-session --self bot.agentid.pub --peer aun#team.group.com
|
|
154
|
+
ec response config single-session --self bot.agentid.pub
|
|
155
|
+
ec response config set tool_use_reminder false --mode single-session --self bot.agentid.pub
|
|
157
156
|
ec response reset --self bot.agentid.pub --peer alice.agentid.pub`;
|
|
158
157
|
// ── list ────────────────────────────────────────────────────────────────
|
|
159
158
|
function cmdList(args, formatJson) {
|
|
@@ -10,8 +10,10 @@ import { tryUpgrade, tryUpgradeAunSdk, tryUpgradeGlobalPkg, resolveGlobalPkg } f
|
|
|
10
10
|
import { resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG } from '../aun/aid/client.js';
|
|
11
11
|
import { isValidAid } from '../aun/aid/index.js';
|
|
12
12
|
import { msgSend } from '../aun/msg/index.js';
|
|
13
|
-
import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner } from '../utils/instance-registry.js';
|
|
13
|
+
import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
|
|
14
14
|
import { WEB_PACKAGE_NAME } from '../product.js';
|
|
15
|
+
import { shouldSuppressRealRestart } from '../utils/restart-safety.js';
|
|
16
|
+
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
15
17
|
const execFileAsync = promisify(execFile);
|
|
16
18
|
// 清理 Claude Code 环境变量,防止 SDK 认为是嵌套会话
|
|
17
19
|
function cleanEnv() {
|
|
@@ -24,6 +26,10 @@ function cleanEnv() {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
export async function cmdRestartMonitor() {
|
|
29
|
+
// Defense in depth: a unit test that accidentally executes the real restart
|
|
30
|
+
// path must not detach a persistent daemon from the test worker.
|
|
31
|
+
if (shouldSuppressRealRestart())
|
|
32
|
+
return;
|
|
27
33
|
const p = resolvePaths();
|
|
28
34
|
const restartLog = path.join(p.logs, 'restart.log');
|
|
29
35
|
const MAX_HEAL_ATTEMPTS = 3;
|
|
@@ -66,6 +72,17 @@ export async function cmdRestartMonitor() {
|
|
|
66
72
|
return s.mains.some(m => m.alive);
|
|
67
73
|
};
|
|
68
74
|
log('Restart monitor started');
|
|
75
|
+
// Test daemons live in one temporary HOME per test, so the current HOME's
|
|
76
|
+
// instance registry cannot see them. Their strict environment markers make
|
|
77
|
+
// them safe to reap globally on every real restart.
|
|
78
|
+
{
|
|
79
|
+
const leakedTestDaemons = findOrphanProcesses().filter(o => o.confirmedTestDaemon);
|
|
80
|
+
if (leakedTestDaemons.length > 0) {
|
|
81
|
+
const killed = killOrphans(leakedTestDaemons);
|
|
82
|
+
log(`Cleaned ${killed.length} leaked test daemon(s): ${killed.join(', ')}`);
|
|
83
|
+
await sleep(500);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
69
86
|
// restart-pending.json 只留给新主进程发送发起会话内的“重启成功”回执。
|
|
70
87
|
const pendingFile = path.join(p.dataDir, 'restart-pending.json');
|
|
71
88
|
// 等待所有活 main 进程退出(可能不止一个)
|
|
@@ -271,6 +288,13 @@ async function spawnAndWaitReady(p, log, timeout) {
|
|
|
271
288
|
// 清理残留 instance 文件和进程
|
|
272
289
|
cleanupInstances();
|
|
273
290
|
cleanEnv();
|
|
291
|
+
const stdoutRotation = rotateStdoutLog(p.logs);
|
|
292
|
+
if (stdoutRotation.rotatedPath) {
|
|
293
|
+
log(`Rotated stdout.log -> ${path.basename(stdoutRotation.rotatedPath)}`);
|
|
294
|
+
}
|
|
295
|
+
if (stdoutRotation.removedArchives.length > 0) {
|
|
296
|
+
log(`Removed ${stdoutRotation.removedArchives.length} expired stdout archive(s)`);
|
|
297
|
+
}
|
|
274
298
|
const stdoutLog = path.join(p.logs, 'stdout.log');
|
|
275
299
|
const out = fs.openSync(stdoutLog, 'a');
|
|
276
300
|
const err = fs.openSync(stdoutLog, 'a');
|
package/dist/cli/stats.js
CHANGED
|
@@ -32,12 +32,14 @@ Usage: ec stats [options]
|
|
|
32
32
|
--context <id> 会话 context breakdown 细目
|
|
33
33
|
--budget 预算状态
|
|
34
34
|
--top-peers [--limit N] 对端排行
|
|
35
|
+
--top-models [--limit N] 模型排行
|
|
36
|
+
--traffic 消息收发条数与字节数
|
|
35
37
|
--sql "<query>" 直接执行只读 SQL
|
|
36
38
|
--rebuild 全量重建日聚合表 usage_daily(运维兜底/排查)
|
|
37
|
-
--peers [--limit N]
|
|
38
|
-
--groups [--limit N]
|
|
39
|
-
--summary
|
|
40
|
-
--peer-detail <id>
|
|
39
|
+
--peers [--limit N] 私聊对端列表(带累计 token/calls/活跃日)
|
|
40
|
+
--groups [--limit N] 群聊列表(同上)
|
|
41
|
+
--summary 指定时间范围总消耗汇总(token/USD/CNY)
|
|
42
|
+
--peer-detail <id> 指定对端 AID 或 peer_key,按天返回消耗明细
|
|
41
43
|
--task-calls <taskId> 一个 task 的逐次大模型调用明细
|
|
42
44
|
--session-calls <id> 一个会话的逐次大模型调用明细
|
|
43
45
|
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolvePaths } from '../paths.js';
|
|
4
4
|
import { ipcQuery } from '../ipc.js';
|
|
5
|
-
import { isHelpFlag } from './help.js';
|
|
5
|
+
import { isHelpFlag, wantsHelp } from './help.js';
|
|
6
6
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
7
7
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
8
8
|
import { normalizeTriggerDefinition, resolveScriptPath, } from '../trigger/validation.js';
|
|
@@ -12,12 +12,25 @@ export async function cmdTrigger(args) {
|
|
|
12
12
|
printHelp();
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (wantsHelp(args)) {
|
|
16
|
+
printHelp();
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const rest = args.slice(1);
|
|
20
20
|
const json = hasFlag(rest, '--json') || flagValue(rest, '--format') === 'json';
|
|
21
|
+
if (sub === 'template') {
|
|
22
|
+
try {
|
|
23
|
+
handleTemplate(rest);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (json)
|
|
27
|
+
console.log(JSON.stringify({ ok: false, error: err?.message || String(err) }, null, 2));
|
|
28
|
+
else
|
|
29
|
+
console.error(err?.message || String(err));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
21
34
|
try {
|
|
22
35
|
switch (sub) {
|
|
23
36
|
case 'list':
|
|
@@ -30,6 +43,7 @@ export async function cmdTrigger(args) {
|
|
|
30
43
|
await showHistory(rest, json);
|
|
31
44
|
return;
|
|
32
45
|
case 'create':
|
|
46
|
+
case 'set':
|
|
33
47
|
await createTrigger(rest, json);
|
|
34
48
|
return;
|
|
35
49
|
case 'update':
|
|
@@ -72,11 +86,12 @@ function printHelp() {
|
|
|
72
86
|
create --file <trigger.json|trigger-dir> [--enable] [--json]
|
|
73
87
|
OR
|
|
74
88
|
create [--agent <aid>] --cron <expr>|--event <pattern> --prompt <text> [--enable] [其他flag]
|
|
89
|
+
set ... (create 的兼容别名)
|
|
75
90
|
update [--agent <aid>] <triggerId> <参数...> [--if-revision <sha256:...>] [--json]
|
|
76
91
|
enable [--agent <aid>] <triggerId>
|
|
77
92
|
disable [--agent <aid>] <triggerId>
|
|
78
93
|
cancel [--agent <aid>] <triggerId> (disable 的兼容别名)
|
|
79
|
-
delete [--agent <aid>] <triggerId>
|
|
94
|
+
delete|remove|rm [--agent <aid>] <triggerId>
|
|
80
95
|
run [--agent <aid>] <triggerId> [--dry-run] [--json]
|
|
81
96
|
template list|show <name> [--json]
|
|
82
97
|
|
|
@@ -85,7 +100,9 @@ Create 参数模式支持:
|
|
|
85
100
|
--exec <script|trigger-session|target-session>
|
|
86
101
|
--prompt <文本>
|
|
87
102
|
--script-path <路径> --script-runtime <node|python|bash>
|
|
88
|
-
--
|
|
103
|
+
--script-args <JSON> --script-timeout <时长>
|
|
104
|
+
--feedback <target> (origin/silent 仅可通过 --file 导入)
|
|
105
|
+
--baseagent <name> (仅 --exec trigger-session)
|
|
89
106
|
--model <模型> --effort <low|medium|high|xhigh|max>
|
|
90
107
|
--max-runs <次数> --max-duration <时长: 30s|15m|2h|1d>
|
|
91
108
|
--permission <readonly|auto|request|bypass>(省略则继承当前身份配置)
|
|
@@ -95,6 +112,9 @@ Create 参数模式支持:
|
|
|
95
112
|
--trigger-thread <per-run|by-trigger>
|
|
96
113
|
--name <名称>
|
|
97
114
|
|
|
115
|
+
通用输出参数:
|
|
116
|
+
--json | --format json
|
|
117
|
+
|
|
98
118
|
Update 仅支持常用字段:
|
|
99
119
|
--once | --delay | --at | --cron | --every | --event [--tz]
|
|
100
120
|
--prompt <文本> --name <名称>
|
|
@@ -120,7 +140,7 @@ async function listTriggers(args, json) {
|
|
|
120
140
|
}
|
|
121
141
|
async function showTrigger(args, json) {
|
|
122
142
|
const agentAid = resolveAgentAid(args);
|
|
123
|
-
const triggerId = positional(args, 0, ['--agent']);
|
|
143
|
+
const triggerId = positional(args, 0, ['--agent', '--format']);
|
|
124
144
|
const res = await request({ type: 'trigger.show', agentAid, triggerId });
|
|
125
145
|
if (json)
|
|
126
146
|
return printJson(res);
|
|
@@ -149,6 +169,8 @@ async function showTrigger(args, json) {
|
|
|
149
169
|
console.log(`limit state: ${parts.join(', ')}`);
|
|
150
170
|
}
|
|
151
171
|
console.log(`execution: ${t.execution.type}`);
|
|
172
|
+
if (t.execution.type === 'trigger_session')
|
|
173
|
+
console.log(`baseagent: ${t.execution.baseagent ?? 'legacy/inherit'}`);
|
|
152
174
|
if (t.execution.type === 'script')
|
|
153
175
|
console.log(`script: ${scriptCommandLabel(t.execution.script)}`);
|
|
154
176
|
console.log(`model: ${t.execution.model ?? 'inherit'}`);
|
|
@@ -208,9 +230,8 @@ async function createTrigger(args, json) {
|
|
|
208
230
|
return;
|
|
209
231
|
}
|
|
210
232
|
// Flag mode: use parser
|
|
211
|
-
const {
|
|
212
|
-
const
|
|
213
|
-
const parseResult = parseTriggerSet(flagStr);
|
|
233
|
+
const { parseTriggerSetArgv } = await import('../trigger/parser.js');
|
|
234
|
+
const parseResult = parseTriggerSetArgv(triggerCreateArgs(args));
|
|
214
235
|
if (!parseResult.ok) {
|
|
215
236
|
throw new Error(parseResult.error);
|
|
216
237
|
}
|
|
@@ -246,7 +267,10 @@ async function createTrigger(args, json) {
|
|
|
246
267
|
...(parsed.model ? { model: parsed.model } : {}),
|
|
247
268
|
...(parsed.effort ? { effort: parsed.effort } : {}),
|
|
248
269
|
...(parsed.permissionMode ? { permissionMode: parsed.permissionMode } : {}),
|
|
249
|
-
...(parsed.executionType === 'trigger_session' ? {
|
|
270
|
+
...(parsed.executionType === 'trigger_session' ? {
|
|
271
|
+
thread: parsed.triggerThread ?? 'by_trigger',
|
|
272
|
+
...(parsed.baseagent ? { baseagent: parsed.baseagent } : {}),
|
|
273
|
+
} : {}),
|
|
250
274
|
onError: 'retry',
|
|
251
275
|
noopSentinel: '[[NOOP]]',
|
|
252
276
|
},
|
|
@@ -272,6 +296,22 @@ async function createTrigger(args, json) {
|
|
|
272
296
|
return printJson(res);
|
|
273
297
|
console.log(`✓ created ${res.trigger.id} (${res.trigger.name})`);
|
|
274
298
|
}
|
|
299
|
+
function triggerCreateArgs(args) {
|
|
300
|
+
const out = [];
|
|
301
|
+
for (let i = 0; i < args.length; i++) {
|
|
302
|
+
const arg = args[i];
|
|
303
|
+
if (arg === '--enable' || arg === '--json')
|
|
304
|
+
continue;
|
|
305
|
+
if (arg === '--format') {
|
|
306
|
+
i += 1;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (arg.startsWith('--format='))
|
|
310
|
+
continue;
|
|
311
|
+
out.push(arg);
|
|
312
|
+
}
|
|
313
|
+
return out;
|
|
314
|
+
}
|
|
275
315
|
function sourceFromParsed(parsed) {
|
|
276
316
|
if (parsed.scheduleType === 'once')
|
|
277
317
|
return { type: 'once' };
|
|
@@ -362,7 +402,7 @@ function triggerUpdateArgs(args) {
|
|
|
362
402
|
}
|
|
363
403
|
async function setEnabled(args, enabled, json) {
|
|
364
404
|
const agentAid = resolveAgentAid(args);
|
|
365
|
-
const triggerId = positional(args, 0, ['--agent']);
|
|
405
|
+
const triggerId = positional(args, 0, ['--agent', '--format']);
|
|
366
406
|
const res = await request({ type: 'trigger.setEnabled', agentAid, triggerId, enabled });
|
|
367
407
|
if (json)
|
|
368
408
|
return printJson(res);
|
|
@@ -370,7 +410,7 @@ async function setEnabled(args, enabled, json) {
|
|
|
370
410
|
}
|
|
371
411
|
async function cancelTrigger(args, json) {
|
|
372
412
|
const agentAid = resolveAgentAid(args);
|
|
373
|
-
const triggerId = positional(args, 0, ['--agent']);
|
|
413
|
+
const triggerId = positional(args, 0, ['--agent', '--format']);
|
|
374
414
|
const res = await request({ type: 'trigger.cancel', agentAid, triggerId });
|
|
375
415
|
if (json)
|
|
376
416
|
return printJson(res);
|
|
@@ -378,7 +418,7 @@ async function cancelTrigger(args, json) {
|
|
|
378
418
|
}
|
|
379
419
|
async function deleteTrigger(args, json) {
|
|
380
420
|
const agentAid = resolveAgentAid(args);
|
|
381
|
-
const triggerId = positional(args, 0, ['--agent']);
|
|
421
|
+
const triggerId = positional(args, 0, ['--agent', '--format']);
|
|
382
422
|
const res = await request({ type: 'trigger.delete', agentAid, triggerId });
|
|
383
423
|
if (json)
|
|
384
424
|
return printJson(res);
|
|
@@ -386,7 +426,7 @@ async function deleteTrigger(args, json) {
|
|
|
386
426
|
}
|
|
387
427
|
async function runTrigger(args, json) {
|
|
388
428
|
const agentAid = resolveAgentAid(args);
|
|
389
|
-
const triggerId = positional(args, 0, ['--agent']);
|
|
429
|
+
const triggerId = positional(args, 0, ['--agent', '--format']);
|
|
390
430
|
const res = await request({ type: 'trigger.run', agentAid, triggerId, dryRun: hasFlag(args, '--dry-run') }, 120_000);
|
|
391
431
|
if (json)
|
|
392
432
|
return printJson(res);
|
|
@@ -406,7 +446,7 @@ function handleTemplate(args) {
|
|
|
406
446
|
return;
|
|
407
447
|
}
|
|
408
448
|
if (sub === 'show') {
|
|
409
|
-
const name = args.
|
|
449
|
+
const name = optionalPositional(args.slice(1), 0, ['--format']);
|
|
410
450
|
if (!name)
|
|
411
451
|
throw new Error('missing template name');
|
|
412
452
|
if (json)
|
package/dist/cli/version.js
CHANGED
|
@@ -5,6 +5,7 @@ import fs from 'fs';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { MAIN_PACKAGE_NAME, PRODUCT_DISPLAY_NAME, WEB_PACKAGE_NAME } from '../product.js';
|
|
8
|
+
import { getArgValue, wantsHelp } from './help.js';
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
const PACKAGE_ROOT = path.resolve(__dirname, '../..');
|
|
10
11
|
const RESET = '\x1b[0m';
|
|
@@ -44,7 +45,11 @@ function findInstalledVersion(pkgName) {
|
|
|
44
45
|
return { name: pkg.name || pkgName, version: pkg.version || '?', buildTs: ts || undefined, path: dir };
|
|
45
46
|
}
|
|
46
47
|
export function handleVersion(args) {
|
|
47
|
-
|
|
48
|
+
if (wantsHelp(args)) {
|
|
49
|
+
console.log(`用法: ec version [--format json|--json]\n\n显示 EvolCore、EC Web、AUN SDK、WebSocket 与 Node.js 版本。`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const isJson = getArgValue(args, '--format') === 'json' || args.includes('--json');
|
|
48
53
|
// 主包
|
|
49
54
|
const mainPkg = readPkgJson(PACKAGE_ROOT);
|
|
50
55
|
const mainEntry = path.join(PACKAGE_ROOT, 'dist', 'cli', 'index.js');
|
|
@@ -2,7 +2,28 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { kitsRoleTemplatesDir } from '../paths.js';
|
|
4
4
|
import { validateRoleConfig } from './role-schema.js';
|
|
5
|
+
import { expectedRoleRank } from './role-ranks.js';
|
|
5
6
|
export const BUILTIN_ROLE_IDS = ['owner', 'admin', 'member', 'visitor'];
|
|
7
|
+
export function validateBuiltinRoleTemplateDefinition(roleId, raw) {
|
|
8
|
+
const issues = validateRoleConfig(raw);
|
|
9
|
+
if (issues.length) {
|
|
10
|
+
return {
|
|
11
|
+
definition: null,
|
|
12
|
+
error: `built-in role template failed validation: ${issues.map(issue => `${issue.field} ${issue.message}`).join('; ')}`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const { $schema_version: _schemaVersion, ...definition } = raw;
|
|
16
|
+
if (BUILTIN_ROLE_IDS.includes(roleId)) {
|
|
17
|
+
const expectedRank = expectedRoleRank(roleId);
|
|
18
|
+
if (definition.rank !== expectedRank) {
|
|
19
|
+
return {
|
|
20
|
+
definition: null,
|
|
21
|
+
error: `built-in role template rank must be ${expectedRank}`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { definition: definition };
|
|
26
|
+
}
|
|
6
27
|
/** Load the versioned package template that defines a built-in role policy. */
|
|
7
28
|
export function readBuiltinRoleTemplate(roleId) {
|
|
8
29
|
const file = path.join(kitsRoleTemplatesDir(), `${roleId}.json`);
|
|
@@ -17,14 +38,5 @@ export function readBuiltinRoleTemplate(roleId) {
|
|
|
17
38
|
error: `cannot read built-in role template: ${error instanceof Error ? error.message : String(error)}`,
|
|
18
39
|
};
|
|
19
40
|
}
|
|
20
|
-
|
|
21
|
-
if (issues.length) {
|
|
22
|
-
return {
|
|
23
|
-
definition: null,
|
|
24
|
-
file,
|
|
25
|
-
error: `built-in role template failed validation: ${issues.map(issue => `${issue.field} ${issue.message}`).join('; ')}`,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const { $schema_version: _schemaVersion, ...definition } = raw;
|
|
29
|
-
return { definition: definition, file };
|
|
41
|
+
return { ...validateBuiltinRoleTemplateDefinition(roleId, raw), file };
|
|
30
42
|
}
|