evolcore 0.0.26 → 0.0.28

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 (177) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/bin/codex-managed-acl.ps1 +43 -0
  3. package/dist/agents/baseagent-availability.js +68 -0
  4. package/dist/agents/baseagent.js +10 -5
  5. package/dist/agents/claude-runner.js +123 -22
  6. package/dist/agents/codex/app-server-client.js +70 -26
  7. package/dist/agents/codex/catalog.js +7 -1
  8. package/dist/agents/codex-runner.js +363 -421
  9. package/dist/agents/ecagent-runner.js +170 -25
  10. package/dist/agents/gemini-runner.js +6 -0
  11. package/dist/agents/runner-types.js +50 -2
  12. package/dist/aun/aid/agentmd.js +73 -31
  13. package/dist/aun/aid/client.js +1 -1
  14. package/dist/aun/aid/control-aid.js +180 -1
  15. package/dist/aun/aid/identity.js +3 -3
  16. package/dist/aun/group/history.js +303 -0
  17. package/dist/aun/group/identity.js +43 -0
  18. package/dist/aun/group/index.js +5 -0
  19. package/dist/aun/{msg/group.js → group/operations.js} +161 -38
  20. package/dist/aun/{menu-client.js → menu/client.js} +13 -7
  21. package/dist/aun/menu/index.js +2 -0
  22. package/dist/aun/menu/transport.js +49 -0
  23. package/dist/aun/msg/index.js +2 -1
  24. package/dist/aun/msg/managed-operation.js +84 -18
  25. package/dist/aun/msg/mention-schema.js +51 -0
  26. package/dist/aun/msg/p2p.js +13 -8
  27. package/dist/aun/msg/upload.js +43 -88
  28. package/dist/aun/outbox.js +29 -7
  29. package/dist/aun/rpc/client.js +1 -0
  30. package/dist/aun/storage/client.js +39 -50
  31. package/dist/channels/aun.js +544 -239
  32. package/dist/channels/daemon.js +10 -6
  33. package/dist/cli/agent-command.js +108 -6
  34. package/dist/cli/agent-create.js +515 -2
  35. package/dist/cli/agent.js +109 -8
  36. package/dist/cli/aun-commands.js +191 -42
  37. package/dist/cli/config.js +8 -5
  38. package/dist/cli/contact.js +2 -2
  39. package/dist/cli/ctl-command.js +2 -2
  40. package/dist/cli/daemon-commands.js +111 -162
  41. package/dist/cli/diag.js +3 -3
  42. package/dist/cli/fs-command.js +3 -3
  43. package/dist/cli/handoff-command.js +6 -6
  44. package/dist/cli/index.js +8 -2
  45. package/dist/cli/init.js +34 -1
  46. package/dist/cli/managed-command-guard.js +2 -1
  47. package/dist/cli/menu-client.js +13 -5
  48. package/dist/cli/model.js +3 -3
  49. package/dist/cli/queue-command.js +2 -2
  50. package/dist/cli/response.js +2 -2
  51. package/dist/cli/restart-monitor.js +81 -19
  52. package/dist/cli/task-command.js +59 -0
  53. package/dist/cli/task-context.js +97 -49
  54. package/dist/cli/trigger-command.js +20 -10
  55. package/dist/config/builtin-roles.js +10 -0
  56. package/dist/config/config-field-policy.js +11 -0
  57. package/dist/config/config-manager.js +32 -4
  58. package/dist/config/config-operation-service.js +20 -5
  59. package/dist/config/contact-book-store.js +1 -1
  60. package/dist/config/contact-book.js +1 -1
  61. package/dist/config/contact-operation-service.js +1 -1
  62. package/dist/config/peer-role-resolver.js +1 -1
  63. package/dist/config/resolved-config-op.js +3 -0
  64. package/dist/config-store.js +1 -1
  65. package/dist/core/agent-application-service.js +5 -0
  66. package/dist/core/audit/event-key.js +17 -2
  67. package/dist/core/audit/log-integrity.js +34 -8
  68. package/dist/core/auth/agent-delegation.js +48 -14
  69. package/dist/core/auth/auth-gateway.js +2 -0
  70. package/dist/core/auth/authorization-audit.js +34 -38
  71. package/dist/core/auth/operation-authorizer.js +67 -5
  72. package/dist/core/auth/operation-catalog.js +110 -0
  73. package/dist/core/auth/remote-access-store.js +115 -9
  74. package/dist/core/bootstrap-messages.js +66 -7
  75. package/dist/core/bootstrap-service.js +110 -19
  76. package/dist/core/command/agent-control.js +88 -7
  77. package/dist/core/command/agent-storage-menu.js +443 -0
  78. package/dist/core/command/cli-intent-parser.js +19 -0
  79. package/dist/core/command/command-handler.js +105 -40
  80. package/dist/core/command/data-root-resolver.js +273 -0
  81. package/dist/core/command/diag-service.js +292 -27
  82. package/dist/core/command/group-menu.js +7 -2
  83. package/dist/core/command/menu-catalog.js +34 -4
  84. package/dist/core/command/menu-handler.js +364 -96
  85. package/dist/core/command/menu-protocol.js +43 -6
  86. package/dist/core/command/role-menu.js +2 -2
  87. package/dist/core/command/slash-handler.js +61 -37
  88. package/dist/core/event-catalog.js +4 -0
  89. package/dist/core/evolagent-registry.js +28 -2
  90. package/dist/core/group/invite-service.js +924 -0
  91. package/dist/core/interaction-router.js +22 -8
  92. package/dist/core/message/im-renderer.js +94 -16
  93. package/dist/core/message/message-bridge.js +140 -13
  94. package/dist/core/message/message-log.js +5 -3
  95. package/dist/core/message/message-queue.js +73 -41
  96. package/dist/core/message/response-engine.js +729 -118
  97. package/dist/core/permission/approval-gateway.js +36 -3
  98. package/dist/core/permission/ec-command-parser.js +76 -36
  99. package/dist/core/permission/protected-paths.js +134 -16
  100. package/dist/core/permission/sandbox-runtime.js +72 -3
  101. package/dist/core/permission/tool-error-code.js +15 -0
  102. package/dist/core/permission/tool-policy.js +8 -8
  103. package/dist/core/relation/peer-identity.js +57 -6
  104. package/dist/core/relation/shared-data.js +106 -0
  105. package/dist/core/role/runtime-policy.js +64 -0
  106. package/dist/core/runtime-lock.js +10 -26
  107. package/dist/core/session/runner-task-history.js +170 -0
  108. package/dist/core/session/session-manager.js +38 -6
  109. package/dist/core/session/session-mapper.js +41 -0
  110. package/dist/core/session/session-turn-coordinator.js +37 -7
  111. package/dist/core/session/session-turns.js +48 -7
  112. package/dist/core/task/task-recovery-service.js +176 -0
  113. package/dist/core/task/task-resume-operation.js +32 -0
  114. package/dist/eck/group-rules-sync.js +5 -3
  115. package/dist/eck/kit-renderer.js +1 -0
  116. package/dist/index.js +322 -207
  117. package/dist/ipc.js +141 -15
  118. package/dist/paths.js +17 -4
  119. package/dist/product.js +3 -0
  120. package/dist/trigger/event-source.js +19 -0
  121. package/dist/trigger/feedback.js +233 -40
  122. package/dist/trigger/parser.js +55 -5
  123. package/dist/trigger/patch.js +9 -0
  124. package/dist/trigger/scheduler.js +30 -4
  125. package/dist/trigger/validation.js +20 -3
  126. package/dist/utils/atomic-write.js +98 -0
  127. package/dist/utils/cross-platform.js +87 -16
  128. package/dist/utils/ecweb-utils.js +1 -0
  129. package/dist/utils/error-utils.js +40 -2
  130. package/dist/utils/logger.js +23 -13
  131. package/dist/utils/npm-ops.js +119 -4
  132. package/dist/utils/package-version-info.js +244 -0
  133. package/dist/utils/tool-summary.js +59 -3
  134. package/dist/utils/welcome.js +174 -1
  135. package/dist/utils/windows-shell-trust.js +37 -0
  136. package/ecagent/dist/harness/agent-harness.js +3 -0
  137. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  138. package/kits/docs/INDEX.md +0 -6
  139. package/kits/docs/channels/aun.md +23 -2
  140. package/kits/docs/channels/feishu.md +1 -1
  141. package/kits/docs/context-assembly.md +29 -17
  142. package/kits/docs/evolcore/INDEX.md +8 -3
  143. package/kits/docs/evolcore/agent-create.md +39 -7
  144. package/kits/docs/evolcore/agent.md +33 -1
  145. package/kits/docs/evolcore/aid.md +9 -1
  146. package/kits/docs/evolcore/config.md +40 -1
  147. package/kits/docs/evolcore/group-collaboration.md +1 -1
  148. package/kits/docs/evolcore/group.md +117 -2
  149. package/kits/docs/evolcore/menu-client.md +16 -0
  150. package/kits/docs/evolcore/msg.md +3 -0
  151. package/kits/docs/evolcore/storage.md +3 -0
  152. package/kits/docs/evolcore/task.md +14 -0
  153. package/kits/docs/evolcore/trigger.md +51 -3
  154. package/kits/docs/venues/group.md +5 -0
  155. package/kits/eck_manifest.json +27 -0
  156. package/kits/rules/01-overview.md +11 -7
  157. package/kits/rules/04-relation.md +2 -1
  158. package/kits/rules/05-venue.md +1 -1
  159. package/kits/rules/06-channel.md +6 -4
  160. package/kits/schemas/agent-config.schema.12.json +25 -1
  161. package/kits/schemas/daemon.schema.6.json +2 -2
  162. package/kits/schemas/defaults.schema.5.json +1 -1
  163. package/kits/schemas/relation-config.schema.1.json +1 -1
  164. package/kits/schemas/relation-config.schema.5.json +1 -1
  165. package/kits/schemas/role-config.schema.1.json +14 -0
  166. package/kits/templates/roles/member.json +5 -0
  167. package/kits/templates/roles/visitor.json +5 -0
  168. package/kits/templates/system-fragments/baseagent.md +1 -1
  169. package/kits/templates/system-fragments/bootstrap.md +26 -9
  170. package/kits/templates/system-fragments/channel.md +8 -44
  171. package/kits/templates/system-fragments/commands.md +10 -2
  172. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  173. package/kits/templates/system-fragments/reply.md +56 -0
  174. package/package.json +7 -3
  175. package/dist/aun/group-identity.js +0 -9
  176. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  177. /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';
@@ -97,11 +103,10 @@ import { atomicWriteJson } from './core/session/session-fs-store.js';
97
103
  import { DAEMON_RUNTIME_EPOCH_ENV, ensureProcessManagedTempDir } from './cli/task-context.js';
98
104
  import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
99
105
  import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
100
- import { MAIN_PACKAGE_NAME } from './product.js';
106
+ import { sanitizeMenuLogValue } from './core/command/menu-protocol.js';
101
107
  import fs from 'fs';
102
108
  import crypto from 'crypto';
103
109
  import { fileURLToPath } from 'url';
104
- import * as platform from './utils/cross-platform.js';
105
110
  const controlMenuDeduper = new MenuRequestDeduper();
106
111
  /** 出站 payload 摘要(用于 channel-out.log) */
107
112
  function summarizeOutboundPayload(payload) {
@@ -365,160 +370,23 @@ function seedUpgradeCheckTrigger(manager, owner) {
365
370
  fs.mkdirSync(dir, { recursive: true });
366
371
  const scriptPath = path.join(dir, scriptName);
367
372
  const packageRoot = getPackageRoot();
368
- const cliPath = path.join(packageRoot, 'dist', 'cli', 'index.js');
369
- const packageJsonPath = path.join(packageRoot, 'package.json');
370
- const devMode = fs.existsSync(path.join(packageRoot, 'src', 'index.ts'));
371
- // Resolve the launch argv at generation time: in a checkout this points the
372
- // monitor at src/ through tsx, so a `npm run build` that wipes dist/ cannot
373
- // take the watchdog down with it.
374
- const monitorEntry = platform.resolveCliEntry(packageRoot);
375
- const stageParent = path.join(resolvePaths().root, 'data', 'monitor-stage');
373
+ // Keep this generated script check-only. It never starts a monitor or runs npm install.
376
374
  fs.writeFileSync(scriptPath, `#!/usr/bin/env node
377
- const fs = require('node:fs');
378
- const path = require('node:path');
379
- const { existsSync, readFileSync } = fs;
380
- const { spawn } = require('node:child_process');
381
-
382
- const CLI_PATH = ${JSON.stringify(monitorEntry.entry)};
383
- const CLI_ARGS = ${JSON.stringify(monitorEntry.args)};
384
- const PACKAGE_ROOT = ${JSON.stringify(packageRoot)};
385
- const STAGE_PARENT = ${JSON.stringify(stageParent)};
386
- const PACKAGE_JSON = ${JSON.stringify(packageJsonPath)};
387
- const PACKAGE_NAME = ${JSON.stringify(MAIN_PACKAGE_NAME)};
388
- const DEV_MODE = ${devMode ? 'true' : 'false'};
389
-
390
- function emit(outcome, text) {
391
- process.stdout.write(JSON.stringify({ outcome, text, files: [] }));
392
- }
393
-
394
- function compareVersions(a, b) {
395
- const pa = a.split('-')[0].split('.').map(Number);
396
- const pb = b.split('-')[0].split('.').map(Number);
397
- const count = Math.max(pa.length, pb.length);
398
- for (let i = 0; i < count; i += 1) {
399
- const av = Number.isFinite(pa[i]) ? pa[i] : 0;
400
- const bv = Number.isFinite(pb[i]) ? pb[i] : 0;
401
- if (av < bv) return -1;
402
- if (av > bv) return 1;
403
- }
404
- return 0;
405
- }
406
-
407
- async function latestVersion() {
408
- const controller = new AbortController();
409
- const timer = setTimeout(() => controller.abort(), 10_000);
410
- try {
411
- const response = await fetch('https://registry.npmjs.org/' + encodeURIComponent(PACKAGE_NAME) + '/latest', {
412
- signal: controller.signal,
413
- headers: { Accept: 'application/json' },
414
- });
415
- if (!response.ok) return null;
416
- const data = await response.json();
417
- return typeof data.version === 'string' ? data.version : null;
418
- } finally {
419
- clearTimeout(timer);
420
- }
421
- }
422
-
375
+ const { pathToFileURL } = require('node:url');
376
+ const entry = ${JSON.stringify(path.join(packageRoot, 'dist', 'utils', 'package-version-info.js'))};
423
377
  async function main() {
424
- if (DEV_MODE) {
425
- emit('noop', 'upgrade check skipped in dev mode');
426
- return;
427
- }
428
-
429
- let localVersion;
430
- try {
431
- localVersion = JSON.parse(readFileSync(PACKAGE_JSON, 'utf8')).version;
432
- } catch {
433
- emit('error', 'failed to read local ec version');
434
- return;
435
- }
436
- if (typeof localVersion !== 'string' || !localVersion) {
437
- emit('error', 'failed to read local ec version');
438
- return;
439
- }
440
-
441
- let remoteVersion;
442
- try {
443
- remoteVersion = await latestVersion();
444
- } catch {
445
- remoteVersion = null;
446
- }
447
- if (!remoteVersion) {
448
- emit('error', 'failed to check evolcore latest version');
449
- return;
450
- }
451
- if (compareVersions(localVersion, remoteVersion) >= 0) {
452
- emit('noop', 'evolcore is already up to date (' + localVersion + '; latest ' + remoteVersion + ')');
453
- return;
454
- }
455
- if (!existsSync(CLI_PATH)) {
456
- emit('error', 'restart-monitor entry not found: ' + CLI_PATH);
457
- return;
458
- }
459
-
460
- // Installed mode: copy the monitor out of the package before it upgrades that
461
- // same package. Mirrors prepareMonitorStage(); kept inline because this file
462
- // is generated standalone CJS. Any failure degrades to launching in place —
463
- // losing upgrade isolation beats losing the upgrade.
464
- let launchArgs = CLI_ARGS;
465
- const launchEnv = { ...process.env };
466
- if (!DEV_MODE && STAGE_PARENT) {
467
- try {
468
- const stageDir = path.join(STAGE_PARENT, 'upgrade-' + process.pid + '-' + Date.now());
469
- fs.mkdirSync(stageDir, { recursive: true });
470
- fs.cpSync(path.join(PACKAGE_ROOT, 'dist'), path.join(stageDir, 'dist'), { recursive: true });
471
- if (existsSync(PACKAGE_JSON)) fs.copyFileSync(PACKAGE_JSON, path.join(stageDir, 'package.json'));
472
- const modulesSource = path.join(PACKAGE_ROOT, 'node_modules');
473
- if (existsSync(modulesSource)) {
474
- const staged = path.join(stageDir, 'node_modules');
475
- try {
476
- // junction works unelevated on Windows; dir symlink elsewhere.
477
- fs.symlinkSync(modulesSource, staged, process.platform === 'win32' ? 'junction' : 'dir');
478
- fs.readdirSync(staged);
479
- } catch (linkError) {
480
- fs.rmSync(staged, { recursive: true, force: true });
481
- fs.cpSync(modulesSource, staged, { recursive: true });
482
- }
483
- }
484
- const stagedEntry = path.join(stageDir, 'dist', 'cli', 'index.js');
485
- if (existsSync(stagedEntry)) {
486
- launchArgs = [stagedEntry];
487
- launchEnv.EVOLCORE_TARGET_PACKAGE_ROOT = PACKAGE_ROOT;
488
- launchEnv.EVOLCORE_MONITOR_STAGE = stageDir;
489
- }
490
- } catch (stageError) {
491
- // Fall through with the in-place entry.
492
- }
493
- }
494
-
495
- try {
496
- const child = spawn(process.execPath, [...launchArgs, 'restart-monitor'], {
497
- detached: true,
498
- stdio: 'ignore',
499
- windowsHide: process.platform === 'win32',
500
- env: launchEnv,
501
- });
502
- child.unref();
503
- const pid = child.pid;
504
- // The daemon is still running here — the monitor is what stops it. So a
505
- // monitor that dies on load costs the upgrade, not the service; still,
506
- // report it accurately instead of claiming success.
507
- await new Promise(resolve => setTimeout(resolve, 3000));
508
- let alive = false;
509
- try { process.kill(pid, 0); alive = true; } catch (e) { alive = false; }
510
- if (!alive) {
511
- emit('error', 'restart-monitor exited during startup; upgrade to ' + remoteVersion + ' not applied');
512
- return;
513
- }
514
- emit('success', 'evolcore upgrade available: ' + localVersion + ' -> ' + remoteVersion + '; restart-monitor started');
515
- } catch (error) {
516
- emit('error', 'failed to start restart-monitor: ' + (error && error.message ? error.message : String(error)));
517
- }
378
+ const { refreshManagedPackageVersions } = await import(pathToFileURL(entry).href);
379
+ const results = await refreshManagedPackageVersions(undefined, { source: 'daily-check' });
380
+ const failed = results.some(result => result.status === 'unavailable');
381
+ process.stdout.write(JSON.stringify({
382
+ outcome: failed ? 'error' : 'success',
383
+ text: results.map(result => result.packageName + ': ' + result.status).join('; '),
384
+ files: [],
385
+ }));
518
386
  }
519
-
520
- main().catch((error) => {
521
- emit('error', 'upgrade check failed: ' + (error && error.message ? error.message : String(error)));
387
+ main().catch(() => {
388
+ process.stdout.write(JSON.stringify({ outcome: 'error', text: 'Version information refresh failed', files: [] }));
389
+ process.exitCode = 1;
522
390
  });
523
391
  `);
524
392
  // Remove the pre-Node script left by older installations so it cannot be
@@ -529,6 +397,51 @@ main().catch((error) => {
529
397
  atomicWriteJson(manager.definitionPath(definition.id), definition);
530
398
  fs.rmSync(manager.activePath(definition.id), { force: true });
531
399
  }
400
+ /**
401
+ * Keep one daemon-owned recovery Trigger for all local Agent sessions. The
402
+ * event-session feedback path resolves the owning Agent from task:error rather
403
+ * than treating the daemon AID as the target Agent.
404
+ */
405
+ function seedTaskRecoveryTrigger(manager, owner) {
406
+ const now = Date.now();
407
+ const definition = normalizeTriggerDefinition({
408
+ $schema_version: 3.1,
409
+ id: '__task-recovery',
410
+ agentAid: owner.aid,
411
+ enabled: true,
412
+ name: '__task-recovery',
413
+ description: 'System trigger: recover failed tasks for local Agents.',
414
+ createdAt: now,
415
+ updatedAt: now,
416
+ origin: {
417
+ channelKey: 'daemon',
418
+ channelType: 'daemon',
419
+ channelId: owner.originPeerId || owner.aid,
420
+ session: 'main',
421
+ peerId: owner.originPeerId || owner.aid,
422
+ sessionKey: `daemon#${owner.originPeerId || owner.aid}#__task-recovery__`,
423
+ },
424
+ source: {
425
+ type: 'event',
426
+ eventPattern: 'task:error',
427
+ },
428
+ execution: {
429
+ type: 'target_session',
430
+ prompt: TASK_RECOVERY_PROMPT,
431
+ onError: 'retry',
432
+ noopSentinel: '[[NOOP]]',
433
+ },
434
+ feedback: { strategy: 'event_session' },
435
+ reliability: {
436
+ concurrency: 'forbid',
437
+ missedPolicy: 'run_once',
438
+ retry: { maxAttempts: 2, backoffMs: 30_000 },
439
+ },
440
+ });
441
+ fs.mkdirSync(manager.triggerDir(definition.id), { recursive: true });
442
+ atomicWriteJson(manager.definitionPath(definition.id), definition);
443
+ fs.rmSync(manager.activePath(definition.id), { force: true });
444
+ }
532
445
  function removeLegacyAgentUpgradeCheck(manager) {
533
446
  let existing;
534
447
  try {
@@ -957,6 +870,10 @@ async function main() {
957
870
  }
958
871
  // ── 自动迁移 ──
959
872
  migrateIdentitiesIfNeeded();
873
+ const relationSharedMigration = migrateRelationSharedDirectories();
874
+ if (relationSharedMigration.copied > 0) {
875
+ logger.info(`[migrate] Synced ${relationSharedMigration.copied} relation shared file(s) across ${relationSharedMigration.relations} relation(s)`);
876
+ }
960
877
  // daemon.json 的旧 ecweb/serviceProxy 结构已在启动前归一化为 services[]。
961
878
  // ── 配置体系初始化(schema 字段不相交硬约束校验)──
962
879
  try {
@@ -1239,6 +1156,11 @@ async function main() {
1239
1156
  });
1240
1157
  // 交互路由器
1241
1158
  const interactionRouter = new InteractionRouter();
1159
+ const groupInviteReviewService = new GroupInviteReviewService(interactionRouter);
1160
+ const removeGroupInviteConfigListener = onConfigWrite(({ target, selector }) => {
1161
+ if (target === ConfigTarget.Agent && selector.self)
1162
+ groupInviteReviewService.configurationChanged(selector.self);
1163
+ });
1242
1164
  // 为所有支持权限的 agent 设置 gateway
1243
1165
  for (const inst of agentInstances) {
1244
1166
  inst.agent.setPermissionGateway?.(permissionGateway);
@@ -1327,6 +1249,7 @@ async function main() {
1327
1249
  // 创建命令处理器
1328
1250
  const cmdHandler = new CommandHandler(sessionManager, agentMap, messageCache, eventBus, primaryRunnerKey);
1329
1251
  let agentApplicationService;
1252
+ let agentInitializationService;
1330
1253
  cmdHandler.setAgentDelegationRegistry(agentDelegationRegistry);
1331
1254
  cmdHandler.setPermissionGateway(permissionGateway);
1332
1255
  cmdHandler.setInteractionRouter(interactionRouter);
@@ -1372,10 +1295,13 @@ async function main() {
1372
1295
  dedupPath: daemonMessageDedupPath(),
1373
1296
  });
1374
1297
  // 设置中断回调(精确中断正在处理的 agent)
1375
- messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
1298
+ messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message', timeout) => {
1376
1299
  void baseagent;
1377
1300
  void evolagentName;
1378
- await responseEngine.interruptSession(sessionKey, reason);
1301
+ if (timeout)
1302
+ await responseEngine.timeoutSession(sessionKey, timeout);
1303
+ else
1304
+ await responseEngine.interruptSession(sessionKey, reason);
1379
1305
  });
1380
1306
  messageQueue.setEventBus(eventBus);
1381
1307
  // Restore persisted input before Trigger schedulers start. Trigger-owned work
@@ -1531,7 +1457,7 @@ async function main() {
1531
1457
  };
1532
1458
  };
1533
1459
  const validateTriggerFeedbackChannels = (definition) => {
1534
- if (definition.feedback.strategy === 'silent')
1460
+ if (definition.feedback.strategy === 'silent' || definition.feedback.strategy === 'event_session')
1535
1461
  return;
1536
1462
  const target = definition.feedback.strategy === 'target'
1537
1463
  ? definition.feedback.target
@@ -1614,6 +1540,9 @@ async function main() {
1614
1540
  if (!effortDecision.ok)
1615
1541
  throw new Error(effortDecision.message || 'trigger effort is not allowed by current role');
1616
1542
  }
1543
+ if (!actor.management && definition.feedback.strategy === 'event_session') {
1544
+ throw new Error('event-session feedback requires owner/admin');
1545
+ }
1617
1546
  if (!actor.management && definition.feedback.strategy === 'target') {
1618
1547
  const target = definition.feedback.target;
1619
1548
  const origin = actor.origin;
@@ -1721,6 +1650,9 @@ async function main() {
1721
1650
  if (privilegedReason && !persistedFullAccessApproval && !hasDaemonTriggerAuthority(subject)) {
1722
1651
  return { allowed: false, reason: `${privilegedReason} requires current DaemonOwner` };
1723
1652
  }
1653
+ if (definition.feedback.strategy === 'event_session' && !isManagementRole(role)) {
1654
+ return { allowed: false, reason: 'event-session feedback requires current owner/admin role' };
1655
+ }
1724
1656
  if (definition.feedback.strategy === 'target' && !isManagementRole(role)) {
1725
1657
  const target = definition.feedback.target;
1726
1658
  if (!target
@@ -1830,6 +1762,7 @@ async function main() {
1830
1762
  const manager = new TriggerDefinitionManager(owner.aid);
1831
1763
  if (opts.seedUpgradeCheck) {
1832
1764
  seedUpgradeCheckTrigger(manager, owner);
1765
+ seedTaskRecoveryTrigger(manager, owner);
1833
1766
  }
1834
1767
  else {
1835
1768
  removeLegacyAgentUpgradeCheck(manager);
@@ -1840,6 +1773,8 @@ async function main() {
1840
1773
  getChannel: getTriggerChannel,
1841
1774
  sessionManager,
1842
1775
  messageQueue,
1776
+ recoverTask: request => responseEngine.recoverTask(request),
1777
+ inspectTargetExecution: (sessionId, attemptId, selfAid) => responseEngine.inspectTargetExecution(sessionId, attemptId, selfAid),
1843
1778
  eventBus,
1844
1779
  tryHandoff: async (input, text, target, binding) => {
1845
1780
  if (input.signal?.aborted) {
@@ -1956,9 +1891,21 @@ async function main() {
1956
1891
  const inst = channelInstances.find(candidate => candidate.adapter.channelKey === channelKey);
1957
1892
  return !!inst && inst.channel.getStatus?.().connected === true;
1958
1893
  };
1894
+ cmdHandler.setAgentStorageClientResolver((channelKey, targetAid) => {
1895
+ const inst = channelInstances.find(candidate => candidate.channelType === 'aun'
1896
+ && (candidate.adapter.channelKey === channelKey || candidate.adapter.channelName === channelKey)
1897
+ && candidate.channel.getAid?.() === targetAid);
1898
+ if (!inst || inst.channel.getStatus?.().connected !== true)
1899
+ return undefined;
1900
+ // A reconnect replaces the Client; never capture it during startup.
1901
+ const client = inst.channel.getClient?.();
1902
+ return client?.aid === targetAid ? client : undefined;
1903
+ });
1959
1904
  const msgBridge = new MessageBridge(defaultProjectPath, sessionManager, processor, messageQueue, cmdHandler, eventBus, primaryAgent?.config.debounce, () => processLevelOwners);
1960
1905
  msgBridge.setAgentRegistry(agentRegistry);
1961
1906
  msgBridge.setInteractionRouter(interactionRouter);
1907
+ msgBridge.setGroupInviteReviewService(groupInviteReviewService);
1908
+ cmdHandler.setGroupInviteDecisionResolver((selfAid, ownerAid, inviteId, action) => groupInviteReviewService.decideManaged(selfAid, ownerAid, inviteId, action));
1962
1909
  msgBridge.setContactBindRuntimeChecker(isContactBindChannelReady);
1963
1910
  msgBridge.setAidStatsCollector(aidStatsCollector);
1964
1911
  cmdHandler.setContactRequestSubmitter((input) => msgBridge.submitAgentContactRequest(input));
@@ -1982,7 +1929,7 @@ async function main() {
1982
1929
  sessionId: envelope.sessionId,
1983
1930
  agentAid: owningAgent?.aid,
1984
1931
  agentName: envelope.agentName,
1985
- payload: summarizeOutboundPayload(payload),
1932
+ payload: sanitizeMenuLogValue(summarizeOutboundPayload(payload)),
1986
1933
  });
1987
1934
  const result = await originalSend(envelope, payload);
1988
1935
  // AUN adapters return an explicit receipt. Only a receipt with a remote
@@ -2552,7 +2499,10 @@ async function main() {
2552
2499
  catch {
2553
2500
  parsed = null;
2554
2501
  }
2555
- const menuResponseContext = () => controlReplyContext(opts, evolMenuResponseTransportMetadata());
2502
+ const menuResponseContext = () => ({
2503
+ ...controlReplyContext(opts, evolMenuResponseTransportMetadata(opts.protectedHeaders?.sdk_version)),
2504
+ ...(opts.peerDeviceId ? { toDeviceId: opts.peerDeviceId } : {}),
2505
+ });
2556
2506
  const sendControlMenuResponse = async (response) => {
2557
2507
  const timedResponse = withMenuProcessingTime(enforceMenuResponseSize(response, 128 * 1024 - 1024), menuTiming);
2558
2508
  const request = activeMenuRequest ?? {
@@ -2637,9 +2587,9 @@ async function main() {
2637
2587
  return;
2638
2588
  }
2639
2589
  if (text.toLowerCase() === '/pair') {
2640
- const pair = remoteAccessService.getPairingCode(opts.peerId);
2590
+ const pair = remoteAccessService.getPairingCode(opts.peerId, Date.now(), 'pair');
2641
2591
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
2642
- const reply = `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效)`;
2592
+ const reply = `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效,仅可配对一次)`;
2643
2593
  await controlChannel.sendMessage(opts.channelId, reply, controlReplyContext(opts));
2644
2594
  return;
2645
2595
  }
@@ -2650,7 +2600,7 @@ async function main() {
2650
2600
  await sendControlMenuResponse(menuFailure({ id: menuControl.id, ...(menuControl.name?.trim() ? { name: menuControl.name } : {}) }, validationError));
2651
2601
  return;
2652
2602
  }
2653
- const deduped = await controlMenuDeduper.execute([opts.channelId, opts.peerId, menuControl.id].join('\u001f'), menuPayloadFingerprint(menuControl.raw), () => cmdHandler.execMenuForControl(parsed, opts.peerId, {
2603
+ const deduped = await controlMenuDeduper.execute([opts.channelId, opts.peerId, opts.peerDeviceId || '', menuControl.id].join('\u001f'), menuPayloadFingerprint(menuControl.raw), () => cmdHandler.execMenuForControl(parsed, opts.peerId, {
2654
2604
  encrypted: opts.encrypted,
2655
2605
  protectedHeaders: opts.protectedHeaders,
2656
2606
  }));
@@ -2848,6 +2798,41 @@ async function main() {
2848
2798
  });
2849
2799
  }
2850
2800
  }
2801
+ async function completeAgentBootstrap(aid) {
2802
+ const aunInstance = channelInstances.find(candidate => {
2803
+ if (candidate.channelType !== 'aun')
2804
+ return false;
2805
+ const owner = agentRegistry.resolveByChannel(candidate.adapter.channelKey)
2806
+ ?? agentRegistry.resolveByChannel(candidate.adapter.channelName);
2807
+ return owner?.aid === aid;
2808
+ });
2809
+ const welcome = aunInstance?.channel;
2810
+ const owningAgent = agentRegistry.get(aid);
2811
+ const firstOwnerAid = getFirstStaticAgentOwner(aid);
2812
+ const sessions = aunInstance && firstOwnerAid && owningAgent
2813
+ ? {
2814
+ ensurePostBootstrapMainSession: async (owner) => {
2815
+ const ownerAid = owner || firstOwnerAid;
2816
+ const channel = aunInstance.adapter.channelName;
2817
+ const active = await sessionManager.getActiveSession(channel, ownerAid);
2818
+ const ensured = await sessionManager.ensureNewMainSessionForOperation({
2819
+ channel,
2820
+ channelId: ownerAid,
2821
+ projectPath: active?.projectPath || owningAgent.projectPath || defaultProjectPath,
2822
+ baseagent: owningAgent.baseagent || active?.baseagent || primaryBaseagent,
2823
+ operationId: postBootstrapWelcomeOperationId(aid, ownerAid),
2824
+ identityMetadata: {
2825
+ ...(active?.metadata ?? {}),
2826
+ channelKey: aunInstance.adapter.channelKey,
2827
+ peerId: ownerAid,
2828
+ },
2829
+ });
2830
+ return { sessionId: ensured.session.id, created: ensured.created };
2831
+ },
2832
+ }
2833
+ : undefined;
2834
+ return completeBootstrapWithWelcome(bootstrapService, aid, welcome, sessions);
2835
+ }
2851
2836
  function configureIpc() {
2852
2837
  ipcServer.setShutdownExecutor(async (reason) => {
2853
2838
  if (!shutdown) {
@@ -2880,39 +2865,10 @@ async function main() {
2880
2865
  return { ok: false, code: 'INVALID_CONTROL_TOKEN', error: 'valid local control token is required' };
2881
2866
  }
2882
2867
  }
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);
2868
+ if (hasSuppliedInitialization(aid) || loadAgent(aid)?.initialization) {
2869
+ return { ok: false, code: 'INITIALIZATION_MANAGED', error: 'Use the initialization service for this Agent' };
2870
+ }
2871
+ return completeAgentBootstrap(aid);
2916
2872
  });
2917
2873
  ipcServer.setDingtalkContactBindExecutor({
2918
2874
  register: (cmd) => registerPendingDingtalkContactBind(cmd),
@@ -3020,6 +2976,14 @@ async function main() {
3020
2976
  aidStatsCollector.recordOutbound(params.aid, params.toPeer, Buffer.byteLength(params.text || '', 'utf-8'), params.text, false, params.encrypt, params.chatmode, 'send');
3021
2977
  });
3022
2978
  ipcServer.setTaskRuntimeContextProvider(({ sessionId }) => responseEngine.getTaskRuntimeContext(sessionId));
2979
+ ipcServer.setTaskRuntimeContextAuthorizer(({ sessionId, delegationToken, delegationCommandHash }) => {
2980
+ // Codex persistent threads carry a command-scoped authorization. Looking
2981
+ // up fresh routing context must not consume the subsequent CLI operation.
2982
+ const authorization = agentDelegationRegistry.validateForContext(delegationToken, sessionId, delegationCommandHash);
2983
+ return authorization.ok
2984
+ ? { ok: true }
2985
+ : { ok: false, code: authorization.code, error: authorization.reason };
2986
+ });
3023
2987
  ipcServer.setCodexPreToolUseExecutor(async (params) => {
3024
2988
  for (const runner of new Set(agentMap.values())) {
3025
2989
  if (typeof runner?.evaluatePreToolUse !== 'function')
@@ -3694,6 +3658,57 @@ async function main() {
3694
3658
  }),
3695
3659
  aunAidStats: () => aidStatsCollector.getAllSnapshots(),
3696
3660
  });
3661
+ agentInitializationService = new AgentInitializationService({
3662
+ register: async (aid) => {
3663
+ const { aidCreate } = await import('./aun/aid/identity.js');
3664
+ const created = await aidCreate(aid);
3665
+ await created.client.close();
3666
+ },
3667
+ publish: async (aid, content) => {
3668
+ const { agentmdPut } = await import('./aun/aid/agentmd.js');
3669
+ await agentmdPut(content, { aid });
3670
+ },
3671
+ fetch: async (aid) => {
3672
+ const { agentmdGet } = await import('./aun/aid/agentmd.js');
3673
+ const card = await agentmdGet(aid, { withVerification: true, remoteOnly: true });
3674
+ return { content: card.content, verified: card.verification.status === 'verified' };
3675
+ },
3676
+ hotLoad: async (aid) => {
3677
+ await coreHotLoadAgent(aid);
3678
+ const until = Date.now() + 20_000;
3679
+ while (Date.now() < until) {
3680
+ if (channelInstances.some(inst => inst.channelType === 'aun'
3681
+ && inst.channel.getAidState?.()?.aid === aid
3682
+ && inst.channel.getAidState?.()?.status === 'connected'))
3683
+ return;
3684
+ await new Promise(resolve => setTimeout(resolve, 250));
3685
+ }
3686
+ throw Object.assign(new Error('AUN connection unavailable'), { code: 'INITIALIZE_CHANNEL_UNAVAILABLE' });
3687
+ },
3688
+ activate: completeAgentBootstrap,
3689
+ authorize: actor => actor === 'local-control' || (loadDaemonConfig().owners ?? []).includes(actor),
3690
+ usable: aid => {
3691
+ const agent = agentRegistry.get(aid);
3692
+ return !!agent && agent.config.enabled !== false && agentMap.has(`${aid}::${agent.baseagent}`)
3693
+ && channelInstances.some(inst => inst.channelType === 'aun'
3694
+ && inst.channel.getAidState?.()?.aid === aid
3695
+ && inst.channel.getAidState?.()?.status === 'connected');
3696
+ },
3697
+ });
3698
+ agentApplicationService.setInitializationService(agentInitializationService);
3699
+ ipcServer.setInitializationExecutor(async (cmd) => executeLocalInitializationCommand(agentInitializationService, cmd));
3700
+ for (const entry of fs.readdirSync(resolvePaths().agentsDir, { withFileTypes: true })) {
3701
+ if (!entry.isDirectory())
3702
+ continue;
3703
+ try {
3704
+ const record = readInitialization(entry.name);
3705
+ if (record?.status === 'in_progress')
3706
+ agentInitializationService.resume(entry.name, record.actor);
3707
+ }
3708
+ catch {
3709
+ logger.warn('[Initialization] Recovery requires review for an incomplete operation');
3710
+ }
3711
+ }
3697
3712
  cmdHandler.setAgentApplicationService(agentApplicationService);
3698
3713
  ipcServer.setAgentApplicationService(agentApplicationService);
3699
3714
  ipcServer.setStatsProvider(() => statsCollector.getSnapshot());
@@ -3796,6 +3811,8 @@ async function main() {
3796
3811
  ? {
3797
3812
  ok: true,
3798
3813
  aid: subject.dataScope === 'daemon' ? (params.targetAid ?? delegation.grant.selfAid) : delegation.grant.selfAid,
3814
+ dataScope: subject.dataScope,
3815
+ management: isManagementRole(subject.role),
3799
3816
  }
3800
3817
  : { ok: false, code: decision.code, error: decision.reason };
3801
3818
  }
@@ -3823,26 +3840,41 @@ async function main() {
3823
3840
  return fail('INVALID_DELEGATION', 'delegation does not match the current session');
3824
3841
  }
3825
3842
  const taskAid = delegation.grant.selfAid;
3843
+ let welcomeArgs;
3844
+ if (sub === 'welcome') {
3845
+ try {
3846
+ welcomeArgs = parseAgentWelcomeArgs(argv.slice(2));
3847
+ }
3848
+ catch (error) {
3849
+ return fail('INVALID_ARGS', error.message);
3850
+ }
3851
+ if (delegation.grant.chatType !== 'private')
3852
+ return fail('NOT_ALLOWED', 'welcome requires a private conversation');
3853
+ }
3826
3854
  const targetAid = sub === 'list'
3827
3855
  ? undefined
3828
3856
  : sub === 'persona'
3829
3857
  ? 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);
3858
+ : sub === 'welcome'
3859
+ ? taskAid
3860
+ : sub === 'show'
3861
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : taskAid)
3862
+ : sub === 'reload'
3863
+ ? (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined)
3864
+ : (argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined);
3835
3865
  const operation = sub === 'list' ? 'agent.list'
3836
3866
  : sub === 'show' ? 'agent.show'
3837
3867
  : 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;
3868
+ : sub === 'welcome' ? 'agent.welcome'
3869
+ : sub === 'initialize' || (sub === 'new' && argv.includes('--initialize')) ? 'agent.initialize'
3870
+ : sub === 'new' ? 'agent.create'
3871
+ : sub === 'enable' ? 'agent.enable'
3872
+ : sub === 'disable' ? 'agent.disable'
3873
+ : sub === 'reload' ? 'agent.reload'
3874
+ : sub === 'delete' ? 'agent.delete' : undefined;
3843
3875
  if (!operation)
3844
3876
  return fail('INVALID_ARGS', `unsupported managed agent command: ${sub}`);
3845
- if (sub === 'new' && !argv.includes('--non-interactive')) {
3877
+ if (sub === 'new' && !argv.includes('--non-interactive') && !argv.includes('--initialize')) {
3846
3878
  return fail('MANAGED_NON_INTERACTIVE_REQUIRED', 'interactive Agent creation is unavailable in a managed task', 'MANAGED_NON_INTERACTIVE_REQUIRED');
3847
3879
  }
3848
3880
  if (sub === 'delete' && argv.includes('--purge') && !argv.includes('--confirm-purge')) {
@@ -3871,7 +3903,7 @@ async function main() {
3871
3903
  subject,
3872
3904
  intent: {
3873
3905
  operation,
3874
- scope: operation === 'agent.show' || operation === 'agent.persona'
3906
+ scope: operation === 'agent.show' || operation === 'agent.persona' || operation === 'agent.welcome'
3875
3907
  ? 'agent'
3876
3908
  : operation === 'agent.reload' && targetAid
3877
3909
  ? 'agent'
@@ -3882,6 +3914,7 @@ async function main() {
3882
3914
  aid: targetAid ?? taskAid,
3883
3915
  taskAgentAid: taskAid,
3884
3916
  targetAgentAid: targetAid ?? taskAid,
3917
+ ...(welcomeArgs ? { action: welcomeArgs.action } : {}),
3885
3918
  },
3886
3919
  },
3887
3920
  auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
@@ -3933,6 +3966,7 @@ async function main() {
3933
3966
  : { config: null, agent_md: null, project: null, data: null },
3934
3967
  ...(subject.dataScope === 'daemon' ? {} : { redacted: true }),
3935
3968
  ...(agent.createProgress ? { createProgress: agent.createProgress } : {}),
3969
+ ...(agent.initialization ? { initialization: agent.initialization } : {}),
3936
3970
  } };
3937
3971
  }
3938
3972
  if (operation === 'agent.persona') {
@@ -3967,6 +4001,48 @@ async function main() {
3967
4001
  ...(result.saved ? { saved: true } : {}),
3968
4002
  } };
3969
4003
  }
4004
+ if (operation === 'agent.welcome') {
4005
+ if (subject.role !== 'owner' && !(welcomeArgs?.action === 'show' && subject.role === 'admin')) {
4006
+ return fail('NOT_ALLOWED', 'welcome requires the current Agent Owner (admin may read)');
4007
+ }
4008
+ const { agentWelcome } = await import('./cli/agent.js');
4009
+ const result = await agentWelcome(taskAid, { text: welcomeArgs?.text, trustedLocal: true });
4010
+ if (!result.ok)
4011
+ return fail(result.code ?? 'INTERNAL', result.error);
4012
+ return { ok: true, result: {
4013
+ ok: true,
4014
+ aid: taskAid,
4015
+ content: result.content,
4016
+ ...(result.path ? { path: result.path } : {}),
4017
+ ...(result.saved ? { saved: true } : {}),
4018
+ ...(result.bytes !== undefined ? { bytes: result.bytes } : {}),
4019
+ ...(result.sha256 ? { sha256: result.sha256 } : {}),
4020
+ } };
4021
+ }
4022
+ if (operation === 'agent.initialize') {
4023
+ try {
4024
+ const parsed = parseInitializationArgs(argv.slice(1));
4025
+ const actor = delegation.grant.actorId;
4026
+ if (parsed.resume)
4027
+ return { ok: true, result: agentInitializationService.resume(parsed.aid, actor) };
4028
+ const createPermission = authorizeOperation({
4029
+ source: 'agent-tool', subject,
4030
+ intent: { operation: 'agent.create', scope: 'control', source: 'agent-tool', args: { aid: parsed.aid } },
4031
+ auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
4032
+ });
4033
+ if (!createPermission.allow)
4034
+ return fail(createPermission.code, createPermission.reason);
4035
+ if (!argv.includes('--owner') && !argv.includes('--owners'))
4036
+ return fail('INITIALIZE_OWNER_MISMATCH', 'Explicit Owner required');
4037
+ const plan = resolveInitializationPlan(argv.slice(1));
4038
+ if (!plan.owners.includes(actor))
4039
+ return fail('INITIALIZE_OWNER_MISMATCH', 'The authenticated requesting Owner must be retained');
4040
+ return { ok: true, result: agentInitializationService.start(plan, actor, parsed.dryRun) };
4041
+ }
4042
+ catch (error) {
4043
+ return fail(error.code ?? 'INVALID_ARGS', error.message);
4044
+ }
4045
+ }
3970
4046
  if (operation === 'agent.create') {
3971
4047
  const aid = argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined;
3972
4048
  if (!aid)
@@ -4094,6 +4170,11 @@ async function main() {
4094
4170
  const result = await execAgentAction(sub, { aid: targetAid ?? taskAid, force: argv.includes('--force') }, delegation.grant.actorId, eventBus, agentApplicationService);
4095
4171
  return 'error' in result ? fail(result.code, result.error) : { ok: true, result: { ok: true, ...(result.data ?? {}) } };
4096
4172
  });
4173
+ ipcServer.setTaskResumeExecutor(params => executeTaskResume(params, {
4174
+ sessions: sessionManager,
4175
+ authorizeManaged: authorizeManagedAgentOperation,
4176
+ recover: request => responseEngine.recoverTask(request),
4177
+ }));
4097
4178
  ipcServer.setQueueOperationExecutor(async (params) => {
4098
4179
  const operation = `ec.queue.${params.action ?? 'read'}`;
4099
4180
  const authorization = await authorizeManagedAgentOperation(params, operation);
@@ -4134,6 +4215,38 @@ async function main() {
4134
4215
  const authorization = await authorizeManagedAgentOperation({ ...params, targetAid: params.aid }, params.operation);
4135
4216
  return authorization.ok ? { ok: true } : authorization;
4136
4217
  });
4218
+ ipcServer.setStorageUploadExecutor(async (params) => {
4219
+ const authorization = await authorizeManagedAgentOperation({ ...params, targetAid: params.aid }, 'storage.upload');
4220
+ if (!authorization.ok)
4221
+ return authorization;
4222
+ const session = await sessionManager.getSessionById(params.sessionId);
4223
+ if (!session)
4224
+ return { ok: false, code: 'SESSION_NOT_FOUND', error: 'current session not found' };
4225
+ try {
4226
+ const projectPath = fs.realpathSync(path.resolve(session.projectPath));
4227
+ const requestedFile = path.resolve(session.projectPath, params.localFile);
4228
+ const requestedStat = fs.lstatSync(requestedFile);
4229
+ if (requestedStat.isSymbolicLink()) {
4230
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: 'Upload source must not be a symbolic link' };
4231
+ }
4232
+ const localFile = fs.realpathSync(requestedFile);
4233
+ const stat = fs.lstatSync(localFile);
4234
+ if (!isSameOrDescendant(localFile, projectPath) || isHClassPath(localFile)) {
4235
+ return { ok: false, code: 'INVALID_LOCAL_PATH', error: 'Upload source must be an unprotected file inside the current session project' };
4236
+ }
4237
+ if (!stat.isFile() || stat.isSymbolicLink()) {
4238
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: 'Upload source must be a regular non-symlink file' };
4239
+ }
4240
+ const { storageUpload } = await import('./aun/storage/index.js');
4241
+ const result = await storageUpload(authorization.aid, localFile, params.remotePath, { isPublic: params.isPublic });
4242
+ return result.ok
4243
+ ? { ok: true, objectKey: result.objectKey, publicUrl: result.publicUrl }
4244
+ : { ok: false, code: 'STORAGE_UPLOAD_FAILED', error: result.error };
4245
+ }
4246
+ catch (error) {
4247
+ return { ok: false, code: 'INVALID_LOCAL_FILE', error: error instanceof Error ? error.message : String(error) };
4248
+ }
4249
+ });
4137
4250
  ipcServer.setTriggerExecutor(async (cmd) => {
4138
4251
  const schedulerFor = (agentAid) => {
4139
4252
  const scheduler = triggerSchedulers.get(agentAid);
@@ -4537,6 +4650,8 @@ async function main() {
4537
4650
  timestamp: Date.now()
4538
4651
  });
4539
4652
  // 断开插件系统的渠道
4653
+ removeGroupInviteConfigListener();
4654
+ await shutdownStep('stop group invitation review', () => groupInviteReviewService.dispose());
4540
4655
  await shutdownStep('disconnect channels', () => channelLoader.disconnectAll(channelInstances));
4541
4656
  for (const inst of channelInstances) {
4542
4657
  const type = inst.channelType || inst.adapter.channelName;