evolcore 0.0.20 → 0.0.21

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 (123) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +58 -9
  3. package/dist/agents/baseagent.js +10 -6
  4. package/dist/agents/claude-runner.js +379 -108
  5. package/dist/agents/codex-app-server-client.js +10 -2
  6. package/dist/agents/codex-runner.js +402 -135
  7. package/dist/agents/ecagent-runner.js +171 -61
  8. package/dist/agents/gemini-runner.js +130 -30
  9. package/dist/agents/request-identity.js +25 -0
  10. package/dist/agents/runner-types.js +19 -0
  11. package/dist/aun/aid/agentmd.js +59 -2
  12. package/dist/aun/aid/identity.js +4 -1
  13. package/dist/aun/aid/index.js +1 -1
  14. package/dist/aun/msg/group.js +72 -6
  15. package/dist/aun/msg/history.js +213 -36
  16. package/dist/aun/msg/managed-operation.js +58 -9
  17. package/dist/aun/msg/p2p.js +5 -0
  18. package/dist/aun/outbox.js +182 -80
  19. package/dist/aun/service-proxy.js +43 -25
  20. package/dist/channels/aun.js +409 -88
  21. package/dist/channels/daemon.js +6 -1
  22. package/dist/cli/agent-command.js +4 -3
  23. package/dist/cli/agent.js +66 -56
  24. package/dist/cli/aun-commands.js +177 -42
  25. package/dist/cli/command-log.js +10 -11
  26. package/dist/cli/contact.js +1 -0
  27. package/dist/cli/daemon-commands.js +69 -115
  28. package/dist/cli/init.js +27 -15
  29. package/dist/cli/task-context.js +46 -0
  30. package/dist/cli/trigger-command.js +1 -1
  31. package/dist/cli/watch-logs.js +10 -3
  32. package/dist/config/builtin-roles.js +1 -0
  33. package/dist/config/config-field-policy.js +16 -5
  34. package/dist/config/config-manager.js +135 -17
  35. package/dist/config/contact-operation-service.js +32 -1
  36. package/dist/config/contact-request-service.js +44 -0
  37. package/dist/config/daemon-services.js +186 -0
  38. package/dist/config/gateway-config.js +20 -9
  39. package/dist/config/role-service.js +54 -3
  40. package/dist/config/schema-migration.js +550 -0
  41. package/dist/config-store.js +151 -9
  42. package/dist/core/agent-application-service.js +279 -0
  43. package/dist/core/audit/log-integrity.js +102 -0
  44. package/dist/core/auth/agent-delegation.js +31 -1
  45. package/dist/core/auth/auth-gateway.js +33 -4
  46. package/dist/core/auth/authorization-audit.js +150 -2
  47. package/dist/core/auth/operation-authorizer.js +41 -1
  48. package/dist/core/auth/operation-catalog.js +9 -1
  49. package/dist/core/bootstrap-service.js +6 -2
  50. package/dist/core/causation/aun-association.js +7 -4
  51. package/dist/core/command/agent-control.js +56 -16
  52. package/dist/core/command/command-handler.js +290 -44
  53. package/dist/core/command/connect-menu.js +3 -4
  54. package/dist/core/command/group-menu.js +5 -7
  55. package/dist/core/command/menu-handler.js +279 -80
  56. package/dist/core/command/role-menu.js +21 -11
  57. package/dist/core/command/slash-gate.js +85 -18
  58. package/dist/core/command/slash-handler.js +350 -32
  59. package/dist/core/event-catalog.js +5 -0
  60. package/dist/core/evolagent.js +4 -0
  61. package/dist/core/handoff/dispatcher.js +4 -0
  62. package/dist/core/handoff/runtime.js +10 -0
  63. package/dist/core/handoff/store.js +32 -9
  64. package/dist/core/inference/text-inference.js +7 -15
  65. package/dist/core/message/im-renderer.js +83 -84
  66. package/dist/core/message/{inbound-admission.js → message-admission.js} +51 -1
  67. package/dist/core/message/message-bridge.js +124 -10
  68. package/dist/core/message/message-log.js +14 -7
  69. package/dist/core/message/message-queue.js +206 -16
  70. package/dist/core/message/message-utils.js +12 -5
  71. package/dist/core/message/response-engine.js +486 -68
  72. package/dist/core/message/send-receipt.js +1 -0
  73. package/dist/core/message/stream-debouncer.js +9 -2
  74. package/dist/core/model/model-catalog.js +23 -15
  75. package/dist/core/model/model-diagnostics.js +28 -10
  76. package/dist/core/permission/approval-gateway.js +180 -6
  77. package/dist/core/permission/ec-command-parser.js +410 -54
  78. package/dist/core/permission/mode.js +18 -3
  79. package/dist/core/{protected-paths.js → permission/protected-paths.js} +17 -5
  80. package/dist/core/permission/readonly-shell-query.js +263 -9
  81. package/dist/core/permission/sandbox-runtime.js +159 -1
  82. package/dist/core/permission/tool-policy.js +575 -21
  83. package/dist/core/session/session-fs-store.js +154 -5
  84. package/dist/core/session/session-manager.js +299 -30
  85. package/dist/core/session/session-renew.js +19 -12
  86. package/dist/core/session/session-turn-coordinator.js +11 -4
  87. package/dist/eck/kit-renderer.js +1 -1
  88. package/dist/index.js +253 -46
  89. package/dist/ipc.js +374 -24
  90. package/dist/paths.js +64 -7
  91. package/dist/response-system/context-builder.js +1 -7
  92. package/dist/trigger/anomaly-store.js +1 -0
  93. package/dist/trigger/feedback.js +56 -5
  94. package/dist/trigger/history.js +79 -4
  95. package/dist/trigger/legacy-session-history.js +2 -2
  96. package/dist/trigger/parser.js +3 -2
  97. package/dist/trigger/validation.js +6 -1
  98. package/dist/utils/atomic-write.js +27 -0
  99. package/dist/utils/ecweb-utils.js +16 -2
  100. package/dist/utils/error-utils.js +4 -1
  101. package/dist/utils/logger.js +21 -2
  102. package/dist/utils/process-tree-stats.js +24 -4
  103. package/dist/utils/process-tree-worker.js +31 -0
  104. package/dist/utils/project-path.js +1 -2
  105. package/kits/docs/INDEX.md +1 -1
  106. package/kits/docs/evolcore/INDEX.md +1 -1
  107. package/kits/docs/evolcore/contact.md +7 -1
  108. package/kits/docs/evolcore/msg.md +16 -0
  109. package/kits/schemas/_meta.json +4 -2
  110. package/kits/schemas/agent-config.schema.11.json +13 -0
  111. package/kits/schemas/daemon.schema.5.json +0 -1
  112. package/kits/schemas/daemon.schema.6.json +131 -0
  113. package/kits/schemas/defaults.schema.5.json +15 -3
  114. package/kits/schemas/migrations/README.md +3 -1
  115. package/kits/schemas/relation-config.schema.8.json +13 -0
  116. package/kits/schemas/role-config.schema.1.json +1 -2
  117. package/kits/schemas/single-session.schema.3.json +32 -0
  118. package/kits/templates/roles/admin.json +1 -0
  119. package/kits/templates/roles/member.json +1 -0
  120. package/kits/templates/roles/visitor.json +1 -0
  121. package/package.json +6 -3
  122. package/skills/eclink/SKILL.md +2 -0
  123. package/dist/config/aun-gateway-config.js +0 -2
@@ -85,6 +85,7 @@ export class DaemonChannel {
85
85
  originChannelType: ctx.trigger.origin?.channelType
86
86
  ?? (ctx.trigger.origin?.channelKey ? channelTypeFromKey(ctx.trigger.origin.channelKey) : undefined),
87
87
  originControl: ctx.trigger.origin?.channelKey === 'daemon',
88
+ authorizedBy: ctx.trigger.authorizedBy,
88
89
  },
89
90
  };
90
91
  const onAbort = () => {
@@ -423,8 +424,10 @@ function normalizeExecutionAnomaly(value) {
423
424
  const toolName = nonEmptyString(value.toolName);
424
425
  const requestId = nonEmptyString(value.requestId);
425
426
  const policyCode = nonEmptyString(value.policyCode);
427
+ const decisionSource = nonEmptyString(value.decisionSource);
426
428
  const policy = normalizeApproverPolicy(value.policy);
427
429
  const agentAid = nonEmptyString(value.agentAid);
430
+ const agentName = nonEmptyString(value.agentName);
428
431
  const sessionId = nonEmptyString(value.sessionId);
429
432
  const permissionMode = normalizePermissionMode(value.permissionMode);
430
433
  const summary = nonEmptyString(value.summary);
@@ -438,8 +441,10 @@ function normalizeExecutionAnomaly(value) {
438
441
  ...(toolName ? { toolName } : {}),
439
442
  ...(requestId ? { requestId } : {}),
440
443
  ...(policyCode ? { policyCode } : {}),
444
+ ...(decisionSource ? { decisionSource } : {}),
441
445
  ...(policy ? { policy } : {}),
442
446
  ...(agentAid ? { agentAid } : {}),
447
+ ...(agentName ? { agentName } : {}),
443
448
  ...(sessionId ? { sessionId } : {}),
444
449
  ...(permissionMode ? { permissionMode } : {}),
445
450
  ...(summary ? { summary: summary.slice(0, 512) } : {}),
@@ -454,7 +459,7 @@ function normalizeApproverPolicy(value) {
454
459
  : undefined;
455
460
  }
456
461
  function normalizePermissionMode(value) {
457
- return value === 'readonly' || value === 'auto' || value === 'request' || value === 'bypass'
462
+ return value === 'readonly' || value === 'auto' || value === 'request' || value === 'bypass' || value === 'fullaccess'
458
463
  ? value
459
464
  : undefined;
460
465
  }
@@ -169,7 +169,8 @@ Options:
169
169
  for (const info of result.agents) {
170
170
  maxNameLen = Math.max(maxNameLen, info.name.length);
171
171
  maxPersonalLen = Math.max(maxPersonalLen, (info.personalName || '—').length);
172
- maxStatusLen = Math.max(maxStatusLen, (info.status || 'stopped').length);
172
+ const displayedStatus = `${info.status || 'unknown'}${info.stale ? ' (stale)' : ''}`;
173
+ maxStatusLen = Math.max(maxStatusLen, displayedStatus.length);
173
174
  const channelsStr = info.channels?.length > 0 ? info.channels.join(', ') : '—';
174
175
  maxChannelsLen = Math.max(maxChannelsLen, channelsStr.length);
175
176
  const projectStr = info.projectPath ? path.basename(info.projectPath) : '—';
@@ -188,7 +189,7 @@ Options:
188
189
  for (const info of result.agents) {
189
190
  const name = info.name;
190
191
  const personal = info.personalName || '—';
191
- const status = info.status || 'stopped';
192
+ const status = `${info.status || 'unknown'}${info.stale ? ' (stale)' : ''}`;
192
193
  const channels = info.channels?.length > 0 ? info.channels.join(', ') : '—';
193
194
  const project = info.projectPath ? path.basename(info.projectPath) : '—';
194
195
  const baseagent = info.baseagent || '—';
@@ -210,7 +211,7 @@ Options:
210
211
  默认: defaults 配置,否则检测本机可用基座
211
212
  --owner <aid> 默认: daemon.json 第一个 owner
212
213
  --name <display-name> 默认: package.json name,否则目录名
213
- --description <text> 默认: package.json description,否则留空
214
+ --description <text> 默认: package.json description,否则使用 EvolCore 默认描述
214
215
  --dry-run 只预览最终参数,不注册 AID、不写文件
215
216
  --force 覆盖已有 config.json
216
217
  --format json 输出 JSON
package/dist/cli/agent.js CHANGED
@@ -17,6 +17,7 @@ import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/p
17
17
  import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
18
18
  import { readTaskRuntimeContextFromEnv } from './task-context.js';
19
19
  import { isValidAid } from '../aun/aid/validation.js';
20
+ import { DEFAULT_AGENT_DESCRIPTION } from '../aun/aid/agentmd.js';
20
21
  function withStaticOwner(config, owner) {
21
22
  const value = owner?.trim();
22
23
  if (!value)
@@ -118,7 +119,7 @@ export function resolveAgentCreatePlan(options) {
118
119
  const owner = options.owner?.trim() || daemon.owners?.[0];
119
120
  const ownerSource = options.owner?.trim() ? 'argument' : owner ? 'daemon' : 'none';
120
121
  const name = options.name?.trim() || metadata.name || projectSlug(project);
121
- const description = options.description?.trim() || metadata.description || '';
122
+ const description = options.description?.trim() || metadata.description || DEFAULT_AGENT_DESCRIPTION;
122
123
  const configExists = isValidAid(aid)
123
124
  && fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
124
125
  return {
@@ -133,7 +134,7 @@ export function resolveAgentCreatePlan(options) {
133
134
  baseagentSource,
134
135
  ownerSource,
135
136
  nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
136
- descriptionSource: options.description?.trim() ? 'argument' : metadata.description ? 'package' : 'none',
137
+ descriptionSource: options.description?.trim() ? 'argument' : metadata.description ? 'package' : 'default',
137
138
  };
138
139
  }
139
140
  export function validateAgentCreatePlan(plan) {
@@ -221,49 +222,54 @@ function toPosix(p) {
221
222
  return p.replace(/\\/g, '/');
222
223
  }
223
224
  // ==================== agentList ====================
224
- export async function agentList() {
225
+ function toAgentListItem(info, stale = false) {
226
+ const storedStatus = info.status || 'unknown';
227
+ return {
228
+ aid: info.aid || info.name,
229
+ name: info.name,
230
+ personalName: info.personalName || null,
231
+ status: stale && storedStatus !== 'disabled' && storedStatus !== 'error' ? 'unknown' : storedStatus,
232
+ channels: info.channels || [],
233
+ projectPath: toPosix(info.projectPath || null),
234
+ baseagent: info.baseagent || null,
235
+ model: info.model || null,
236
+ lastActivity: info.lastActivity || null,
237
+ ...(stale ? { stale: true } : {}),
238
+ };
239
+ }
240
+ /**
241
+ * List agents from the live daemon when called externally. Core-owned callers
242
+ * can inject the already-loaded registry to avoid a socket round trip to self.
243
+ */
244
+ export async function agentList(registry) {
225
245
  const p = resolvePaths();
246
+ // Explicit injection is reserved for Core-owned callers and tests. The
247
+ // normal standalone CLI path below remains IPC-first.
248
+ if (registry) {
249
+ return { ok: true, agents: registry.list().map(info => toAgentListItem(info)) };
250
+ }
226
251
  // Try IPC first (running process has real status)
227
252
  try {
228
253
  const result = await ipcQuery(p.socket, { type: 'evolagent.list' });
229
254
  if (result && result.ok && result.agents) {
230
- const agents = result.agents.map((info) => ({
231
- aid: info.aid || info.name,
232
- name: info.name,
233
- personalName: info.personalName || null,
234
- status: info.status || 'stopped',
235
- channels: info.channels || [],
236
- projectPath: toPosix(info.projectPath || null),
237
- baseagent: info.baseagent || null,
238
- model: info.model || null,
239
- lastActivity: info.lastActivity || null,
240
- }));
255
+ const agents = result.agents.map((info) => toAgentListItem(info));
241
256
  return { ok: true, agents };
242
257
  }
243
258
  }
244
259
  catch { }
245
260
  // Cold mode: read from disk
246
261
  const { EvolAgentRegistry } = await import('../core/evolagent-registry.js');
247
- const registry = new EvolAgentRegistry(p.agentsDir);
248
- registry.loadAll();
249
- const agents = registry.list().map((info) => ({
250
- aid: info.aid || info.name,
251
- name: info.name,
252
- personalName: info.personalName || null,
253
- status: info.status || 'stopped',
254
- channels: info.channels || [],
255
- projectPath: toPosix(info.projectPath || null),
256
- baseagent: info.baseagent || null,
257
- model: info.model || null,
258
- lastActivity: info.lastActivity || null,
259
- }));
260
- return { ok: true, agents };
262
+ const diskRegistry = new EvolAgentRegistry(p.agentsDir);
263
+ diskRegistry.loadAll();
264
+ const agents = diskRegistry.list().map(info => toAgentListItem(info, true));
265
+ return { ok: true, agents, stale: true };
261
266
  }
262
267
  // ==================== agentShow ====================
263
268
  export async function agentShow(aid) {
264
269
  const p = resolvePaths();
265
270
  let agentInfo = null;
266
271
  let connectionInfo = null;
272
+ let stale = false;
267
273
  // Try IPC for live data
268
274
  try {
269
275
  const [showResp, aidsResp, statsResp] = await Promise.all([
@@ -301,6 +307,7 @@ export async function agentShow(aid) {
301
307
  catch { }
302
308
  // Cold mode fallback for agent info
303
309
  if (!agentInfo) {
310
+ stale = true;
304
311
  const { EvolAgentRegistry } = await import('../core/evolagent-registry.js');
305
312
  const registry = new EvolAgentRegistry(p.agentsDir);
306
313
  registry.loadAll();
@@ -313,7 +320,7 @@ export async function agentShow(aid) {
313
320
  agentInfo = {
314
321
  name: agent.name,
315
322
  aid: agent.aid || agent.name,
316
- status: agent.status,
323
+ status: agent.status === 'disabled' || agent.status === 'error' ? agent.status : 'unknown',
317
324
  baseagent: agent.baseagent,
318
325
  model: agent.model,
319
326
  effort: agent.effort,
@@ -330,7 +337,7 @@ export async function agentShow(aid) {
330
337
  return {
331
338
  ok: true,
332
339
  aid,
333
- status: agentInfo.status || 'stopped',
340
+ status: agentInfo.status || 'unknown',
334
341
  identity,
335
342
  config: {
336
343
  baseagent: agentInfo.baseagent || null,
@@ -350,6 +357,7 @@ export async function agentShow(aid) {
350
357
  project: toPosix(agentInfo.projectPath || null),
351
358
  data: toPosix(path.join(p.agentsDir, aid, 'data')),
352
359
  },
360
+ ...(stale ? { stale: true } : {}),
353
361
  };
354
362
  }
355
363
  export async function agentCreateInteractive(opts = {}) {
@@ -526,11 +534,7 @@ export async function agentCreateInteractive(opts = {}) {
526
534
  let agentmdUploaded = false;
527
535
  try {
528
536
  const { buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
529
- let content = buildInitialAgentMd({ aid });
530
- content = content.replace(/^name:\s*".*?"$/m, `name: "${agentName}"`);
531
- if (agentDescription) {
532
- content = content.replace(/^description:\s*".*?"$/m, `description: "${agentDescription}"`);
533
- }
537
+ const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription });
534
538
  const aunPath = process.env.AUN_HOME || defaultAunPath();
535
539
  // agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
536
540
  // Upload with retry (3 attempts, 2s delay between retries)
@@ -665,7 +669,7 @@ async function promptAgentOwnerManually(aid) {
665
669
  rl.close();
666
670
  }
667
671
  }
668
- export async function agentCreateNonInteractive(opts) {
672
+ export async function agentCreateNonInteractive(opts, runtime = {}) {
669
673
  const p = resolvePaths();
670
674
  const { isValidAid, aidCreate } = await import('../aun/aid/index.js');
671
675
  opts.onPhase?.('validating', 'begin');
@@ -772,13 +776,11 @@ export async function agentCreateNonInteractive(opts) {
772
776
  let agentmdUploaded = false;
773
777
  try {
774
778
  const { buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
775
- const agentName = opts.name || opts.aid.split('.')[0];
776
- const agentDescription = opts.description || '';
777
- let content = buildInitialAgentMd({ aid: opts.aid });
778
- content = content.replace(/^name:\s*".*?"$/m, `name: "${agentName}"`);
779
- if (agentDescription) {
780
- content = content.replace(/^description:\s*".*?"$/m, `description: "${agentDescription}"`);
781
- }
779
+ const content = buildInitialAgentMd({
780
+ aid: opts.aid,
781
+ name: opts.name,
782
+ description: opts.description,
783
+ });
782
784
  const aunPath = process.env.AUN_HOME || defaultAunPath();
783
785
  // agentmdPut 会写本地文件到 agentMdPath(aid) 并调用 publishAgentMd
784
786
  const MAX_ATTEMPTS = 3;
@@ -808,29 +810,37 @@ export async function agentCreateNonInteractive(opts) {
808
810
  console.warn(`⚠ agent.md generation failed: ${e?.message || e}`);
809
811
  opts.onPhase?.('uploading_agentmd', 'warn', `generation failed: ${e?.message || e}`);
810
812
  }
811
- // Attempt hot-load via IPC (if daemon is running).
812
- // Cold-starting a new agent (connecting AUN WebSocket) routinely takes
813
- // >3s, so use a generous timeout to avoid a false "service not running"
814
- // report while the daemon actually finishes bringing the agent online.
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.
815
816
  let hotLoaded = false;
816
817
  let hotLoadError;
817
818
  opts.onPhase?.('hot_loading', 'begin');
818
819
  try {
819
- const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid }, 30_000);
820
- if (ipcResult?.ok) {
820
+ if (runtime.hotLoadAgent) {
821
+ await runtime.hotLoadAgent(opts.aid);
821
822
  hotLoaded = true;
822
823
  opts.onPhase?.('hot_loading', 'done');
823
824
  }
824
- else if (ipcResult) {
825
- hotLoadError = ipcResult.error;
826
- opts.onPhase?.('hot_loading', 'warn', hotLoadError);
827
- }
828
825
  else {
829
- opts.onPhase?.('hot_loading', 'warn', 'daemon not running');
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
+ }
830
838
  }
831
839
  }
832
- catch {
833
- opts.onPhase?.('hot_loading', 'warn', 'daemon not running'); /* daemon not running */
840
+ catch (error) {
841
+ const message = error instanceof Error ? error.message : String(error);
842
+ hotLoadError = message;
843
+ opts.onPhase?.('hot_loading', 'warn', message);
834
844
  }
835
845
  return {
836
846
  ok: true,