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
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import { CodexSessionFileAdapter } from './core/session/adapters/codex-session-f
14
14
  import { GeminiSessionFileAdapter } from './core/session/adapters/gemini-session-file-adapter.js';
15
15
  import { EcagentSessionFileAdapter } from './core/session/adapters/ecagent-session-file-adapter.js';
16
16
  import { autoMigrateIfNeeded, loadDefaults, loadAllAgents, migrateIdentitiesIfNeeded, loadDaemonConfig, initializeEckSnapshotsConfig, isFullAccessEnabled } from './config-store.js';
17
+ import { migrateRelationSharedDirectories } from './core/relation/shared-data.js';
17
18
  import { DEFAULT_ECWEB_PORT, ecwebService } from './config/daemon-services.js';
18
19
  import { ConfigTarget, initConfigManager, onConfigWrite, read as readConfig, shouldFailFastForMissingOwners } from './config/config-manager.js';
19
20
  import { ensureRoleConfigV4OnStartup, ensureRoleConfigV5OnStartup } from './config/role-migration-startup.js';
@@ -53,6 +54,8 @@ import { BootstrapService, completeBootstrapWithWelcome } from './core/bootstrap
53
54
  import { postBootstrapWelcomeOperationId } from './core/bootstrap-messages.js';
54
55
  import { MessageCache } from './core/message/message-cache.js';
55
56
  import { CommandHandler, isProcessLevelOwner } from './core/command/command-handler.js';
57
+ import { executeLocalInitializationCommand, AgentInitializationService, hasSuppliedInitialization, readInitialization, parseInitializationArgs, parseAgentWelcomeArgs, resolveInitializationPlan, } from './cli/agent-create.js';
58
+ import { loadAgent } from './config-store.js';
56
59
  import { AgentApplicationService } from './core/agent-application-service.js';
57
60
  import { EventBus } from './core/event-bus.js';
58
61
  import { eventPatternIncludesInternal, getEventCatalog } from './core/event-catalog.js';
@@ -60,12 +63,13 @@ import { StatsCollector } from './utils/stats.js';
60
63
  import { AidStatsCollector } from './utils/stats.js';
61
64
  import { PermissionGateway } from './core/permission/approval-gateway.js';
62
65
  import { InteractionRouter, registerAdapterInteractions } from './core/interaction-router.js';
66
+ import { GroupInviteReviewService } from './core/group/invite-service.js';
63
67
  import { AgentDelegationRegistry, authorizeDelegatedAunMsgSend, hasTrustedFullAccessDelegation, trustedExecutionIdentityInput, } from './core/auth/agent-delegation.js';
64
68
  import { authorizeOperation, buildAuthSubject, canApprovePersistentFullAccessTrigger, isCrossAgentTriggerOperationAllowed, } from './core/auth/auth-gateway.js';
65
69
  import { authorizationDenialData, formatAuthorizationDenial } from './core/auth/authorization-denial.js';
66
70
  import { auditFullAccessEvent } from './core/auth/authorization-audit.js';
67
71
  import { parsePeerKey } from './core/relation/peer-identity.js';
68
- import { isHClassPath } from './core/permission/protected-paths.js';
72
+ import { isHClassPath, isSameOrDescendant } from './core/permission/protected-paths.js';
69
73
  import { ChannelLoader, tryParseChannelKey } from './core/channel-loader.js';
70
74
  import { AgentLoader } from './core/baseagent-loader.js';
71
75
  import { EvolAgentRegistry } from './core/evolagent-registry.js';
@@ -73,6 +77,8 @@ import { createRunnerReloadTransaction, disposeAgentInstances } from './core/run
73
77
  import { AgentReloadBusyError, AgentReloadCoordinator } from './core/agent-reload-coordinator.js';
74
78
  import { buildReloadHooks } from './core/channel-loader.js';
75
79
  import { IpcServer } from './ipc.js';
80
+ import { executeTaskResume } from './core/task/task-resume-operation.js';
81
+ import { TASK_RECOVERY_PROMPT } from './core/task/task-recovery-service.js';
76
82
  import { logger, setLogLevel } from './utils/logger.js';
77
83
  import { remoteAccessService } from './core/auth/remote-access-store.js';
78
84
  import { DiagService, executeDiagIpc } from './core/command/diag-service.js';
@@ -98,6 +104,7 @@ import { DAEMON_RUNTIME_EPOCH_ENV, ensureProcessManagedTempDir } from './cli/tas
98
104
  import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
99
105
  import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
100
106
  import { MAIN_PACKAGE_NAME } from './product.js';
107
+ import { sanitizeMenuLogValue } from './core/command/menu-protocol.js';
101
108
  import fs from 'fs';
102
109
  import crypto from 'crypto';
103
110
  import { fileURLToPath } from 'url';
@@ -529,6 +536,51 @@ main().catch((error) => {
529
536
  atomicWriteJson(manager.definitionPath(definition.id), definition);
530
537
  fs.rmSync(manager.activePath(definition.id), { force: true });
531
538
  }
539
+ /**
540
+ * Keep one daemon-owned recovery Trigger for all local Agent sessions. The
541
+ * event-session feedback path resolves the owning Agent from task:error rather
542
+ * than treating the daemon AID as the target Agent.
543
+ */
544
+ function seedTaskRecoveryTrigger(manager, owner) {
545
+ const now = Date.now();
546
+ const definition = normalizeTriggerDefinition({
547
+ $schema_version: 3.1,
548
+ id: '__task-recovery',
549
+ agentAid: owner.aid,
550
+ enabled: true,
551
+ name: '__task-recovery',
552
+ description: 'System trigger: recover failed tasks for local Agents.',
553
+ createdAt: now,
554
+ updatedAt: now,
555
+ origin: {
556
+ channelKey: 'daemon',
557
+ channelType: 'daemon',
558
+ channelId: owner.originPeerId || owner.aid,
559
+ session: 'main',
560
+ peerId: owner.originPeerId || owner.aid,
561
+ sessionKey: `daemon#${owner.originPeerId || owner.aid}#__task-recovery__`,
562
+ },
563
+ source: {
564
+ type: 'event',
565
+ eventPattern: 'task:error',
566
+ },
567
+ execution: {
568
+ type: 'target_session',
569
+ prompt: TASK_RECOVERY_PROMPT,
570
+ onError: 'retry',
571
+ noopSentinel: '[[NOOP]]',
572
+ },
573
+ feedback: { strategy: 'event_session' },
574
+ reliability: {
575
+ concurrency: 'forbid',
576
+ missedPolicy: 'run_once',
577
+ retry: { maxAttempts: 2, backoffMs: 30_000 },
578
+ },
579
+ });
580
+ fs.mkdirSync(manager.triggerDir(definition.id), { recursive: true });
581
+ atomicWriteJson(manager.definitionPath(definition.id), definition);
582
+ fs.rmSync(manager.activePath(definition.id), { force: true });
583
+ }
532
584
  function removeLegacyAgentUpgradeCheck(manager) {
533
585
  let existing;
534
586
  try {
@@ -957,6 +1009,10 @@ async function main() {
957
1009
  }
958
1010
  // ── 自动迁移 ──
959
1011
  migrateIdentitiesIfNeeded();
1012
+ const relationSharedMigration = migrateRelationSharedDirectories();
1013
+ if (relationSharedMigration.copied > 0) {
1014
+ logger.info(`[migrate] Synced ${relationSharedMigration.copied} relation shared file(s) across ${relationSharedMigration.relations} relation(s)`);
1015
+ }
960
1016
  // daemon.json 的旧 ecweb/serviceProxy 结构已在启动前归一化为 services[]。
961
1017
  // ── 配置体系初始化(schema 字段不相交硬约束校验)──
962
1018
  try {
@@ -1239,6 +1295,11 @@ async function main() {
1239
1295
  });
1240
1296
  // 交互路由器
1241
1297
  const interactionRouter = new InteractionRouter();
1298
+ const groupInviteReviewService = new GroupInviteReviewService(interactionRouter);
1299
+ const removeGroupInviteConfigListener = onConfigWrite(({ target, selector }) => {
1300
+ if (target === ConfigTarget.Agent && selector.self)
1301
+ groupInviteReviewService.configurationChanged(selector.self);
1302
+ });
1242
1303
  // 为所有支持权限的 agent 设置 gateway
1243
1304
  for (const inst of agentInstances) {
1244
1305
  inst.agent.setPermissionGateway?.(permissionGateway);
@@ -1327,6 +1388,7 @@ async function main() {
1327
1388
  // 创建命令处理器
1328
1389
  const cmdHandler = new CommandHandler(sessionManager, agentMap, messageCache, eventBus, primaryRunnerKey);
1329
1390
  let agentApplicationService;
1391
+ let agentInitializationService;
1330
1392
  cmdHandler.setAgentDelegationRegistry(agentDelegationRegistry);
1331
1393
  cmdHandler.setPermissionGateway(permissionGateway);
1332
1394
  cmdHandler.setInteractionRouter(interactionRouter);
@@ -1372,10 +1434,13 @@ async function main() {
1372
1434
  dedupPath: daemonMessageDedupPath(),
1373
1435
  });
1374
1436
  // 设置中断回调(精确中断正在处理的 agent)
1375
- messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
1437
+ messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message', timeout) => {
1376
1438
  void baseagent;
1377
1439
  void evolagentName;
1378
- await responseEngine.interruptSession(sessionKey, reason);
1440
+ if (timeout)
1441
+ await responseEngine.timeoutSession(sessionKey, timeout);
1442
+ else
1443
+ await responseEngine.interruptSession(sessionKey, reason);
1379
1444
  });
1380
1445
  messageQueue.setEventBus(eventBus);
1381
1446
  // Restore persisted input before Trigger schedulers start. Trigger-owned work
@@ -1531,7 +1596,7 @@ async function main() {
1531
1596
  };
1532
1597
  };
1533
1598
  const validateTriggerFeedbackChannels = (definition) => {
1534
- if (definition.feedback.strategy === 'silent')
1599
+ if (definition.feedback.strategy === 'silent' || definition.feedback.strategy === 'event_session')
1535
1600
  return;
1536
1601
  const target = definition.feedback.strategy === 'target'
1537
1602
  ? definition.feedback.target
@@ -1614,6 +1679,9 @@ async function main() {
1614
1679
  if (!effortDecision.ok)
1615
1680
  throw new Error(effortDecision.message || 'trigger effort is not allowed by current role');
1616
1681
  }
1682
+ if (!actor.management && definition.feedback.strategy === 'event_session') {
1683
+ throw new Error('event-session feedback requires owner/admin');
1684
+ }
1617
1685
  if (!actor.management && definition.feedback.strategy === 'target') {
1618
1686
  const target = definition.feedback.target;
1619
1687
  const origin = actor.origin;
@@ -1721,6 +1789,9 @@ async function main() {
1721
1789
  if (privilegedReason && !persistedFullAccessApproval && !hasDaemonTriggerAuthority(subject)) {
1722
1790
  return { allowed: false, reason: `${privilegedReason} requires current DaemonOwner` };
1723
1791
  }
1792
+ if (definition.feedback.strategy === 'event_session' && !isManagementRole(role)) {
1793
+ return { allowed: false, reason: 'event-session feedback requires current owner/admin role' };
1794
+ }
1724
1795
  if (definition.feedback.strategy === 'target' && !isManagementRole(role)) {
1725
1796
  const target = definition.feedback.target;
1726
1797
  if (!target
@@ -1830,6 +1901,7 @@ async function main() {
1830
1901
  const manager = new TriggerDefinitionManager(owner.aid);
1831
1902
  if (opts.seedUpgradeCheck) {
1832
1903
  seedUpgradeCheckTrigger(manager, owner);
1904
+ seedTaskRecoveryTrigger(manager, owner);
1833
1905
  }
1834
1906
  else {
1835
1907
  removeLegacyAgentUpgradeCheck(manager);
@@ -1840,6 +1912,8 @@ async function main() {
1840
1912
  getChannel: getTriggerChannel,
1841
1913
  sessionManager,
1842
1914
  messageQueue,
1915
+ recoverTask: request => responseEngine.recoverTask(request),
1916
+ inspectTargetExecution: (sessionId, attemptId, selfAid) => responseEngine.inspectTargetExecution(sessionId, attemptId, selfAid),
1843
1917
  eventBus,
1844
1918
  tryHandoff: async (input, text, target, binding) => {
1845
1919
  if (input.signal?.aborted) {
@@ -1956,9 +2030,21 @@ async function main() {
1956
2030
  const inst = channelInstances.find(candidate => candidate.adapter.channelKey === channelKey);
1957
2031
  return !!inst && inst.channel.getStatus?.().connected === true;
1958
2032
  };
2033
+ cmdHandler.setAgentStorageClientResolver((channelKey, targetAid) => {
2034
+ const inst = channelInstances.find(candidate => candidate.channelType === 'aun'
2035
+ && (candidate.adapter.channelKey === channelKey || candidate.adapter.channelName === channelKey)
2036
+ && candidate.channel.getAid?.() === targetAid);
2037
+ if (!inst || inst.channel.getStatus?.().connected !== true)
2038
+ return undefined;
2039
+ // A reconnect replaces the Client; never capture it during startup.
2040
+ const client = inst.channel.getClient?.();
2041
+ return client?.aid === targetAid ? client : undefined;
2042
+ });
1959
2043
  const msgBridge = new MessageBridge(defaultProjectPath, sessionManager, processor, messageQueue, cmdHandler, eventBus, primaryAgent?.config.debounce, () => processLevelOwners);
1960
2044
  msgBridge.setAgentRegistry(agentRegistry);
1961
2045
  msgBridge.setInteractionRouter(interactionRouter);
2046
+ msgBridge.setGroupInviteReviewService(groupInviteReviewService);
2047
+ cmdHandler.setGroupInviteDecisionResolver((selfAid, ownerAid, inviteId, action) => groupInviteReviewService.decideManaged(selfAid, ownerAid, inviteId, action));
1962
2048
  msgBridge.setContactBindRuntimeChecker(isContactBindChannelReady);
1963
2049
  msgBridge.setAidStatsCollector(aidStatsCollector);
1964
2050
  cmdHandler.setContactRequestSubmitter((input) => msgBridge.submitAgentContactRequest(input));
@@ -1982,7 +2068,7 @@ async function main() {
1982
2068
  sessionId: envelope.sessionId,
1983
2069
  agentAid: owningAgent?.aid,
1984
2070
  agentName: envelope.agentName,
1985
- payload: summarizeOutboundPayload(payload),
2071
+ payload: sanitizeMenuLogValue(summarizeOutboundPayload(payload)),
1986
2072
  });
1987
2073
  const result = await originalSend(envelope, payload);
1988
2074
  // AUN adapters return an explicit receipt. Only a receipt with a remote
@@ -2552,7 +2638,10 @@ async function main() {
2552
2638
  catch {
2553
2639
  parsed = null;
2554
2640
  }
2555
- const menuResponseContext = () => controlReplyContext(opts, evolMenuResponseTransportMetadata());
2641
+ const menuResponseContext = () => ({
2642
+ ...controlReplyContext(opts, evolMenuResponseTransportMetadata(opts.protectedHeaders?.sdk_version)),
2643
+ ...(opts.peerDeviceId ? { toDeviceId: opts.peerDeviceId } : {}),
2644
+ });
2556
2645
  const sendControlMenuResponse = async (response) => {
2557
2646
  const timedResponse = withMenuProcessingTime(enforceMenuResponseSize(response, 128 * 1024 - 1024), menuTiming);
2558
2647
  const request = activeMenuRequest ?? {
@@ -2637,9 +2726,9 @@ async function main() {
2637
2726
  return;
2638
2727
  }
2639
2728
  if (text.toLowerCase() === '/pair') {
2640
- const pair = remoteAccessService.getPairingCode(opts.peerId);
2729
+ const pair = remoteAccessService.getPairingCode(opts.peerId, Date.now(), 'pair');
2641
2730
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
2642
- const reply = `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效)`;
2731
+ const reply = `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效,仅可配对一次)`;
2643
2732
  await controlChannel.sendMessage(opts.channelId, reply, controlReplyContext(opts));
2644
2733
  return;
2645
2734
  }
@@ -2650,7 +2739,7 @@ async function main() {
2650
2739
  await sendControlMenuResponse(menuFailure({ id: menuControl.id, ...(menuControl.name?.trim() ? { name: menuControl.name } : {}) }, validationError));
2651
2740
  return;
2652
2741
  }
2653
- const deduped = await controlMenuDeduper.execute([opts.channelId, opts.peerId, menuControl.id].join('\u001f'), menuPayloadFingerprint(menuControl.raw), () => cmdHandler.execMenuForControl(parsed, opts.peerId, {
2742
+ const deduped = await controlMenuDeduper.execute([opts.channelId, opts.peerId, opts.peerDeviceId || '', menuControl.id].join('\u001f'), menuPayloadFingerprint(menuControl.raw), () => cmdHandler.execMenuForControl(parsed, opts.peerId, {
2654
2743
  encrypted: opts.encrypted,
2655
2744
  protectedHeaders: opts.protectedHeaders,
2656
2745
  }));
@@ -2848,6 +2937,41 @@ async function main() {
2848
2937
  });
2849
2938
  }
2850
2939
  }
2940
+ async function completeAgentBootstrap(aid) {
2941
+ const aunInstance = channelInstances.find(candidate => {
2942
+ if (candidate.channelType !== 'aun')
2943
+ return false;
2944
+ const owner = agentRegistry.resolveByChannel(candidate.adapter.channelKey)
2945
+ ?? agentRegistry.resolveByChannel(candidate.adapter.channelName);
2946
+ return owner?.aid === aid;
2947
+ });
2948
+ const welcome = aunInstance?.channel;
2949
+ const owningAgent = agentRegistry.get(aid);
2950
+ const firstOwnerAid = getFirstStaticAgentOwner(aid);
2951
+ const sessions = aunInstance && firstOwnerAid && owningAgent
2952
+ ? {
2953
+ ensurePostBootstrapMainSession: async (owner) => {
2954
+ const ownerAid = owner || firstOwnerAid;
2955
+ const channel = aunInstance.adapter.channelName;
2956
+ const active = await sessionManager.getActiveSession(channel, ownerAid);
2957
+ const ensured = await sessionManager.ensureNewMainSessionForOperation({
2958
+ channel,
2959
+ channelId: ownerAid,
2960
+ projectPath: active?.projectPath || owningAgent.projectPath || defaultProjectPath,
2961
+ baseagent: owningAgent.baseagent || active?.baseagent || primaryBaseagent,
2962
+ operationId: postBootstrapWelcomeOperationId(aid, ownerAid),
2963
+ identityMetadata: {
2964
+ ...(active?.metadata ?? {}),
2965
+ channelKey: aunInstance.adapter.channelKey,
2966
+ peerId: ownerAid,
2967
+ },
2968
+ });
2969
+ return { sessionId: ensured.session.id, created: ensured.created };
2970
+ },
2971
+ }
2972
+ : undefined;
2973
+ return completeBootstrapWithWelcome(bootstrapService, aid, welcome, sessions);
2974
+ }
2851
2975
  function configureIpc() {
2852
2976
  ipcServer.setShutdownExecutor(async (reason) => {
2853
2977
  if (!shutdown) {
@@ -2880,39 +3004,10 @@ async function main() {
2880
3004
  return { ok: false, code: 'INVALID_CONTROL_TOKEN', error: 'valid local control token is required' };
2881
3005
  }
2882
3006
  }
2883
- const aunInstance = channelInstances.find(candidate => {
2884
- if (candidate.channelType !== 'aun')
2885
- return false;
2886
- const owner = agentRegistry.resolveByChannel(candidate.adapter.channelKey)
2887
- ?? agentRegistry.resolveByChannel(candidate.adapter.channelName);
2888
- return owner?.aid === aid;
2889
- });
2890
- const welcome = aunInstance?.channel;
2891
- const owningAgent = agentRegistry.get(aid);
2892
- const firstOwnerAid = getFirstStaticAgentOwner(aid);
2893
- const sessions = aunInstance && firstOwnerAid && owningAgent
2894
- ? {
2895
- ensurePostBootstrapMainSession: async (owner) => {
2896
- const ownerAid = owner || firstOwnerAid;
2897
- const channel = aunInstance.adapter.channelName;
2898
- const active = await sessionManager.getActiveSession(channel, ownerAid);
2899
- const ensured = await sessionManager.ensureNewMainSessionForOperation({
2900
- channel,
2901
- channelId: ownerAid,
2902
- projectPath: active?.projectPath || owningAgent.projectPath || defaultProjectPath,
2903
- baseagent: owningAgent.baseagent || active?.baseagent || primaryBaseagent,
2904
- operationId: postBootstrapWelcomeOperationId(aid, ownerAid),
2905
- identityMetadata: {
2906
- ...(active?.metadata ?? {}),
2907
- channelKey: aunInstance.adapter.channelKey,
2908
- peerId: ownerAid,
2909
- },
2910
- });
2911
- return { sessionId: ensured.session.id, created: ensured.created };
2912
- },
2913
- }
2914
- : undefined;
2915
- return completeBootstrapWithWelcome(bootstrapService, aid, welcome, sessions);
3007
+ if (hasSuppliedInitialization(aid) || loadAgent(aid)?.initialization) {
3008
+ return { ok: false, code: 'INITIALIZATION_MANAGED', error: 'Use the initialization service for this Agent' };
3009
+ }
3010
+ return completeAgentBootstrap(aid);
2916
3011
  });
2917
3012
  ipcServer.setDingtalkContactBindExecutor({
2918
3013
  register: (cmd) => registerPendingDingtalkContactBind(cmd),
@@ -3020,6 +3115,14 @@ async function main() {
3020
3115
  aidStatsCollector.recordOutbound(params.aid, params.toPeer, Buffer.byteLength(params.text || '', 'utf-8'), params.text, false, params.encrypt, params.chatmode, 'send');
3021
3116
  });
3022
3117
  ipcServer.setTaskRuntimeContextProvider(({ sessionId }) => responseEngine.getTaskRuntimeContext(sessionId));
3118
+ ipcServer.setTaskRuntimeContextAuthorizer(({ sessionId, delegationToken, delegationCommandHash }) => {
3119
+ // Codex persistent threads carry a command-scoped authorization. Looking
3120
+ // up fresh routing context must not consume the subsequent CLI operation.
3121
+ const authorization = agentDelegationRegistry.validateForContext(delegationToken, sessionId, delegationCommandHash);
3122
+ return authorization.ok
3123
+ ? { ok: true }
3124
+ : { ok: false, code: authorization.code, error: authorization.reason };
3125
+ });
3023
3126
  ipcServer.setCodexPreToolUseExecutor(async (params) => {
3024
3127
  for (const runner of new Set(agentMap.values())) {
3025
3128
  if (typeof runner?.evaluatePreToolUse !== 'function')
@@ -3694,6 +3797,57 @@ async function main() {
3694
3797
  }),
3695
3798
  aunAidStats: () => aidStatsCollector.getAllSnapshots(),
3696
3799
  });
3800
+ agentInitializationService = new AgentInitializationService({
3801
+ register: async (aid) => {
3802
+ const { aidCreate } = await import('./aun/aid/identity.js');
3803
+ const created = await aidCreate(aid);
3804
+ await created.client.close();
3805
+ },
3806
+ publish: async (aid, content) => {
3807
+ const { agentmdPut } = await import('./aun/aid/agentmd.js');
3808
+ await agentmdPut(content, { aid });
3809
+ },
3810
+ fetch: async (aid) => {
3811
+ const { agentmdGet } = await import('./aun/aid/agentmd.js');
3812
+ const card = await agentmdGet(aid, { withVerification: true, remoteOnly: true });
3813
+ return { content: card.content, verified: card.verification.status === 'verified' };
3814
+ },
3815
+ hotLoad: async (aid) => {
3816
+ await coreHotLoadAgent(aid);
3817
+ const until = Date.now() + 20_000;
3818
+ while (Date.now() < until) {
3819
+ if (channelInstances.some(inst => inst.channelType === 'aun'
3820
+ && inst.channel.getAidState?.()?.aid === aid
3821
+ && inst.channel.getAidState?.()?.status === 'connected'))
3822
+ return;
3823
+ await new Promise(resolve => setTimeout(resolve, 250));
3824
+ }
3825
+ throw Object.assign(new Error('AUN connection unavailable'), { code: 'INITIALIZE_CHANNEL_UNAVAILABLE' });
3826
+ },
3827
+ activate: completeAgentBootstrap,
3828
+ authorize: actor => actor === 'local-control' || (loadDaemonConfig().owners ?? []).includes(actor),
3829
+ usable: aid => {
3830
+ const agent = agentRegistry.get(aid);
3831
+ return !!agent && agent.config.enabled !== false && agentMap.has(`${aid}::${agent.baseagent}`)
3832
+ && channelInstances.some(inst => inst.channelType === 'aun'
3833
+ && inst.channel.getAidState?.()?.aid === aid
3834
+ && inst.channel.getAidState?.()?.status === 'connected');
3835
+ },
3836
+ });
3837
+ agentApplicationService.setInitializationService(agentInitializationService);
3838
+ ipcServer.setInitializationExecutor(async (cmd) => executeLocalInitializationCommand(agentInitializationService, cmd));
3839
+ for (const entry of fs.readdirSync(resolvePaths().agentsDir, { withFileTypes: true })) {
3840
+ if (!entry.isDirectory())
3841
+ continue;
3842
+ try {
3843
+ const record = readInitialization(entry.name);
3844
+ if (record?.status === 'in_progress')
3845
+ agentInitializationService.resume(entry.name, record.actor);
3846
+ }
3847
+ catch {
3848
+ logger.warn('[Initialization] Recovery requires review for an incomplete operation');
3849
+ }
3850
+ }
3697
3851
  cmdHandler.setAgentApplicationService(agentApplicationService);
3698
3852
  ipcServer.setAgentApplicationService(agentApplicationService);
3699
3853
  ipcServer.setStatsProvider(() => statsCollector.getSnapshot());
@@ -3796,6 +3950,8 @@ async function main() {
3796
3950
  ? {
3797
3951
  ok: true,
3798
3952
  aid: subject.dataScope === 'daemon' ? (params.targetAid ?? delegation.grant.selfAid) : delegation.grant.selfAid,
3953
+ dataScope: subject.dataScope,
3954
+ management: isManagementRole(subject.role),
3799
3955
  }
3800
3956
  : { ok: false, code: decision.code, error: decision.reason };
3801
3957
  }
@@ -3823,26 +3979,41 @@ async function main() {
3823
3979
  return fail('INVALID_DELEGATION', 'delegation does not match the current session');
3824
3980
  }
3825
3981
  const taskAid = delegation.grant.selfAid;
3982
+ let welcomeArgs;
3983
+ if (sub === 'welcome') {
3984
+ try {
3985
+ welcomeArgs = parseAgentWelcomeArgs(argv.slice(2));
3986
+ }
3987
+ catch (error) {
3988
+ return fail('INVALID_ARGS', error.message);
3989
+ }
3990
+ if (delegation.grant.chatType !== 'private')
3991
+ return fail('NOT_ALLOWED', 'welcome requires a private conversation');
3992
+ }
3826
3993
  const targetAid = sub === 'list'
3827
3994
  ? undefined
3828
3995
  : sub === 'persona'
3829
3996
  ? taskAid
3830
- : sub === 'show'
3831
- ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : taskAid)
3832
- : sub === 'reload'
3833
- ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined)
3834
- : (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined);
3997
+ : sub === 'welcome'
3998
+ ? taskAid
3999
+ : sub === 'show'
4000
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : taskAid)
4001
+ : sub === 'reload'
4002
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined)
4003
+ : (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined);
3835
4004
  const operation = sub === 'list' ? 'agent.list'
3836
4005
  : sub === 'show' ? 'agent.show'
3837
4006
  : sub === 'persona' ? 'agent.persona'
3838
- : sub === 'new' ? 'agent.create'
3839
- : sub === 'enable' ? 'agent.enable'
3840
- : sub === 'disable' ? 'agent.disable'
3841
- : sub === 'reload' ? 'agent.reload'
3842
- : sub === 'delete' ? 'agent.delete' : undefined;
4007
+ : sub === 'welcome' ? 'agent.welcome'
4008
+ : sub === 'initialize' || (sub === 'new' && argv.includes('--initialize')) ? 'agent.initialize'
4009
+ : sub === 'new' ? 'agent.create'
4010
+ : sub === 'enable' ? 'agent.enable'
4011
+ : sub === 'disable' ? 'agent.disable'
4012
+ : sub === 'reload' ? 'agent.reload'
4013
+ : sub === 'delete' ? 'agent.delete' : undefined;
3843
4014
  if (!operation)
3844
4015
  return fail('INVALID_ARGS', `unsupported managed agent command: ${sub}`);
3845
- if (sub === 'new' && !argv.includes('--non-interactive')) {
4016
+ if (sub === 'new' && !argv.includes('--non-interactive') && !argv.includes('--initialize')) {
3846
4017
  return fail('MANAGED_NON_INTERACTIVE_REQUIRED', 'interactive Agent creation is unavailable in a managed task', 'MANAGED_NON_INTERACTIVE_REQUIRED');
3847
4018
  }
3848
4019
  if (sub === 'delete' && argv.includes('--purge') && !argv.includes('--confirm-purge')) {
@@ -3871,7 +4042,7 @@ async function main() {
3871
4042
  subject,
3872
4043
  intent: {
3873
4044
  operation,
3874
- scope: operation === 'agent.show' || operation === 'agent.persona'
4045
+ scope: operation === 'agent.show' || operation === 'agent.persona' || operation === 'agent.welcome'
3875
4046
  ? 'agent'
3876
4047
  : operation === 'agent.reload' && targetAid
3877
4048
  ? 'agent'
@@ -3882,6 +4053,7 @@ async function main() {
3882
4053
  aid: targetAid ?? taskAid,
3883
4054
  taskAgentAid: taskAid,
3884
4055
  targetAgentAid: targetAid ?? taskAid,
4056
+ ...(welcomeArgs ? { action: welcomeArgs.action } : {}),
3885
4057
  },
3886
4058
  },
3887
4059
  auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
@@ -3933,6 +4105,7 @@ async function main() {
3933
4105
  : { config: null, agent_md: null, project: null, data: null },
3934
4106
  ...(subject.dataScope === 'daemon' ? {} : { redacted: true }),
3935
4107
  ...(agent.createProgress ? { createProgress: agent.createProgress } : {}),
4108
+ ...(agent.initialization ? { initialization: agent.initialization } : {}),
3936
4109
  } };
3937
4110
  }
3938
4111
  if (operation === 'agent.persona') {
@@ -3967,6 +4140,48 @@ async function main() {
3967
4140
  ...(result.saved ? { saved: true } : {}),
3968
4141
  } };
3969
4142
  }
4143
+ if (operation === 'agent.welcome') {
4144
+ if (subject.role !== 'owner' && !(welcomeArgs?.action === 'show' && subject.role === 'admin')) {
4145
+ return fail('NOT_ALLOWED', 'welcome requires the current Agent Owner (admin may read)');
4146
+ }
4147
+ const { agentWelcome } = await import('./cli/agent.js');
4148
+ const result = await agentWelcome(taskAid, { text: welcomeArgs?.text, trustedLocal: true });
4149
+ if (!result.ok)
4150
+ return fail(result.code ?? 'INTERNAL', result.error);
4151
+ return { ok: true, result: {
4152
+ ok: true,
4153
+ aid: taskAid,
4154
+ content: result.content,
4155
+ ...(result.path ? { path: result.path } : {}),
4156
+ ...(result.saved ? { saved: true } : {}),
4157
+ ...(result.bytes !== undefined ? { bytes: result.bytes } : {}),
4158
+ ...(result.sha256 ? { sha256: result.sha256 } : {}),
4159
+ } };
4160
+ }
4161
+ if (operation === 'agent.initialize') {
4162
+ try {
4163
+ const parsed = parseInitializationArgs(argv.slice(1));
4164
+ const actor = delegation.grant.actorId;
4165
+ if (parsed.resume)
4166
+ return { ok: true, result: agentInitializationService.resume(parsed.aid, actor) };
4167
+ const createPermission = authorizeOperation({
4168
+ source: 'agent-tool', subject,
4169
+ intent: { operation: 'agent.create', scope: 'control', source: 'agent-tool', args: { aid: parsed.aid } },
4170
+ auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
4171
+ });
4172
+ if (!createPermission.allow)
4173
+ return fail(createPermission.code, createPermission.reason);
4174
+ if (!argv.includes('--owner') && !argv.includes('--owners'))
4175
+ return fail('INITIALIZE_OWNER_MISMATCH', 'Explicit Owner required');
4176
+ const plan = resolveInitializationPlan(argv.slice(1));
4177
+ if (!plan.owners.includes(actor))
4178
+ return fail('INITIALIZE_OWNER_MISMATCH', 'The authenticated requesting Owner must be retained');
4179
+ return { ok: true, result: agentInitializationService.start(plan, actor, parsed.dryRun) };
4180
+ }
4181
+ catch (error) {
4182
+ return fail(error.code ?? 'INVALID_ARGS', error.message);
4183
+ }
4184
+ }
3970
4185
  if (operation === 'agent.create') {
3971
4186
  const aid = argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined;
3972
4187
  if (!aid)
@@ -4094,6 +4309,11 @@ async function main() {
4094
4309
  const result = await execAgentAction(sub, { aid: targetAid ?? taskAid, force: argv.includes('--force') }, delegation.grant.actorId, eventBus, agentApplicationService);
4095
4310
  return 'error' in result ? fail(result.code, result.error) : { ok: true, result: { ok: true, ...(result.data ?? {}) } };
4096
4311
  });
4312
+ ipcServer.setTaskResumeExecutor(params => executeTaskResume(params, {
4313
+ sessions: sessionManager,
4314
+ authorizeManaged: authorizeManagedAgentOperation,
4315
+ recover: request => responseEngine.recoverTask(request),
4316
+ }));
4097
4317
  ipcServer.setQueueOperationExecutor(async (params) => {
4098
4318
  const operation = `ec.queue.${params.action ?? 'read'}`;
4099
4319
  const authorization = await authorizeManagedAgentOperation(params, operation);
@@ -4134,6 +4354,38 @@ async function main() {
4134
4354
  const authorization = await authorizeManagedAgentOperation({ ...params, targetAid: params.aid }, params.operation);
4135
4355
  return authorization.ok ? { ok: true } : authorization;
4136
4356
  });
4357
+ ipcServer.setStorageUploadExecutor(async (params) => {
4358
+ const authorization = await authorizeManagedAgentOperation({ ...params, targetAid: params.aid }, 'storage.upload');
4359
+ if (!authorization.ok)
4360
+ return authorization;
4361
+ const session = await sessionManager.getSessionById(params.sessionId);
4362
+ if (!session)
4363
+ return { ok: false, code: 'SESSION_NOT_FOUND', error: 'current session not found' };
4364
+ try {
4365
+ const projectPath = fs.realpathSync(path.resolve(session.projectPath));
4366
+ const requestedFile = path.resolve(session.projectPath, params.localFile);
4367
+ const requestedStat = fs.lstatSync(requestedFile);
4368
+ if (requestedStat.isSymbolicLink()) {
4369
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: 'Upload source must not be a symbolic link' };
4370
+ }
4371
+ const localFile = fs.realpathSync(requestedFile);
4372
+ const stat = fs.lstatSync(localFile);
4373
+ if (!isSameOrDescendant(localFile, projectPath) || isHClassPath(localFile)) {
4374
+ return { ok: false, code: 'INVALID_LOCAL_PATH', error: 'Upload source must be an unprotected file inside the current session project' };
4375
+ }
4376
+ if (!stat.isFile() || stat.isSymbolicLink()) {
4377
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: 'Upload source must be a regular non-symlink file' };
4378
+ }
4379
+ const { storageUpload } = await import('./aun/storage/index.js');
4380
+ const result = await storageUpload(authorization.aid, localFile, params.remotePath, { isPublic: params.isPublic });
4381
+ return result.ok
4382
+ ? { ok: true, objectKey: result.objectKey, publicUrl: result.publicUrl }
4383
+ : { ok: false, code: 'STORAGE_UPLOAD_FAILED', error: result.error };
4384
+ }
4385
+ catch (error) {
4386
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: error instanceof Error ? error.message : String(error) };
4387
+ }
4388
+ });
4137
4389
  ipcServer.setTriggerExecutor(async (cmd) => {
4138
4390
  const schedulerFor = (agentAid) => {
4139
4391
  const scheduler = triggerSchedulers.get(agentAid);
@@ -4537,6 +4789,8 @@ async function main() {
4537
4789
  timestamp: Date.now()
4538
4790
  });
4539
4791
  // 断开插件系统的渠道
4792
+ removeGroupInviteConfigListener();
4793
+ await shutdownStep('stop group invitation review', () => groupInviteReviewService.dispose());
4540
4794
  await shutdownStep('disconnect channels', () => channelLoader.disconnectAll(channelInstances));
4541
4795
  for (const inst of channelInstances) {
4542
4796
  const type = inst.channelType || inst.adapter.channelName;