evolcore 0.0.25 → 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.
- package/CHANGELOG.md +632 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +203 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +172 -33
- package/dist/agents/codex/app-server-client.js +76 -31
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +434 -446
- package/dist/agents/ecagent-runner.js +174 -34
- package/dist/agents/gemini-runner.js +8 -7
- package/dist/agents/runner-types.js +75 -19
- package/dist/aun/aid/agentmd.js +151 -36
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +4 -4
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +162 -39
- package/dist/aun/{menu-client.js → menu/client.js} +85 -6
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +85 -19
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +19 -9
- package/dist/aun/msg/upload.js +43 -80
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +842 -318
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +212 -89
- package/dist/cli/agent-create.js +626 -11
- package/dist/cli/agent.js +125 -13
- package/dist/cli/aun-commands.js +487 -337
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +55 -33
- package/dist/cli/contact.js +72 -15
- package/dist/cli/ctl-command.js +24 -24
- package/dist/cli/daemon-commands.js +140 -63
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +70 -70
- package/dist/cli/handoff-command.js +46 -14
- package/dist/cli/index.js +91 -79
- package/dist/cli/init.js +34 -1
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +5 -1
- package/dist/cli/menu-client.js +51 -32
- package/dist/cli/model.js +3 -3
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +31 -31
- package/dist/cli/response.js +32 -32
- package/dist/cli/restart-monitor.js +103 -42
- package/dist/cli/stats.js +51 -51
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +74 -64
- package/dist/config/builtin-roles.js +11 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +160 -0
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +97 -8
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +30 -7
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +7 -1
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +53 -49
- package/dist/core/auth/operation-authorizer.js +90 -7
- package/dist/core/auth/operation-catalog.js +145 -4
- package/dist/core/auth/remote-access-store.js +155 -10
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +111 -20
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +159 -65
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +46 -7
- package/dist/core/command/menu-handler.js +392 -100
- package/dist/core/command/menu-protocol.js +45 -6
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +123 -43
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +146 -34
- package/dist/core/message/message-bridge.js +163 -20
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +99 -41
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +755 -144
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +112 -41
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +108 -17
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +9 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +34 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +588 -217
- package/dist/ipc.js +193 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +2 -0
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +61 -2
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +26 -14
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +196 -23
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +60 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +69 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +379 -367
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +76 -71
- package/kits/docs/evolcore/agent-create.md +202 -165
- package/kits/docs/evolcore/agent.md +99 -67
- package/kits/docs/evolcore/aid.md +68 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +241 -195
- package/kits/docs/evolcore/contact.md +75 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +244 -244
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +267 -152
- package/kits/docs/evolcore/menu-client.md +58 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +169 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +53 -50
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +623 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +269 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +42 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +217 -190
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +166 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +76 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +65 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +451 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +215 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +92 -92
- package/kits/templates/roles/member.json +101 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +90 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +53 -34
- package/kits/templates/system-fragments/channel.md +28 -64
- package/kits/templates/system-fragments/commands.md +36 -28
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/reply.md +56 -0
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +104 -98
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /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';
|
|
@@ -46,13 +47,15 @@ import { MessageQueue } from './core/message/message-queue.js';
|
|
|
46
47
|
import { MessageBridge } from './core/message/message-bridge.js';
|
|
47
48
|
import { evaluateOutboundContactAdmission } from './core/message/message-admission.js';
|
|
48
49
|
import { enforceMenuResponseSize, evaluateMenuClientCompatibility, evolMenuResponseTransportMetadata, MenuRequestDeduper, hasValidMenuId, menuFailure, menuPayloadFingerprint, normalizeMenuResponseTiming, parseMenuControl, validateMenuRequest, withMenuProcessingTime, logMenuRequestCompleted, logMenuRequestReceived } from './core/command/menu-protocol.js';
|
|
49
|
-
import { readInstalledEvolcoreVersion } from './utils/evolcore-version.js';
|
|
50
|
+
import { computeBuildId, readBuildIdentity, readEvolcoreRuntimeFlavor, readEvolcoreStartedAtIso, readInstalledEvolcoreVersion, tagErrorTextWithEvolcoreVersion, } from './utils/evolcore-version.js';
|
|
50
51
|
import { recoverAllRoleMutationsSync } from './core/command/role-menu.js';
|
|
51
52
|
import { HandoffRuntime } from './core/handoff/runtime.js';
|
|
52
53
|
import { BootstrapService, completeBootstrapWithWelcome } from './core/bootstrap-service.js';
|
|
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,8 +77,11 @@ 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';
|
|
84
|
+
import { DiagService, executeDiagIpc } from './core/command/diag-service.js';
|
|
78
85
|
import { createEcwebSupervisor } from './utils/ecweb-supervisor.js';
|
|
79
86
|
import { writeMain, removeAll, isMainWinner, scanInstances } from './utils/instance-registry.js';
|
|
80
87
|
import { detectDuplicates } from './core/evolagent-registry.js';
|
|
@@ -97,6 +104,7 @@ import { DAEMON_RUNTIME_EPOCH_ENV, ensureProcessManagedTempDir } from './cli/tas
|
|
|
97
104
|
import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
|
|
98
105
|
import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
|
|
99
106
|
import { MAIN_PACKAGE_NAME } from './product.js';
|
|
107
|
+
import { sanitizeMenuLogValue } from './core/command/menu-protocol.js';
|
|
100
108
|
import fs from 'fs';
|
|
101
109
|
import crypto from 'crypto';
|
|
102
110
|
import { fileURLToPath } from 'url';
|
|
@@ -147,6 +155,45 @@ function summarizeOutboundPayload(payload) {
|
|
|
147
155
|
}
|
|
148
156
|
return s;
|
|
149
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* 给用户可见的错误文案打上 EvolCore 版本标记,便于从对端截图直接判断版本与运行形态。
|
|
160
|
+
*
|
|
161
|
+
* 打标范围只含"出错了"语义的 payload:
|
|
162
|
+
* - `result.error` / `system.error`:任务级与系统级失败(含沙箱、权限、超时)
|
|
163
|
+
* - `status.error`:终态元数据,附带结构化版本字段供前端不受截断影响地展示
|
|
164
|
+
* - `command.error`:仅当带 `reasonCode`(授权/权限拒绝)时才打。命令参数写错、
|
|
165
|
+
* 未知命令这类输入校验反馈不打——它们与版本无关,逐条加前缀只会变成噪音。
|
|
166
|
+
*
|
|
167
|
+
* 返回新对象,不改调用方持有的 payload(同一 payload 可能被重复发送到多个渠道)。
|
|
168
|
+
*/
|
|
169
|
+
function tagErrorPayloadWithEvolcoreVersion(payload) {
|
|
170
|
+
switch (payload.kind) {
|
|
171
|
+
case 'result.error':
|
|
172
|
+
case 'system.error':
|
|
173
|
+
return { ...payload, text: tagErrorTextWithEvolcoreVersion(payload.text) };
|
|
174
|
+
case 'command.error':
|
|
175
|
+
if (!payload.reasonCode)
|
|
176
|
+
return payload;
|
|
177
|
+
return { ...payload, text: tagErrorTextWithEvolcoreVersion(payload.text) };
|
|
178
|
+
case 'status.error': {
|
|
179
|
+
const metadata = payload.metadata;
|
|
180
|
+
return {
|
|
181
|
+
...payload,
|
|
182
|
+
metadata: {
|
|
183
|
+
...metadata,
|
|
184
|
+
...(typeof metadata?.message === 'string'
|
|
185
|
+
? { message: tagErrorTextWithEvolcoreVersion(metadata.message) }
|
|
186
|
+
: {}),
|
|
187
|
+
evolcoreVersion: readInstalledEvolcoreVersion(),
|
|
188
|
+
evolcoreFlavor: readEvolcoreRuntimeFlavor(),
|
|
189
|
+
evolcoreStartedAt: readEvolcoreStartedAtIso(),
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
default:
|
|
194
|
+
return payload;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
150
197
|
function shouldCountSentPayload(payload) {
|
|
151
198
|
return [
|
|
152
199
|
'result.text',
|
|
@@ -333,153 +380,153 @@ function seedUpgradeCheckTrigger(manager, owner) {
|
|
|
333
380
|
// take the watchdog down with it.
|
|
334
381
|
const monitorEntry = platform.resolveCliEntry(packageRoot);
|
|
335
382
|
const stageParent = path.join(resolvePaths().root, 'data', 'monitor-stage');
|
|
336
|
-
fs.writeFileSync(scriptPath, `#!/usr/bin/env node
|
|
337
|
-
const fs = require('node:fs');
|
|
338
|
-
const path = require('node:path');
|
|
339
|
-
const { existsSync, readFileSync } = fs;
|
|
340
|
-
const { spawn } = require('node:child_process');
|
|
341
|
-
|
|
342
|
-
const CLI_PATH = ${JSON.stringify(monitorEntry.entry)};
|
|
343
|
-
const CLI_ARGS = ${JSON.stringify(monitorEntry.args)};
|
|
344
|
-
const PACKAGE_ROOT = ${JSON.stringify(packageRoot)};
|
|
345
|
-
const STAGE_PARENT = ${JSON.stringify(stageParent)};
|
|
346
|
-
const PACKAGE_JSON = ${JSON.stringify(packageJsonPath)};
|
|
347
|
-
const PACKAGE_NAME = ${JSON.stringify(MAIN_PACKAGE_NAME)};
|
|
348
|
-
const DEV_MODE = ${devMode ? 'true' : 'false'};
|
|
349
|
-
|
|
350
|
-
function emit(outcome, text) {
|
|
351
|
-
process.stdout.write(JSON.stringify({ outcome, text, files: [] }));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function compareVersions(a, b) {
|
|
355
|
-
const pa = a.split('-')[0].split('.').map(Number);
|
|
356
|
-
const pb = b.split('-')[0].split('.').map(Number);
|
|
357
|
-
const count = Math.max(pa.length, pb.length);
|
|
358
|
-
for (let i = 0; i < count; i += 1) {
|
|
359
|
-
const av = Number.isFinite(pa[i]) ? pa[i] : 0;
|
|
360
|
-
const bv = Number.isFinite(pb[i]) ? pb[i] : 0;
|
|
361
|
-
if (av < bv) return -1;
|
|
362
|
-
if (av > bv) return 1;
|
|
363
|
-
}
|
|
364
|
-
return 0;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function latestVersion() {
|
|
368
|
-
const controller = new AbortController();
|
|
369
|
-
const timer = setTimeout(() => controller.abort(), 10_000);
|
|
370
|
-
try {
|
|
371
|
-
const response = await fetch('https://registry.npmjs.org/' + encodeURIComponent(PACKAGE_NAME) + '/latest', {
|
|
372
|
-
signal: controller.signal,
|
|
373
|
-
headers: { Accept: 'application/json' },
|
|
374
|
-
});
|
|
375
|
-
if (!response.ok) return null;
|
|
376
|
-
const data = await response.json();
|
|
377
|
-
return typeof data.version === 'string' ? data.version : null;
|
|
378
|
-
} finally {
|
|
379
|
-
clearTimeout(timer);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async function main() {
|
|
384
|
-
if (DEV_MODE) {
|
|
385
|
-
emit('noop', 'upgrade check skipped in dev mode');
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
let localVersion;
|
|
390
|
-
try {
|
|
391
|
-
localVersion = JSON.parse(readFileSync(PACKAGE_JSON, 'utf8')).version;
|
|
392
|
-
} catch {
|
|
393
|
-
emit('error', 'failed to read local ec version');
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
if (typeof localVersion !== 'string' || !localVersion) {
|
|
397
|
-
emit('error', 'failed to read local ec version');
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
let remoteVersion;
|
|
402
|
-
try {
|
|
403
|
-
remoteVersion = await latestVersion();
|
|
404
|
-
} catch {
|
|
405
|
-
remoteVersion = null;
|
|
406
|
-
}
|
|
407
|
-
if (!remoteVersion) {
|
|
408
|
-
emit('error', 'failed to check evolcore latest version');
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
if (compareVersions(localVersion, remoteVersion) >= 0) {
|
|
412
|
-
emit('noop', 'evolcore is already up to date (' + localVersion + '; latest ' + remoteVersion + ')');
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
if (!existsSync(CLI_PATH)) {
|
|
416
|
-
emit('error', 'restart-monitor entry not found: ' + CLI_PATH);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Installed mode: copy the monitor out of the package before it upgrades that
|
|
421
|
-
// same package. Mirrors prepareMonitorStage(); kept inline because this file
|
|
422
|
-
// is generated standalone CJS. Any failure degrades to launching in place —
|
|
423
|
-
// losing upgrade isolation beats losing the upgrade.
|
|
424
|
-
let launchArgs = CLI_ARGS;
|
|
425
|
-
const launchEnv = { ...process.env };
|
|
426
|
-
if (!DEV_MODE && STAGE_PARENT) {
|
|
427
|
-
try {
|
|
428
|
-
const stageDir = path.join(STAGE_PARENT, 'upgrade-' + process.pid + '-' + Date.now());
|
|
429
|
-
fs.mkdirSync(stageDir, { recursive: true });
|
|
430
|
-
fs.cpSync(path.join(PACKAGE_ROOT, 'dist'), path.join(stageDir, 'dist'), { recursive: true });
|
|
431
|
-
if (existsSync(PACKAGE_JSON)) fs.copyFileSync(PACKAGE_JSON, path.join(stageDir, 'package.json'));
|
|
432
|
-
const modulesSource = path.join(PACKAGE_ROOT, 'node_modules');
|
|
433
|
-
if (existsSync(modulesSource)) {
|
|
434
|
-
const staged = path.join(stageDir, 'node_modules');
|
|
435
|
-
try {
|
|
436
|
-
// junction works unelevated on Windows; dir symlink elsewhere.
|
|
437
|
-
fs.symlinkSync(modulesSource, staged, process.platform === 'win32' ? 'junction' : 'dir');
|
|
438
|
-
fs.readdirSync(staged);
|
|
439
|
-
} catch (linkError) {
|
|
440
|
-
fs.rmSync(staged, { recursive: true, force: true });
|
|
441
|
-
fs.cpSync(modulesSource, staged, { recursive: true });
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const stagedEntry = path.join(stageDir, 'dist', 'cli', 'index.js');
|
|
445
|
-
if (existsSync(stagedEntry)) {
|
|
446
|
-
launchArgs = [stagedEntry];
|
|
447
|
-
launchEnv.EVOLCORE_TARGET_PACKAGE_ROOT = PACKAGE_ROOT;
|
|
448
|
-
launchEnv.EVOLCORE_MONITOR_STAGE = stageDir;
|
|
449
|
-
}
|
|
450
|
-
} catch (stageError) {
|
|
451
|
-
// Fall through with the in-place entry.
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
try {
|
|
456
|
-
const child = spawn(process.execPath, [...launchArgs, 'restart-monitor'], {
|
|
457
|
-
detached: true,
|
|
458
|
-
stdio: 'ignore',
|
|
459
|
-
windowsHide: process.platform === 'win32',
|
|
460
|
-
env: launchEnv,
|
|
461
|
-
});
|
|
462
|
-
child.unref();
|
|
463
|
-
const pid = child.pid;
|
|
464
|
-
// The daemon is still running here — the monitor is what stops it. So a
|
|
465
|
-
// monitor that dies on load costs the upgrade, not the service; still,
|
|
466
|
-
// report it accurately instead of claiming success.
|
|
467
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
468
|
-
let alive = false;
|
|
469
|
-
try { process.kill(pid, 0); alive = true; } catch (e) { alive = false; }
|
|
470
|
-
if (!alive) {
|
|
471
|
-
emit('error', 'restart-monitor exited during startup; upgrade to ' + remoteVersion + ' not applied');
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
emit('success', 'evolcore upgrade available: ' + localVersion + ' -> ' + remoteVersion + '; restart-monitor started');
|
|
475
|
-
} catch (error) {
|
|
476
|
-
emit('error', 'failed to start restart-monitor: ' + (error && error.message ? error.message : String(error)));
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
main().catch((error) => {
|
|
481
|
-
emit('error', 'upgrade check failed: ' + (error && error.message ? error.message : String(error)));
|
|
482
|
-
});
|
|
383
|
+
fs.writeFileSync(scriptPath, `#!/usr/bin/env node
|
|
384
|
+
const fs = require('node:fs');
|
|
385
|
+
const path = require('node:path');
|
|
386
|
+
const { existsSync, readFileSync } = fs;
|
|
387
|
+
const { spawn } = require('node:child_process');
|
|
388
|
+
|
|
389
|
+
const CLI_PATH = ${JSON.stringify(monitorEntry.entry)};
|
|
390
|
+
const CLI_ARGS = ${JSON.stringify(monitorEntry.args)};
|
|
391
|
+
const PACKAGE_ROOT = ${JSON.stringify(packageRoot)};
|
|
392
|
+
const STAGE_PARENT = ${JSON.stringify(stageParent)};
|
|
393
|
+
const PACKAGE_JSON = ${JSON.stringify(packageJsonPath)};
|
|
394
|
+
const PACKAGE_NAME = ${JSON.stringify(MAIN_PACKAGE_NAME)};
|
|
395
|
+
const DEV_MODE = ${devMode ? 'true' : 'false'};
|
|
396
|
+
|
|
397
|
+
function emit(outcome, text) {
|
|
398
|
+
process.stdout.write(JSON.stringify({ outcome, text, files: [] }));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function compareVersions(a, b) {
|
|
402
|
+
const pa = a.split('-')[0].split('.').map(Number);
|
|
403
|
+
const pb = b.split('-')[0].split('.').map(Number);
|
|
404
|
+
const count = Math.max(pa.length, pb.length);
|
|
405
|
+
for (let i = 0; i < count; i += 1) {
|
|
406
|
+
const av = Number.isFinite(pa[i]) ? pa[i] : 0;
|
|
407
|
+
const bv = Number.isFinite(pb[i]) ? pb[i] : 0;
|
|
408
|
+
if (av < bv) return -1;
|
|
409
|
+
if (av > bv) return 1;
|
|
410
|
+
}
|
|
411
|
+
return 0;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function latestVersion() {
|
|
415
|
+
const controller = new AbortController();
|
|
416
|
+
const timer = setTimeout(() => controller.abort(), 10_000);
|
|
417
|
+
try {
|
|
418
|
+
const response = await fetch('https://registry.npmjs.org/' + encodeURIComponent(PACKAGE_NAME) + '/latest', {
|
|
419
|
+
signal: controller.signal,
|
|
420
|
+
headers: { Accept: 'application/json' },
|
|
421
|
+
});
|
|
422
|
+
if (!response.ok) return null;
|
|
423
|
+
const data = await response.json();
|
|
424
|
+
return typeof data.version === 'string' ? data.version : null;
|
|
425
|
+
} finally {
|
|
426
|
+
clearTimeout(timer);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async function main() {
|
|
431
|
+
if (DEV_MODE) {
|
|
432
|
+
emit('noop', 'upgrade check skipped in dev mode');
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let localVersion;
|
|
437
|
+
try {
|
|
438
|
+
localVersion = JSON.parse(readFileSync(PACKAGE_JSON, 'utf8')).version;
|
|
439
|
+
} catch {
|
|
440
|
+
emit('error', 'failed to read local ec version');
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (typeof localVersion !== 'string' || !localVersion) {
|
|
444
|
+
emit('error', 'failed to read local ec version');
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
let remoteVersion;
|
|
449
|
+
try {
|
|
450
|
+
remoteVersion = await latestVersion();
|
|
451
|
+
} catch {
|
|
452
|
+
remoteVersion = null;
|
|
453
|
+
}
|
|
454
|
+
if (!remoteVersion) {
|
|
455
|
+
emit('error', 'failed to check evolcore latest version');
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (compareVersions(localVersion, remoteVersion) >= 0) {
|
|
459
|
+
emit('noop', 'evolcore is already up to date (' + localVersion + '; latest ' + remoteVersion + ')');
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (!existsSync(CLI_PATH)) {
|
|
463
|
+
emit('error', 'restart-monitor entry not found: ' + CLI_PATH);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Installed mode: copy the monitor out of the package before it upgrades that
|
|
468
|
+
// same package. Mirrors prepareMonitorStage(); kept inline because this file
|
|
469
|
+
// is generated standalone CJS. Any failure degrades to launching in place —
|
|
470
|
+
// losing upgrade isolation beats losing the upgrade.
|
|
471
|
+
let launchArgs = CLI_ARGS;
|
|
472
|
+
const launchEnv = { ...process.env };
|
|
473
|
+
if (!DEV_MODE && STAGE_PARENT) {
|
|
474
|
+
try {
|
|
475
|
+
const stageDir = path.join(STAGE_PARENT, 'upgrade-' + process.pid + '-' + Date.now());
|
|
476
|
+
fs.mkdirSync(stageDir, { recursive: true });
|
|
477
|
+
fs.cpSync(path.join(PACKAGE_ROOT, 'dist'), path.join(stageDir, 'dist'), { recursive: true });
|
|
478
|
+
if (existsSync(PACKAGE_JSON)) fs.copyFileSync(PACKAGE_JSON, path.join(stageDir, 'package.json'));
|
|
479
|
+
const modulesSource = path.join(PACKAGE_ROOT, 'node_modules');
|
|
480
|
+
if (existsSync(modulesSource)) {
|
|
481
|
+
const staged = path.join(stageDir, 'node_modules');
|
|
482
|
+
try {
|
|
483
|
+
// junction works unelevated on Windows; dir symlink elsewhere.
|
|
484
|
+
fs.symlinkSync(modulesSource, staged, process.platform === 'win32' ? 'junction' : 'dir');
|
|
485
|
+
fs.readdirSync(staged);
|
|
486
|
+
} catch (linkError) {
|
|
487
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
488
|
+
fs.cpSync(modulesSource, staged, { recursive: true });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const stagedEntry = path.join(stageDir, 'dist', 'cli', 'index.js');
|
|
492
|
+
if (existsSync(stagedEntry)) {
|
|
493
|
+
launchArgs = [stagedEntry];
|
|
494
|
+
launchEnv.EVOLCORE_TARGET_PACKAGE_ROOT = PACKAGE_ROOT;
|
|
495
|
+
launchEnv.EVOLCORE_MONITOR_STAGE = stageDir;
|
|
496
|
+
}
|
|
497
|
+
} catch (stageError) {
|
|
498
|
+
// Fall through with the in-place entry.
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
try {
|
|
503
|
+
const child = spawn(process.execPath, [...launchArgs, 'restart-monitor'], {
|
|
504
|
+
detached: true,
|
|
505
|
+
stdio: 'ignore',
|
|
506
|
+
windowsHide: process.platform === 'win32',
|
|
507
|
+
env: launchEnv,
|
|
508
|
+
});
|
|
509
|
+
child.unref();
|
|
510
|
+
const pid = child.pid;
|
|
511
|
+
// The daemon is still running here — the monitor is what stops it. So a
|
|
512
|
+
// monitor that dies on load costs the upgrade, not the service; still,
|
|
513
|
+
// report it accurately instead of claiming success.
|
|
514
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
515
|
+
let alive = false;
|
|
516
|
+
try { process.kill(pid, 0); alive = true; } catch (e) { alive = false; }
|
|
517
|
+
if (!alive) {
|
|
518
|
+
emit('error', 'restart-monitor exited during startup; upgrade to ' + remoteVersion + ' not applied');
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
emit('success', 'evolcore upgrade available: ' + localVersion + ' -> ' + remoteVersion + '; restart-monitor started');
|
|
522
|
+
} catch (error) {
|
|
523
|
+
emit('error', 'failed to start restart-monitor: ' + (error && error.message ? error.message : String(error)));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
main().catch((error) => {
|
|
528
|
+
emit('error', 'upgrade check failed: ' + (error && error.message ? error.message : String(error)));
|
|
529
|
+
});
|
|
483
530
|
`);
|
|
484
531
|
// Remove the pre-Node script left by older installations so it cannot be
|
|
485
532
|
// selected by a stale trigger definition or run manually by accident.
|
|
@@ -489,6 +536,51 @@ main().catch((error) => {
|
|
|
489
536
|
atomicWriteJson(manager.definitionPath(definition.id), definition);
|
|
490
537
|
fs.rmSync(manager.activePath(definition.id), { force: true });
|
|
491
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
|
+
}
|
|
492
584
|
function removeLegacyAgentUpgradeCheck(manager) {
|
|
493
585
|
let existing;
|
|
494
586
|
try {
|
|
@@ -610,6 +702,7 @@ async function runBindBootstrapDaemon(daemonCfg) {
|
|
|
610
702
|
}));
|
|
611
703
|
ipcServer.setControlToken(controlToken);
|
|
612
704
|
ipcServer.setRemoteAccessService(remoteAccessService);
|
|
705
|
+
ipcServer.setRemoteAccessOwnerProvider(() => daemonCfg.owners?.[0]);
|
|
613
706
|
ipcServer.setShutdownExecutor(async (reason) => {
|
|
614
707
|
if (!shutdown) {
|
|
615
708
|
pendingShutdownReason = reason;
|
|
@@ -757,6 +850,12 @@ async function main() {
|
|
|
757
850
|
// Service managers do not necessarily export TMPDIR. Establish the private
|
|
758
851
|
// managed root before any runner or task runtime is initialized.
|
|
759
852
|
ensureProcessManagedTempDir();
|
|
853
|
+
const runtimeEntry = fileURLToPath(import.meta.url);
|
|
854
|
+
const diskDistDir = path.join(getPackageRoot(), 'dist');
|
|
855
|
+
const runtimeIsDist = path.resolve(path.dirname(runtimeEntry)) === path.resolve(diskDistDir);
|
|
856
|
+
const runtimeBuildIdentity = readBuildIdentity(runtimeIsDist ? path.dirname(runtimeEntry) : diskDistDir, readEvolcoreVersion());
|
|
857
|
+
if (!runtimeIsDist)
|
|
858
|
+
runtimeBuildIdentity.id = null;
|
|
760
859
|
// 启动信息:目录类型 + 版本号 + 代码最新时间戳
|
|
761
860
|
{
|
|
762
861
|
const pkgRoot = getPackageRoot();
|
|
@@ -798,6 +897,10 @@ async function main() {
|
|
|
798
897
|
console.error(`[EvolCore] 代码时间: ${latestMtime ? fmtTime(latestMtime) : '?'}`);
|
|
799
898
|
}
|
|
800
899
|
console.error('[EvolCore] ✓ Version info printed');
|
|
900
|
+
const diskBuildId = computeBuildId(diskDistDir);
|
|
901
|
+
console.error(`[EvolCore] 运行 build ID: ${runtimeIsDist ? (runtimeBuildIdentity.id ?? '?') : 'source'}`);
|
|
902
|
+
console.error(`[EvolCore] 磁盘 dist build ID: ${diskBuildId ?? '?'}`);
|
|
903
|
+
logger.info(`[Build] runtimeMode=${runtimeIsDist ? 'dist' : 'source'} runtimeBuildId=${runtimeBuildIdentity.id ?? 'source'} diskDistBuildId=${diskBuildId ?? 'unknown'} match=${runtimeIsDist && runtimeBuildIdentity.id !== null && runtimeBuildIdentity.id === diskBuildId}`);
|
|
801
904
|
// 过滤飞书 SDK 的 info 日志
|
|
802
905
|
const originalLog = console.log;
|
|
803
906
|
const originalInfo = console.info;
|
|
@@ -906,6 +1009,10 @@ async function main() {
|
|
|
906
1009
|
}
|
|
907
1010
|
// ── 自动迁移 ──
|
|
908
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
|
+
}
|
|
909
1016
|
// daemon.json 的旧 ecweb/serviceProxy 结构已在启动前归一化为 services[]。
|
|
910
1017
|
// ── 配置体系初始化(schema 字段不相交硬约束校验)──
|
|
911
1018
|
try {
|
|
@@ -975,13 +1082,13 @@ async function main() {
|
|
|
975
1082
|
port: ecwebConfig.port ?? DEFAULT_ECWEB_PORT,
|
|
976
1083
|
logger,
|
|
977
1084
|
});
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1085
|
+
// ECWeb is optional and has its own health checks/restart loop. Starting
|
|
1086
|
+
// it must not hold up the daemon's agent/IPC initialization or ready
|
|
1087
|
+
// signal; status will report it as starting until the first healthy probe.
|
|
1088
|
+
onShutdown(() => ecwebSupervisor?.stop());
|
|
1089
|
+
void ecwebSupervisor.start().catch((error) => {
|
|
983
1090
|
logger.warn(`ECWeb supervisor 启动失败(不影响 daemon 主流程): ${error?.message || error}`);
|
|
984
|
-
}
|
|
1091
|
+
});
|
|
985
1092
|
}
|
|
986
1093
|
if (bindBootstrapMode && daemonCfg.aid && loadAllAgents().agents.length === 0) {
|
|
987
1094
|
await runBindBootstrapDaemon(daemonCfg);
|
|
@@ -1188,6 +1295,11 @@ async function main() {
|
|
|
1188
1295
|
});
|
|
1189
1296
|
// 交互路由器
|
|
1190
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
|
+
});
|
|
1191
1303
|
// 为所有支持权限的 agent 设置 gateway
|
|
1192
1304
|
for (const inst of agentInstances) {
|
|
1193
1305
|
inst.agent.setPermissionGateway?.(permissionGateway);
|
|
@@ -1276,6 +1388,7 @@ async function main() {
|
|
|
1276
1388
|
// 创建命令处理器
|
|
1277
1389
|
const cmdHandler = new CommandHandler(sessionManager, agentMap, messageCache, eventBus, primaryRunnerKey);
|
|
1278
1390
|
let agentApplicationService;
|
|
1391
|
+
let agentInitializationService;
|
|
1279
1392
|
cmdHandler.setAgentDelegationRegistry(agentDelegationRegistry);
|
|
1280
1393
|
cmdHandler.setPermissionGateway(permissionGateway);
|
|
1281
1394
|
cmdHandler.setInteractionRouter(interactionRouter);
|
|
@@ -1321,10 +1434,13 @@ async function main() {
|
|
|
1321
1434
|
dedupPath: daemonMessageDedupPath(),
|
|
1322
1435
|
});
|
|
1323
1436
|
// 设置中断回调(精确中断正在处理的 agent)
|
|
1324
|
-
messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
|
|
1437
|
+
messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message', timeout) => {
|
|
1325
1438
|
void baseagent;
|
|
1326
1439
|
void evolagentName;
|
|
1327
|
-
|
|
1440
|
+
if (timeout)
|
|
1441
|
+
await responseEngine.timeoutSession(sessionKey, timeout);
|
|
1442
|
+
else
|
|
1443
|
+
await responseEngine.interruptSession(sessionKey, reason);
|
|
1328
1444
|
});
|
|
1329
1445
|
messageQueue.setEventBus(eventBus);
|
|
1330
1446
|
// Restore persisted input before Trigger schedulers start. Trigger-owned work
|
|
@@ -1480,7 +1596,7 @@ async function main() {
|
|
|
1480
1596
|
};
|
|
1481
1597
|
};
|
|
1482
1598
|
const validateTriggerFeedbackChannels = (definition) => {
|
|
1483
|
-
if (definition.feedback.strategy === 'silent')
|
|
1599
|
+
if (definition.feedback.strategy === 'silent' || definition.feedback.strategy === 'event_session')
|
|
1484
1600
|
return;
|
|
1485
1601
|
const target = definition.feedback.strategy === 'target'
|
|
1486
1602
|
? definition.feedback.target
|
|
@@ -1563,6 +1679,9 @@ async function main() {
|
|
|
1563
1679
|
if (!effortDecision.ok)
|
|
1564
1680
|
throw new Error(effortDecision.message || 'trigger effort is not allowed by current role');
|
|
1565
1681
|
}
|
|
1682
|
+
if (!actor.management && definition.feedback.strategy === 'event_session') {
|
|
1683
|
+
throw new Error('event-session feedback requires owner/admin');
|
|
1684
|
+
}
|
|
1566
1685
|
if (!actor.management && definition.feedback.strategy === 'target') {
|
|
1567
1686
|
const target = definition.feedback.target;
|
|
1568
1687
|
const origin = actor.origin;
|
|
@@ -1670,6 +1789,9 @@ async function main() {
|
|
|
1670
1789
|
if (privilegedReason && !persistedFullAccessApproval && !hasDaemonTriggerAuthority(subject)) {
|
|
1671
1790
|
return { allowed: false, reason: `${privilegedReason} requires current DaemonOwner` };
|
|
1672
1791
|
}
|
|
1792
|
+
if (definition.feedback.strategy === 'event_session' && !isManagementRole(role)) {
|
|
1793
|
+
return { allowed: false, reason: 'event-session feedback requires current owner/admin role' };
|
|
1794
|
+
}
|
|
1673
1795
|
if (definition.feedback.strategy === 'target' && !isManagementRole(role)) {
|
|
1674
1796
|
const target = definition.feedback.target;
|
|
1675
1797
|
if (!target
|
|
@@ -1779,6 +1901,7 @@ async function main() {
|
|
|
1779
1901
|
const manager = new TriggerDefinitionManager(owner.aid);
|
|
1780
1902
|
if (opts.seedUpgradeCheck) {
|
|
1781
1903
|
seedUpgradeCheckTrigger(manager, owner);
|
|
1904
|
+
seedTaskRecoveryTrigger(manager, owner);
|
|
1782
1905
|
}
|
|
1783
1906
|
else {
|
|
1784
1907
|
removeLegacyAgentUpgradeCheck(manager);
|
|
@@ -1789,6 +1912,8 @@ async function main() {
|
|
|
1789
1912
|
getChannel: getTriggerChannel,
|
|
1790
1913
|
sessionManager,
|
|
1791
1914
|
messageQueue,
|
|
1915
|
+
recoverTask: request => responseEngine.recoverTask(request),
|
|
1916
|
+
inspectTargetExecution: (sessionId, attemptId, selfAid) => responseEngine.inspectTargetExecution(sessionId, attemptId, selfAid),
|
|
1792
1917
|
eventBus,
|
|
1793
1918
|
tryHandoff: async (input, text, target, binding) => {
|
|
1794
1919
|
if (input.signal?.aborted) {
|
|
@@ -1905,9 +2030,21 @@ async function main() {
|
|
|
1905
2030
|
const inst = channelInstances.find(candidate => candidate.adapter.channelKey === channelKey);
|
|
1906
2031
|
return !!inst && inst.channel.getStatus?.().connected === true;
|
|
1907
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
|
+
});
|
|
1908
2043
|
const msgBridge = new MessageBridge(defaultProjectPath, sessionManager, processor, messageQueue, cmdHandler, eventBus, primaryAgent?.config.debounce, () => processLevelOwners);
|
|
1909
2044
|
msgBridge.setAgentRegistry(agentRegistry);
|
|
1910
2045
|
msgBridge.setInteractionRouter(interactionRouter);
|
|
2046
|
+
msgBridge.setGroupInviteReviewService(groupInviteReviewService);
|
|
2047
|
+
cmdHandler.setGroupInviteDecisionResolver((selfAid, ownerAid, inviteId, action) => groupInviteReviewService.decideManaged(selfAid, ownerAid, inviteId, action));
|
|
1911
2048
|
msgBridge.setContactBindRuntimeChecker(isContactBindChannelReady);
|
|
1912
2049
|
msgBridge.setAidStatsCollector(aidStatsCollector);
|
|
1913
2050
|
cmdHandler.setContactRequestSubmitter((input) => msgBridge.submitAgentContactRequest(input));
|
|
@@ -1918,7 +2055,9 @@ async function main() {
|
|
|
1918
2055
|
function registerChannelInstance(inst) {
|
|
1919
2056
|
// 0. 包装 adapter.send,记录所有出站到 channel-out.log
|
|
1920
2057
|
const originalSend = inst.adapter.send.bind(inst.adapter);
|
|
1921
|
-
inst.adapter.send = async (envelope,
|
|
2058
|
+
inst.adapter.send = async (envelope, rawPayload) => {
|
|
2059
|
+
// 版本标记在记账之前打,让 channel-out.log 与对端看到的文案一致。
|
|
2060
|
+
const payload = rawPayload ? tagErrorPayloadWithEvolcoreVersion(rawPayload) : rawPayload;
|
|
1922
2061
|
const owningAgent = agentRegistry.resolveByChannel(inst.adapter.channelKey)
|
|
1923
2062
|
?? agentRegistry.resolveByChannel(inst.adapter.channelName);
|
|
1924
2063
|
logger.channelOut({
|
|
@@ -1929,7 +2068,7 @@ async function main() {
|
|
|
1929
2068
|
sessionId: envelope.sessionId,
|
|
1930
2069
|
agentAid: owningAgent?.aid,
|
|
1931
2070
|
agentName: envelope.agentName,
|
|
1932
|
-
payload: summarizeOutboundPayload(payload),
|
|
2071
|
+
payload: sanitizeMenuLogValue(summarizeOutboundPayload(payload)),
|
|
1933
2072
|
});
|
|
1934
2073
|
const result = await originalSend(envelope, payload);
|
|
1935
2074
|
// AUN adapters return an explicit receipt. Only a receipt with a remote
|
|
@@ -2316,6 +2455,14 @@ async function main() {
|
|
|
2316
2455
|
// A failed bind (for example, a stale Windows named pipe) must abort startup
|
|
2317
2456
|
// without creating a second AUN session that can kick the old daemon.
|
|
2318
2457
|
let controlChannel;
|
|
2458
|
+
const diagService = new DiagService(() => ({ controlAid: loadDaemonConfig().aid, owners: loadDaemonConfig().owners ?? [] }), async (to, text) => {
|
|
2459
|
+
if (!controlChannel)
|
|
2460
|
+
throw new Error('Control AID channel is unavailable');
|
|
2461
|
+
const result = await controlChannel.sendDaemonMsg({ to, payload: { type: 'text', text }, encrypt: true });
|
|
2462
|
+
if (!result.ok)
|
|
2463
|
+
throw new Error(result.error ?? 'Invitation send failed');
|
|
2464
|
+
});
|
|
2465
|
+
cmdHandler.setDiagService(diagService);
|
|
2319
2466
|
let shutdown;
|
|
2320
2467
|
let pendingShutdownReason;
|
|
2321
2468
|
const ipcServer = new IpcServer(resolvePaths().socket, () => {
|
|
@@ -2335,6 +2482,13 @@ async function main() {
|
|
|
2335
2482
|
return {
|
|
2336
2483
|
pid: process.pid,
|
|
2337
2484
|
uptime: snap.uptimeMs,
|
|
2485
|
+
build: {
|
|
2486
|
+
runtimeMode: runtimeIsDist ? 'dist' : 'source',
|
|
2487
|
+
runtimeId: runtimeBuildIdentity.id,
|
|
2488
|
+
diskDistId: computeBuildId(diskDistDir),
|
|
2489
|
+
entry: runtimeBuildIdentity.entry,
|
|
2490
|
+
version: runtimeBuildIdentity.version,
|
|
2491
|
+
},
|
|
2338
2492
|
controlPlane: {
|
|
2339
2493
|
ready: true,
|
|
2340
2494
|
owned: processLevelOwners.length > 0,
|
|
@@ -2384,6 +2538,7 @@ async function main() {
|
|
|
2384
2538
|
return cmdHandler.handleCtl(cmd, sessionId, delegation.grant);
|
|
2385
2539
|
});
|
|
2386
2540
|
ipcServer.setDaemonRuntimeEpoch(agentDelegationRegistry.getRuntimeEpoch());
|
|
2541
|
+
ipcServer.setRemoteAccessOwnerProvider(() => processLevelOwners[0]);
|
|
2387
2542
|
cmdHandler.setDaemonMonitorProvider(() => ipcServer.getMonitorSnapshot().snapshot);
|
|
2388
2543
|
// Register every IPC executor/provider before exposing the endpoint. The
|
|
2389
2544
|
// function declaration is hoisted, while its invocation remains here so a
|
|
@@ -2446,14 +2601,16 @@ async function main() {
|
|
|
2446
2601
|
aunSdkLog: daemonCfg.debug?.aunSdkLog,
|
|
2447
2602
|
});
|
|
2448
2603
|
// connect() 失败不置空实例:AUNChannel 内部有无限重连(SDK auto_reconnect +
|
|
2449
|
-
// scheduleReconnect
|
|
2450
|
-
|
|
2451
|
-
|
|
2604
|
+
// scheduleReconnect),首连失败会自愈;启动连接放到后台,避免 ready signal
|
|
2605
|
+
// 被远端网关/TLS 首连延迟阻塞。Attach the handlers below before the
|
|
2606
|
+
// promise can complete so an early control message is still accepted.
|
|
2607
|
+
const controlConnectPromise = controlChannel.connect()
|
|
2608
|
+
.then(() => {
|
|
2452
2609
|
logger.info(`✓ 控制 AID 已连接: ${daemonCfg.aid}`);
|
|
2453
|
-
}
|
|
2454
|
-
|
|
2610
|
+
})
|
|
2611
|
+
.catch((e) => {
|
|
2455
2612
|
logger.warn(`控制 AID 首连失败(后台自动重连,不影响 daemon 主流程): ${e?.message || e}`);
|
|
2456
|
-
}
|
|
2613
|
+
});
|
|
2457
2614
|
// 控制 AID 接收 daemon-owner 或有效远程访问 token 授权的指令:
|
|
2458
2615
|
// 1. /pair — daemon 远程控制配对码(文本快路径)
|
|
2459
2616
|
// 2. menu.* JSON — 路由到 cmdHandler.execMenuForControl(进程级 + 全量权限)
|
|
@@ -2481,7 +2638,10 @@ async function main() {
|
|
|
2481
2638
|
catch {
|
|
2482
2639
|
parsed = null;
|
|
2483
2640
|
}
|
|
2484
|
-
const menuResponseContext = () =>
|
|
2641
|
+
const menuResponseContext = () => ({
|
|
2642
|
+
...controlReplyContext(opts, evolMenuResponseTransportMetadata(opts.protectedHeaders?.sdk_version)),
|
|
2643
|
+
...(opts.peerDeviceId ? { toDeviceId: opts.peerDeviceId } : {}),
|
|
2644
|
+
});
|
|
2485
2645
|
const sendControlMenuResponse = async (response) => {
|
|
2486
2646
|
const timedResponse = withMenuProcessingTime(enforceMenuResponseSize(response, 128 * 1024 - 1024), menuTiming);
|
|
2487
2647
|
const request = activeMenuRequest ?? {
|
|
@@ -2522,6 +2682,13 @@ async function main() {
|
|
|
2522
2682
|
const isRoleMenu = menuControl.isMenu
|
|
2523
2683
|
&& (menuControl.name === 'role' || menuControl.request.cmd === '/role');
|
|
2524
2684
|
const currentProcessOwners = loadDaemonConfig().owners ?? [];
|
|
2685
|
+
if (/^\/diag(?:\s|$)/i.test(text)) {
|
|
2686
|
+
const command = text.slice(5).trim();
|
|
2687
|
+
const result = await diagService.execute(command.toLowerCase() === 'stop'
|
|
2688
|
+
? { action: 'stop' } : { action: 'start', problem: command }, opts.peerId);
|
|
2689
|
+
await controlChannel.sendMessage(opts.channelId, result.message, controlReplyContext(opts));
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2525
2692
|
if (menuControl.isMenu && !hasValidMenuId(menuControl)) {
|
|
2526
2693
|
logger.warn(`[ControlMenu] dropped malformed request without id type=${menuControl.type}`);
|
|
2527
2694
|
logMenuRequestCompleted(menuControl.request, undefined, menuFlowContext, {
|
|
@@ -2559,9 +2726,9 @@ async function main() {
|
|
|
2559
2726
|
return;
|
|
2560
2727
|
}
|
|
2561
2728
|
if (text.toLowerCase() === '/pair') {
|
|
2562
|
-
const pair = remoteAccessService.getPairingCode(opts.peerId);
|
|
2729
|
+
const pair = remoteAccessService.getPairingCode(opts.peerId, Date.now(), 'pair');
|
|
2563
2730
|
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
2564
|
-
const reply = `远程控制配对码:${pair.code}(约 ${mins}
|
|
2731
|
+
const reply = `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效,仅可配对一次)`;
|
|
2565
2732
|
await controlChannel.sendMessage(opts.channelId, reply, controlReplyContext(opts));
|
|
2566
2733
|
return;
|
|
2567
2734
|
}
|
|
@@ -2572,7 +2739,7 @@ async function main() {
|
|
|
2572
2739
|
await sendControlMenuResponse(menuFailure({ id: menuControl.id, ...(menuControl.name?.trim() ? { name: menuControl.name } : {}) }, validationError));
|
|
2573
2740
|
return;
|
|
2574
2741
|
}
|
|
2575
|
-
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, {
|
|
2576
2743
|
encrypted: opts.encrypted,
|
|
2577
2744
|
protectedHeaders: opts.protectedHeaders,
|
|
2578
2745
|
}));
|
|
@@ -2595,7 +2762,7 @@ async function main() {
|
|
|
2595
2762
|
return;
|
|
2596
2763
|
}
|
|
2597
2764
|
// owner 发的其他内容:提示可用指令
|
|
2598
|
-
await controlChannel.sendMessage(opts.channelId, '可用指令:/pair
|
|
2765
|
+
await controlChannel.sendMessage(opts.channelId, '可用指令:/pair(获取远程控制配对码)、/diag <问题描述>、/diag stop', controlReplyContext(opts));
|
|
2599
2766
|
}
|
|
2600
2767
|
catch (e) {
|
|
2601
2768
|
if (activeMenuRequest && !menuCompletionLogged) {
|
|
@@ -2608,6 +2775,7 @@ async function main() {
|
|
|
2608
2775
|
logger.warn(`控制 AID 消息处理失败: ${e?.message || e}`);
|
|
2609
2776
|
}
|
|
2610
2777
|
});
|
|
2778
|
+
void controlConnectPromise;
|
|
2611
2779
|
// ── Service Proxy:把本地服务(ecweb 等)通过控制 AID 暴露到 AUN 网络 ──
|
|
2612
2780
|
// 挂在控制 AUNChannel 上,动态解引用其 client(规避重连换 client)。
|
|
2613
2781
|
// 失败只 warn,不影响 daemon 主流程。
|
|
@@ -2769,6 +2937,41 @@ async function main() {
|
|
|
2769
2937
|
});
|
|
2770
2938
|
}
|
|
2771
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
|
+
}
|
|
2772
2975
|
function configureIpc() {
|
|
2773
2976
|
ipcServer.setShutdownExecutor(async (reason) => {
|
|
2774
2977
|
if (!shutdown) {
|
|
@@ -2801,39 +3004,10 @@ async function main() {
|
|
|
2801
3004
|
return { ok: false, code: 'INVALID_CONTROL_TOKEN', error: 'valid local control token is required' };
|
|
2802
3005
|
}
|
|
2803
3006
|
}
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
?? agentRegistry.resolveByChannel(candidate.adapter.channelName);
|
|
2809
|
-
return owner?.aid === aid;
|
|
2810
|
-
});
|
|
2811
|
-
const welcome = aunInstance?.channel;
|
|
2812
|
-
const owningAgent = agentRegistry.get(aid);
|
|
2813
|
-
const firstOwnerAid = getFirstStaticAgentOwner(aid);
|
|
2814
|
-
const sessions = aunInstance && firstOwnerAid && owningAgent
|
|
2815
|
-
? {
|
|
2816
|
-
ensurePostBootstrapMainSession: async (owner) => {
|
|
2817
|
-
const ownerAid = owner || firstOwnerAid;
|
|
2818
|
-
const channel = aunInstance.adapter.channelName;
|
|
2819
|
-
const active = await sessionManager.getActiveSession(channel, ownerAid);
|
|
2820
|
-
const ensured = await sessionManager.ensureNewMainSessionForOperation({
|
|
2821
|
-
channel,
|
|
2822
|
-
channelId: ownerAid,
|
|
2823
|
-
projectPath: active?.projectPath || owningAgent.projectPath || defaultProjectPath,
|
|
2824
|
-
baseagent: owningAgent.baseagent || active?.baseagent || primaryBaseagent,
|
|
2825
|
-
operationId: postBootstrapWelcomeOperationId(aid, ownerAid),
|
|
2826
|
-
identityMetadata: {
|
|
2827
|
-
...(active?.metadata ?? {}),
|
|
2828
|
-
channelKey: aunInstance.adapter.channelKey,
|
|
2829
|
-
peerId: ownerAid,
|
|
2830
|
-
},
|
|
2831
|
-
});
|
|
2832
|
-
return { sessionId: ensured.session.id, created: ensured.created };
|
|
2833
|
-
},
|
|
2834
|
-
}
|
|
2835
|
-
: undefined;
|
|
2836
|
-
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);
|
|
2837
3011
|
});
|
|
2838
3012
|
ipcServer.setDingtalkContactBindExecutor({
|
|
2839
3013
|
register: (cmd) => registerPendingDingtalkContactBind(cmd),
|
|
@@ -2859,6 +3033,17 @@ async function main() {
|
|
|
2859
3033
|
ipcServer.setConfigOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleConfigOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
2860
3034
|
ipcServer.setContactOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleContactOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
2861
3035
|
ipcServer.setAidOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleAidOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
3036
|
+
ipcServer.setDiagExecutor(cmd => executeDiagIpc(diagService, agentDelegationRegistry, loadDaemonConfig().owners ?? [], cmd));
|
|
3037
|
+
ipcServer.setMenuClientExecutor(async (cmd) => {
|
|
3038
|
+
if (!Array.isArray(cmd.argv) || cmd.argv.some((v) => typeof v !== 'string') || typeof cmd.sessionId !== 'string')
|
|
3039
|
+
return { ok: false, code: 'INVALID_ARGUMENT', error: 'A managed session and Menu argv are required' };
|
|
3040
|
+
return cmdHandler.handleMenuClientOperation(cmd.argv, cmd.sessionId, cmd.delegationToken, cmd.delegationCommandHash, async (options) => {
|
|
3041
|
+
const instance = channelInstances.find(item => item.channelType === 'aun' && item.channel.getAidState()?.aid === options.fromAid);
|
|
3042
|
+
if (!instance)
|
|
3043
|
+
throw new Error('Current Agent AUN channel is unavailable');
|
|
3044
|
+
return instance.channel.requestRemoteMenu(options);
|
|
3045
|
+
});
|
|
3046
|
+
});
|
|
2862
3047
|
ipcServer.setGroupOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleGroupOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
2863
3048
|
ipcServer.setMsgOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleMsgOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
2864
3049
|
ipcServer.setFsOperationExecutor((argv, sessionId, delegationToken, delegationCommandHash) => cmdHandler.handleFsOperation(argv, sessionId, delegationToken, delegationCommandHash));
|
|
@@ -2930,6 +3115,14 @@ async function main() {
|
|
|
2930
3115
|
aidStatsCollector.recordOutbound(params.aid, params.toPeer, Buffer.byteLength(params.text || '', 'utf-8'), params.text, false, params.encrypt, params.chatmode, 'send');
|
|
2931
3116
|
});
|
|
2932
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
|
+
});
|
|
2933
3126
|
ipcServer.setCodexPreToolUseExecutor(async (params) => {
|
|
2934
3127
|
for (const runner of new Set(agentMap.values())) {
|
|
2935
3128
|
if (typeof runner?.evaluatePreToolUse !== 'function')
|
|
@@ -3005,7 +3198,14 @@ async function main() {
|
|
|
3005
3198
|
error: decision.reason,
|
|
3006
3199
|
};
|
|
3007
3200
|
}
|
|
3008
|
-
return {
|
|
3201
|
+
return {
|
|
3202
|
+
ok: true,
|
|
3203
|
+
aid: selfAid,
|
|
3204
|
+
currentSessionId: params.sessionId,
|
|
3205
|
+
managementRole,
|
|
3206
|
+
role: subject.role,
|
|
3207
|
+
actorId: delegation.grant.actorId,
|
|
3208
|
+
};
|
|
3009
3209
|
};
|
|
3010
3210
|
const resolveHandoffQueryScope = async (params, operation) => {
|
|
3011
3211
|
if (params.sessionId) {
|
|
@@ -3027,6 +3227,22 @@ async function main() {
|
|
|
3027
3227
|
return scope;
|
|
3028
3228
|
return responseEngine.returnAuthorizedHandoffResult({ sessionId: params.sessionId, handoffId: params.handoffId, content: params.content }, scope.aid);
|
|
3029
3229
|
});
|
|
3230
|
+
ipcServer.setHandoffRecoverReturnExecutor(async (params) => {
|
|
3231
|
+
if (!params.sessionId)
|
|
3232
|
+
return { ok: false, code: 'HANDOFF_CALL_SESSION_INVALID', error: 'current session is required' };
|
|
3233
|
+
const scope = await resolveManagedHandoffScope({ ...params, sessionId: params.sessionId }, 'ec.handoff.recover');
|
|
3234
|
+
if (!scope.ok)
|
|
3235
|
+
return scope;
|
|
3236
|
+
if (scope.role !== 'owner') {
|
|
3237
|
+
return { ok: false, code: 'ROLE_ACCESS_DENIED', error: 'handoff recovery requires the current Agent owner' };
|
|
3238
|
+
}
|
|
3239
|
+
return responseEngine.recoverAuthorizedHandoffResult({
|
|
3240
|
+
sessionId: params.sessionId,
|
|
3241
|
+
handoffId: params.handoffId,
|
|
3242
|
+
content: params.content,
|
|
3243
|
+
actorId: scope.actorId,
|
|
3244
|
+
}, scope.aid);
|
|
3245
|
+
});
|
|
3030
3246
|
ipcServer.setHandoffStatusExecutor(async (params) => {
|
|
3031
3247
|
const scope = await resolveHandoffQueryScope(params, 'ec.handoff.status');
|
|
3032
3248
|
if (!scope.ok)
|
|
@@ -3177,6 +3393,7 @@ async function main() {
|
|
|
3177
3393
|
thread: params.thread,
|
|
3178
3394
|
targetChatType: params.scope === 'group' ? 'group' : 'private',
|
|
3179
3395
|
explicitReturnPolicy: params.returnPolicy,
|
|
3396
|
+
handoffContext: params.handoffContext,
|
|
3180
3397
|
originAuthorization: {
|
|
3181
3398
|
actorId: delegation.grant.actorId,
|
|
3182
3399
|
channelKey: delegation.grant.channel,
|
|
@@ -3580,6 +3797,57 @@ async function main() {
|
|
|
3580
3797
|
}),
|
|
3581
3798
|
aunAidStats: () => aidStatsCollector.getAllSnapshots(),
|
|
3582
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
|
+
}
|
|
3583
3851
|
cmdHandler.setAgentApplicationService(agentApplicationService);
|
|
3584
3852
|
ipcServer.setAgentApplicationService(agentApplicationService);
|
|
3585
3853
|
ipcServer.setStatsProvider(() => statsCollector.getSnapshot());
|
|
@@ -3682,6 +3950,8 @@ async function main() {
|
|
|
3682
3950
|
? {
|
|
3683
3951
|
ok: true,
|
|
3684
3952
|
aid: subject.dataScope === 'daemon' ? (params.targetAid ?? delegation.grant.selfAid) : delegation.grant.selfAid,
|
|
3953
|
+
dataScope: subject.dataScope,
|
|
3954
|
+
management: isManagementRole(subject.role),
|
|
3685
3955
|
}
|
|
3686
3956
|
: { ok: false, code: decision.code, error: decision.reason };
|
|
3687
3957
|
}
|
|
@@ -3709,26 +3979,41 @@ async function main() {
|
|
|
3709
3979
|
return fail('INVALID_DELEGATION', 'delegation does not match the current session');
|
|
3710
3980
|
}
|
|
3711
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
|
+
}
|
|
3712
3993
|
const targetAid = sub === 'list'
|
|
3713
3994
|
? undefined
|
|
3714
3995
|
: sub === 'persona'
|
|
3715
3996
|
? taskAid
|
|
3716
|
-
: sub === '
|
|
3717
|
-
?
|
|
3718
|
-
: sub === '
|
|
3719
|
-
? (argv[2] && !argv[2].startsWith('--') ? argv[2] :
|
|
3720
|
-
:
|
|
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);
|
|
3721
4004
|
const operation = sub === 'list' ? 'agent.list'
|
|
3722
4005
|
: sub === 'show' ? 'agent.show'
|
|
3723
4006
|
: sub === 'persona' ? 'agent.persona'
|
|
3724
|
-
: sub === '
|
|
3725
|
-
: sub === '
|
|
3726
|
-
: sub === '
|
|
3727
|
-
: sub === '
|
|
3728
|
-
: sub === '
|
|
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;
|
|
3729
4014
|
if (!operation)
|
|
3730
4015
|
return fail('INVALID_ARGS', `unsupported managed agent command: ${sub}`);
|
|
3731
|
-
if (sub === 'new' && !argv.includes('--non-interactive')) {
|
|
4016
|
+
if (sub === 'new' && !argv.includes('--non-interactive') && !argv.includes('--initialize')) {
|
|
3732
4017
|
return fail('MANAGED_NON_INTERACTIVE_REQUIRED', 'interactive Agent creation is unavailable in a managed task', 'MANAGED_NON_INTERACTIVE_REQUIRED');
|
|
3733
4018
|
}
|
|
3734
4019
|
if (sub === 'delete' && argv.includes('--purge') && !argv.includes('--confirm-purge')) {
|
|
@@ -3757,7 +4042,7 @@ async function main() {
|
|
|
3757
4042
|
subject,
|
|
3758
4043
|
intent: {
|
|
3759
4044
|
operation,
|
|
3760
|
-
scope: operation === 'agent.show' || operation === 'agent.persona'
|
|
4045
|
+
scope: operation === 'agent.show' || operation === 'agent.persona' || operation === 'agent.welcome'
|
|
3761
4046
|
? 'agent'
|
|
3762
4047
|
: operation === 'agent.reload' && targetAid
|
|
3763
4048
|
? 'agent'
|
|
@@ -3768,6 +4053,7 @@ async function main() {
|
|
|
3768
4053
|
aid: targetAid ?? taskAid,
|
|
3769
4054
|
taskAgentAid: taskAid,
|
|
3770
4055
|
targetAgentAid: targetAid ?? taskAid,
|
|
4056
|
+
...(welcomeArgs ? { action: welcomeArgs.action } : {}),
|
|
3771
4057
|
},
|
|
3772
4058
|
},
|
|
3773
4059
|
auditMetadata: { taskId: delegation.grant.taskId, messageId: delegation.grant.messageId },
|
|
@@ -3803,6 +4089,7 @@ async function main() {
|
|
|
3803
4089
|
ok: true,
|
|
3804
4090
|
aid: agent.aid,
|
|
3805
4091
|
status: agent.status,
|
|
4092
|
+
lifecycle: agent.lifecycle ?? null,
|
|
3806
4093
|
identity: agent.identity ?? { name: null, description: null },
|
|
3807
4094
|
config: {
|
|
3808
4095
|
baseagent: agent.config?.baseagent ?? null,
|
|
@@ -3818,6 +4105,7 @@ async function main() {
|
|
|
3818
4105
|
: { config: null, agent_md: null, project: null, data: null },
|
|
3819
4106
|
...(subject.dataScope === 'daemon' ? {} : { redacted: true }),
|
|
3820
4107
|
...(agent.createProgress ? { createProgress: agent.createProgress } : {}),
|
|
4108
|
+
...(agent.initialization ? { initialization: agent.initialization } : {}),
|
|
3821
4109
|
} };
|
|
3822
4110
|
}
|
|
3823
4111
|
if (operation === 'agent.persona') {
|
|
@@ -3852,6 +4140,48 @@ async function main() {
|
|
|
3852
4140
|
...(result.saved ? { saved: true } : {}),
|
|
3853
4141
|
} };
|
|
3854
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
|
+
}
|
|
3855
4185
|
if (operation === 'agent.create') {
|
|
3856
4186
|
const aid = argv[2] && !argv[2].startsWith('--') ? argv[2] : undefined;
|
|
3857
4187
|
if (!aid)
|
|
@@ -3879,6 +4209,7 @@ async function main() {
|
|
|
3879
4209
|
handoff: value('--handoff'),
|
|
3880
4210
|
name: value('--name'),
|
|
3881
4211
|
description: value('--description'),
|
|
4212
|
+
type: value('--type'),
|
|
3882
4213
|
tags,
|
|
3883
4214
|
force: argv.includes('--force'),
|
|
3884
4215
|
});
|
|
@@ -3936,6 +4267,7 @@ async function main() {
|
|
|
3936
4267
|
owners: plan.owners,
|
|
3937
4268
|
name: plan.name,
|
|
3938
4269
|
description: plan.description,
|
|
4270
|
+
type: plan.type,
|
|
3939
4271
|
tags: plan.tags,
|
|
3940
4272
|
force: argv.includes('--force'),
|
|
3941
4273
|
};
|
|
@@ -3977,6 +4309,11 @@ async function main() {
|
|
|
3977
4309
|
const result = await execAgentAction(sub, { aid: targetAid ?? taskAid, force: argv.includes('--force') }, delegation.grant.actorId, eventBus, agentApplicationService);
|
|
3978
4310
|
return 'error' in result ? fail(result.code, result.error) : { ok: true, result: { ok: true, ...(result.data ?? {}) } };
|
|
3979
4311
|
});
|
|
4312
|
+
ipcServer.setTaskResumeExecutor(params => executeTaskResume(params, {
|
|
4313
|
+
sessions: sessionManager,
|
|
4314
|
+
authorizeManaged: authorizeManagedAgentOperation,
|
|
4315
|
+
recover: request => responseEngine.recoverTask(request),
|
|
4316
|
+
}));
|
|
3980
4317
|
ipcServer.setQueueOperationExecutor(async (params) => {
|
|
3981
4318
|
const operation = `ec.queue.${params.action ?? 'read'}`;
|
|
3982
4319
|
const authorization = await authorizeManagedAgentOperation(params, operation);
|
|
@@ -4017,6 +4354,38 @@ async function main() {
|
|
|
4017
4354
|
const authorization = await authorizeManagedAgentOperation({ ...params, targetAid: params.aid }, params.operation);
|
|
4018
4355
|
return authorization.ok ? { ok: true } : authorization;
|
|
4019
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
|
+
});
|
|
4020
4389
|
ipcServer.setTriggerExecutor(async (cmd) => {
|
|
4021
4390
|
const schedulerFor = (agentAid) => {
|
|
4022
4391
|
const scheduler = triggerSchedulers.get(agentAid);
|
|
@@ -4420,6 +4789,8 @@ async function main() {
|
|
|
4420
4789
|
timestamp: Date.now()
|
|
4421
4790
|
});
|
|
4422
4791
|
// 断开插件系统的渠道
|
|
4792
|
+
removeGroupInviteConfigListener();
|
|
4793
|
+
await shutdownStep('stop group invitation review', () => groupInviteReviewService.dispose());
|
|
4423
4794
|
await shutdownStep('disconnect channels', () => channelLoader.disconnectAll(channelInstances));
|
|
4424
4795
|
for (const inst of channelInstances) {
|
|
4425
4796
|
const type = inst.channelType || inst.adapter.channelName;
|