evolcore 0.0.26 → 0.0.27

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 (169) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/bin/codex-managed-acl.ps1 +43 -0
  3. package/dist/agents/baseagent-availability.js +68 -0
  4. package/dist/agents/claude-runner.js +123 -22
  5. package/dist/agents/codex/app-server-client.js +63 -26
  6. package/dist/agents/codex-runner.js +316 -411
  7. package/dist/agents/ecagent-runner.js +170 -25
  8. package/dist/agents/gemini-runner.js +6 -0
  9. package/dist/agents/runner-types.js +50 -2
  10. package/dist/aun/aid/agentmd.js +73 -31
  11. package/dist/aun/aid/client.js +1 -1
  12. package/dist/aun/aid/control-aid.js +180 -1
  13. package/dist/aun/aid/identity.js +3 -3
  14. package/dist/aun/group/history.js +303 -0
  15. package/dist/aun/group/identity.js +43 -0
  16. package/dist/aun/group/index.js +5 -0
  17. package/dist/aun/{msg/group.js → group/operations.js} +161 -38
  18. package/dist/aun/{menu-client.js → menu/client.js} +12 -7
  19. package/dist/aun/menu/index.js +2 -0
  20. package/dist/aun/menu/transport.js +49 -0
  21. package/dist/aun/msg/index.js +2 -1
  22. package/dist/aun/msg/managed-operation.js +84 -18
  23. package/dist/aun/msg/mention-schema.js +51 -0
  24. package/dist/aun/msg/p2p.js +13 -8
  25. package/dist/aun/msg/upload.js +43 -88
  26. package/dist/aun/outbox.js +29 -7
  27. package/dist/aun/rpc/client.js +1 -0
  28. package/dist/aun/storage/client.js +39 -50
  29. package/dist/channels/aun.js +522 -233
  30. package/dist/channels/daemon.js +10 -6
  31. package/dist/cli/agent-command.js +108 -6
  32. package/dist/cli/agent-create.js +515 -2
  33. package/dist/cli/agent.js +109 -8
  34. package/dist/cli/aun-commands.js +191 -42
  35. package/dist/cli/config.js +8 -5
  36. package/dist/cli/contact.js +2 -2
  37. package/dist/cli/ctl-command.js +2 -2
  38. package/dist/cli/daemon-commands.js +35 -23
  39. package/dist/cli/diag.js +2 -2
  40. package/dist/cli/fs-command.js +3 -3
  41. package/dist/cli/handoff-command.js +6 -6
  42. package/dist/cli/index.js +8 -2
  43. package/dist/cli/init.js +34 -1
  44. package/dist/cli/managed-command-guard.js +2 -1
  45. package/dist/cli/menu-client.js +9 -5
  46. package/dist/cli/model.js +3 -3
  47. package/dist/cli/queue-command.js +2 -2
  48. package/dist/cli/response.js +2 -2
  49. package/dist/cli/restart-monitor.js +16 -2
  50. package/dist/cli/task-command.js +59 -0
  51. package/dist/cli/task-context.js +97 -49
  52. package/dist/cli/trigger-command.js +20 -10
  53. package/dist/config/builtin-roles.js +10 -0
  54. package/dist/config/config-field-policy.js +11 -0
  55. package/dist/config/config-manager.js +32 -4
  56. package/dist/config/config-operation-service.js +20 -5
  57. package/dist/config/contact-book-store.js +1 -1
  58. package/dist/config/contact-book.js +1 -1
  59. package/dist/config/contact-operation-service.js +1 -1
  60. package/dist/config/peer-role-resolver.js +1 -1
  61. package/dist/config/resolved-config-op.js +3 -0
  62. package/dist/config-store.js +1 -1
  63. package/dist/core/agent-application-service.js +5 -0
  64. package/dist/core/audit/event-key.js +17 -2
  65. package/dist/core/audit/log-integrity.js +34 -8
  66. package/dist/core/auth/agent-delegation.js +48 -14
  67. package/dist/core/auth/auth-gateway.js +2 -0
  68. package/dist/core/auth/authorization-audit.js +34 -38
  69. package/dist/core/auth/operation-authorizer.js +67 -5
  70. package/dist/core/auth/operation-catalog.js +110 -0
  71. package/dist/core/auth/remote-access-store.js +115 -9
  72. package/dist/core/bootstrap-messages.js +66 -7
  73. package/dist/core/bootstrap-service.js +110 -19
  74. package/dist/core/command/agent-control.js +88 -7
  75. package/dist/core/command/agent-storage-menu.js +443 -0
  76. package/dist/core/command/cli-intent-parser.js +19 -0
  77. package/dist/core/command/command-handler.js +76 -39
  78. package/dist/core/command/data-root-resolver.js +273 -0
  79. package/dist/core/command/group-menu.js +7 -2
  80. package/dist/core/command/menu-catalog.js +34 -4
  81. package/dist/core/command/menu-handler.js +348 -77
  82. package/dist/core/command/menu-protocol.js +40 -6
  83. package/dist/core/command/role-menu.js +2 -2
  84. package/dist/core/command/slash-handler.js +37 -22
  85. package/dist/core/event-catalog.js +4 -0
  86. package/dist/core/evolagent-registry.js +28 -2
  87. package/dist/core/group/invite-service.js +924 -0
  88. package/dist/core/interaction-router.js +22 -8
  89. package/dist/core/message/im-renderer.js +76 -15
  90. package/dist/core/message/message-bridge.js +94 -11
  91. package/dist/core/message/message-log.js +5 -3
  92. package/dist/core/message/message-queue.js +73 -41
  93. package/dist/core/message/response-engine.js +709 -117
  94. package/dist/core/permission/approval-gateway.js +36 -3
  95. package/dist/core/permission/ec-command-parser.js +61 -29
  96. package/dist/core/permission/protected-paths.js +134 -16
  97. package/dist/core/permission/sandbox-runtime.js +72 -3
  98. package/dist/core/permission/tool-error-code.js +15 -0
  99. package/dist/core/permission/tool-policy.js +7 -7
  100. package/dist/core/relation/peer-identity.js +57 -6
  101. package/dist/core/relation/shared-data.js +106 -0
  102. package/dist/core/role/runtime-policy.js +64 -0
  103. package/dist/core/runtime-lock.js +10 -26
  104. package/dist/core/session/runner-task-history.js +170 -0
  105. package/dist/core/session/session-manager.js +34 -6
  106. package/dist/core/session/session-mapper.js +41 -0
  107. package/dist/core/session/session-turn-coordinator.js +37 -7
  108. package/dist/core/session/session-turns.js +48 -7
  109. package/dist/core/task/task-recovery-service.js +176 -0
  110. package/dist/core/task/task-resume-operation.js +32 -0
  111. package/dist/eck/group-rules-sync.js +5 -3
  112. package/dist/eck/kit-renderer.js +1 -0
  113. package/dist/index.js +308 -54
  114. package/dist/ipc.js +141 -15
  115. package/dist/paths.js +17 -4
  116. package/dist/product.js +2 -0
  117. package/dist/trigger/event-source.js +19 -0
  118. package/dist/trigger/feedback.js +233 -40
  119. package/dist/trigger/parser.js +55 -5
  120. package/dist/trigger/patch.js +9 -0
  121. package/dist/trigger/scheduler.js +30 -4
  122. package/dist/trigger/validation.js +20 -3
  123. package/dist/utils/ecweb-utils.js +1 -0
  124. package/dist/utils/error-utils.js +40 -2
  125. package/dist/utils/logger.js +23 -13
  126. package/dist/utils/tool-summary.js +59 -3
  127. package/dist/utils/welcome.js +174 -1
  128. package/ecagent/dist/harness/agent-harness.js +3 -0
  129. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  130. package/kits/docs/INDEX.md +0 -6
  131. package/kits/docs/channels/aun.md +15 -2
  132. package/kits/docs/channels/feishu.md +1 -1
  133. package/kits/docs/context-assembly.md +29 -17
  134. package/kits/docs/evolcore/INDEX.md +8 -3
  135. package/kits/docs/evolcore/agent-create.md +39 -7
  136. package/kits/docs/evolcore/agent.md +33 -1
  137. package/kits/docs/evolcore/aid.md +9 -1
  138. package/kits/docs/evolcore/config.md +40 -1
  139. package/kits/docs/evolcore/group-collaboration.md +1 -1
  140. package/kits/docs/evolcore/group.md +117 -2
  141. package/kits/docs/evolcore/menu-client.md +16 -0
  142. package/kits/docs/evolcore/msg.md +3 -0
  143. package/kits/docs/evolcore/storage.md +3 -0
  144. package/kits/docs/evolcore/task.md +14 -0
  145. package/kits/docs/evolcore/trigger.md +51 -3
  146. package/kits/docs/venues/group.md +5 -0
  147. package/kits/eck_manifest.json +27 -0
  148. package/kits/rules/01-overview.md +11 -7
  149. package/kits/rules/04-relation.md +2 -1
  150. package/kits/rules/05-venue.md +1 -1
  151. package/kits/rules/06-channel.md +6 -4
  152. package/kits/schemas/agent-config.schema.12.json +25 -1
  153. package/kits/schemas/daemon.schema.6.json +2 -2
  154. package/kits/schemas/defaults.schema.5.json +1 -1
  155. package/kits/schemas/relation-config.schema.1.json +1 -1
  156. package/kits/schemas/relation-config.schema.5.json +1 -1
  157. package/kits/schemas/role-config.schema.1.json +14 -0
  158. package/kits/templates/roles/member.json +5 -0
  159. package/kits/templates/roles/visitor.json +5 -0
  160. package/kits/templates/system-fragments/baseagent.md +1 -1
  161. package/kits/templates/system-fragments/bootstrap.md +26 -9
  162. package/kits/templates/system-fragments/channel.md +8 -44
  163. package/kits/templates/system-fragments/commands.md +10 -2
  164. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  165. package/kits/templates/system-fragments/reply.md +56 -0
  166. package/package.json +7 -3
  167. package/dist/aun/group-identity.js +0 -9
  168. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  169. /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
@@ -23,7 +23,7 @@ import { displaySessionTitle } from '../core/session/session-title.js';
23
23
  import { isNonAgentSessionChannel } from '../core/system-channels.js';
24
24
  import { printCodeStats } from './code-stats.js';
25
25
  import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
26
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
26
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
27
27
  import { WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js';
28
28
  import { rotateStdoutLog } from '../utils/log-writer.js';
29
29
  import { inspectDataMigrationRequirement } from '../core/data-migration.js';
@@ -40,6 +40,8 @@ export function ensureCodexHookBeforeLifecycle(onRepaired) {
40
40
  try {
41
41
  const usesCodex = loadDefaults()?.active_baseagent === 'codex'
42
42
  || loadAllAgents().agents.some(agent => {
43
+ if (agent.enabled === false)
44
+ return false;
43
45
  try {
44
46
  return resolveEffective({ self: agent.aid }).active_baseagent === 'codex';
45
47
  }
@@ -146,7 +148,7 @@ function rejectPidIsolatedLifecycle(action, status, ping) {
146
148
  }
147
149
  async function tryDelegatedDaemonRestart(socketPath) {
148
150
  const sessionId = process.env.EVOLCORE_SESSION_ID;
149
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
151
+ const delegationToken = readDelegationCredential();
150
152
  if (!sessionId || !delegationToken)
151
153
  return false;
152
154
  const response = await ipcQuery(socketPath, {
@@ -2720,17 +2722,18 @@ function findAliveEcweb(p) {
2720
2722
  return alive[0] ?? null;
2721
2723
  }
2722
2724
  /**
2723
- * 轻量 HTTP 就绪探测:GET / 返回 2xx 即视为就绪。
2724
- * 不走 /api/pair-code(会触发配对码刷新副作用),不走 /api/health(不存在)。
2725
- * 根路径由 serveStatic 处理,返回 index.html,无副作用。
2725
+ * 轻量 HTTP 就绪探测:ECWeb 的健康端点必须返回明确的服务标识。
2726
+ * 不走 /api/pair-code(会触发配对码刷新副作用),也不依赖静态页面内容。
2726
2727
  */
2727
2728
  async function probeEcwebReady(port) {
2728
2729
  try {
2729
- const res = await fetch(`http://127.0.0.1:${port}/`, {
2730
- method: 'GET',
2730
+ const res = await fetch(`http://127.0.0.1:${port}/api/health`, {
2731
2731
  signal: AbortSignal.timeout(2000),
2732
2732
  });
2733
- return res.ok;
2733
+ if (!res.ok)
2734
+ return false;
2735
+ const body = await res.json();
2736
+ return body.ok === true && body.service === 'ecweb';
2734
2737
  }
2735
2738
  catch {
2736
2739
  return false;
@@ -2756,8 +2759,9 @@ async function waitForExistingEcweb(p, timeoutMs = 3_000) {
2756
2759
  }
2757
2760
  /**
2758
2761
  * 输出 ECWeb 状态。判定口径:
2759
- * 1. 进程是否存活(instance/ 下的 pid 文件 + isProcessRunning)
2760
- * 2. HTTP 是否就绪——探测根路径 /(serveStatic → index.html, 无副作用)。
2762
+ * 1. HTTP 是否就绪——探测 ECWeb 专用 /api/health 端点。
2763
+ * 2. 进程是否存活(instance/ 下的 pid 文件 + isProcessRunning)仅用于补充诊断;
2764
+ * 某些 CLI 运行在隔离 PID namespace 中,看不到宿主 ECWeb PID 是正常情况。
2761
2765
  */
2762
2766
  async function printEcwebStatus(p) {
2763
2767
  try {
@@ -2773,6 +2777,15 @@ async function printEcwebStatus(p) {
2773
2777
  // still provide an authoritative runtime status without local config access.
2774
2778
  }
2775
2779
  const entries = readEcwebInstanceEntries(p);
2780
+ // Probe before consulting PID visibility. The daemon and CLI can be in
2781
+ // different PID namespaces while sharing the host network namespace.
2782
+ let readyEntry;
2783
+ for (const entry of entries) {
2784
+ if (await probeEcwebReady(entry.record.port)) {
2785
+ readyEntry = entry;
2786
+ break;
2787
+ }
2788
+ }
2776
2789
  const aliveEntries = [];
2777
2790
  for (const entry of entries) {
2778
2791
  if (platform.isProcessRunning(entry.record.pid)) {
@@ -2781,22 +2794,21 @@ async function printEcwebStatus(p) {
2781
2794
  else {
2782
2795
  // A stale EC Web record must never be used to report the PID of an
2783
2796
  // unrelated process that later inherited the port.
2784
- try {
2785
- fs.unlinkSync(entry.filePath);
2797
+ // Keep a record whose dedicated health endpoint just proved live: the
2798
+ // PID may be hidden by a namespace boundary rather than actually dead.
2799
+ if (entry.filePath !== readyEntry?.filePath) {
2800
+ try {
2801
+ fs.unlinkSync(entry.filePath);
2802
+ }
2803
+ catch { }
2786
2804
  }
2787
- catch { }
2788
- }
2789
- }
2790
- let readyEntry;
2791
- for (const entry of aliveEntries) {
2792
- if (await probeEcwebReady(entry.record.port)) {
2793
- readyEntry = entry;
2794
- break;
2795
2805
  }
2796
2806
  }
2797
2807
  if (readyEntry) {
2798
2808
  console.log('');
2799
- console.log(`🔭 ECWeb: 运行中 (PID: ${readyEntry.record.pid}) http://localhost:${readyEntry.record.port}`);
2809
+ const pidVisible = aliveEntries.some(entry => entry.filePath === readyEntry.filePath);
2810
+ const pidText = pidVisible ? `PID: ${readyEntry.record.pid}` : `PID: ${readyEntry.record.pid}(当前 namespace 不可见)`;
2811
+ console.log(`🔭 ECWeb: 运行中 (${pidText}) http://localhost:${readyEntry.record.port}`);
2800
2812
  return;
2801
2813
  }
2802
2814
  const occupiedPids = new Set();
@@ -2991,7 +3003,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
2991
3003
  console.log(`✓ ECWeb ${actionLabel} (PID: ${pid}) http://localhost:${port}`);
2992
3004
  if (pair) {
2993
3005
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
2994
- console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,已配对过的浏览器无需重新配对)`);
3006
+ console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,已配对过的浏览器无需重新配对)`);
2995
3007
  }
2996
3008
  else {
2997
3009
  console.log(' daemon 尚未提供配对码;EvolCore 启动后可通过 /pair 或 ECWeb 页面获取');
@@ -3027,7 +3039,7 @@ async function printEcwebAccess(port) {
3027
3039
  }
3028
3040
  if (pair) {
3029
3041
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
3030
- console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,配对后远程访问 token 缓存 30 天)`);
3042
+ console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,token 缓存 7 天,有访问自动续期)`);
3031
3043
  }
3032
3044
  else {
3033
3045
  console.log(' 配对码: 暂不可用(稍后重试 ec watch web,或查看 logs/watch-web.log)');
package/dist/cli/diag.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ipcQuery } from '../ipc.js';
2
2
  import { resolvePaths } from '../paths.js';
3
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
3
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
4
4
  import { parseDiagArgs } from '../core/command/diag-service.js';
5
5
  import { wantsHelp } from './help.js';
6
6
  export async function cmdDiag(args) {
@@ -17,7 +17,7 @@ export async function cmdDiag(args) {
17
17
  type: 'diag', argv,
18
18
  ...(process.env.EVOLCORE_SESSION_ID ? {
19
19
  sessionId: process.env.EVOLCORE_SESSION_ID,
20
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
20
+ delegationToken: readDelegationCredential(),
21
21
  } : {}),
22
22
  }, 30_000) ?? { ok: false, code: 'DAEMON_UNAVAILABLE', message: 'daemon 未返回结果,请检查其运行状态;发送结果尚未确认' };
23
23
  }
@@ -5,8 +5,8 @@ import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
5
5
  import { agentmdGet, getAidStore, isValidAid, loadClient, SLOT } from '../aun/aid/index.js';
6
6
  import { ipcQuery } from '../ipc.js';
7
7
  import { resolvePaths } from '../paths.js';
8
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
9
- import { downloadGroupFsBytes } from '../aun/group-fs-download.js';
8
+ import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
9
+ import { downloadGroupFsBytes } from '../aun/group/index.js';
10
10
  class FsCliError extends Error {
11
11
  code;
12
12
  suggestion;
@@ -209,7 +209,7 @@ export async function cmdFs(args) {
209
209
  }
210
210
  async function runManagedFs(args, formatJson) {
211
211
  const sessionId = process.env.EVOLCORE_SESSION_ID;
212
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
212
+ const delegationToken = readDelegationCredential();
213
213
  const fail = (code, message) => {
214
214
  if (formatJson)
215
215
  console.log(JSON.stringify({ ok: false, code, error: message }));
@@ -4,7 +4,7 @@ import { ipcQuery } from '../ipc.js';
4
4
  import { HANDOFF_QUERY_DEFAULT_LIMIT, HANDOFF_QUERY_MAX_LIMIT, HANDOFF_STATES } from '../core/handoff/types.js';
5
5
  import { HANDOFF_ID_RE } from '../core/handoff/store.js';
6
6
  import { isHelpFlag, wantsHelp } from './help.js';
7
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
7
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
8
8
  function parseLimit(value) {
9
9
  const limit = Number(value);
10
10
  if (!value || !Number.isInteger(limit) || limit < 1 || limit > HANDOFF_QUERY_MAX_LIMIT) {
@@ -186,7 +186,7 @@ Commands:
186
186
  sessionId: process.env.EVOLCORE_SESSION_ID,
187
187
  handoffId: parsed.handoffId,
188
188
  content: parsed.content,
189
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
189
+ delegationToken: readDelegationCredential(),
190
190
  }, 5000);
191
191
  if (!result) {
192
192
  console.error('✗ daemon 暂时不可用');
@@ -216,7 +216,7 @@ Commands:
216
216
  sessionId: process.env.EVOLCORE_SESSION_ID,
217
217
  handoffId: parsed.handoffId,
218
218
  content: parsed.content,
219
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
219
+ delegationToken: readDelegationCredential(),
220
220
  }, 5000);
221
221
  if (!result) {
222
222
  console.error('✗ daemon 暂时不可用');
@@ -235,7 +235,7 @@ Commands:
235
235
  }
236
236
  const result = await ipcQuery(resolvePaths().socket, {
237
237
  type: 'handoff-status', sessionId: process.env.EVOLCORE_SESSION_ID, handoffId,
238
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
238
+ delegationToken: readDelegationCredential(),
239
239
  }, 5000);
240
240
  if (!result) {
241
241
  console.error('✗ daemon 暂时不可用');
@@ -267,7 +267,7 @@ Commands:
267
267
  state: parsed.state,
268
268
  filterSessionId: parsed.sessionId,
269
269
  limit: parsed.limit,
270
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
270
+ delegationToken: readDelegationCredential(),
271
271
  }, 5000);
272
272
  if (!result) {
273
273
  console.error('✗ daemon 暂时不可用');
@@ -310,7 +310,7 @@ Commands:
310
310
  agent: parsed.agent,
311
311
  handoffId: parsed.handoffId,
312
312
  limit: parsed.limit,
313
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
313
+ delegationToken: readDelegationCredential(),
314
314
  }, 5000);
315
315
  if (!result) {
316
316
  console.error('✗ daemon 暂时不可用');
package/dist/cli/index.js CHANGED
@@ -5,7 +5,7 @@ import fs from 'fs';
5
5
  import path from 'path';
6
6
  import { getPackageRoot, resolvePaths } from '../paths.js';
7
7
  import { ipcQuery } from '../ipc.js';
8
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
8
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
9
9
  import { cmdInit } from './init.js';
10
10
  import { cmdInitWechat, cmdInitFeishu, cmdInitDingtalk, cmdInitQQBot, cmdInitWecom, cmdInitAun } from './init-channel.js';
11
11
  import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
@@ -34,6 +34,7 @@ Agent 与会话:
34
34
  agent 管理 EvolAgent
35
35
  ctl 当前托管会话的控制命令
36
36
  queue 查询或操作 agent 消息队列
37
+ task 恢复暂停或异常中断的会话任务
37
38
  trigger 管理定时与事件触发器
38
39
  handoff 查询和完成跨会话回流
39
40
  model 查看或设置模型与推理强度
@@ -247,7 +248,7 @@ export async function main(args) {
247
248
  }
248
249
  if (process.env.EVOLCORE_SESSION_ID) {
249
250
  const sessionId = process.env.EVOLCORE_SESSION_ID;
250
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
251
+ const delegationToken = readDelegationCredential();
251
252
  const result = await ipcQuery(resolvePaths().socket, {
252
253
  type: 'status.auth', sessionId, delegationToken,
253
254
  });
@@ -328,6 +329,11 @@ export async function main(args) {
328
329
  case 'queue':
329
330
  await cmdQueue(args.slice(1));
330
331
  break;
332
+ case 'task': {
333
+ const { cmdTask } = await import('./task-command.js');
334
+ await cmdTask(args.slice(1));
335
+ break;
336
+ }
331
337
  case 'trigger':
332
338
  {
333
339
  const { cmdTrigger } = await import('./trigger-command.js');
package/dist/cli/init.js CHANGED
@@ -7,7 +7,7 @@ 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
9
  import { ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
10
- import { generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
10
+ import { ensureControlAgentMd, generateControlAid, resolveControlAidDomain } from '../aun/aid/control-aid.js';
11
11
  import { getCodexAppServerAvailability } from '../agents/codex-runner.js';
12
12
  import { DEFAULT_ECAGENT_BASE_URL, resolveEcagentConfig } from '../agents/baseagent.js';
13
13
  import { defaultProjectsRoot } from '../utils/project-path.js';
@@ -484,6 +484,12 @@ export async function initTail(options = {}) {
484
484
  let ownerBindingInterrupted = false;
485
485
  if (daemonConfig.aid) {
486
486
  console.log(`✓ 控制 AID 已存在: ${daemonConfig.aid}`);
487
+ try {
488
+ await ensureControlAgentMd(daemonConfig.aid);
489
+ }
490
+ catch (e) {
491
+ console.error(`⚠️ 控制 AID agent.md 补全失败(本次继续,后续启动会重试): ${e?.message || e}`);
492
+ }
487
493
  }
488
494
  else {
489
495
  try {
@@ -861,6 +867,33 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
861
867
  fail('CONTROL_AID_CREATE_FAILED', `control AID creation failed: ${e?.message || e}`, EXIT_RUNTIME, format);
862
868
  }
863
869
  }
870
+ if (controlAid) {
871
+ const certPath = path.join(resolvePaths().root, 'AIDs', controlAid, 'public', 'cert.pem');
872
+ if (!fs.existsSync(certPath)) {
873
+ // An externally supplied/pre-created AID without a local certificate
874
+ // cannot be signed or uploaded by this process. Avoid entering the SDK
875
+ // network path during non-interactive init; later daemon startup can
876
+ // retry once the identity material is provisioned.
877
+ console.error(`control AID agent.md publish skipped: local certificate not found for ${controlAid}`);
878
+ }
879
+ else {
880
+ try {
881
+ await ensureControlAgentMd(controlAid);
882
+ }
883
+ catch (e) {
884
+ // A registered control AID remains usable when the Name Service is
885
+ // temporarily unavailable; startup and the next init retry publication.
886
+ if (format === 'json') {
887
+ // Keep the successful init result machine-readable; surface the
888
+ // warning through stderr so stdout remains valid JSON.
889
+ console.error(`control AID agent.md publish warning: ${e?.message || e}`);
890
+ }
891
+ else {
892
+ console.error(`⚠️ 控制 AID agent.md 补全失败(本次继续,后续启动会重试): ${e?.message || e}`);
893
+ }
894
+ }
895
+ }
896
+ }
864
897
  // ── 9. 写 daemon.json(aid + owners + ecweb)──
865
898
  try {
866
899
  const next = {
@@ -20,6 +20,7 @@ const MANAGED_TASK_COMMANDS = new Set([
20
20
  'stats',
21
21
  'status',
22
22
  'storage',
23
+ 'task',
23
24
  'trigger',
24
25
  'version',
25
26
  '-v',
@@ -30,7 +31,7 @@ export class ManagedCommandNotAllowedError extends Error {
30
31
  command;
31
32
  code = 'NOT_ALLOWED';
32
33
  constructor(command) {
33
- super(`Command ${command} is not available in a managed Agent task`);
34
+ super(`Command ${command} is not available in a managed Agent task; run it from the host terminal after the task completes`);
34
35
  this.command = command;
35
36
  this.name = 'ManagedCommandNotAllowedError';
36
37
  }
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import { getArgValue, wantsHelp } from './help.js';
3
- import { executeMenuClientRequest, MenuClientError } from '../aun/menu-client.js';
4
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
3
+ import { executeMenuClientRequest, MenuClientError } from '../aun/menu/index.js';
4
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
5
5
  function parseDurationMs(value) {
6
6
  if (value === undefined)
7
7
  return undefined;
@@ -94,12 +94,16 @@ export async function cmdMenuClient(args) {
94
94
  }
95
95
  let response;
96
96
  if (process.env.EVOLCORE_SESSION_ID) {
97
- const { ipcQuery } = await import('../ipc.js');
97
+ const { ipcQuery, IpcTransportError } = await import('../ipc.js');
98
98
  const { resolvePaths } = await import('../paths.js');
99
99
  const result = await ipcQuery(resolvePaths().socket, {
100
100
  type: 'menu-client.request', argv: args, sessionId: process.env.EVOLCORE_SESSION_ID,
101
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
102
- }, 250_000);
101
+ delegationToken: readDelegationCredential(),
102
+ }, 250_000, { throwOnError: true }).catch(error => {
103
+ if (!(error instanceof IpcTransportError))
104
+ throw error;
105
+ throw new MenuClientError(error.code, error.message);
106
+ });
103
107
  if (!result?.ok)
104
108
  throw new MenuClientError(result?.code ?? 'DAEMON_UNAVAILABLE', result?.error ?? 'Managed Menu daemon is unavailable');
105
109
  response = result.response;
package/dist/cli/model.js CHANGED
@@ -20,7 +20,7 @@ import { ipcQuery } from '../ipc.js';
20
20
  import { parsePeerKey } from '../core/relation/peer-identity.js';
21
21
  import { resolvePeerRoleDetail } from '../config/peer-role-resolver.js';
22
22
  import { getFieldPermission } from '../config/roles.js';
23
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
23
+ import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
24
24
  import { formatModelCheck, runModelCheck } from '../core/model/model-diagnostics.js';
25
25
  import { validateRuntimeStringFieldOverride } from '../core/role/runtime-policy.js';
26
26
  const ALL_EFFORTS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'auto'];
@@ -61,7 +61,7 @@ async function runCtlCommand(cmd, formatJson, timeoutMs = 10_000) {
61
61
  type: 'ctl',
62
62
  cmd,
63
63
  sessionId,
64
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
64
+ delegationToken: readDelegationCredential(),
65
65
  }, timeoutMs);
66
66
  if (!result)
67
67
  fail(formatJson, 'DAEMON_UNAVAILABLE', '无法连接 evolcore 服务');
@@ -80,7 +80,7 @@ async function runManagedConfigOperation(args, formatJson) {
80
80
  const sessionId = process.env.EVOLCORE_SESSION_ID;
81
81
  if (!sessionId)
82
82
  fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID 未设置');
83
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
83
+ const delegationToken = readDelegationCredential();
84
84
  if (!delegationToken) {
85
85
  fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} 未设置`);
86
86
  }
@@ -1,6 +1,6 @@
1
1
  import { resolvePaths } from '../paths.js';
2
2
  import { ipcQuery } from '../ipc.js';
3
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
3
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
4
4
  import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
5
5
  export async function cmdQueue(args) {
6
6
  if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
@@ -98,7 +98,7 @@ JSON 时间字段:
98
98
  after,
99
99
  before,
100
100
  sessionId: managed,
101
- delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
101
+ delegationToken: readDelegationCredential(),
102
102
  } : {
103
103
  type: 'queue-snapshot',
104
104
  agent,
@@ -17,7 +17,7 @@ import { ResponseModeRegistry } from '../response-system/registry.js';
17
17
  import { registerBuiltinModes } from '../response-system/modes/index.js';
18
18
  import { ipcQuery } from '../ipc.js';
19
19
  import { resolvePaths } from '../paths.js';
20
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
20
+ import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
21
21
  const RESPONSE_MODE_FIELD = 'responseMode';
22
22
  const RESPONSE_MODE_PARAMS_FIELD = 'responseModeParams';
23
23
  /**
@@ -59,7 +59,7 @@ function fail(formatJson, code, message) {
59
59
  }
60
60
  async function managedConfig(fieldArgs, formatJson) {
61
61
  const sessionId = process.env.EVOLCORE_SESSION_ID;
62
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
62
+ const delegationToken = readDelegationCredential();
63
63
  if (!sessionId)
64
64
  fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
65
65
  if (!delegationToken)
@@ -17,6 +17,8 @@ import { inspectDataMigrationRequirement } from '../core/data-migration.js';
17
17
  import { DAEMON_SHUTDOWN_TIMEOUT_MS, requestDaemonShutdown } from './daemon-commands.js';
18
18
  import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
19
19
  const execFileAsync = promisify(execFile);
20
+ // Bound network notifications so they cannot hold up recovery after shutdown.
21
+ const OWNER_NOTIFICATION_TIMEOUT_MS = 5000;
20
22
  /**
21
23
  * The package this monitor operates on, which is not always the one it runs
22
24
  * from.
@@ -480,6 +482,18 @@ async function sendHealSummary(p, attempts, log) {
480
482
  function sleep(ms) {
481
483
  return new Promise(resolve => setTimeout(resolve, ms));
482
484
  }
485
+ function withTimeout(promise, timeoutMs) {
486
+ let timer;
487
+ const timeout = new Promise((_, reject) => {
488
+ timer = setTimeout(() => reject(new Error(`timeout after ${timeoutMs}ms`)), timeoutMs);
489
+ // Keep the monitor alive until recovery can resume, even if the SDK's
490
+ // pending operation has no referenced handles of its own.
491
+ });
492
+ return Promise.race([promise, timeout]).finally(() => {
493
+ if (timer)
494
+ clearTimeout(timer);
495
+ });
496
+ }
483
497
  function normalizePath(value) {
484
498
  return value.replace(/[\\/]+/g, '/').toLowerCase();
485
499
  }
@@ -1009,12 +1023,12 @@ async function notifyDaemonOwners(p, message, log) {
1009
1023
  const text = formatDaemonOwnerNotice(p, message);
1010
1024
  for (const owner of validOwners) {
1011
1025
  try {
1012
- const result = await msgSend({
1026
+ const result = await withTimeout(msgSend({
1013
1027
  from: daemonAid,
1014
1028
  to: owner,
1015
1029
  body: { mode: 'text', text },
1016
1030
  slotId: 'restart-monitor',
1017
- });
1031
+ }), OWNER_NOTIFICATION_TIMEOUT_MS);
1018
1032
  if (!result.ok) {
1019
1033
  log(`Daemon owner notification failed for ${owner}: ${result.error}`);
1020
1034
  continue;
@@ -0,0 +1,59 @@
1
+ import { resolvePaths } from '../paths.js';
2
+ import { ipcQuery } from '../ipc.js';
3
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
4
+ import { wantsHelp } from './help.js';
5
+ const TASK_HELP = `用法: ec task resume <sessionId> [--format json]
6
+
7
+ 恢复指定 EvolCore 会话的暂停任务或异常中断任务。
8
+ 暂停时释放工具门控;异常中断时继续原 baseagent 会话。
9
+ 已完成、正在执行或等待必要输入/审批的任务不会重复启动。
10
+
11
+ 独立 CLI 使用本地 control token;托管任务使用当前会话的 delegation,
12
+ 需有 Agent 管理权限,普通托管任务只能恢复本 Agent 的会话。`;
13
+ export async function cmdTask(args) {
14
+ if (!args.length || wantsHelp(args)) {
15
+ console.log(TASK_HELP);
16
+ return;
17
+ }
18
+ const json = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
19
+ const printError = (code, error) => {
20
+ if (json)
21
+ console.log(JSON.stringify({ ok: false, code, error }));
22
+ else
23
+ console.error(error);
24
+ process.exitCode = 1;
25
+ };
26
+ const targetSessionId = args[1]?.trim();
27
+ if (args[0] !== 'resume' || !targetSessionId || targetSessionId.startsWith('-')
28
+ || !(args.length === 2 || (args.length === 4 && args[2] === '--format' && args[3] === 'json'))) {
29
+ printError('INVALID_ARGUMENT', TASK_HELP);
30
+ return;
31
+ }
32
+ const sessionId = process.env.EVOLCORE_SESSION_ID;
33
+ const delegationToken = readDelegationCredential();
34
+ if (sessionId !== undefined && !sessionId.trim()) {
35
+ printError('INVALID_DELEGATION', 'EVOLCORE_SESSION_ID 不能为空');
36
+ return;
37
+ }
38
+ if (sessionId && !delegationToken) {
39
+ printError('DELEGATION_REQUIRED', '托管任务缺少 delegation token');
40
+ return;
41
+ }
42
+ const result = await ipcQuery(resolvePaths().socket, {
43
+ type: 'task.resume',
44
+ targetSessionId,
45
+ ...(sessionId ? { sessionId, delegationToken } : {}),
46
+ }, 10_000);
47
+ if (!result) {
48
+ printError('IPC_UNAVAILABLE', '无法连接 EvolCore 服务;请查询任务状态后再决定是否重试');
49
+ return;
50
+ }
51
+ if (json)
52
+ console.log(JSON.stringify(result));
53
+ else if ('message' in result)
54
+ console.log(result.message);
55
+ else
56
+ console.error(result.error);
57
+ if (!result.ok)
58
+ process.exitCode = 1;
59
+ }