evolcore 0.0.23 → 0.0.24
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 +50 -0
- package/README.md +3 -1
- package/bin/codex-managed-acl.ps1 +7 -2
- package/bin/codex-managed-hook.mjs +127 -10
- package/bin/ec-safe-output.js +85 -3
- package/bin/install-codex-managed-hooks.mjs +17 -6
- package/dist/agents/baseagent-availability.js +4 -4
- package/dist/agents/baseagent.js +29 -1
- package/dist/agents/claude-runner.js +148 -13
- package/dist/agents/codex/app-server-client.js +18 -8
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +215 -0
- package/dist/agents/codex-runner.js +438 -59
- package/dist/agents/ecagent-runner.js +17 -3
- package/dist/agents/gemini-runner.js +60 -2
- package/dist/agents/runner-types.js +1 -1
- package/dist/aun/aid/managed-operation.js +28 -6
- package/dist/aun/aid/store.js +41 -0
- package/dist/aun/msg/managed-operation.js +6 -1
- package/dist/aun/outbox.js +56 -18
- package/dist/aun/rpc/client.js +4 -5
- package/dist/channels/aun.js +147 -76
- package/dist/channels/daemon.js +7 -1
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +10 -4
- package/dist/channels/wecom.js +2 -1
- package/dist/cli/agent-command.js +29 -3
- package/dist/cli/agent-create.js +538 -0
- package/dist/cli/agent.js +26 -675
- package/dist/cli/aun-commands.js +60 -20
- package/dist/cli/ctl-command.js +2 -0
- package/dist/cli/daemon-commands.js +148 -17
- package/dist/cli/index.js +2 -2
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/restart-monitor.js +432 -8
- package/dist/cli/stats.js +110 -0
- package/dist/config/builtin-roles.js +2 -0
- package/dist/core/auth/auth-gateway.js +3 -2
- package/dist/core/auth/authorization-audit.js +72 -19
- package/dist/core/auth/operation-authorizer.js +63 -3
- package/dist/core/auth/operation-catalog.js +10 -2
- package/dist/core/auth/remote-access-store.js +3 -2
- package/dist/core/baseagent-loader.js +4 -4
- package/dist/core/bootstrap-messages.js +39 -18
- package/dist/core/bootstrap-service.js +32 -26
- package/dist/core/capability/capability-manager.js +8 -4
- package/dist/core/capability/providers/codex-capability-provider.js +1 -1
- package/dist/core/command/agent-control.js +7 -2
- package/dist/core/command/command-handler.js +87 -25
- package/dist/core/command/menu-catalog.js +3 -1
- package/dist/core/command/menu-handler.js +274 -70
- package/dist/core/command/menu-protocol.js +6 -2
- package/dist/core/command/slash-gate.js +1 -3
- package/dist/core/command/slash-handler.js +157 -48
- package/dist/core/data-migration.js +5 -15
- package/dist/core/event-catalog.js +3 -0
- package/dist/core/handoff/runtime.js +3 -1
- package/dist/core/handoff/store.js +7 -1
- package/dist/core/message/im-renderer.js +13 -6
- package/dist/core/message/message-bridge.js +5 -36
- package/dist/core/message/message-utils.js +6 -3
- package/dist/core/message/response-engine.js +73 -21
- package/dist/core/model/catalog-service.js +3 -1
- package/dist/core/model/model-catalog.js +10 -0
- package/dist/core/model/model-permission.js +4 -1
- package/dist/core/permission/approval-gateway.js +169 -33
- package/dist/core/permission/tool-policy.js +13 -6
- package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
- package/dist/core/session/session-manager.js +49 -13
- package/dist/core/session/session-renew.js +1 -0
- package/dist/index.js +174 -28
- package/dist/ipc.js +68 -21
- package/dist/paths.js +23 -1
- package/dist/stats/billing.js +18 -4
- package/dist/utils/atomic-write.js +26 -2
- package/dist/utils/cross-platform.js +436 -1
- package/dist/utils/error-utils.js +11 -4
- package/dist/utils/model-prices.jsonl +23 -20
- package/dist/utils/npm-ops.js +24 -1
- package/dist/utils/windows-autostart.js +1 -1
- package/kits/templates/roles/admin.json +2 -0
- package/package.json +7 -3
- package/AGENTS.md +0 -62
- package/dist/utils/codex-cli.js +0 -43
package/dist/cli/agent.js
CHANGED
|
@@ -1,32 +1,18 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import readline from 'readline';
|
|
4
3
|
import { resolvePaths, agentMdPath as getAgentMdPathFromPaths, aunPath as defaultAunPath } from '../paths.js';
|
|
5
|
-
import { loadDefaults, loadAllAgents, loadAgent, saveAgent, ensureAgentDirSkeleton
|
|
6
|
-
import {
|
|
4
|
+
import { loadDefaults, loadAllAgents, loadAgent, saveAgent, ensureAgentDirSkeleton } from '../config-store.js';
|
|
5
|
+
import { initConfigManager } from '../config/config-manager.js';
|
|
7
6
|
import { resolveConfigCommand } from '../config/resolved-config-op.js';
|
|
8
7
|
import { executeResolvedConfigCommand } from '../config/config-operation-service.js';
|
|
9
|
-
import { ipcQuery } from '../ipc.js';
|
|
8
|
+
import { ipcQuery, IpcTransportError } from '../ipc.js';
|
|
10
9
|
import { CONFIG_SCHEMA_VERSION } from '../types.js';
|
|
11
10
|
import { ensureInitialRoleRegistry } from '../config/role-service.js';
|
|
12
|
-
import { isValidChannelName } from '../core/channel-loader.js';
|
|
13
|
-
import { commandExists } from '../utils/cross-platform.js';
|
|
14
|
-
import { getCodexAppServerAvailability, isCodexAppServerAvailable } from '../agents/codex-runner.js';
|
|
15
|
-
import { resolveEcagentConfig } from '../agents/baseagent.js';
|
|
16
11
|
import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
|
|
12
|
+
import { isValidChannelName } from '../core/channel-loader.js';
|
|
17
13
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
18
14
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
19
|
-
|
|
20
|
-
import { DEFAULT_AGENT_DESCRIPTION } from '../aun/aid/agentmd.js';
|
|
21
|
-
function withStaticOwner(config, owner) {
|
|
22
|
-
const value = owner?.trim();
|
|
23
|
-
if (!value)
|
|
24
|
-
return config;
|
|
25
|
-
const owners = config.owners ?? [];
|
|
26
|
-
if (owners.includes(value))
|
|
27
|
-
return config;
|
|
28
|
-
return { ...config, owners: [...owners, value] };
|
|
29
|
-
}
|
|
15
|
+
export { agentCreateInteractive, agentCreateNonInteractive, parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan, validateAgentOwnerOptions, } from './agent-create.js';
|
|
30
16
|
/** Route agent lifecycle commands from a managed task through daemon IPC. */
|
|
31
17
|
export async function runManagedAgentOperation(argv) {
|
|
32
18
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
@@ -53,174 +39,32 @@ export async function runManagedAgentOperation(argv) {
|
|
|
53
39
|
return { ok: false, code: 'DAEMON_UNAVAILABLE', error: error instanceof Error ? error.message : String(error) };
|
|
54
40
|
}
|
|
55
41
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const AUTO_BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
59
|
-
function isBaseagentAvailable(baseagent) {
|
|
60
|
-
if (baseagent === 'codex')
|
|
61
|
-
return isCodexAppServerAvailable();
|
|
62
|
-
if (baseagent === 'ecagent')
|
|
63
|
-
return true;
|
|
64
|
-
return commandExists(baseagent);
|
|
65
|
-
}
|
|
66
|
-
function detectAvailableBaseagents() {
|
|
67
|
-
return BASEAGENT_CANDIDATES.filter(isBaseagentAvailable);
|
|
68
|
-
}
|
|
69
|
-
function pickDefaultBaseagent(available) {
|
|
70
|
-
return AUTO_BASEAGENT_CANDIDATES.find(candidate => available.includes(candidate)) ?? null;
|
|
71
|
-
}
|
|
72
|
-
function readProjectMetadata(project) {
|
|
73
|
-
try {
|
|
74
|
-
const packageJsonPath = path.join(project, 'package.json');
|
|
75
|
-
if (!fs.existsSync(packageJsonPath))
|
|
76
|
-
return {};
|
|
77
|
-
const parsed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
78
|
-
return {
|
|
79
|
-
name: typeof parsed.name === 'string' ? parsed.name.trim() : undefined,
|
|
80
|
-
description: typeof parsed.description === 'string' ? parsed.description.trim() : undefined,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
return {};
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function projectSlug(project) {
|
|
88
|
-
const basename = path.basename(project) || 'agent';
|
|
89
|
-
const slug = basename
|
|
90
|
-
.normalize('NFKD')
|
|
91
|
-
.replace(/[^a-zA-Z0-9-]+/g, '-')
|
|
92
|
-
.replace(/^-+|-+$/g, '')
|
|
93
|
-
.toLowerCase()
|
|
94
|
-
.slice(0, 63)
|
|
95
|
-
.replace(/-+$/g, '');
|
|
96
|
-
return slug || 'agent';
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Resolve non-interactive creation defaults without performing any network or
|
|
100
|
-
* filesystem mutation. The CLI uses this for both execution and --dry-run.
|
|
101
|
-
*/
|
|
102
|
-
export function resolveAgentCreatePlan(options) {
|
|
103
|
-
const aid = options.aid.trim();
|
|
104
|
-
const project = path.resolve(options.project || process.cwd());
|
|
105
|
-
const metadata = readProjectMetadata(project);
|
|
106
|
-
const defaults = loadDefaults();
|
|
107
|
-
const daemon = loadDaemonConfig();
|
|
108
|
-
const configuredBaseagent = defaults?.active_baseagent;
|
|
109
|
-
const available = detectAvailableBaseagents();
|
|
110
|
-
const defaultBaseagent = configuredBaseagent && available.includes(configuredBaseagent)
|
|
111
|
-
? configuredBaseagent
|
|
112
|
-
: pickDefaultBaseagent(available) ?? undefined;
|
|
113
|
-
const baseagent = options.baseagent || defaultBaseagent;
|
|
114
|
-
const baseagentSource = options.baseagent
|
|
115
|
-
? 'argument'
|
|
116
|
-
: configuredBaseagent && baseagent === configuredBaseagent
|
|
117
|
-
? 'defaults'
|
|
118
|
-
: 'detected';
|
|
119
|
-
const owner = options.owner?.trim() || daemon.owners?.[0];
|
|
120
|
-
const ownerSource = options.owner?.trim() ? 'argument' : owner ? 'daemon' : 'none';
|
|
121
|
-
const name = options.name?.trim() || metadata.name || projectSlug(project);
|
|
122
|
-
const description = options.description?.trim() || metadata.description || DEFAULT_AGENT_DESCRIPTION;
|
|
123
|
-
const configExists = isValidAid(aid)
|
|
124
|
-
&& fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
|
|
125
|
-
return {
|
|
126
|
-
aid,
|
|
127
|
-
project,
|
|
128
|
-
baseagent,
|
|
129
|
-
owner,
|
|
130
|
-
name,
|
|
131
|
-
description,
|
|
132
|
-
force: options.force === true,
|
|
133
|
-
configExists,
|
|
134
|
-
baseagentSource,
|
|
135
|
-
ownerSource,
|
|
136
|
-
nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
|
|
137
|
-
descriptionSource: options.description?.trim() ? 'argument' : metadata.description ? 'package' : 'default',
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
export function validateAgentCreatePlan(plan) {
|
|
141
|
-
if (!isValidAid(plan.aid)) {
|
|
142
|
-
return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`;
|
|
143
|
-
}
|
|
144
|
-
if (plan.configExists && !plan.force) {
|
|
145
|
-
return `Agent "${plan.aid}" already exists (use --force to overwrite)`;
|
|
146
|
-
}
|
|
147
|
-
if (!plan.baseagent) {
|
|
148
|
-
return 'No usable baseagent detected. Pass --baseagent or configure a baseagent in agents/defaults.json.';
|
|
149
|
-
}
|
|
150
|
-
if (!BASEAGENT_CANDIDATES.includes(plan.baseagent)) {
|
|
151
|
-
return `Invalid baseagent: ${plan.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`;
|
|
152
|
-
}
|
|
153
|
-
if (!isBaseagentAvailable(plan.baseagent)) {
|
|
154
|
-
return `${plan.baseagent} is not available in the current environment`;
|
|
155
|
-
}
|
|
156
|
-
if (plan.baseagent === 'ecagent') {
|
|
157
|
-
const reason = ecagentUnavailableReason();
|
|
158
|
-
if (reason)
|
|
159
|
-
return reason;
|
|
160
|
-
}
|
|
161
|
-
if (plan.owner && !isValidAid(plan.owner)) {
|
|
162
|
-
return `Invalid owner: ${plan.owner}`;
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
function ecagentUnavailableReason() {
|
|
167
|
-
try {
|
|
168
|
-
resolveEcagentConfig({ agents: { ecagent: {} } });
|
|
169
|
-
return undefined;
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
return error instanceof Error ? error.message : String(error);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
function buildBaseagentsBlock(chosen) {
|
|
176
|
-
return { [chosen]: {} };
|
|
42
|
+
function getAgentMdPath(aid) {
|
|
43
|
+
return getAgentMdPathFromPaths(aid);
|
|
177
44
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
* 写入新 agent 的初始配置(所有字段统一在 config.json)。
|
|
181
|
-
* mentionMode 不写初始值,继承 schema 出厂默认(disabled)。
|
|
182
|
-
*/
|
|
183
|
-
function saveInitialBehavior(aid, baseagent) {
|
|
184
|
-
const behavior = {
|
|
185
|
-
active_baseagent: baseagent,
|
|
186
|
-
baseagents: buildBaseagentsBlock(baseagent),
|
|
187
|
-
chatmode: { ...DEFAULT_CHATMODE },
|
|
188
|
-
};
|
|
189
|
-
const sel = { self: aid };
|
|
190
|
-
const existingBehavior = cfgRead(ConfigTarget.Agent, sel) || {};
|
|
191
|
-
cfgEnsure(ConfigTarget.Agent, sel);
|
|
192
|
-
cfgWrite(ConfigTarget.Agent, { ...existingBehavior, ...behavior }, sel);
|
|
45
|
+
function toPosix(value) {
|
|
46
|
+
return value ? value.replace(/\\/g, '/') : null;
|
|
193
47
|
}
|
|
194
48
|
function readAgentMdIdentity(aid) {
|
|
195
|
-
const
|
|
49
|
+
const file = getAgentMdPath(aid);
|
|
196
50
|
try {
|
|
197
|
-
if (!fs.existsSync(
|
|
51
|
+
if (!fs.existsSync(file))
|
|
198
52
|
return { name: null, description: null };
|
|
199
|
-
const content = fs.readFileSync(
|
|
200
|
-
const
|
|
201
|
-
if (!
|
|
53
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
54
|
+
const frontmatter = content.match(/^---\n([\s\S]*?)\n---/);
|
|
55
|
+
if (!frontmatter)
|
|
202
56
|
return { name: null, description: null };
|
|
203
|
-
const
|
|
204
|
-
const nameMatch = fm.match(/^name:\s*["']?(.+?)["']?\s*$/m);
|
|
205
|
-
const descMatch = fm.match(/^description:\s*["']?(.+?)["']?\s*$/m);
|
|
57
|
+
const body = frontmatter[1];
|
|
206
58
|
return {
|
|
207
|
-
name:
|
|
208
|
-
description:
|
|
59
|
+
name: body.match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1]?.trim() || null,
|
|
60
|
+
description: body.match(/^description:\s*["']?(.+?)["']?\s*$/m)?.[1]?.trim() || null,
|
|
209
61
|
};
|
|
210
62
|
}
|
|
211
63
|
catch {
|
|
212
64
|
return { name: null, description: null };
|
|
213
65
|
}
|
|
214
66
|
}
|
|
215
|
-
|
|
216
|
-
return getAgentMdPathFromPaths(aid);
|
|
217
|
-
}
|
|
218
|
-
/** Normalize path separators to forward slashes for cross-platform consistent display. */
|
|
219
|
-
function toPosix(p) {
|
|
220
|
-
if (!p)
|
|
221
|
-
return null;
|
|
222
|
-
return p.replace(/\\/g, '/');
|
|
223
|
-
}
|
|
67
|
+
// ==================== Helpers ====================
|
|
224
68
|
// ==================== agentList ====================
|
|
225
69
|
function toAgentListItem(info, stale = false) {
|
|
226
70
|
const storedStatus = info.status || 'unknown';
|
|
@@ -360,499 +204,6 @@ export async function agentShow(aid) {
|
|
|
360
204
|
...(stale ? { stale: true } : {}),
|
|
361
205
|
};
|
|
362
206
|
}
|
|
363
|
-
export async function agentCreateInteractive(opts = {}) {
|
|
364
|
-
const p = resolvePaths();
|
|
365
|
-
const ownRl = !opts.rl;
|
|
366
|
-
const rl = opts.rl ?? readline.createInterface({
|
|
367
|
-
input: opts.stdin || process.stdin,
|
|
368
|
-
output: opts.stdout || process.stdout,
|
|
369
|
-
});
|
|
370
|
-
const ask = (q) => new Promise(r => rl.question(q, r));
|
|
371
|
-
try {
|
|
372
|
-
const { isValidAid, aidCreate } = await import('../aun/aid/index.js');
|
|
373
|
-
const aidPrompt = opts.suggestedName
|
|
374
|
-
? `AID [${opts.suggestedName}]: `
|
|
375
|
-
: 'AID (e.g. mybot.agentid.pub): ';
|
|
376
|
-
let aid = '';
|
|
377
|
-
while (!aid) {
|
|
378
|
-
const aidInput = (await ask(aidPrompt)).trim();
|
|
379
|
-
const candidate = aidInput || opts.suggestedName;
|
|
380
|
-
if (!candidate) {
|
|
381
|
-
console.log(' ⚠ AID is required.');
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
if (!isValidAid(candidate)) {
|
|
385
|
-
console.log(` ⚠ Invalid AID "${candidate}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
aid = candidate;
|
|
389
|
-
}
|
|
390
|
-
const agentDirPath = path.join(p.agentsDir, aid);
|
|
391
|
-
const configExists = fs.existsSync(path.join(agentDirPath, 'config.json'));
|
|
392
|
-
if (configExists) {
|
|
393
|
-
const ans = (await ask(`Agent "${aid}" already exists. Overwrite config.json? (AID 与 agent.md 保留) [y/N]: `)).trim().toLowerCase();
|
|
394
|
-
if (ans !== 'y' && ans !== 'yes') {
|
|
395
|
-
return { ok: false, error: 'Aborted.' };
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
console.log(`\nCreating agent: ${aid}\n`);
|
|
399
|
-
let aidCreated = false;
|
|
400
|
-
try {
|
|
401
|
-
const result = await aidCreate(aid);
|
|
402
|
-
try {
|
|
403
|
-
await result.client.close();
|
|
404
|
-
}
|
|
405
|
-
catch { /* ignore */ }
|
|
406
|
-
aidCreated = !result.alreadyExisted;
|
|
407
|
-
console.log(` ✓ AID ${result.alreadyExisted ? 'reused' : 'created'}: ${aid}`);
|
|
408
|
-
}
|
|
409
|
-
catch (e) {
|
|
410
|
-
return { ok: false, error: `AID creation failed: ${e?.message || e}` };
|
|
411
|
-
}
|
|
412
|
-
// Project path
|
|
413
|
-
let suggestedProjectPath = '';
|
|
414
|
-
try {
|
|
415
|
-
const defaults = loadDefaults();
|
|
416
|
-
const rootPath = agentProjectRootFromDefaults(defaults, p.root);
|
|
417
|
-
suggestedProjectPath = deriveAgentProjectPath(rootPath, aid);
|
|
418
|
-
}
|
|
419
|
-
catch {
|
|
420
|
-
suggestedProjectPath = deriveAgentProjectPath(agentProjectRootFromDefaults(null, p.root), aid);
|
|
421
|
-
}
|
|
422
|
-
const projectInput = (await ask(`Project path [${suggestedProjectPath}]: `)).trim();
|
|
423
|
-
const projectPath = projectInput || suggestedProjectPath;
|
|
424
|
-
if (!path.isAbsolute(projectPath)) {
|
|
425
|
-
return { ok: false, error: 'Project path must be an absolute path.' };
|
|
426
|
-
}
|
|
427
|
-
if (!fs.existsSync(projectPath)) {
|
|
428
|
-
const create = (await ask(`Project path does not exist. Create? [Y/n]: `)).trim().toLowerCase();
|
|
429
|
-
if (create === '' || create === 'y' || create === 'yes') {
|
|
430
|
-
try {
|
|
431
|
-
fs.mkdirSync(projectPath, { recursive: true });
|
|
432
|
-
}
|
|
433
|
-
catch (e) {
|
|
434
|
-
return { ok: false, error: `Failed to create project path "${projectPath}": ${e?.message || e}` };
|
|
435
|
-
}
|
|
436
|
-
console.log(` ✓ Created ${projectPath}`);
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
return { ok: false, error: 'Aborted.' };
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
// Baseagent
|
|
443
|
-
const available = detectAvailableBaseagents();
|
|
444
|
-
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
445
|
-
return { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.` };
|
|
446
|
-
}
|
|
447
|
-
const defaultBa = pickDefaultBaseagent(available);
|
|
448
|
-
let baseagent;
|
|
449
|
-
if (available.length === 1 && defaultBa) {
|
|
450
|
-
console.log(` Baseagent: ${defaultBa}`);
|
|
451
|
-
baseagent = defaultBa;
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
let chosen = null;
|
|
455
|
-
while (chosen === null) {
|
|
456
|
-
const defaultHint = defaultBa ? ` [${defaultBa}]` : '';
|
|
457
|
-
const input = (await ask(`Baseagent (${available.join('/')})${defaultHint}: `)).trim() || defaultBa;
|
|
458
|
-
if (!input) {
|
|
459
|
-
console.log(' ecagent is optional; enter ecagent to select it explicitly.');
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
if (!BASEAGENT_CANDIDATES.includes(input)) {
|
|
463
|
-
console.log(` Invalid choice. Options: ${BASEAGENT_CANDIDATES.join('/')}`);
|
|
464
|
-
continue;
|
|
465
|
-
}
|
|
466
|
-
if (!available.includes(input)) {
|
|
467
|
-
console.log(` ${input} is not available in the current environment. Available: ${available.join('/')}`);
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if (input === 'ecagent') {
|
|
471
|
-
const reason = ecagentUnavailableReason();
|
|
472
|
-
if (reason) {
|
|
473
|
-
console.log(` ecagent is unavailable: ${reason}`);
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
chosen = input;
|
|
478
|
-
}
|
|
479
|
-
baseagent = chosen;
|
|
480
|
-
}
|
|
481
|
-
// Owner: only prompt if daemon (daemon.json) has owners configured.
|
|
482
|
-
// If daemon has no owner, agent owner is meaningless and should be skipped entirely.
|
|
483
|
-
const { loadDaemonConfig } = await import('../config-store.js');
|
|
484
|
-
const daemonCfg = loadDaemonConfig();
|
|
485
|
-
const daemonHasOwner = daemonCfg.owners && daemonCfg.owners.length > 0;
|
|
486
|
-
let owner;
|
|
487
|
-
let skipQrBinding = false;
|
|
488
|
-
if (daemonHasOwner) {
|
|
489
|
-
const defaultOwner = daemonCfg.owners[0];
|
|
490
|
-
while (true) {
|
|
491
|
-
const prompt = `Owner AID [${defaultOwner}]: `;
|
|
492
|
-
const ownerInput = (await ask(prompt)).trim();
|
|
493
|
-
// User pressed Enter - use default owner
|
|
494
|
-
if (!ownerInput) {
|
|
495
|
-
owner = defaultOwner;
|
|
496
|
-
break;
|
|
497
|
-
}
|
|
498
|
-
// User entered "new" or "qr" - trigger QR binding flow
|
|
499
|
-
if (ownerInput.toLowerCase() === 'new' || ownerInput.toLowerCase() === 'qr') {
|
|
500
|
-
owner = undefined;
|
|
501
|
-
skipQrBinding = false;
|
|
502
|
-
break;
|
|
503
|
-
}
|
|
504
|
-
// User entered a specific AID - validate and use it
|
|
505
|
-
if (!isValidAid(ownerInput)) {
|
|
506
|
-
console.log(` ⚠ Invalid Owner AID "${ownerInput}": must be a valid multi-level domain (e.g. alice.agentid.pub)`);
|
|
507
|
-
console.log(` 提示: 直接回车使用 ${defaultOwner},输入 "new" 扫码绑定新 AID`);
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
owner = ownerInput;
|
|
511
|
-
skipQrBinding = true; // Skip QR if user manually entered an AID
|
|
512
|
-
break;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
// Name + description for agent.md
|
|
516
|
-
const defaultName = aid.split('.')[0];
|
|
517
|
-
const agentName = (await ask(`Display name [${defaultName}]: `)).trim() || defaultName;
|
|
518
|
-
const agentDescription = (await ask('Description (optional): ')).trim() || '';
|
|
519
|
-
if (ownRl)
|
|
520
|
-
rl.close();
|
|
521
|
-
const agentConfig = withStaticOwner({
|
|
522
|
-
$schema_version: CONFIG_SCHEMA_VERSION,
|
|
523
|
-
aid,
|
|
524
|
-
enabled: true,
|
|
525
|
-
lifecycle: 'created',
|
|
526
|
-
channels: [],
|
|
527
|
-
projects: { defaultPath: projectPath },
|
|
528
|
-
}, owner);
|
|
529
|
-
saveAgent(agentConfig);
|
|
530
|
-
ensureInitialRoleRegistry(aid);
|
|
531
|
-
saveInitialBehavior(aid, baseagent);
|
|
532
|
-
ensureAgentDirSkeleton(aid);
|
|
533
|
-
// Generate and upload agent.md
|
|
534
|
-
let agentmdUploaded = false;
|
|
535
|
-
try {
|
|
536
|
-
const { buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
|
|
537
|
-
const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription });
|
|
538
|
-
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
539
|
-
// agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
|
|
540
|
-
// Upload with retry (3 attempts, 2s delay between retries)
|
|
541
|
-
const MAX_ATTEMPTS = 3;
|
|
542
|
-
const RETRY_DELAY_MS = 2000;
|
|
543
|
-
let lastError;
|
|
544
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
545
|
-
try {
|
|
546
|
-
if (attempt > 1) {
|
|
547
|
-
process.stdout.write(` ↻ agent.md 上传重试 (${attempt}/${MAX_ATTEMPTS})...\n`);
|
|
548
|
-
await new Promise(r => setTimeout(r, RETRY_DELAY_MS));
|
|
549
|
-
}
|
|
550
|
-
await agentmdPut(content, { aid, aunPath });
|
|
551
|
-
agentmdUploaded = true;
|
|
552
|
-
break;
|
|
553
|
-
}
|
|
554
|
-
catch (e) {
|
|
555
|
-
lastError = e;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (!agentmdUploaded) {
|
|
559
|
-
console.warn(` ⚠ agent.md upload failed: ${lastError?.message || lastError}`);
|
|
560
|
-
console.warn(` → Retry later with: ec aid agentmd put ${aid}`);
|
|
561
|
-
}
|
|
562
|
-
// Yield to allow the SDK WebSocket to fully close before IPC
|
|
563
|
-
await new Promise(r => setTimeout(r, 0));
|
|
564
|
-
}
|
|
565
|
-
catch (e) {
|
|
566
|
-
console.warn(` ⚠ agent.md generation failed: ${e?.message || e}`);
|
|
567
|
-
}
|
|
568
|
-
// Attempt hot-load via IPC (if daemon is running).
|
|
569
|
-
// Cold-starting a new agent (connecting AUN WebSocket) routinely takes
|
|
570
|
-
// >3s, so use a generous timeout to avoid a false "service not running"
|
|
571
|
-
// report while the daemon actually finishes bringing the agent online.
|
|
572
|
-
let hotLoaded = false;
|
|
573
|
-
let hotLoadError;
|
|
574
|
-
try {
|
|
575
|
-
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid }, 30_000);
|
|
576
|
-
if (ipcResult?.ok) {
|
|
577
|
-
hotLoaded = true;
|
|
578
|
-
}
|
|
579
|
-
else if (ipcResult) {
|
|
580
|
-
hotLoadError = ipcResult.error;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
catch { /* daemon not running */ }
|
|
584
|
-
let ownerBoundAid;
|
|
585
|
-
let ownerBindSkipped = false;
|
|
586
|
-
let ownerBindInterrupted = false;
|
|
587
|
-
// Only prompt for agent owner binding if:
|
|
588
|
-
// 1. User didn't manually input owner during setup (owner is undefined)
|
|
589
|
-
// 2. User didn't skip QR binding explicitly (skipQrBinding is false)
|
|
590
|
-
// 3. We're in an interactive terminal
|
|
591
|
-
// 4. The daemon (daemon.json) has at least one owner configured
|
|
592
|
-
if (!owner && !skipQrBinding && process.stdin.isTTY && daemonHasOwner) {
|
|
593
|
-
console.log('\n📡 Agent owner 绑定 — 请用 evol app 扫描二维码,10 分钟内有效\n');
|
|
594
|
-
try {
|
|
595
|
-
const { runAgentOwnerQrBindFlow } = await import('./init-channel.js');
|
|
596
|
-
const bound = await runAgentOwnerQrBindFlow(aid, agentName);
|
|
597
|
-
if (bound.action === 'bound') {
|
|
598
|
-
ownerBoundAid = bound.boundAid;
|
|
599
|
-
console.log(` ✓ 已配置 agent owner: ${bound.boundAid}`);
|
|
600
|
-
}
|
|
601
|
-
else if (bound.action === 'manual') {
|
|
602
|
-
ownerBindSkipped = true;
|
|
603
|
-
ownerBoundAid = await promptAgentOwnerManually(aid);
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
ownerBindInterrupted = true;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
catch (e) {
|
|
610
|
-
ownerBindSkipped = true;
|
|
611
|
-
console.log(` ⚠ 扫码绑定不可用: ${e?.message || e}`);
|
|
612
|
-
ownerBoundAid = await promptAgentOwnerManually(aid);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
ok: true,
|
|
617
|
-
aid,
|
|
618
|
-
configPath: toPosix(path.join(agentDirPath, 'config.json')),
|
|
619
|
-
aidCreated,
|
|
620
|
-
agentmdUploaded,
|
|
621
|
-
hotLoaded,
|
|
622
|
-
hotLoadError,
|
|
623
|
-
ownerBoundAid,
|
|
624
|
-
ownerBindSkipped,
|
|
625
|
-
ownerBindInterrupted,
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
finally {
|
|
629
|
-
if (ownRl) {
|
|
630
|
-
try {
|
|
631
|
-
rl.close();
|
|
632
|
-
}
|
|
633
|
-
catch { /* ignore */ }
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
async function promptAgentOwnerManually(aid) {
|
|
638
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
639
|
-
try {
|
|
640
|
-
while (true) {
|
|
641
|
-
const raw = await new Promise(resolve => rl.question('\n扫码未完成。手动输入 agent owner AID(留空跳过): ', resolve));
|
|
642
|
-
const owner = raw.trim();
|
|
643
|
-
if (!owner) {
|
|
644
|
-
console.log(' 已跳过 agent owner 配置');
|
|
645
|
-
return undefined;
|
|
646
|
-
}
|
|
647
|
-
const { isValidAid } = await import('../aun/aid/index.js');
|
|
648
|
-
if (!isValidAid(owner)) {
|
|
649
|
-
console.log(' ⚠ Owner AID 格式无效(需合法多级域名,如 alice.agentid.pub)');
|
|
650
|
-
continue;
|
|
651
|
-
}
|
|
652
|
-
const agent = loadAgent(aid);
|
|
653
|
-
if (!agent) {
|
|
654
|
-
console.log(` ⚠ 无法加载 agent 配置: ${aid}`);
|
|
655
|
-
return undefined;
|
|
656
|
-
}
|
|
657
|
-
saveAgent(withStaticOwner(agent, owner));
|
|
658
|
-
try {
|
|
659
|
-
const result = await ipcQuery(resolvePaths().socket, { type: 'evolagent.reload', name: aid }, 30_000);
|
|
660
|
-
if (result?.ok)
|
|
661
|
-
console.log(' ✓ agent owner 已热重载');
|
|
662
|
-
}
|
|
663
|
-
catch { /* daemon not running */ }
|
|
664
|
-
console.log(` ✓ 已配置 agent owner: ${owner}`);
|
|
665
|
-
return owner;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
finally {
|
|
669
|
-
rl.close();
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
export async function agentCreateNonInteractive(opts, runtime = {}) {
|
|
673
|
-
const p = resolvePaths();
|
|
674
|
-
const { isValidAid, aidCreate } = await import('../aun/aid/index.js');
|
|
675
|
-
opts.onPhase?.('validating', 'begin');
|
|
676
|
-
/** 校验失败:透出 failed 进度并返回原结构(控制流不变)。 */
|
|
677
|
-
const failValidating = (error) => {
|
|
678
|
-
opts.onPhase?.('validating', 'failed', error);
|
|
679
|
-
return { ok: false, error };
|
|
680
|
-
};
|
|
681
|
-
if (!isValidAid(opts.aid)) {
|
|
682
|
-
return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
|
|
683
|
-
}
|
|
684
|
-
const agentDirPath = path.join(p.agentsDir, opts.aid);
|
|
685
|
-
const configExists = fs.existsSync(path.join(agentDirPath, 'config.json'));
|
|
686
|
-
if (configExists && !opts.force) {
|
|
687
|
-
return failValidating(`Agent "${opts.aid}" already exists: ${agentDirPath}/config.json (use --force to overwrite)`);
|
|
688
|
-
}
|
|
689
|
-
// Baseagent
|
|
690
|
-
const available = detectAvailableBaseagents();
|
|
691
|
-
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
692
|
-
return failValidating(`No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.`);
|
|
693
|
-
}
|
|
694
|
-
let baseagent;
|
|
695
|
-
if (opts.baseagent) {
|
|
696
|
-
if (!BASEAGENT_CANDIDATES.includes(opts.baseagent)) {
|
|
697
|
-
return failValidating(`Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`);
|
|
698
|
-
}
|
|
699
|
-
if (!available.includes(opts.baseagent)) {
|
|
700
|
-
const reason = opts.baseagent === 'codex'
|
|
701
|
-
? getCodexAppServerAvailability().reason
|
|
702
|
-
: undefined;
|
|
703
|
-
return failValidating(reason || `${opts.baseagent} is not available in the current environment (available: ${available.join('/')})`);
|
|
704
|
-
}
|
|
705
|
-
if (opts.baseagent === 'ecagent') {
|
|
706
|
-
const reason = ecagentUnavailableReason();
|
|
707
|
-
if (reason)
|
|
708
|
-
return failValidating(reason);
|
|
709
|
-
}
|
|
710
|
-
baseagent = opts.baseagent;
|
|
711
|
-
}
|
|
712
|
-
else {
|
|
713
|
-
const defaultBaseagent = pickDefaultBaseagent(available);
|
|
714
|
-
if (!defaultBaseagent)
|
|
715
|
-
return failValidating('ecagent is optional; pass --baseagent ecagent after configuring its API key');
|
|
716
|
-
baseagent = defaultBaseagent;
|
|
717
|
-
}
|
|
718
|
-
if (!path.isAbsolute(opts.project)) {
|
|
719
|
-
return failValidating(`--project must be absolute: ${opts.project}`);
|
|
720
|
-
}
|
|
721
|
-
if (!fs.existsSync(opts.project)) {
|
|
722
|
-
try {
|
|
723
|
-
fs.mkdirSync(opts.project, { recursive: true });
|
|
724
|
-
}
|
|
725
|
-
catch (e) {
|
|
726
|
-
return failValidating(`Failed to create ${opts.project}: ${e?.message || e}`);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
if (opts.owner && !isValidAid(opts.owner)) {
|
|
730
|
-
return failValidating(`Invalid owner: ${opts.owner}`);
|
|
731
|
-
}
|
|
732
|
-
opts.onPhase?.('validating', 'done');
|
|
733
|
-
// Register AID
|
|
734
|
-
opts.onPhase?.('registering_aid', 'begin');
|
|
735
|
-
let aidCreated = false;
|
|
736
|
-
try {
|
|
737
|
-
const result = await aidCreate(opts.aid);
|
|
738
|
-
try {
|
|
739
|
-
await result.client.close();
|
|
740
|
-
}
|
|
741
|
-
catch { /* ignore */ }
|
|
742
|
-
aidCreated = !result.alreadyExisted;
|
|
743
|
-
opts.onPhase?.('registering_aid', 'done', aidCreated ? 'created' : 'existed');
|
|
744
|
-
}
|
|
745
|
-
catch (e) {
|
|
746
|
-
const error = `AID creation failed: ${e?.message || e}`;
|
|
747
|
-
opts.onPhase?.('registering_aid', 'failed', error);
|
|
748
|
-
return { ok: false, error };
|
|
749
|
-
}
|
|
750
|
-
// Force 模式下若 agent 已存在,保留生命周期(避免重复 bootstrap/welcome)。
|
|
751
|
-
let preservedLifecycle = 'created';
|
|
752
|
-
if (configExists) {
|
|
753
|
-
try {
|
|
754
|
-
const existing = loadAgent(opts.aid);
|
|
755
|
-
if (existing?.lifecycle)
|
|
756
|
-
preservedLifecycle = existing.lifecycle;
|
|
757
|
-
}
|
|
758
|
-
catch { /* ignore */ }
|
|
759
|
-
}
|
|
760
|
-
const agentConfig = withStaticOwner({
|
|
761
|
-
$schema_version: CONFIG_SCHEMA_VERSION,
|
|
762
|
-
aid: opts.aid,
|
|
763
|
-
enabled: true,
|
|
764
|
-
lifecycle: preservedLifecycle,
|
|
765
|
-
channels: [],
|
|
766
|
-
projects: { defaultPath: opts.project },
|
|
767
|
-
}, opts.owner);
|
|
768
|
-
opts.onPhase?.('config_saved', 'begin');
|
|
769
|
-
saveAgent(agentConfig);
|
|
770
|
-
ensureInitialRoleRegistry(opts.aid);
|
|
771
|
-
saveInitialBehavior(opts.aid, baseagent);
|
|
772
|
-
ensureAgentDirSkeleton(opts.aid);
|
|
773
|
-
opts.onPhase?.('config_saved', 'done');
|
|
774
|
-
// Generate and upload agent.md
|
|
775
|
-
opts.onPhase?.('uploading_agentmd', 'begin');
|
|
776
|
-
let agentmdUploaded = false;
|
|
777
|
-
try {
|
|
778
|
-
const { buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
|
|
779
|
-
const content = buildInitialAgentMd({
|
|
780
|
-
aid: opts.aid,
|
|
781
|
-
name: opts.name,
|
|
782
|
-
description: opts.description,
|
|
783
|
-
});
|
|
784
|
-
const aunPath = process.env.AUN_HOME || defaultAunPath();
|
|
785
|
-
// agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
|
|
786
|
-
const MAX_ATTEMPTS = 3;
|
|
787
|
-
const RETRY_DELAY_MS = 2000;
|
|
788
|
-
let lastError;
|
|
789
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
790
|
-
try {
|
|
791
|
-
if (attempt > 1)
|
|
792
|
-
await new Promise(r => setTimeout(r, RETRY_DELAY_MS));
|
|
793
|
-
await agentmdPut(content, { aid: opts.aid, aunPath });
|
|
794
|
-
agentmdUploaded = true;
|
|
795
|
-
opts.onPhase?.('uploading_agentmd', 'done');
|
|
796
|
-
break;
|
|
797
|
-
}
|
|
798
|
-
catch (e) {
|
|
799
|
-
lastError = e;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
if (!agentmdUploaded) {
|
|
803
|
-
console.warn(`⚠ agent.md upload failed: ${lastError?.message || lastError}`);
|
|
804
|
-
console.warn(` Retry later with: ec aid agentmd put ${opts.aid}`);
|
|
805
|
-
opts.onPhase?.('uploading_agentmd', 'warn', `upload failed: ${lastError?.message || lastError}`);
|
|
806
|
-
}
|
|
807
|
-
await new Promise(r => setTimeout(r, 0));
|
|
808
|
-
}
|
|
809
|
-
catch (e) {
|
|
810
|
-
console.warn(`⚠ agent.md generation failed: ${e?.message || e}`);
|
|
811
|
-
opts.onPhase?.('uploading_agentmd', 'warn', `generation failed: ${e?.message || e}`);
|
|
812
|
-
}
|
|
813
|
-
// Core-owned callers invoke the already-loaded runtime directly. Standalone
|
|
814
|
-
// CLI callers retain the IPC path so this module remains usable without a
|
|
815
|
-
// daemon instance in the current process.
|
|
816
|
-
let hotLoaded = false;
|
|
817
|
-
let hotLoadError;
|
|
818
|
-
opts.onPhase?.('hot_loading', 'begin');
|
|
819
|
-
try {
|
|
820
|
-
if (runtime.hotLoadAgent) {
|
|
821
|
-
await runtime.hotLoadAgent(opts.aid);
|
|
822
|
-
hotLoaded = true;
|
|
823
|
-
opts.onPhase?.('hot_loading', 'done');
|
|
824
|
-
}
|
|
825
|
-
else {
|
|
826
|
-
const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid }, 30_000);
|
|
827
|
-
if (ipcResult?.ok) {
|
|
828
|
-
hotLoaded = true;
|
|
829
|
-
opts.onPhase?.('hot_loading', 'done');
|
|
830
|
-
}
|
|
831
|
-
else if (ipcResult) {
|
|
832
|
-
hotLoadError = ipcResult.error;
|
|
833
|
-
opts.onPhase?.('hot_loading', 'warn', hotLoadError);
|
|
834
|
-
}
|
|
835
|
-
else {
|
|
836
|
-
opts.onPhase?.('hot_loading', 'warn', 'daemon not running');
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
catch (error) {
|
|
841
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
842
|
-
hotLoadError = message;
|
|
843
|
-
opts.onPhase?.('hot_loading', 'warn', message);
|
|
844
|
-
}
|
|
845
|
-
return {
|
|
846
|
-
ok: true,
|
|
847
|
-
aid: opts.aid,
|
|
848
|
-
ownerAid: opts.owner,
|
|
849
|
-
configPath: toPosix(path.join(agentDirPath, 'config.json')),
|
|
850
|
-
aidCreated,
|
|
851
|
-
agentmdUploaded,
|
|
852
|
-
hotLoaded,
|
|
853
|
-
hotLoadError,
|
|
854
|
-
};
|
|
855
|
-
}
|
|
856
207
|
// ==================== agentSyncAids (deprecated) ====================
|
|
857
208
|
/** @deprecated sync-aids 已废弃,不再从 CLI 调用 */
|
|
858
209
|
export async function agentSyncAids() {
|
|
@@ -930,32 +281,32 @@ export async function agentReload(aid, options = {}) {
|
|
|
930
281
|
}
|
|
931
282
|
// Full resync
|
|
932
283
|
try {
|
|
933
|
-
const result = await ipcQuery(p.socket, { type: 'evolagent.resync' }, AGENT_RESYNC_TIMEOUT_MS);
|
|
284
|
+
const result = await ipcQuery(p.socket, { type: 'evolagent.resync' }, AGENT_RESYNC_TIMEOUT_MS, { throwOnError: true });
|
|
934
285
|
if (result === null) {
|
|
935
|
-
return { ok: false, error: '
|
|
286
|
+
return { ok: false, code: 'IPC_INVALID_RESPONSE', error: 'daemon IPC 未返回有效响应,请检查 ec status' };
|
|
936
287
|
}
|
|
937
288
|
if (result?.ok) {
|
|
938
289
|
return { ok: true, results: result.results || [] };
|
|
939
290
|
}
|
|
940
291
|
return { ok: false, error: result?.error || 'unknown error' };
|
|
941
292
|
}
|
|
942
|
-
catch {
|
|
943
|
-
return { ok: false, error: '
|
|
293
|
+
catch (error) {
|
|
294
|
+
return { ok: false, code: error instanceof IpcTransportError ? `IPC_${error.code}` : 'IPC_FAILED', error: String(error instanceof Error ? error.message : error) };
|
|
944
295
|
}
|
|
945
296
|
}
|
|
946
297
|
// Single agent reload
|
|
947
298
|
try {
|
|
948
|
-
const result = await ipcQuery(p.socket, { type: 'evolagent.reload', name: aid, force: options.force === true }, AGENT_RELOAD_TIMEOUT_MS);
|
|
299
|
+
const result = await ipcQuery(p.socket, { type: 'evolagent.reload', name: aid, force: options.force === true }, AGENT_RELOAD_TIMEOUT_MS, { throwOnError: true });
|
|
949
300
|
if (result === null) {
|
|
950
|
-
return { ok: false, error: '
|
|
301
|
+
return { ok: false, code: 'IPC_INVALID_RESPONSE', error: 'daemon IPC 未返回有效响应,请检查 ec status' };
|
|
951
302
|
}
|
|
952
303
|
if (result?.ok) {
|
|
953
304
|
return { ok: true };
|
|
954
305
|
}
|
|
955
306
|
return { ok: false, code: result?.code, error: result?.error || 'unknown error' };
|
|
956
307
|
}
|
|
957
|
-
catch {
|
|
958
|
-
return { ok: false, error: '
|
|
308
|
+
catch (error) {
|
|
309
|
+
return { ok: false, code: error instanceof IpcTransportError ? `IPC_${error.code}` : 'IPC_FAILED', error: String(error instanceof Error ? error.message : error) };
|
|
959
310
|
}
|
|
960
311
|
}
|
|
961
312
|
// ==================== agentEnable / agentDisable ====================
|