evolcore 0.0.7 → 0.0.9
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 +43 -0
- package/README.md +38 -4
- package/dist/agents/baseagent.js +117 -24
- package/dist/agents/claude-runner.js +31 -2
- package/dist/agents/codex-app-server-client.js +37 -2
- package/dist/agents/codex-runner.js +11 -3
- package/dist/aun/aid/control-aid.js +40 -27
- package/dist/aun/aid/domain.js +23 -0
- package/dist/aun/msg/group.js +9 -9
- package/dist/aun/msg/p2p.js +11 -6
- package/dist/aun/msg/upload.js +43 -29
- package/dist/aun/outbox.js +48 -5
- package/dist/channels/aun.js +225 -71
- package/dist/cli/aun-commands.js +10 -7
- package/dist/cli/bench.js +4 -3
- package/dist/cli/daemon-commands.js +208 -68
- package/dist/cli/data-command.js +62 -35
- package/dist/cli/index.js +11 -1
- package/dist/cli/init-channel.js +1 -1
- package/dist/cli/init.js +112 -17
- package/dist/cli/model.js +5 -5
- package/dist/cli/restart-monitor.js +102 -22
- package/dist/config/builtin-role-templates.js +4 -3
- package/dist/config/config-field-policy.js +6 -2
- package/dist/config/config-manager.js +79 -11
- package/dist/config/gateway-config.js +80 -35
- package/dist/config/role-schema.js +18 -3
- package/dist/config/role-service.js +3 -3
- package/dist/config/role-store.js +4 -3
- package/dist/config-store.js +19 -3
- package/dist/core/auth/operation-authorizer.js +3 -1
- package/dist/core/baseagent-loader.js +5 -3
- package/dist/core/bootstrap-service.js +0 -12
- package/dist/core/capability/providers/codex-capability-provider.js +2 -2
- package/dist/core/channel-loader.js +15 -2
- package/dist/core/command/command-handler.js +1 -1
- package/dist/core/command/evol-menu-version-gate.js +3 -2
- package/dist/core/command/menu-handler.js +50 -28
- package/dist/core/command/menu-protocol.js +7 -4
- package/dist/core/command/slash-handler.js +4 -4
- package/dist/core/data-migration.js +517 -24
- package/dist/core/inference/text-inference.js +18 -5
- package/dist/core/message/message-bridge.js +17 -6
- package/dist/core/message/response-engine.js +22 -3
- package/dist/core/model/config-scope.js +3 -3
- package/dist/core/permission/tool-policy.js +18 -0
- package/dist/core/protected-paths.js +12 -1
- package/dist/index.js +794 -725
- package/dist/ipc.js +3 -1
- package/dist/product.js +1 -0
- package/dist/utils/autostart.js +27 -0
- package/dist/utils/codex-cli.js +39 -0
- package/dist/utils/cross-platform.js +147 -18
- package/dist/utils/ecweb-utils.js +15 -2
- package/dist/utils/instance-registry.js +43 -6
- package/dist/utils/macos-autostart.js +179 -0
- package/dist/utils/process-introspect.js +7 -3
- package/dist/utils/windows-autostart.js +130 -0
- package/ecagent/dist/agent-loop.d.ts +1 -1
- package/ecagent/dist/agent-loop.js +1 -1
- package/ecagent/dist/agent.d.ts +1 -1
- package/ecagent/dist/agent.js +1 -1
- package/ecagent/dist/harness/agent-harness.d.ts +1 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts +1 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts +1 -1
- package/ecagent/dist/harness/compaction/utils.d.ts +1 -1
- package/ecagent/dist/harness/messages.d.ts +1 -1
- package/ecagent/dist/harness/session/session.d.ts +1 -1
- package/ecagent/dist/harness/types.d.ts +1 -1
- package/ecagent/dist/proxy.d.ts +1 -1
- package/ecagent/dist/proxy.js +1 -1
- package/ecagent/dist/types.d.ts +1 -1
- package/kits/migrations/migrate-role-config-v5.mjs +27 -2
- package/kits/rules/01-overview.md +3 -2
- package/kits/schemas/_meta.json +2 -1
- package/kits/schemas/agent-config.schema.10.json +19 -1
- package/kits/schemas/daemon.schema.4.json +136 -0
- package/kits/schemas/defaults.schema.4.json +15 -1
- package/kits/schemas/relation-config.schema.8.json +22 -1
- package/kits/schemas/role-config.schema.1.json +2 -2
- package/package.json +2 -4
- package/ecagent/dist/agent-loop.d.ts.map +0 -1
- package/ecagent/dist/agent-loop.js.map +0 -1
- package/ecagent/dist/agent.d.ts.map +0 -1
- package/ecagent/dist/agent.js.map +0 -1
- package/ecagent/dist/harness/agent-harness.d.ts.map +0 -1
- package/ecagent/dist/harness/agent-harness.js.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.js.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.js.map +0 -1
- package/ecagent/dist/harness/compaction/utils.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/utils.js.map +0 -1
- package/ecagent/dist/harness/env/nodejs.d.ts.map +0 -1
- package/ecagent/dist/harness/env/nodejs.js.map +0 -1
- package/ecagent/dist/harness/messages.d.ts.map +0 -1
- package/ecagent/dist/harness/messages.js.map +0 -1
- package/ecagent/dist/harness/prompt-templates.d.ts.map +0 -1
- package/ecagent/dist/harness/prompt-templates.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.js.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.js.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.js.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.d.ts.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.js.map +0 -1
- package/ecagent/dist/harness/session/session.d.ts.map +0 -1
- package/ecagent/dist/harness/session/session.js.map +0 -1
- package/ecagent/dist/harness/session/uuid.d.ts.map +0 -1
- package/ecagent/dist/harness/session/uuid.js.map +0 -1
- package/ecagent/dist/harness/skills.d.ts.map +0 -1
- package/ecagent/dist/harness/skills.js.map +0 -1
- package/ecagent/dist/harness/system-prompt.d.ts.map +0 -1
- package/ecagent/dist/harness/system-prompt.js.map +0 -1
- package/ecagent/dist/harness/types.d.ts.map +0 -1
- package/ecagent/dist/harness/types.js.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.js.map +0 -1
- package/ecagent/dist/harness/utils/truncate.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/truncate.js.map +0 -1
- package/ecagent/dist/index.d.ts.map +0 -1
- package/ecagent/dist/index.js.map +0 -1
- package/ecagent/dist/node.d.ts.map +0 -1
- package/ecagent/dist/node.js.map +0 -1
- package/ecagent/dist/proxy.d.ts.map +0 -1
- package/ecagent/dist/proxy.js.map +0 -1
- package/ecagent/dist/runtime/api/lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/lazy.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +0 -1
- package/ecagent/dist/runtime/auth/context.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/context.js.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.js.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.js.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.js.map +0 -1
- package/ecagent/dist/runtime/auth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/types.js.map +0 -1
- package/ecagent/dist/runtime/compat.d.ts.map +0 -1
- package/ecagent/dist/runtime/compat.js.map +0 -1
- package/ecagent/dist/runtime/index.d.ts.map +0 -1
- package/ecagent/dist/runtime/index.js.map +0 -1
- package/ecagent/dist/runtime/models.d.ts.map +0 -1
- package/ecagent/dist/runtime/models.js.map +0 -1
- package/ecagent/dist/runtime/oauth.d.ts.map +0 -1
- package/ecagent/dist/runtime/oauth.js.map +0 -1
- package/ecagent/dist/runtime/providers/faux.d.ts.map +0 -1
- package/ecagent/dist/runtime/providers/faux.js.map +0 -1
- package/ecagent/dist/runtime/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.js.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.js.map +0 -1
- package/ecagent/dist/runtime/utils/headers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/headers.js.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.js.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.js.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.js.map +0 -1
- package/ecagent/dist/runtime/utils/retry.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/retry.js.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.js.map +0 -1
- package/ecagent/dist/runtime/utils/validation.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/validation.js.map +0 -1
- package/ecagent/dist/types.d.ts.map +0 -1
- package/ecagent/dist/types.js.map +0 -1
- package/ecagent/package.json +0 -93
- package/ecagent/src/agent-loop.ts +0 -792
- package/ecagent/src/agent.ts +0 -575
- package/ecagent/src/harness/agent-harness.ts +0 -1029
- package/ecagent/src/harness/compaction/branch-summarization.ts +0 -261
- package/ecagent/src/harness/compaction/compaction.ts +0 -753
- package/ecagent/src/harness/compaction/utils.ts +0 -144
- package/ecagent/src/harness/env/nodejs.ts +0 -569
- package/ecagent/src/harness/messages.ts +0 -164
- package/ecagent/src/harness/prompt-templates.ts +0 -267
- package/ecagent/src/harness/session/jsonl-repo.ts +0 -179
- package/ecagent/src/harness/session/jsonl-storage.ts +0 -314
- package/ecagent/src/harness/session/memory-repo.ts +0 -50
- package/ecagent/src/harness/session/memory-storage.ts +0 -133
- package/ecagent/src/harness/session/repo-utils.ts +0 -51
- package/ecagent/src/harness/session/session.ts +0 -338
- package/ecagent/src/harness/session/uuid.ts +0 -54
- package/ecagent/src/harness/skills.ts +0 -375
- package/ecagent/src/harness/system-prompt.ts +0 -34
- package/ecagent/src/harness/types.ts +0 -838
- package/ecagent/src/harness/utils/shell-output.ts +0 -135
- package/ecagent/src/harness/utils/truncate.ts +0 -344
- package/ecagent/src/index.ts +0 -46
- package/ecagent/src/node.ts +0 -2
- package/ecagent/src/proxy.ts +0 -367
- package/ecagent/src/runtime/api/lazy.ts +0 -70
- package/ecagent/src/runtime/api/pi-messages.lazy.ts +0 -4
- package/ecagent/src/runtime/api/pi-messages.ts +0 -436
- package/ecagent/src/runtime/auth/context.ts +0 -45
- package/ecagent/src/runtime/auth/credential-store.ts +0 -47
- package/ecagent/src/runtime/auth/helpers.ts +0 -46
- package/ecagent/src/runtime/auth/resolve.ts +0 -141
- package/ecagent/src/runtime/auth/types.ts +0 -182
- package/ecagent/src/runtime/compat.ts +0 -158
- package/ecagent/src/runtime/index.ts +0 -31
- package/ecagent/src/runtime/models.ts +0 -452
- package/ecagent/src/runtime/oauth.ts +0 -1
- package/ecagent/src/runtime/providers/faux.ts +0 -538
- package/ecagent/src/runtime/types.ts +0 -718
- package/ecagent/src/runtime/utils/diagnostics.ts +0 -45
- package/ecagent/src/runtime/utils/event-stream.ts +0 -88
- package/ecagent/src/runtime/utils/headers.ts +0 -18
- package/ecagent/src/runtime/utils/json-parse.ts +0 -124
- package/ecagent/src/runtime/utils/oauth/types.ts +0 -79
- package/ecagent/src/runtime/utils/overflow.ts +0 -165
- package/ecagent/src/runtime/utils/provider-env.ts +0 -52
- package/ecagent/src/runtime/utils/retry.ts +0 -101
- package/ecagent/src/runtime/utils/typebox-helpers.ts +0 -24
- package/ecagent/src/runtime/utils/validation.ts +0 -310
- package/ecagent/src/types.ts +0 -430
- package/ecagent/tsconfig.build.json +0 -32
package/dist/cli/init.js
CHANGED
|
@@ -6,11 +6,12 @@ import { resolvePaths, ensureDataDirs } from '../paths.js';
|
|
|
6
6
|
import { commandExists } from '../utils/cross-platform.js';
|
|
7
7
|
import { scanInstances } from '../utils/instance-registry.js';
|
|
8
8
|
import { saveDefaultsSafe, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from '../config-store.js';
|
|
9
|
-
import { generateControlAid,
|
|
9
|
+
import { generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
|
|
10
10
|
import { getCodexAppServerAvailability, isCodexAppServerAvailable } from '../agents/codex-runner.js';
|
|
11
11
|
import { resolveEcagentConfig } from '../agents/baseagent.js';
|
|
12
12
|
import { defaultProjectsRoot } from '../utils/project-path.js';
|
|
13
13
|
import { WEB_CLI_BIN, WEB_PACKAGE_LATEST } from '../product.js';
|
|
14
|
+
import { autostartInstalled, autostartPlatformLabel, configureAutostart } from '../utils/autostart.js';
|
|
14
15
|
// ==================== Helpers ====================
|
|
15
16
|
function ask(rl, question) {
|
|
16
17
|
return new Promise(resolve => rl.question(question, resolve));
|
|
@@ -66,6 +67,40 @@ function buildDefaults(chosen, available, projectsDefaultPath) {
|
|
|
66
67
|
function writeDefaults(chosen, available, projectsDefaultPath) {
|
|
67
68
|
saveDefaultsSafe(buildDefaults(chosen, available, projectsDefaultPath));
|
|
68
69
|
}
|
|
70
|
+
function hasCompletedInitConfig() {
|
|
71
|
+
const p = resolvePaths();
|
|
72
|
+
const daemon = loadDaemonConfig();
|
|
73
|
+
if (!daemon.aid || !Array.isArray(daemon.owners) || daemon.owners.length === 0)
|
|
74
|
+
return false;
|
|
75
|
+
try {
|
|
76
|
+
const defaults = JSON.parse(fs.readFileSync(p.defaultsConfig, 'utf8'));
|
|
77
|
+
return typeof defaults?.active_baseagent === 'string' && defaults.active_baseagent.trim().length > 0;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isAutostartOnlyRequest(options) {
|
|
84
|
+
return options?.autoStart !== undefined
|
|
85
|
+
&& !options.baseagent
|
|
86
|
+
&& !options.force
|
|
87
|
+
&& !options.owner
|
|
88
|
+
&& options.projectpath === undefined
|
|
89
|
+
&& options.ecweb === undefined
|
|
90
|
+
&& options.format === undefined;
|
|
91
|
+
}
|
|
92
|
+
function applyExplicitAutostart(enabled, runtimeRoot) {
|
|
93
|
+
const result = configureAutostart(enabled, runtimeRoot);
|
|
94
|
+
if (!result.ok) {
|
|
95
|
+
console.log(`❌ ${autostartPlatformLabel() || '登录自启'}配置失败: ${result.error || '未知错误'}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(enabled
|
|
99
|
+
? `✓ 已启用 ${autostartPlatformLabel() || '登录'}自启`
|
|
100
|
+
: `✓ 已禁用 ${autostartPlatformLabel() || '登录'}自启`);
|
|
101
|
+
}
|
|
102
|
+
return result.ok;
|
|
103
|
+
}
|
|
69
104
|
/** 启动门禁判定:缺控制 AID 且处于交互式终端时,应进 init 向导补全。
|
|
70
105
|
* 非 TTY(restart-monitor/systemd/管道)即使缺 aid 也不进 init(无法交互),由 daemon 侧 warn 兜底。 */
|
|
71
106
|
export function needsControlAidInit(aid, isTty) {
|
|
@@ -128,14 +163,29 @@ export async function cmdInit(options) {
|
|
|
128
163
|
ecweb: options.ecweb,
|
|
129
164
|
force: options.force,
|
|
130
165
|
format: options.format,
|
|
166
|
+
autoStart: options.autoStart,
|
|
131
167
|
});
|
|
132
168
|
return true;
|
|
133
169
|
}
|
|
170
|
+
if (options?.autoStart === true && !autostartPlatformLabel()) {
|
|
171
|
+
console.log('❌ --auto-start 仅支持 Windows 和 macOS 主机');
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
134
174
|
const p = resolvePaths();
|
|
135
175
|
ensureDataDirs();
|
|
176
|
+
// A bound installation may toggle login autostart independently of the
|
|
177
|
+
// Baseagent setup wizard. This is also the path used by public installers.
|
|
178
|
+
if (isAutostartOnlyRequest(options) && hasCompletedInitConfig()) {
|
|
179
|
+
return applyExplicitAutostart(options.autoStart, p.root);
|
|
180
|
+
}
|
|
136
181
|
// ── 1. 单进程互斥 ──
|
|
137
182
|
const aliveMains = scanInstances().mains.filter(m => m.alive);
|
|
138
183
|
if (aliveMains.length > 0) {
|
|
184
|
+
// Explicit autostart flags only change the login task; they do not need
|
|
185
|
+
// to rewrite init configuration or stop an already running daemon.
|
|
186
|
+
if (isAutostartOnlyRequest(options)) {
|
|
187
|
+
return applyExplicitAutostart(options.autoStart, p.root);
|
|
188
|
+
}
|
|
139
189
|
const pids = aliveMains.map(m => m.record.pid).join(', ');
|
|
140
190
|
console.log(`❌ EvolCore 正在运行 (PID: ${pids}),请先执行 ec stop`);
|
|
141
191
|
return false;
|
|
@@ -207,7 +257,11 @@ export async function cmdInit(options) {
|
|
|
207
257
|
await runInteractive();
|
|
208
258
|
}
|
|
209
259
|
// ── 共享 tail(单一出口):提示创建 agent + 生成控制 AID ──
|
|
210
|
-
return initTail({
|
|
260
|
+
return initTail({
|
|
261
|
+
invokedByStart: options?.invokedByStart,
|
|
262
|
+
nonInteractive: options?.nonInteractive,
|
|
263
|
+
autoStart: options?.autoStart,
|
|
264
|
+
});
|
|
211
265
|
// ── 内部函数 ──
|
|
212
266
|
async function runInteractive() {
|
|
213
267
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -313,38 +367,35 @@ export async function initTail(options = {}) {
|
|
|
313
367
|
const { agents } = loadAllAgents();
|
|
314
368
|
if (agents.length === 0 && !options.invokedByStart) {
|
|
315
369
|
console.log('\n提示:尚无 agent,运行以下命令创建:');
|
|
316
|
-
console.log(' ec agent new <aid>.
|
|
370
|
+
console.log(' ec agent new <aid>.example.com');
|
|
317
371
|
}
|
|
318
372
|
// 控制 AID:daemon 进程身份。缺失则生成并写回 daemon.json(幂等:已存在则跳过)。
|
|
319
373
|
const daemonConfig = loadDaemonConfig();
|
|
320
374
|
let controlAidReady = !!daemonConfig.aid;
|
|
375
|
+
let autoStartReady = true;
|
|
321
376
|
if (daemonConfig.aid) {
|
|
322
|
-
const targetIssuer = resolveControlIssuer();
|
|
323
|
-
const currentIssuer = daemonConfig.aid.split('.').slice(1).join('.');
|
|
324
|
-
if (currentIssuer !== targetIssuer) {
|
|
325
|
-
console.log(`⚠️ 控制 AID issuer (${currentIssuer}) 与目标 issuer (${targetIssuer}) 不一致`);
|
|
326
|
-
console.log(` 如需切换,请删除 daemon.json 中的 aid 字段后重新运行 init`);
|
|
327
|
-
}
|
|
328
377
|
console.log(`✓ 控制 AID 已存在: ${daemonConfig.aid}`);
|
|
329
378
|
}
|
|
330
379
|
else {
|
|
331
380
|
try {
|
|
332
|
-
const
|
|
381
|
+
const aidDomain = resolveControlAidDomain(daemonConfig.aun?.defaultAidDomain);
|
|
382
|
+
const { aid } = await generateControlAid(aidDomain);
|
|
333
383
|
saveDaemonConfig({ ...daemonConfig, $schema_version: daemonConfig.$schema_version ?? 1, aid });
|
|
334
384
|
controlAidReady = true;
|
|
335
385
|
console.log(`✓ 已生成控制 AID: ${aid}`);
|
|
336
386
|
}
|
|
337
387
|
catch (e) {
|
|
338
|
-
console.error(`⚠️ 控制 AID
|
|
388
|
+
console.error(`⚠️ 控制 AID 生成失败(请检查 AID domain 配置或 Gateway 连通性): ${e?.message || e}`);
|
|
339
389
|
controlAidReady = false;
|
|
340
390
|
}
|
|
341
391
|
}
|
|
342
392
|
// 交互式询问:使用单一 readline 实例避免 stdin 状态混乱
|
|
343
|
-
if (process.stdin.isTTY) {
|
|
393
|
+
if (!options.nonInteractive && process.stdin.isTTY) {
|
|
344
394
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
345
395
|
try {
|
|
346
396
|
await handleOwnersPrompt(rl);
|
|
347
397
|
await handleEcwebPrompt(rl);
|
|
398
|
+
await handleAutostartPrompt(rl);
|
|
348
399
|
}
|
|
349
400
|
finally {
|
|
350
401
|
try {
|
|
@@ -353,6 +404,38 @@ export async function initTail(options = {}) {
|
|
|
353
404
|
catch { /* ignore */ }
|
|
354
405
|
}
|
|
355
406
|
}
|
|
407
|
+
else if (options.autoStart !== undefined) {
|
|
408
|
+
autoStartReady = applyAutostart(options.autoStart);
|
|
409
|
+
}
|
|
410
|
+
async function handleAutostartPrompt(rl) {
|
|
411
|
+
if (options.autoStart !== undefined) {
|
|
412
|
+
autoStartReady = applyAutostart(options.autoStart);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (!autostartPlatformLabel())
|
|
416
|
+
return;
|
|
417
|
+
if (autostartInstalled()) {
|
|
418
|
+
console.log(`✓ ${autostartPlatformLabel()} 登录自启已启用`);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const platform = autostartPlatformLabel();
|
|
422
|
+
const answer = (await ask(rl, `\n是否启用 ${platform} 登录自启?[y/N] `)).trim().toLowerCase();
|
|
423
|
+
if (answer === 'y' || answer === 'yes')
|
|
424
|
+
autoStartReady = applyAutostart(true);
|
|
425
|
+
else
|
|
426
|
+
console.log(` 已跳过 ${platform} 登录自启(可日后重新运行 ec init 开启)`);
|
|
427
|
+
}
|
|
428
|
+
function applyAutostart(enabled) {
|
|
429
|
+
const result = configureAutostart(enabled, resolvePaths().root);
|
|
430
|
+
if (!result.ok) {
|
|
431
|
+
console.log(` ❌ ${autostartPlatformLabel() || '登录自启'}配置失败: ${result.error || '未知错误'}`);
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
console.log(enabled
|
|
435
|
+
? ` ✓ 已启用 ${autostartPlatformLabel() || '登录'}自启`
|
|
436
|
+
: ` ✓ 已禁用 ${autostartPlatformLabel() || '登录'}自启`);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
356
439
|
async function handleOwnersPrompt(rl) {
|
|
357
440
|
const daemonConfigForOwners = loadDaemonConfig();
|
|
358
441
|
if (daemonConfigForOwners.aid && (!daemonConfigForOwners.owners || daemonConfigForOwners.owners.length === 0)) {
|
|
@@ -432,11 +515,13 @@ export async function initTail(options = {}) {
|
|
|
432
515
|
}
|
|
433
516
|
// ec start 会接着启动 daemon,并在其 ready 后给出可用的 Agent 创建入口。
|
|
434
517
|
if (options.invokedByStart)
|
|
435
|
-
return controlAidReady;
|
|
518
|
+
return controlAidReady && autoStartReady;
|
|
436
519
|
if (!controlAidReady) {
|
|
437
520
|
console.error('\n❌ EvolCore 初始化未完成:控制 AID 未配置。联网后重新运行 ec init。');
|
|
438
521
|
return false;
|
|
439
522
|
}
|
|
523
|
+
if (!autoStartReady)
|
|
524
|
+
return false;
|
|
440
525
|
// 初始化完成总结
|
|
441
526
|
console.log('\n✓ EvolCore 初始化完成');
|
|
442
527
|
const finalCfg = loadDaemonConfig();
|
|
@@ -446,7 +531,7 @@ export async function initTail(options = {}) {
|
|
|
446
531
|
const { agents: finalAgents } = loadAllAgents();
|
|
447
532
|
if (finalAgents.length === 0) {
|
|
448
533
|
console.log('\n📌 下一步:创建 agent');
|
|
449
|
-
console.log(' ec agent new <your-aid>.
|
|
534
|
+
console.log(' ec agent new <your-aid>.example.com');
|
|
450
535
|
console.log(' ec init feishu # 绑定飞书');
|
|
451
536
|
console.log(' ec start # 启动服务');
|
|
452
537
|
}
|
|
@@ -530,6 +615,9 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
530
615
|
if (format !== undefined && format !== 'json') {
|
|
531
616
|
fail('INVALID_FORMAT', `--format only supports json: ${format}`, EXIT_USAGE, format);
|
|
532
617
|
}
|
|
618
|
+
if (opts.autoStart === true && !autostartPlatformLabel()) {
|
|
619
|
+
fail('AUTOSTART_UNSUPPORTED', '--auto-start is supported only on Windows and macOS hosts', EXIT_USAGE, format);
|
|
620
|
+
}
|
|
533
621
|
// ── 1. owner 校验 ──
|
|
534
622
|
if (!opts.owner) {
|
|
535
623
|
fail('MISSING_OWNER', '--owner is required in non-interactive mode', EXIT_USAGE, format);
|
|
@@ -632,11 +720,12 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
632
720
|
let controlAid = existingCfg.aid;
|
|
633
721
|
if (!controlAid) {
|
|
634
722
|
try {
|
|
635
|
-
const
|
|
723
|
+
const aidDomain = resolveControlAidDomain(existingCfg.aun?.defaultAidDomain);
|
|
724
|
+
const { aid } = await generateControlAid(aidDomain);
|
|
636
725
|
controlAid = aid;
|
|
637
726
|
}
|
|
638
727
|
catch (e) {
|
|
639
|
-
fail('CONTROL_AID_CREATE_FAILED', `
|
|
728
|
+
fail('CONTROL_AID_CREATE_FAILED', `control AID creation failed: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
640
729
|
}
|
|
641
730
|
}
|
|
642
731
|
// ── 9. 写 daemon.json(aid + owners + ecweb)──
|
|
@@ -653,6 +742,12 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
653
742
|
catch (e) {
|
|
654
743
|
fail('IO_ERROR', `failed to write daemon.json: ${e?.message || e}`, EXIT_RUNTIME, format);
|
|
655
744
|
}
|
|
745
|
+
if (opts.autoStart !== undefined) {
|
|
746
|
+
const autostart = configureAutostart(opts.autoStart, p.root);
|
|
747
|
+
if (!autostart.ok) {
|
|
748
|
+
fail('AUTOSTART_CONFIG_FAILED', autostart.error || 'failed to configure login autostart', EXIT_RUNTIME, format);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
656
751
|
// ── 10. 输出 init.result ──
|
|
657
752
|
const result = {
|
|
658
753
|
type: 'init.result',
|
|
@@ -660,7 +755,7 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
660
755
|
controlAid: controlAid,
|
|
661
756
|
ownerAid,
|
|
662
757
|
owners: [ownerAid],
|
|
663
|
-
ecwebEnabled: opts.ecweb === true,
|
|
758
|
+
ecwebEnabled: opts.ecweb === true || existingCfg.ecweb?.enabled === true,
|
|
664
759
|
baseagent: chosenBaseagent,
|
|
665
760
|
projectsDefaultPath: projectsDefaultPath ?? null,
|
|
666
761
|
defaultsPath: p.defaultsConfig,
|
package/dist/cli/model.js
CHANGED
|
@@ -205,7 +205,7 @@ function modelScopeFromSource(source) {
|
|
|
205
205
|
return undefined;
|
|
206
206
|
}
|
|
207
207
|
function resolveModelConfig(sel, baseagent) {
|
|
208
|
-
const effortKey =
|
|
208
|
+
const effortKey = 'effort';
|
|
209
209
|
const model = resolveEffectiveFieldWithSource(`baseagents.${baseagent}.model`, sel, { cache: true });
|
|
210
210
|
const effort = resolveEffectiveFieldWithSource(`baseagents.${baseagent}.${effortKey}`, sel, { cache: true });
|
|
211
211
|
const modelDecision = sel.role
|
|
@@ -448,12 +448,12 @@ async function cmdUse(args, formatJson) {
|
|
|
448
448
|
const effortVal = effort === 'auto' ? null : (effort ?? undefined);
|
|
449
449
|
if (isManagedTargetedWriteEnv(args)) {
|
|
450
450
|
if (effortVal !== undefined) {
|
|
451
|
-
const effortKey =
|
|
451
|
+
const effortKey = 'effort';
|
|
452
452
|
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.${effortKey}`, effortVal, formatJson);
|
|
453
453
|
}
|
|
454
454
|
await setManagedModelField(sel, `baseagents.${ba}.model`, modelId, formatJson);
|
|
455
455
|
if (effortVal !== undefined) {
|
|
456
|
-
const effortKey =
|
|
456
|
+
const effortKey = 'effort';
|
|
457
457
|
await setManagedModelField(sel, `baseagents.${ba}.${effortKey}`, effortVal, formatJson);
|
|
458
458
|
}
|
|
459
459
|
describeWrite(scope, sel, modelId, effort ?? null, formatJson);
|
|
@@ -490,7 +490,7 @@ async function cmdEffort(args, formatJson) {
|
|
|
490
490
|
const ba = activeBaseagent(sel.self);
|
|
491
491
|
const val = level === 'auto' ? null : level;
|
|
492
492
|
if (isManagedTargetedWriteEnv(args)) {
|
|
493
|
-
const effortKey =
|
|
493
|
+
const effortKey = 'effort';
|
|
494
494
|
preflightManagedFieldOverride(sel, explicitOrDerivedRole(args, sel), `baseagents.${ba}.${effortKey}`, val, formatJson);
|
|
495
495
|
await setManagedModelField(sel, `baseagents.${ba}.${effortKey}`, val, formatJson);
|
|
496
496
|
describeWrite(scope, sel, null, level, formatJson);
|
|
@@ -520,7 +520,7 @@ async function cmdReset(args, formatJson) {
|
|
|
520
520
|
const scope = determineWriteScope(sel, formatJson);
|
|
521
521
|
const ba = activeBaseagent(sel.self);
|
|
522
522
|
if (isManagedTargetedWriteEnv(args)) {
|
|
523
|
-
const effortKey =
|
|
523
|
+
const effortKey = 'effort';
|
|
524
524
|
const role = explicitOrDerivedRole(args, sel);
|
|
525
525
|
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.model`, null, formatJson);
|
|
526
526
|
preflightManagedFieldOverride(sel, role, `baseagents.${ba}.${effortKey}`, null, formatJson);
|
|
@@ -93,6 +93,37 @@ export async function cmdRestartMonitor() {
|
|
|
93
93
|
await sleep(500);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
// A stale instance record can disappear while the real Windows process is
|
|
97
|
+
// still alive. Refuse to create a second daemon when an unregistered process
|
|
98
|
+
// from this package is found; a duplicate would connect AUN and kick the
|
|
99
|
+
// existing session before failing on IPC/port ownership.
|
|
100
|
+
const runtimeOrphans = findOrphanProcesses().filter(o => {
|
|
101
|
+
if (o.confirmedTestDaemon)
|
|
102
|
+
return false;
|
|
103
|
+
const homeMatches = o.evolcoreHome && normalizePath(o.evolcoreHome) === normalizePath(p.root);
|
|
104
|
+
const packageMatches = !o.evolcoreHome && normalizePath(o.cmdline).includes(normalizePath(getPackageRoot()));
|
|
105
|
+
return Boolean(homeMatches || packageMatches);
|
|
106
|
+
});
|
|
107
|
+
if (runtimeOrphans.length > 0) {
|
|
108
|
+
const pids = runtimeOrphans.map(o => o.pid).join(', ');
|
|
109
|
+
log(`Stopping unregistered EvolCore process(es): ${pids}`);
|
|
110
|
+
for (const orphan of runtimeOrphans) {
|
|
111
|
+
platform.killProcess(orphan.pid, false);
|
|
112
|
+
}
|
|
113
|
+
const exited = await Promise.all(runtimeOrphans.map(async (orphan) => {
|
|
114
|
+
if (await platform.waitForProcessExit(orphan.pid, 10_000))
|
|
115
|
+
return true;
|
|
116
|
+
platform.killProcess(orphan.pid, true);
|
|
117
|
+
return platform.waitForProcessExit(orphan.pid, 5_000);
|
|
118
|
+
}));
|
|
119
|
+
if (exited.some(result => !result)) {
|
|
120
|
+
const message = `未登记的 EvolCore 进程仍未退出(PID: ${pids}),已停止重启以避免重复连接 AUN。`;
|
|
121
|
+
log(message);
|
|
122
|
+
await notifyDaemonOwners(p, `❌ ${message}`, log);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
cleanupInstances();
|
|
126
|
+
}
|
|
96
127
|
// restart-pending.json 只留给新主进程发送发起会话内的“重启成功”回执。
|
|
97
128
|
const pendingFile = path.join(daemonControlDir(), 'restart-pending.json');
|
|
98
129
|
// 等待所有活 main 进程退出(可能不止一个)
|
|
@@ -108,24 +139,24 @@ export async function cmdRestartMonitor() {
|
|
|
108
139
|
}
|
|
109
140
|
catch { }
|
|
110
141
|
}
|
|
111
|
-
await Promise.all(oldPids.map(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
142
|
+
const exited = await Promise.all(oldPids.map(async (oldPid) => {
|
|
143
|
+
if (await platform.waitForProcessExit(oldPid, 30_000)) {
|
|
144
|
+
log(`Process ${oldPid} has exited`);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
log(`ERROR: Process ${oldPid} still running after 30s, force killing`);
|
|
148
|
+
platform.killProcess(oldPid, true);
|
|
149
|
+
const forced = await platform.waitForProcessExit(oldPid, 5_000);
|
|
150
|
+
if (!forced)
|
|
151
|
+
log(`ERROR: Process ${oldPid} survived forced termination`);
|
|
152
|
+
return forced;
|
|
153
|
+
}));
|
|
154
|
+
if (exited.some(result => !result)) {
|
|
155
|
+
log('❌ Existing daemon process could not be stopped; refusing to spawn a replacement');
|
|
156
|
+
await notifyDaemonOwners(p, '❌ 旧 EvolCore 进程未能退出,已停止重启,避免重复连接 AUN。', log);
|
|
157
|
+
cleanupPendingFile(pendingFile, log);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
129
160
|
await sleep(3000);
|
|
130
161
|
cleanupInstances();
|
|
131
162
|
}
|
|
@@ -206,10 +237,25 @@ export async function cmdRestartMonitor() {
|
|
|
206
237
|
cleanupPendingFile(pendingFile, log);
|
|
207
238
|
process.exit(1);
|
|
208
239
|
}
|
|
240
|
+
if (hasStartupResourceConflict(p)) {
|
|
241
|
+
const message = '服务启动失败:IPC 管道或端口仍被占用,已跳过自动修复,避免重复连接 AUN。';
|
|
242
|
+
log(message);
|
|
243
|
+
await notifyDaemonOwners(p, `❌ ${message}`, log);
|
|
244
|
+
cleanupPendingFile(pendingFile, log);
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
209
247
|
// 启动失败,进入 self-heal 循环
|
|
210
248
|
log('❌ Service failed to start, entering self-heal loop');
|
|
211
249
|
eventBus.publish({ type: 'self-heal:started', reason: 'Service failed to start after restart' });
|
|
212
250
|
await notifyDaemonOwners(p, '⚠️ 服务启动失败,正在尝试自动修复...', log);
|
|
251
|
+
const claudePath = platform.resolveCommandPath('claude');
|
|
252
|
+
if (!claudePath) {
|
|
253
|
+
const message = '找不到 claude CLI,已停止自动修复;请检查后台进程 PATH。';
|
|
254
|
+
log(message);
|
|
255
|
+
await notifyDaemonOwners(p, `❌ ${message}`, log);
|
|
256
|
+
cleanupPendingFile(pendingFile, log);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
213
259
|
for (let attempt = 1; attempt <= MAX_HEAL_ATTEMPTS; attempt++) {
|
|
214
260
|
// 前置检查:服务可能已被上一轮 claude 修复并启动
|
|
215
261
|
if (isServiceAlive()) {
|
|
@@ -223,7 +269,7 @@ export async function cmdRestartMonitor() {
|
|
|
223
269
|
log(`Self-heal attempt ${attempt}/${MAX_HEAL_ATTEMPTS}`);
|
|
224
270
|
eventBus.publish({ type: 'self-heal:attempt', attemptNumber: attempt, maxAttempts: MAX_HEAL_ATTEMPTS });
|
|
225
271
|
await notifyDaemonOwners(p, `🔧 自动修复中(第 ${attempt}/${MAX_HEAL_ATTEMPTS} 次)...`, log);
|
|
226
|
-
const healed = await invokeClaude(p, attempt, MAX_HEAL_ATTEMPTS, HEAL_TIMEOUT, log);
|
|
272
|
+
const healed = await invokeClaude(claudePath, p, attempt, MAX_HEAL_ATTEMPTS, HEAL_TIMEOUT, log);
|
|
227
273
|
// 后置检查:不管 invokeClaude 返回什么,都检查服务实际状态
|
|
228
274
|
if (isServiceAlive()) {
|
|
229
275
|
log(`✓ Service is running after attempt ${attempt}`);
|
|
@@ -290,6 +336,30 @@ async function sendHealSummary(p, attempts, log) {
|
|
|
290
336
|
function sleep(ms) {
|
|
291
337
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
292
338
|
}
|
|
339
|
+
function normalizePath(value) {
|
|
340
|
+
return value.replace(/[\\/]+/g, '/').toLowerCase();
|
|
341
|
+
}
|
|
342
|
+
function hasStartupResourceConflict(p) {
|
|
343
|
+
let daemonLog = null;
|
|
344
|
+
try {
|
|
345
|
+
daemonLog = fs.readdirSync(p.logs, { withFileTypes: true })
|
|
346
|
+
.filter(entry => entry.isFile() && /^daemon-.*\.log$/.test(entry.name))
|
|
347
|
+
.sort((a, b) => b.name.localeCompare(a.name))
|
|
348
|
+
.slice(0, 1)
|
|
349
|
+
.map(entry => path.join(p.logs, entry.name))[0] ?? null;
|
|
350
|
+
}
|
|
351
|
+
catch { }
|
|
352
|
+
const files = [path.join(p.logs, 'stdout.log'), ...(daemonLog ? [daemonLog] : [])];
|
|
353
|
+
return files.some(file => {
|
|
354
|
+
try {
|
|
355
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
356
|
+
return /EADDRINUSE|address already in use|pipe-.*already in use/i.test(content.slice(-64 * 1024));
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
293
363
|
function cleanupPendingFile(filePath, log) {
|
|
294
364
|
try {
|
|
295
365
|
if (fs.existsSync(filePath)) {
|
|
@@ -353,9 +423,17 @@ async function spawnAndWaitReady(p, log, timeout) {
|
|
|
353
423
|
}
|
|
354
424
|
}
|
|
355
425
|
log(`Ready signal not received within ${timeout / 1000}s`);
|
|
356
|
-
//
|
|
426
|
+
// A timeout is still a live-process race: do not let self-heal spawn a
|
|
427
|
+
// replacement while the timed-out daemon owns the IPC endpoint or a port.
|
|
357
428
|
if (platform.isProcessRunning(childPid)) {
|
|
358
429
|
platform.killProcess(childPid);
|
|
430
|
+
if (!await platform.waitForProcessExit(childPid, 5_000)) {
|
|
431
|
+
log(`Process ${childPid} survived graceful termination, forcing kill`);
|
|
432
|
+
platform.killProcess(childPid, true);
|
|
433
|
+
if (!await platform.waitForProcessExit(childPid, 5_000)) {
|
|
434
|
+
log(`ERROR: Process ${childPid} survived forced termination`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
359
437
|
}
|
|
360
438
|
cleanupInstances();
|
|
361
439
|
return false;
|
|
@@ -363,7 +441,7 @@ async function spawnAndWaitReady(p, log, timeout) {
|
|
|
363
441
|
/**
|
|
364
442
|
* 调用 claude CLI 进行自动修复
|
|
365
443
|
*/
|
|
366
|
-
async function invokeClaude(p, attempt, maxAttempts, timeout, log) {
|
|
444
|
+
async function invokeClaude(claudePath, p, attempt, maxAttempts, timeout, log) {
|
|
367
445
|
const projectDir = getPackageRoot();
|
|
368
446
|
const selfHealLog = p.selfHealLog;
|
|
369
447
|
const stdoutLog = path.join(p.logs, 'stdout.log');
|
|
@@ -401,7 +479,7 @@ async function invokeClaude(p, attempt, maxAttempts, timeout, log) {
|
|
|
401
479
|
注意:只修复导致启动失败的问题,不要做额外的重构或优化。`;
|
|
402
480
|
try {
|
|
403
481
|
log(`Invoking claude CLI (attempt ${attempt}, timeout ${timeout / 60000}min)...`);
|
|
404
|
-
const { stdout, stderr } = await execFileAsync(
|
|
482
|
+
const { stdout, stderr } = await execFileAsync(claudePath, [
|
|
405
483
|
'-p', prompt,
|
|
406
484
|
'--allowedTools', 'Read,Write,Edit,Bash,Glob,Grep',
|
|
407
485
|
'--output-format', 'text',
|
|
@@ -409,6 +487,8 @@ async function invokeClaude(p, attempt, maxAttempts, timeout, log) {
|
|
|
409
487
|
], {
|
|
410
488
|
cwd: projectDir,
|
|
411
489
|
timeout,
|
|
490
|
+
// Windows npm CLIs are .cmd shims; execFile needs a shell to run them.
|
|
491
|
+
shell: platform.isWindows,
|
|
412
492
|
env: { ...process.env, CLAUDE_CODE_ENTRYPOINT: 'cli' },
|
|
413
493
|
maxBuffer: 10 * 1024 * 1024,
|
|
414
494
|
});
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { kitsRoleTemplatesDir } from '../paths.js';
|
|
3
3
|
import { createErrorCapturingReader, fileCache } from '../core/daemon-file-cache.js';
|
|
4
|
-
import { validateRoleConfig } from './role-schema.js';
|
|
4
|
+
import { normalizeRoleEffortCompat, validateRoleConfig } from './role-schema.js';
|
|
5
5
|
import { expectedRoleRank } from './role-ranks.js';
|
|
6
6
|
export const BUILTIN_ROLE_IDS = ['owner', 'admin', 'member', 'visitor'];
|
|
7
7
|
export function validateBuiltinRoleTemplateDefinition(roleId, raw) {
|
|
8
|
-
const
|
|
8
|
+
const normalizedRaw = normalizeRoleEffortCompat(raw);
|
|
9
|
+
const issues = validateRoleConfig(normalizedRaw);
|
|
9
10
|
if (issues.length) {
|
|
10
11
|
return {
|
|
11
12
|
definition: null,
|
|
12
13
|
error: `built-in role template failed validation: ${issues.map(issue => `${issue.field} ${issue.message}`).join('; ')}`,
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
|
-
const { $schema_version: _schemaVersion, ...definition } =
|
|
16
|
+
const { $schema_version: _schemaVersion, ...definition } = normalizedRaw;
|
|
16
17
|
if (BUILTIN_ROLE_IDS.includes(roleId)) {
|
|
17
18
|
const expectedRank = expectedRoleRank(roleId);
|
|
18
19
|
if (definition.rank !== expectedRank) {
|
|
@@ -75,7 +75,7 @@ export function resolveConfigFieldRule(fieldPath) {
|
|
|
75
75
|
const [, baseagent, leaf] = parts;
|
|
76
76
|
if (!SUPPORTED_BASEAGENTS.has(baseagent))
|
|
77
77
|
return { class: 'unknown' };
|
|
78
|
-
const permissionKey = `baseagents.${baseagent}.${leaf}`;
|
|
78
|
+
const permissionKey = `baseagents.${baseagent}.${leaf === 'reasoning' ? 'effort' : leaf}`;
|
|
79
79
|
if (leaf === 'model' && parts.length === 3)
|
|
80
80
|
return scalar(permissionKey, 'string');
|
|
81
81
|
if ((leaf === 'effort' || leaf === 'reasoning') && parts.length === 3)
|
|
@@ -178,7 +178,11 @@ export function resolveRoleFieldPermission(permissions, fieldPath) {
|
|
|
178
178
|
const rule = resolveConfigFieldRule(fieldPath);
|
|
179
179
|
if (!rule.rolePermissionKey)
|
|
180
180
|
return undefined;
|
|
181
|
-
return permissions[fieldPath]
|
|
181
|
+
return permissions[fieldPath]
|
|
182
|
+
?? permissions[rule.rolePermissionKey]
|
|
183
|
+
?? (rule.rolePermissionKey === 'baseagents.codex.effort'
|
|
184
|
+
? permissions['baseagents.codex.reasoning']
|
|
185
|
+
: undefined);
|
|
182
186
|
}
|
|
183
187
|
/**
|
|
184
188
|
* Map relation-scoped config fields back to their public command capability.
|