evolcore 0.0.29 → 0.0.30

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.
Files changed (68) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/agents/codex-runner.js +61 -14
  3. package/dist/aun/aid/agentmd.js +224 -19
  4. package/dist/aun/aid/index.js +2 -1
  5. package/dist/aun/aid/managed-operation.js +70 -4
  6. package/dist/aun/group/index.js +1 -0
  7. package/dist/{core → aun}/group/invite-service.js +4 -4
  8. package/dist/channels/daemon.js +1 -1
  9. package/dist/cli/agent-command.js +7 -7
  10. package/dist/cli/aun-commands.js +97 -37
  11. package/dist/cli/data-command.js +2 -1
  12. package/dist/cli/managed-command-guard.js +2 -2
  13. package/dist/cli/model.js +1 -1
  14. package/dist/cli/response.js +1 -1
  15. package/dist/cli/trigger-command.js +52 -29
  16. package/dist/config/boot-log.js +95 -1
  17. package/dist/config/builtin-roles.js +1 -0
  18. package/dist/config/peer-role-resolver.js +21 -0
  19. package/dist/core/agent-ipc-registration.js +409 -0
  20. package/dist/core/agent-runtime.js +435 -0
  21. package/dist/core/auth/delegation-authorization.js +58 -0
  22. package/dist/core/auth/operation-catalog.js +8 -0
  23. package/dist/core/bootstrap-service.js +65 -1
  24. package/dist/core/channel-runtime.js +435 -0
  25. package/dist/core/command/command-handler.js +4 -1
  26. package/dist/core/daemon-bootstrap.js +151 -0
  27. package/dist/core/daemon-control.js +205 -0
  28. package/dist/core/daemon-lifecycle.js +225 -0
  29. package/dist/core/data-migration.js +4 -1
  30. package/dist/core/handoff/ipc-registration.js +156 -0
  31. package/dist/core/ipc-registration.js +457 -0
  32. package/dist/core/memory/consolidation-trigger.js +8 -0
  33. package/dist/core/memory/consolidation.js +838 -0
  34. package/dist/core/message/aun-ipc-sender.js +226 -0
  35. package/dist/core/message/outbound.js +165 -0
  36. package/dist/core/permission/approval-gateway.js +13 -0
  37. package/dist/core/permission/ec-command-parser.js +80 -35
  38. package/dist/core/permission/sandbox-runtime.js +23 -2
  39. package/dist/core/permission/tool-error-code.js +1 -0
  40. package/dist/core/permission/tool-policy.js +61 -24
  41. package/dist/core/session/session-idle-monitor.js +17 -0
  42. package/dist/index.js +352 -4841
  43. package/dist/ipc.js +2 -1
  44. package/dist/stats/db.js +24 -0
  45. package/dist/stats/index.js +1 -1
  46. package/dist/stats/writer.js +25 -1
  47. package/dist/trigger/application-service.js +157 -0
  48. package/dist/trigger/authorization.js +371 -0
  49. package/dist/trigger/ipc-service.js +406 -0
  50. package/dist/trigger/local-files.js +133 -0
  51. package/dist/trigger/manager.js +235 -22
  52. package/dist/trigger/scheduler.js +30 -5
  53. package/dist/trigger/script-executor.js +176 -39
  54. package/dist/trigger/script-sandbox.js +458 -0
  55. package/dist/trigger/system-definitions.js +188 -0
  56. package/dist/trigger/validation.js +0 -3
  57. package/dist/utils/aid-bind.js +1 -1
  58. package/dist/utils/evolcore-version.js +74 -0
  59. package/dist/utils/logger.js +16 -0
  60. package/kits/docs/evolcore/INDEX.md +1 -1
  61. package/kits/docs/evolcore/aid.md +9 -1
  62. package/kits/docs/evolcore/model.md +3 -2
  63. package/kits/docs/evolcore/rpc.md +4 -0
  64. package/kits/docs/evolcore/trigger.md +15 -1
  65. package/kits/schemas/relation-config.schema.9.json +1 -1
  66. package/kits/templates/system-fragments/commands.md +0 -1
  67. package/package.json +1 -1
  68. package/dist/core/memory/launch-consolidation.js +0 -395
@@ -0,0 +1,409 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { loadDaemonConfig } from '../config-store.js';
4
+ import { parseAgentWelcomeArgs, parseInitializationArgs, resolveInitializationPlan, } from '../cli/agent-create.js';
5
+ import { trustedExecutionIdentityInput } from './auth/agent-delegation.js';
6
+ import { authorizeOperation, buildAuthSubject } from './auth/auth-gateway.js';
7
+ import { authorizationDenialData } from './auth/authorization-denial.js';
8
+ import { parsePeerKey } from './relation/peer-identity.js';
9
+ import { isHClassPath, isLClassPath, isSameOrDescendant } from './permission/protected-paths.js';
10
+ export function registerAgentOperationExecutor({ ipcServer, sessionManager, agentDelegationRegistry, eventBus, responseEngine, handoffRuntime, agentApplicationService, agentInitializationService, }) {
11
+ ipcServer.setAgentOperationExecutor(async (argv, sessionId, delegationToken, delegationCommandHash) => {
12
+ const fail = (code, error, reasonCode) => ({
13
+ ok: false,
14
+ code,
15
+ error,
16
+ ...(reasonCode ? { data: authorizationDenialData(reasonCode) } : {}),
17
+ });
18
+ if (!Array.isArray(argv) || argv[0] !== 'agent')
19
+ return fail('INVALID_REQUEST', 'agent.op requires an agent command');
20
+ const sub = argv[1];
21
+ if (!sub)
22
+ return fail('INVALID_ARGS', 'missing agent subcommand');
23
+ const value = (flag) => {
24
+ const index = argv.indexOf(flag);
25
+ return index >= 0 && index + 1 < argv.length && !argv[index + 1].startsWith('--') ? argv[index + 1] : undefined;
26
+ };
27
+ const taskSession = await sessionManager.getSessionById(sessionId);
28
+ const delegation = agentDelegationRegistry.validate(delegationToken, sessionId, delegationCommandHash);
29
+ if (!delegation.ok)
30
+ return fail(delegation.code, delegation.reason);
31
+ if (!taskSession || taskSession.selfAID !== delegation.grant.selfAid) {
32
+ return fail('INVALID_DELEGATION', 'delegation does not match the current session');
33
+ }
34
+ const taskAid = delegation.grant.selfAid;
35
+ let welcomeArgs;
36
+ if (sub === 'welcome') {
37
+ try {
38
+ welcomeArgs = parseAgentWelcomeArgs(argv.slice(2));
39
+ }
40
+ catch (error) {
41
+ return fail('INVALID_ARGS', error.message);
42
+ }
43
+ if (delegation.grant.chatType !== 'private')
44
+ return fail('NOT_ALLOWED', 'welcome requires a private conversation');
45
+ }
46
+ const targetAid = sub === 'list'
47
+ ? undefined
48
+ : sub === 'persona'
49
+ ? taskAid
50
+ : sub === 'welcome'
51
+ ? taskAid
52
+ : sub === 'show'
53
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : taskAid)
54
+ : sub === 'reload'
55
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined)
56
+ : (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined);
57
+ const operation = sub === 'list' ? 'agent.list'
58
+ : sub === 'show' ? 'agent.show'
59
+ : sub === 'persona' ? 'agent.persona'
60
+ : sub === 'welcome' ? 'agent.welcome'
61
+ : sub === 'initialize' || (sub === 'new' && argv.includes('--initialize')) ? 'agent.initialize'
62
+ : sub === 'new' ? 'agent.create'
63
+ : sub === 'enable' ? 'agent.enable'
64
+ : sub === 'disable' ? 'agent.disable'
65
+ : sub === 'reload' ? 'agent.reload'
66
+ : sub === 'delete' ? 'agent.delete' : undefined;
67
+ if (!operation)
68
+ return fail('INVALID_ARGS', `unsupported managed agent command: ${sub}`);
69
+ if (sub === 'new' && !argv.includes('--non-interactive') && !argv.includes('--initialize')) {
70
+ return fail('MANAGED_NON_INTERACTIVE_REQUIRED', 'interactive Agent creation is unavailable in a managed task', 'MANAGED_NON_INTERACTIVE_REQUIRED');
71
+ }
72
+ if (sub === 'delete' && argv.includes('--purge') && !argv.includes('--confirm-purge')) {
73
+ return fail('PURGE_CONFIRMATION_REQUIRED', 'agent delete --purge requires explicit --confirm-purge', 'PURGE_CONFIRMATION_REQUIRED');
74
+ }
75
+ let conversationId;
76
+ try {
77
+ conversationId = parsePeerKey(delegation.grant.peerKey).channelId;
78
+ }
79
+ catch {
80
+ return fail('INVALID_DELEGATION', 'delegation contains an invalid relation key');
81
+ }
82
+ const subject = buildAuthSubject({
83
+ selfAid: taskAid,
84
+ actorId: delegation.grant.actorId,
85
+ channel: delegation.grant.channel,
86
+ channelType: delegation.grant.channelType,
87
+ channelId: conversationId,
88
+ chatType: delegation.grant.chatType,
89
+ conversationId,
90
+ processOwners: loadDaemonConfig().owners ?? [],
91
+ ...trustedExecutionIdentityInput(delegation.grant),
92
+ });
93
+ const decision = authorizeOperation({
94
+ source: 'agent-tool',
95
+ subject,
96
+ intent: {
97
+ operation,
98
+ scope: operation === 'agent.show' || operation === 'agent.persona' || operation === 'agent.welcome'
99
+ ? 'agent'
100
+ : operation === 'agent.reload' && targetAid
101
+ ? 'agent'
102
+ : 'control',
103
+ source: 'agent-tool',
104
+ args: {
105
+ self: taskAid,
106
+ aid: targetAid ?? taskAid,
107
+ taskAgentAid: taskAid,
108
+ targetAgentAid: targetAid ?? taskAid,
109
+ ...(welcomeArgs ? { action: welcomeArgs.action } : {}),
110
+ },
111
+ },
112
+ auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
113
+ });
114
+ if (!decision.allow) {
115
+ const reasonCode = decision.command?.reasonCode;
116
+ return fail(decision.code, decision.reason, reasonCode);
117
+ }
118
+ const { execAgentAction, execAgentOptions, execAgentQuery } = await import('./command/agent-control.js');
119
+ if (operation === 'agent.list') {
120
+ const result = await execAgentOptions({ options: 'all' }, agentApplicationService);
121
+ if ('error' in result)
122
+ return fail(result.code, result.error);
123
+ const agents = Array.isArray(result.data?.agents) ? result.data.agents.map((agent) => ({
124
+ aid: agent.aid,
125
+ name: agent.name,
126
+ personalName: agent.personalName ?? null,
127
+ status: agent.status,
128
+ channels: Array.isArray(agent.channels) ? agent.channels : [],
129
+ projectPath: null,
130
+ baseagent: agent.baseagent ?? null,
131
+ model: agent.model ?? null,
132
+ lastActivity: agent.lastActivity ?? null,
133
+ })) : [];
134
+ return { ok: true, result: { ok: true, agents, redacted: true } };
135
+ }
136
+ if (operation === 'agent.show') {
137
+ const result = await execAgentQuery({ aid: targetAid }, agentApplicationService);
138
+ if ('error' in result)
139
+ return fail(result.code, result.error);
140
+ const agent = result.data ?? {};
141
+ return { ok: true, result: {
142
+ ok: true,
143
+ aid: agent.aid,
144
+ status: agent.status,
145
+ lifecycle: agent.lifecycle ?? null,
146
+ identity: agent.identity ?? { name: null, description: null },
147
+ config: {
148
+ baseagent: agent.config?.baseagent ?? null,
149
+ model: agent.config?.model ?? null,
150
+ effort: agent.config?.effort ?? null,
151
+ chatmode: agent.config?.chatmode ?? null,
152
+ channels: Array.isArray(agent.config?.channels) ? agent.config.channels : [],
153
+ },
154
+ connection: agent.connection ?? null,
155
+ sessions: agent.sessions ?? { active: 0, last_activity: null },
156
+ paths: subject.dataScope === 'daemon'
157
+ ? (agent.paths ?? { config: null, agent_md: null, project: null, data: null })
158
+ : { config: null, agent_md: null, project: null, data: null },
159
+ ...(subject.dataScope === 'daemon' ? {} : { redacted: true }),
160
+ ...(agent.createProgress ? { createProgress: agent.createProgress } : {}),
161
+ ...(agent.initialization ? { initialization: agent.initialization } : {}),
162
+ } };
163
+ }
164
+ if (operation === 'agent.persona') {
165
+ const rawPersonaArgs = argv.slice(2);
166
+ const hasFormatSuffix = rawPersonaArgs.length >= 2
167
+ && rawPersonaArgs.at(-2) === '--format'
168
+ && rawPersonaArgs.at(-1) === 'json';
169
+ const personaArgs = hasFormatSuffix ? rawPersonaArgs.slice(0, -2) : rawPersonaArgs;
170
+ if (!hasFormatSuffix && rawPersonaArgs.includes('--format')) {
171
+ return fail('INVALID_ARGS', 'persona 仅支持末尾的 --format json');
172
+ }
173
+ if (personaArgs.length === 2 && personaArgs[0] === '--file') {
174
+ return fail('INVALID_ARGS', '托管 persona --file 必须由 CLI 读取后作为文本提交');
175
+ }
176
+ const wantsShow = personaArgs.length === 1 && personaArgs[0] === 'show';
177
+ const text = personaArgs.length === 2 && personaArgs[0] === '--text'
178
+ ? personaArgs[1]
179
+ : undefined;
180
+ if (!wantsShow && !(personaArgs.length === 2 && personaArgs[0] === '--text')) {
181
+ return fail('INVALID_ARGS', '用法: ec agent persona show | --text <text>');
182
+ }
183
+ if (text === undefined && !wantsShow)
184
+ return fail('INVALID_ARGS', 'persona --text 缺少参数');
185
+ const { agentPersona } = await import('../cli/agent.js');
186
+ const result = await agentPersona(taskAid, wantsShow ? { trustedLocal: true } : { text, trustedLocal: true });
187
+ if (!result.ok)
188
+ return fail(result.code ?? 'INTERNAL', result.error);
189
+ return { ok: true, result: {
190
+ ok: true,
191
+ aid: taskAid,
192
+ content: result.content,
193
+ ...(result.saved ? { saved: true } : {}),
194
+ } };
195
+ }
196
+ if (operation === 'agent.welcome') {
197
+ if (subject.role !== 'owner' && !(welcomeArgs?.action === 'show' && subject.role === 'admin')) {
198
+ return fail('NOT_ALLOWED', 'welcome requires the current Agent Owner (admin may read)');
199
+ }
200
+ const { agentWelcome } = await import('../cli/agent.js');
201
+ const result = await agentWelcome(taskAid, { text: welcomeArgs?.text, trustedLocal: true });
202
+ if (!result.ok)
203
+ return fail(result.code ?? 'INTERNAL', result.error);
204
+ return { ok: true, result: {
205
+ ok: true,
206
+ aid: taskAid,
207
+ content: result.content,
208
+ ...(result.path ? { path: result.path } : {}),
209
+ ...(result.saved ? { saved: true } : {}),
210
+ ...(result.bytes !== undefined ? { bytes: result.bytes } : {}),
211
+ ...(result.sha256 ? { sha256: result.sha256 } : {}),
212
+ } };
213
+ }
214
+ if (operation === 'agent.initialize') {
215
+ try {
216
+ const parsed = parseInitializationArgs(argv.slice(1));
217
+ const actor = delegation.grant.actorId;
218
+ if (parsed.resume)
219
+ return { ok: true, result: agentInitializationService.resume(parsed.aid, actor) };
220
+ const createPermission = authorizeOperation({
221
+ source: 'agent-tool', subject,
222
+ intent: { operation: 'agent.create', scope: 'control', source: 'agent-tool', args: { aid: parsed.aid } },
223
+ auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
224
+ });
225
+ if (!createPermission.allow)
226
+ return fail(createPermission.code, createPermission.reason);
227
+ if (!argv.includes('--owner') && !argv.includes('--owners'))
228
+ return fail('INITIALIZE_OWNER_MISMATCH', 'Explicit Owner required');
229
+ const plan = resolveInitializationPlan(argv.slice(1));
230
+ if (plan.avatarFile?.startsWith('attachment:')) {
231
+ const { readRelationAttachment } = await import('../utils/media-cache.js');
232
+ plan.avatarFile = readRelationAttachment(taskAid, delegation.grant.peerKey, plan.avatarFile.slice('attachment:'.length)).attachment.filePath;
233
+ }
234
+ else if (plan.avatarFile) {
235
+ const session = await sessionManager.getSessionById(sessionId);
236
+ const candidate = path.resolve(plan.avatarFile);
237
+ const roots = [session?.projectPath, delegation.grant.sessionRuntimeDir]
238
+ .filter((root) => !!root && path.isAbsolute(root))
239
+ .map(root => fs.realpathSync(root));
240
+ const real = fs.realpathSync(candidate);
241
+ if (!roots.some(root => isSameOrDescendant(real, root)) || isHClassPath(real) || isLClassPath(real)) {
242
+ return fail('AVATAR_INVALID', '--avatar-file must be a current project/TMPDIR file or authorized relation attachment');
243
+ }
244
+ plan.avatarFile = real;
245
+ }
246
+ if (!plan.owners.includes(actor))
247
+ return fail('INITIALIZE_OWNER_MISMATCH', 'The authenticated requesting Owner must be retained');
248
+ return { ok: true, result: agentInitializationService.start(plan, actor, parsed.dryRun) };
249
+ }
250
+ catch (error) {
251
+ return fail(error.code ?? 'INVALID_ARGS', error.message);
252
+ }
253
+ }
254
+ if (operation === 'agent.create') {
255
+ const aid = argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined;
256
+ if (!aid)
257
+ return fail('INVALID_ARGS', 'ec agent new requires an AID');
258
+ const { agentCreateNonInteractive, resolveAgentCreatePlan, validateAgentCreatePlan, parseAgentOwnerArgs, parseAgentTags } = await import('../cli/agent-create.js');
259
+ let ownerOptions;
260
+ try {
261
+ ownerOptions = parseAgentOwnerArgs(argv);
262
+ }
263
+ catch (error) {
264
+ return fail('INVALID_ARGS', error instanceof Error ? error.message : String(error));
265
+ }
266
+ let tags;
267
+ try {
268
+ tags = parseAgentTags(value('--tags'));
269
+ }
270
+ catch (error) {
271
+ return fail('INVALID_ARGS', error instanceof Error ? error.message : String(error));
272
+ }
273
+ const plan = resolveAgentCreatePlan({
274
+ aid,
275
+ project: value('--project'),
276
+ baseagent: value('--baseagent'),
277
+ ...ownerOptions,
278
+ handoff: value('--handoff'),
279
+ name: value('--name'),
280
+ description: value('--description'),
281
+ type: value('--type'),
282
+ tags,
283
+ avatarFile: value('--avatar-file'),
284
+ avatarUrl: value('--avatar-url'),
285
+ force: argv.includes('--force'),
286
+ });
287
+ const validationError = validateAgentCreatePlan(plan);
288
+ if (validationError)
289
+ return fail('INVALID_ARGS', validationError);
290
+ if (argv.includes('--handoff')) {
291
+ if (!delegation.grant.messageId)
292
+ return fail('INVALID_ARGS', '--handoff requires an originating message');
293
+ if (!plan.handoff?.trim())
294
+ return fail('INVALID_ARGS', '--handoff requires non-empty context');
295
+ if ((plan.owners?.[0] ?? plan.owner) !== taskAid) {
296
+ return fail('INVALID_ARGS', '--handoff requires the creating Agent to be the first Owner');
297
+ }
298
+ if (plan.configExists)
299
+ return fail('INVALID_ARGS', '--handoff requires a new Agent');
300
+ }
301
+ if (argv.includes('--dry-run'))
302
+ return { ok: true, result: { ok: true, dryRun: true, plan } };
303
+ let handoffId;
304
+ if (plan.handoff) {
305
+ try {
306
+ const created = await handoffRuntime.createOutbound({
307
+ selfAid: taskAid,
308
+ to: aid,
309
+ originSessionId: sessionId,
310
+ originMessageId: delegation.grant.messageId,
311
+ payload: { type: 'text', text: plan.handoff },
312
+ encrypt: true,
313
+ targetChatType: 'private',
314
+ explicitReturnPolicy: 'required',
315
+ contextOnly: true,
316
+ originAuthorization: {
317
+ actorId: delegation.grant.actorId,
318
+ channelKey: delegation.grant.channel,
319
+ channelType: delegation.grant.channelType,
320
+ chatType: delegation.grant.chatType,
321
+ peerKey: delegation.grant.peerKey,
322
+ },
323
+ causation: responseEngine.getTaskRuntimeContext(sessionId)?.causation,
324
+ });
325
+ handoffId = created.handoff?.handoff_id;
326
+ if (!handoffId)
327
+ return fail('INVALID_ARGS', '--handoff requires a different target session');
328
+ }
329
+ catch (error) {
330
+ return fail('HANDOFF_PREPARE_FAILED', error instanceof Error ? error.message : String(error));
331
+ }
332
+ }
333
+ const createOptions = {
334
+ aid: plan.aid,
335
+ project: plan.project,
336
+ baseagent: plan.baseagent,
337
+ owner: plan.owner,
338
+ owners: plan.owners,
339
+ name: plan.name,
340
+ description: plan.description,
341
+ type: plan.type,
342
+ tags: plan.tags,
343
+ force: argv.includes('--force'),
344
+ avatarFile: value('--avatar-file'),
345
+ avatarUrl: value('--avatar-url'),
346
+ };
347
+ if (createOptions.avatarFile) {
348
+ try {
349
+ if (createOptions.avatarFile.startsWith('attachment:')) {
350
+ const { readRelationAttachment } = await import('../utils/media-cache.js');
351
+ const source = readRelationAttachment(taskAid, delegation.grant.peerKey, createOptions.avatarFile.slice('attachment:'.length));
352
+ createOptions.avatarFile = source.attachment.filePath;
353
+ }
354
+ else {
355
+ const session = await sessionManager.getSessionById(sessionId);
356
+ const candidate = path.resolve(createOptions.avatarFile);
357
+ const roots = [session?.projectPath, delegation.grant.sessionRuntimeDir]
358
+ .filter((root) => !!root && path.isAbsolute(root))
359
+ .map(root => fs.realpathSync(root));
360
+ const real = fs.realpathSync(candidate);
361
+ if (!roots.some(root => isSameOrDescendant(real, root)) || isHClassPath(real) || isLClassPath(real)) {
362
+ return fail('AVATAR_INVALID', '--avatar-file must be a current project/TMPDIR file or authorized relation attachment');
363
+ }
364
+ createOptions.avatarFile = real;
365
+ }
366
+ }
367
+ catch (error) {
368
+ return fail('AVATAR_INVALID', error instanceof Error ? error.message : String(error));
369
+ }
370
+ }
371
+ try {
372
+ const result = agentApplicationService
373
+ ? await agentApplicationService.create(createOptions)
374
+ : await agentCreateNonInteractive(createOptions);
375
+ if (!result.ok) {
376
+ if (handoffId)
377
+ handoffRuntime.store.discard(taskAid, handoffId, 'operation_failed');
378
+ return fail(result.code ?? 'INTERNAL', result.error);
379
+ }
380
+ return { ok: true, result: { ...result, configPath: '[redacted]', ...(handoffId ? { handoff_id: handoffId } : {}) } };
381
+ }
382
+ catch (error) {
383
+ if (handoffId)
384
+ handoffRuntime.store.discard(taskAid, handoffId, 'operation_failed');
385
+ return fail('INTERNAL', error instanceof Error ? error.message : String(error));
386
+ }
387
+ }
388
+ if (operation === 'agent.delete') {
389
+ const result = agentApplicationService
390
+ ? await agentApplicationService.delete(targetAid ?? '', argv.includes('--purge'))
391
+ : await (async () => {
392
+ const { agentDelete } = await import('../cli/agent.js');
393
+ return await agentDelete(targetAid ?? '', argv.includes('--purge'));
394
+ })();
395
+ return 'error' in result ? fail(result.code ?? 'INTERNAL', result.error) : { ok: true, result };
396
+ }
397
+ if (operation === 'agent.reload' && !targetAid) {
398
+ const result = agentApplicationService
399
+ ? await agentApplicationService.reload()
400
+ : await (async () => {
401
+ const { agentReload } = await import('../cli/agent.js');
402
+ return await agentReload();
403
+ })();
404
+ return !result.ok ? fail(result.code ?? 'INTERNAL', result.error) : { ok: true, result };
405
+ }
406
+ const result = await execAgentAction(sub, { aid: targetAid ?? taskAid, force: argv.includes('--force') }, delegation.grant.actorId, eventBus, agentApplicationService);
407
+ return 'error' in result ? fail(result.code, result.error) : { ok: true, result: { ok: true, ...(result.data ?? {}) } };
408
+ });
409
+ }