evolcore 0.0.35 → 0.0.37
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 +42 -0
- package/README.md +6 -0
- package/bin/install-codex-managed-hooks.mjs +20 -3
- package/dist/agents/baseagent-availability.js +1 -1
- package/dist/agents/baseagent.js +88 -0
- package/dist/agents/claude-runner.js +59 -12
- package/dist/agents/codex/app-server-client.js +18 -1
- package/dist/agents/codex-runner.js +262 -21
- package/dist/agents/ecagent-runner.js +47 -11
- package/dist/agents/gemini-runner.js +36 -12
- package/dist/aun/aid/client.js +4 -3
- package/dist/aun/aid/control-aid.js +270 -8
- package/dist/aun/aid/identity.js +6 -3
- package/dist/aun/aid/ownership-operation.js +58 -0
- package/dist/aun/aid/store.js +1 -0
- package/dist/aun/group/fs-download.js +67 -2
- package/dist/aun/group/history.js +20 -5
- package/dist/aun/group/operations.js +8 -2
- package/dist/aun/menu/client.js +39 -2
- package/dist/aun/menu/transport.js +1 -1
- package/dist/aun/msg/history.js +43 -4
- package/dist/aun/msg/managed-operation.js +30 -53
- package/dist/aun/msg/p2p.js +51 -15
- package/dist/aun/outbox.js +4 -0
- package/dist/channels/aun.js +260 -73
- package/dist/channels/daemon.js +6 -4
- package/dist/channels/feishu.js +3 -0
- package/dist/cli/agent-command.js +161 -223
- package/dist/cli/agent-create.js +190 -223
- package/dist/cli/agent.js +3 -1
- package/dist/cli/aid-bind-command.js +53 -0
- package/dist/cli/aun-commands.js +384 -91
- package/dist/cli/bench.js +1 -1
- package/dist/cli/cli-argv.js +74 -0
- package/dist/cli/daemon-commands.js +105 -74
- package/dist/cli/diag.js +1 -1
- package/dist/cli/fs-command.js +18 -19
- package/dist/cli/getmeta-command.js +159 -6
- package/dist/cli/index.js +6 -12
- package/dist/cli/init-channel.js +8 -55
- package/dist/cli/init.js +125 -218
- package/dist/cli/queue-command.js +11 -8
- package/dist/cli/restart-monitor.js +177 -85
- package/dist/cli/session-command.js +1 -1
- package/dist/cli/stats.js +7 -5
- package/dist/cli/thread-command.js +103 -30
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg-diag.js +1 -0
- package/dist/config/access-policy.js +2 -2
- package/dist/config/boot-log.js +14 -11
- package/dist/config/config-field-policy.js +9 -1
- package/dist/config/config-manager.js +176 -90
- package/dist/config/config-operation-service.js +7 -14
- package/dist/config/contact-book-store.js +142 -26
- package/dist/config/contact-book.js +4 -2
- package/dist/config/lifecycle.js +1 -1
- package/dist/config/owner-config.js +96 -0
- package/dist/config/peer-role-resolver.js +12 -18
- package/dist/config/providers-config.js +382 -0
- package/dist/config/providers-import.js +74 -0
- package/dist/config/providers-management.js +328 -0
- package/dist/config/providers.js +22 -0
- package/dist/config/resolved-config-op.js +17 -14
- package/dist/config/snapshot.js +28 -16
- package/dist/config-store.js +18 -14
- package/dist/core/agent-ipc-registration.js +21 -63
- package/dist/core/agent-runtime.js +16 -5
- package/dist/core/auth/agent-delegation.js +199 -25
- package/dist/core/auth/auth-gateway.js +44 -2
- package/dist/core/auth/authorization-denial.js +1 -1
- package/dist/core/auth/debug-context.js +2 -1
- package/dist/core/auth/delegation-authorization.js +2 -2
- package/dist/core/auth/delegation-diagnostics.js +4 -1
- package/dist/core/auth/operation-authorizer.js +10 -1
- package/dist/core/auth/operation-catalog.js +19 -1
- package/dist/core/bootstrap-service.js +43 -20
- package/dist/core/channel-loader.js +0 -1
- package/dist/core/channel-runtime.js +30 -4
- package/dist/core/command/agent-control.js +196 -37
- package/dist/core/command/cli-intent-parser.js +60 -4
- package/dist/core/command/command-handler.js +212 -60
- package/dist/core/command/connect-menu.js +1 -0
- package/dist/core/command/diag-service.js +5 -4
- package/dist/core/command/file-search.js +368 -0
- package/dist/core/command/menu-catalog.js +2 -1
- package/dist/core/command/menu-handler.js +292 -107
- package/dist/core/command/menu-protocol.js +23 -0
- package/dist/core/command/role-menu.js +7 -19
- package/dist/core/command/skill-slash.js +130 -25
- package/dist/core/command/slash-handler.js +101 -53
- package/dist/core/command/topic-slash.js +16 -5
- package/dist/core/daemon-bootstrap.js +7 -1
- package/dist/core/daemon-control.js +19 -1
- package/dist/core/daemon-lifecycle.js +2 -1
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/evolagent-registry.js +13 -2
- package/dist/core/evolagent.js +3 -6
- package/dist/core/handoff/ipc-registration.js +2 -2
- package/dist/core/handoff/runtime.js +40 -6
- package/dist/core/handoff/store.js +1 -0
- package/dist/core/inference/text-inference.js +95 -6
- package/dist/core/ipc-registration.js +43 -24
- package/dist/core/memory/consolidation-context.js +4 -1
- package/dist/core/memory/consolidation.js +25 -14
- package/dist/core/message/aun-ipc-sender.js +296 -88
- package/dist/core/message/aun-request-registry.js +226 -0
- package/dist/core/message/create-status.js +33 -4
- package/dist/core/message/message-bridge.js +62 -13
- package/dist/core/message/message-log.js +0 -1
- package/dist/core/message/message-queue.js +4 -1
- package/dist/core/message/message-utils.js +8 -1
- package/dist/core/message/peer-mode.js +17 -9
- package/dist/core/message/response-engine.js +266 -124
- package/dist/core/message/retry-scheduler.js +11 -8
- package/dist/core/model/catalog-service.js +60 -18
- package/dist/core/model/model-catalog.js +112 -9
- package/dist/core/model/model-fallback.js +94 -26
- package/dist/core/ownership/owner-resolver.js +687 -0
- package/dist/core/permission/approval-gateway.js +196 -62
- package/dist/core/permission/ec-command-parser.js +138 -25
- package/dist/core/permission/filesystem-approval-scope.js +141 -0
- package/dist/core/permission/protected-paths.js +14 -1
- package/dist/core/permission/sandbox-runtime.js +171 -18
- package/dist/core/permission/tool-policy.js +13 -2
- package/dist/core/role/runtime-policy.js +3 -4
- package/dist/core/session/session-idle-monitor.js +10 -8
- package/dist/core/session/session-manager.js +72 -45
- package/dist/core/session/session-mapper.js +18 -7
- package/dist/core/session/session-renew.js +5 -4
- package/dist/core/session/session-title.js +2 -1
- package/dist/core/session/session-turn-coordinator.js +4 -2
- package/dist/core/skill/index-generator.js +2 -16
- package/dist/core/task/task-recovery-service.js +15 -2
- package/dist/core/thread/command-parser.js +28 -13
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +11 -8
- package/dist/core/thread/thread-operation.js +79 -44
- package/dist/core/thread/thread-route.js +54 -6
- package/dist/core/thread/thread-service.js +236 -45
- package/dist/core/thread/topic-id.js +248 -0
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/eck/message-renderer.js +12 -2
- package/dist/index.js +50 -27
- package/dist/ipc.js +59 -6
- package/dist/paths.js +1 -0
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +10 -3
- package/dist/stats/db.js +8 -0
- package/dist/stats/writer.js +26 -4
- package/dist/trigger/authorization.js +48 -3
- package/dist/trigger/feedback.js +28 -10
- package/dist/trigger/ipc-service.js +86 -10
- package/dist/trigger/local-files.js +55 -23
- package/dist/trigger/scheduler.js +57 -11
- package/dist/trigger/system-definitions.js +1 -0
- package/dist/trigger/validation.js +44 -15
- package/dist/utils/aid-bind.js +17 -297
- package/dist/utils/avatar-upload.js +16 -4
- package/dist/utils/cross-platform.js +115 -36
- package/dist/utils/ecweb-supervisor.js +1 -1
- package/dist/utils/ecweb-utils.js +8 -1
- package/dist/utils/error-utils.js +44 -6
- package/dist/utils/instance-registry.js +12 -2
- package/dist/utils/npm-ops.js +102 -27
- package/dist/utils/package-version-info.js +72 -27
- package/dist/utils/restart-safety.js +50 -0
- package/dist/utils/upgrade-jobs.js +304 -0
- package/dist/utils/windows-autostart.js +17 -10
- package/kits/docs/INDEX.md +5 -0
- package/kits/docs/aun/ABILITY_CALLING.md +239 -0
- package/kits/docs/evolcore/INDEX.md +14 -3
- package/kits/docs/evolcore/agent-create.md +55 -141
- package/kits/docs/evolcore/agent.md +38 -16
- package/kits/docs/evolcore/aid.md +34 -0
- package/kits/docs/evolcore/config.md +20 -1
- package/kits/docs/evolcore/event.md +2 -2
- package/kits/docs/evolcore/fs.md +18 -2
- package/kits/docs/evolcore/group-collaboration.md +13 -246
- package/kits/docs/evolcore/group.md +2 -1
- package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +65 -1
- package/kits/docs/evolcore/msg.md +64 -2
- package/kits/docs/evolcore/skill.md +86 -0
- package/kits/docs/evolcore/stats.md +6 -0
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +145 -51
- package/kits/docs/evolcore/trigger.md +48 -3
- package/kits/eck_manifest.json +21 -0
- package/kits/eck_message_manifest.json +4 -4
- package/kits/migrations/migrate-role-config-v5.mjs +20 -7
- package/kits/rules/01-overview.md +2 -1
- package/kits/rules/03-identity.md +3 -1
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/07-memory-and-thread.md +1 -1
- package/kits/schemas/_meta.json +16 -1
- package/kits/schemas/agent-config.schema.13.json +44 -2
- package/kits/schemas/contact-book.schema.3.json +5 -0
- package/kits/schemas/daemon.schema.6.json +3 -1
- package/kits/schemas/daemon.schema.8.json +329 -0
- package/kits/schemas/defaults.schema.5.json +39 -3
- package/kits/schemas/providers.schema.1.json +76 -0
- package/kits/schemas/relation-config.schema.9.json +5 -1
- package/kits/skills/.switches.json +28 -0
- package/kits/skills/aid-ability/SKILL.md +214 -0
- package/kits/skills/ec-agent-create/SKILL.md +162 -0
- package/kits/skills/ec-group/SKILL.md +2 -1
- package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
- package/kits/skills/ec-identity/SKILL.md +143 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
- package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
- package/kits/skills/ec-trigger/SKILL.md +167 -0
- package/kits/skills/ec-trigger/references/examples.md +153 -0
- package/kits/skills/thread-ops/SKILL.md +108 -420
- package/kits/templates/message-fragments/thread-context.md +1 -2
- package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
- package/kits/templates/roles/member.json +1 -1
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +1 -0
- package/kits/templates/system-fragments/channel.md +2 -1
- package/kits/templates/system-fragments/commands.md +5 -4
- package/kits/templates/system-fragments/identity.md +2 -0
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -3
|
@@ -6,10 +6,14 @@ import { parseMenuClientArgs } from '../../cli/menu-client.js';
|
|
|
6
6
|
import { ensureSessionRuntimeDir } from '../../cli/task-context.js';
|
|
7
7
|
import { renderCommandCardAsText } from '../interaction-router.js';
|
|
8
8
|
import { buildEnvelope, deliveryTargetFromSession, isInteractionSendAccepted, replyContextFromSession, sendInteractionPayload } from '../message/message-utils.js';
|
|
9
|
+
import { sessionTopicThreadId } from '../thread/topic-id.js';
|
|
9
10
|
import { resolvePaths, getPackageRoot } from '../../paths.js';
|
|
10
11
|
import { loadDaemonConfig } from '../../config-store.js';
|
|
12
|
+
import { parseOwnershipCommand, executeOwnershipCommand, ownershipFailure } from '../../aun/aid/ownership-operation.js';
|
|
13
|
+
import { ownerResolver, refreshOwnershipForAuthorization } from '../ownership/owner-resolver.js';
|
|
11
14
|
import { logger } from '../../utils/logger.js';
|
|
12
15
|
import { resolvePeerRoleDetail, roleToSessionIdentity } from '../../config/peer-role-resolver.js';
|
|
16
|
+
import { ThreadService } from '../thread/thread-service.js';
|
|
13
17
|
import { isManagementRole } from '../../config/builtin-roles.js';
|
|
14
18
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
15
19
|
import { sameGroupAid } from '../../aun/group/index.js';
|
|
@@ -22,12 +26,13 @@ import { parseDuration, parseTriggerSet, parseTriggerUpdate } from '../../trigge
|
|
|
22
26
|
import { applyTriggerPatch, replaceEditableTriggerDefinition } from '../../trigger/patch.js';
|
|
23
27
|
import { definitionRevision } from '../../trigger/validation.js';
|
|
24
28
|
import { isDaemonEventSessionTrigger, matchTriggerEvent } from '../../trigger/event-source.js';
|
|
29
|
+
import { isTriggerOperator } from '../../trigger/authorization.js';
|
|
25
30
|
import { tryParseChannelKey } from '../channel-loader.js';
|
|
26
31
|
import { displaySessionTitle } from '../session/session-title.js';
|
|
27
32
|
import { buildTranscriptTurns } from '../session/session-transcript.js';
|
|
28
33
|
import { resolveConfigCommand } from '../../config/resolved-config-op.js';
|
|
29
34
|
import { AUTHENTICATED_CONFIG_ROLE_ENV, executeResolvedConfigCommandAsync } from '../../config/config-operation-service.js';
|
|
30
|
-
import { splitConfigBatchGetArgv } from '../../cli/cli-argv.js';
|
|
35
|
+
import { parseTimeArg, TIME_ARG_FORMATS, splitConfigBatchGetArgv } from '../../cli/cli-argv.js';
|
|
31
36
|
import { auditCommandAuthorization, auditFullAccessEvent, hashArgv } from '../auth/authorization-audit.js';
|
|
32
37
|
import { ResponseModeRegistry } from '../../response-system/registry.js';
|
|
33
38
|
import { registerBuiltinModes } from '../../response-system/modes/index.js';
|
|
@@ -36,7 +41,7 @@ import { hasTrustedFullAccessDelegation, trustedExecutionIdentityInput } from '.
|
|
|
36
41
|
import { executeManagedAidOperation, ManagedAidOperationError, managedAidShowViewForRole, resolveManagedAidOperation, } from '../../aun/aid/managed-operation.js';
|
|
37
42
|
import { MAX_AVATAR_SOURCE_BYTES } from '../../utils/avatar-upload.js';
|
|
38
43
|
import { executeManagedGroupOperation, isManagedGroupRelationRead, isManagedGroupRelationWrite, ManagedGroupOperationError, resolveManagedGroupOperation, executeManagedMsgOperation, ManagedMsgOperationError, resolveManagedMsgOperation, executeManagedFsOperation, ManagedFsOperationError, resolveManagedFsOperation, } from '../../aun/msg/managed-operation.js';
|
|
39
|
-
import {
|
|
44
|
+
import { authorizeFreshOperation, buildAuthSubject } from '../auth/auth-gateway.js';
|
|
40
45
|
import { isHClassPath, isLClassPath, isSameOrDescendant } from '../permission/protected-paths.js';
|
|
41
46
|
import { validateModelSelectionForRole } from '../model/model-permission.js';
|
|
42
47
|
import { getModelInfo } from '../model/model-catalog.js';
|
|
@@ -146,6 +151,7 @@ export class CommandHandler {
|
|
|
146
151
|
daemonStatusProvider;
|
|
147
152
|
daemonMonitorProvider;
|
|
148
153
|
agentDelegationRegistry;
|
|
154
|
+
threadSystemMsgSender;
|
|
149
155
|
handoffRuntime;
|
|
150
156
|
diagService;
|
|
151
157
|
setDiagService(service) { this.diagService = service; }
|
|
@@ -163,7 +169,7 @@ export class CommandHandler {
|
|
|
163
169
|
const subject = buildAuthSubject({ selfAid: grant.selfAid, actorId: grant.actorId, channel: grant.channel,
|
|
164
170
|
channelType: grant.channelType, channelId, chatType: grant.chatType, conversationId: channelId,
|
|
165
171
|
processOwners: [], ...trustedExecutionIdentityInput(grant) });
|
|
166
|
-
const decision =
|
|
172
|
+
const decision = await authorizeFreshOperation({ source: 'agent-tool', subject,
|
|
167
173
|
intent: { operation: 'ec.menu.request', scope: 'relation', source: 'agent-tool', args: { self: grant.selfAid, peer: argv[2], targetId: argv[2] } },
|
|
168
174
|
auditMetadata: { taskId: grant.taskId, sessionId, messageId: grant.messageId } });
|
|
169
175
|
if (!decision.allow)
|
|
@@ -325,7 +331,10 @@ export class CommandHandler {
|
|
|
325
331
|
this.daemonTriggerChannel = String(channel || 'daemon').trim() || 'daemon';
|
|
326
332
|
}
|
|
327
333
|
/** Used by control-menu routing; daemon owner is not in the Agent registry. */
|
|
328
|
-
|
|
334
|
+
getDaemonTriggerChannel() {
|
|
335
|
+
return this.daemonTriggerChannel;
|
|
336
|
+
}
|
|
337
|
+
getDaemonTriggerOwnerAid(channel = this.daemonTriggerChannel) {
|
|
329
338
|
if (channel !== this.daemonTriggerChannel)
|
|
330
339
|
return undefined;
|
|
331
340
|
if (this.daemonTriggerOwnerAid)
|
|
@@ -398,7 +407,7 @@ export class CommandHandler {
|
|
|
398
407
|
channelName: session.channel,
|
|
399
408
|
channelId: session.channelId,
|
|
400
409
|
chatType: session.chatType,
|
|
401
|
-
...(session
|
|
410
|
+
...(sessionTopicThreadId(session) ? { threadId: sessionTopicThreadId(session) } : {}),
|
|
402
411
|
peerId: session.metadata?.peerId || session.channelId,
|
|
403
412
|
};
|
|
404
413
|
const valid = enabled.some(definition => definition.source.type === 'event'
|
|
@@ -513,7 +522,7 @@ export class CommandHandler {
|
|
|
513
522
|
primaryFeedbackTarget(definition) {
|
|
514
523
|
if (definition.feedback.strategy === 'target')
|
|
515
524
|
return definition.feedback.target;
|
|
516
|
-
if (definition.feedback.strategy
|
|
525
|
+
if (definition.feedback.strategy !== 'origin')
|
|
517
526
|
return undefined;
|
|
518
527
|
if (!definition.origin)
|
|
519
528
|
return undefined;
|
|
@@ -525,10 +534,14 @@ export class CommandHandler {
|
|
|
525
534
|
chatType: definition.origin.delivery?.chatType,
|
|
526
535
|
};
|
|
527
536
|
}
|
|
528
|
-
|
|
537
|
+
/**
|
|
538
|
+
* 与 IPC 侧同一判据:操作主体集合由定义的 operatorPeers 决定(缺省时按
|
|
539
|
+
* origin 对端 + feedback 目标对端现算)。群聊身份是群 AID,调用方传 channelId。
|
|
540
|
+
*/
|
|
541
|
+
canAccessTriggerDefinition(definition, actorConversationPeerId, isAdmin) {
|
|
529
542
|
if (isAdmin)
|
|
530
543
|
return true;
|
|
531
|
-
return definition
|
|
544
|
+
return isTriggerOperator(definition, actorConversationPeerId);
|
|
532
545
|
}
|
|
533
546
|
triggerPermissionFromParsed(parsed) {
|
|
534
547
|
return parsed.permissionMode ?? undefined;
|
|
@@ -537,7 +550,7 @@ export class CommandHandler {
|
|
|
537
550
|
* Persist fullaccess approval provenance as the canonical process owner,
|
|
538
551
|
* rather than the transport-specific peer id. A Feishu/other-channel
|
|
539
552
|
* alias may authenticate as a daemon-owner while its raw peer id is not an
|
|
540
|
-
*
|
|
553
|
+
* the verified Control AID protocol Owner; storing that alias would make the Trigger
|
|
541
554
|
* fail its next scheduler-time owner check.
|
|
542
555
|
*/
|
|
543
556
|
canonicalDaemonOwnerId(selfAid, channel, peerId, chatType) {
|
|
@@ -636,11 +649,11 @@ export class CommandHandler {
|
|
|
636
649
|
}
|
|
637
650
|
return undefined;
|
|
638
651
|
}
|
|
639
|
-
findTriggerDefinition(scheduler, nameOrId,
|
|
652
|
+
findTriggerDefinition(scheduler, nameOrId, actorConversationPeerId, isAdmin) {
|
|
640
653
|
return scheduler
|
|
641
654
|
.list({ all: true })
|
|
642
655
|
.find(definition => (definition.id === nameOrId || definition.name === nameOrId)
|
|
643
|
-
&& this.canAccessTriggerDefinition(definition,
|
|
656
|
+
&& this.canAccessTriggerDefinition(definition, actorConversationPeerId, isAdmin));
|
|
644
657
|
}
|
|
645
658
|
async buildTriggerDefinitionFromParsed(parsed, channel, channelId, peerId, isAdmin, messageId, chatType, threadId, isDaemonOwner = false, canApprovePersistentFullAccess = isDaemonOwner) {
|
|
646
659
|
const now = Date.now();
|
|
@@ -659,6 +672,7 @@ export class CommandHandler {
|
|
|
659
672
|
const targetChannelType = this.resolveChannelType(feedbackChannel);
|
|
660
673
|
const feedbackChannelId = parsed.targetChannelId ?? originConversationId;
|
|
661
674
|
const schedulerAid = parsed.agentId
|
|
675
|
+
?? this.getDaemonTriggerOwnerAid(channel)
|
|
662
676
|
?? this.getOwningAgent(feedbackChannel)?.aid
|
|
663
677
|
?? tryParseChannelKey(feedbackChannel)?.selfAID
|
|
664
678
|
?? this.triggerSchedulerFallbackAid;
|
|
@@ -733,14 +747,20 @@ export class CommandHandler {
|
|
|
733
747
|
return { error: 'Trigger baseagent 仅适用于 trigger_session' };
|
|
734
748
|
}
|
|
735
749
|
}
|
|
736
|
-
const
|
|
750
|
+
const daemonScheduler = schedulerAid === this.getDaemonTriggerOwnerAid(channel);
|
|
751
|
+
const triggerOwner = daemonScheduler
|
|
752
|
+
? undefined
|
|
753
|
+
: this.agentRegistry?.get?.(schedulerAid) ?? this.getOwningAgent(channel);
|
|
737
754
|
const executionBaseagent = parsed.executionType === 'trigger_session'
|
|
738
755
|
? parsed.baseagent?.trim() ?? triggerOwner?.baseagent ?? triggerRole.baseagent
|
|
756
|
+
?? (daemonScheduler ? this.parseDefaultBaseagent() : undefined)
|
|
739
757
|
: undefined;
|
|
740
758
|
if (parsed.executionType === 'trigger_session') {
|
|
741
759
|
if (!executionBaseagent)
|
|
742
760
|
return { error: '无法确定 Trigger 会话的 baseagent' };
|
|
743
|
-
const ownerName =
|
|
761
|
+
const ownerName = daemonScheduler
|
|
762
|
+
? this.primaryRunnerKey.split('::')[0]
|
|
763
|
+
: triggerOwner?.name || '<unknown>';
|
|
744
764
|
const available = this.getAvailableBaseagentsForOwner(ownerName);
|
|
745
765
|
if (!available.includes(executionBaseagent)) {
|
|
746
766
|
return {
|
|
@@ -1111,9 +1131,9 @@ export class CommandHandler {
|
|
|
1111
1131
|
return !!userId && topic.metadata?.peerId === userId;
|
|
1112
1132
|
}
|
|
1113
1133
|
buildTopicMenuItem(s) {
|
|
1114
|
-
const displayName = displaySessionTitle(s.name, s
|
|
1134
|
+
const displayName = displaySessionTitle(s.name, sessionTopicThreadId(s) || s.id.slice(0, 8));
|
|
1115
1135
|
const item = {
|
|
1116
|
-
value: s
|
|
1136
|
+
value: sessionTopicThreadId(s) ?? '',
|
|
1117
1137
|
label: displayName,
|
|
1118
1138
|
topicLabel: s.label || null,
|
|
1119
1139
|
topicStatus: s.topicStatus ?? 'pending',
|
|
@@ -1385,10 +1405,12 @@ export class CommandHandler {
|
|
|
1385
1405
|
return await handleSlashCommand.call(this, content, channel, channelId, sendMessage, userId, threadId, chatType, source, messageId, selfAID, overrideIdentity, authSubject, replyContext, applyGroupSlashPolicy);
|
|
1386
1406
|
}
|
|
1387
1407
|
async handleTriggerCommand(scheduler, content, channel, channelId, peerId, isAdmin, messageId, chatType, threadId, isDaemonOwner = false, canApprovePersistentFullAccess = isDaemonOwner) {
|
|
1408
|
+
// 操作主体身份:群聊是群 AID(channelId),私聊是对端 AID(peerId)。
|
|
1409
|
+
const actorConversationPeerId = chatType === 'group' ? channelId : peerId;
|
|
1388
1410
|
if (content === '/trigger') {
|
|
1389
1411
|
const visible = scheduler
|
|
1390
1412
|
.list()
|
|
1391
|
-
.filter(definition => this.canAccessTriggerDefinition(definition,
|
|
1413
|
+
.filter(definition => this.canAccessTriggerDefinition(definition, actorConversationPeerId, isAdmin));
|
|
1392
1414
|
if (visible.length === 0)
|
|
1393
1415
|
return '📭 当前没有活跃的触发器';
|
|
1394
1416
|
const lines = visible.map(definition => {
|
|
@@ -1403,7 +1425,7 @@ export class CommandHandler {
|
|
|
1403
1425
|
const includeDisabled = sub.includes('--all') || sub.includes('all');
|
|
1404
1426
|
const visible = scheduler
|
|
1405
1427
|
.list({ all: includeDisabled })
|
|
1406
|
-
.filter(definition => this.canAccessTriggerDefinition(definition,
|
|
1428
|
+
.filter(definition => this.canAccessTriggerDefinition(definition, actorConversationPeerId, isAdmin));
|
|
1407
1429
|
if (visible.length === 0)
|
|
1408
1430
|
return '📭 没有触发器记录';
|
|
1409
1431
|
const lines = visible.map(definition => {
|
|
@@ -1419,7 +1441,7 @@ export class CommandHandler {
|
|
|
1419
1441
|
const nameOrId = sub.slice(prefix.length).trim();
|
|
1420
1442
|
if (!nameOrId)
|
|
1421
1443
|
throw new Error(`❌ 用法:/trigger ${action} <名称>`);
|
|
1422
|
-
const definition = this.findTriggerDefinition(scheduler, nameOrId,
|
|
1444
|
+
const definition = this.findTriggerDefinition(scheduler, nameOrId, actorConversationPeerId, isAdmin);
|
|
1423
1445
|
if (!definition) {
|
|
1424
1446
|
throw new Error(isAdmin
|
|
1425
1447
|
? `❌ 未找到触发器:${nameOrId}`
|
|
@@ -1528,7 +1550,7 @@ export class CommandHandler {
|
|
|
1528
1550
|
: args.trim();
|
|
1529
1551
|
if (!nameOrId)
|
|
1530
1552
|
return '❌ 用法:/trigger run <名称> [--dry-run]';
|
|
1531
|
-
const definition = this.findTriggerDefinition(scheduler, nameOrId,
|
|
1553
|
+
const definition = this.findTriggerDefinition(scheduler, nameOrId, actorConversationPeerId, isAdmin);
|
|
1532
1554
|
if (!definition) {
|
|
1533
1555
|
return isAdmin
|
|
1534
1556
|
? `❌ 未找到触发器:${nameOrId}`
|
|
@@ -1548,7 +1570,7 @@ export class CommandHandler {
|
|
|
1548
1570
|
const result = parseTriggerUpdate(args);
|
|
1549
1571
|
if (!result.ok)
|
|
1550
1572
|
return `❌ ${result.error}`;
|
|
1551
|
-
const updated = await this.updateTriggerFromPatch(scheduler, result.nameOrId, result.value, channel, channelId, peerId, isAdmin, messageId, threadId, isDaemonOwner, canApprovePersistentFullAccess);
|
|
1573
|
+
const updated = await this.updateTriggerFromPatch(scheduler, result.nameOrId, result.value, channel, channelId, peerId, isAdmin, messageId, threadId, isDaemonOwner, canApprovePersistentFullAccess, chatType);
|
|
1552
1574
|
if (!updated.ok)
|
|
1553
1575
|
return `❌ ${updated.error}`;
|
|
1554
1576
|
const nextStr = updated.trigger.nextFireAt ? new Date(updated.trigger.nextFireAt).toLocaleString() : '未计算';
|
|
@@ -1589,8 +1611,9 @@ export class CommandHandler {
|
|
|
1589
1611
|
return '⚠️ 触发器功能未启用';
|
|
1590
1612
|
return await this.handleTriggerCommand(scheduler, content, channel, channelId, peerId, isAdmin, messageId, chatType, threadId, isDaemonOwner, canApprovePersistentFullAccess);
|
|
1591
1613
|
}
|
|
1592
|
-
async updateTriggerFromPatch(scheduler, nameOrId, patch, channel, channelId, peerId, isAdmin, messageId, threadId, isDaemonOwner = false, canApprovePersistentFullAccess = isDaemonOwner) {
|
|
1593
|
-
const
|
|
1614
|
+
async updateTriggerFromPatch(scheduler, nameOrId, patch, channel, channelId, peerId, isAdmin, messageId, threadId, isDaemonOwner = false, canApprovePersistentFullAccess = isDaemonOwner, chatType) {
|
|
1615
|
+
const actorConversationPeerId = chatType === 'group' ? channelId : peerId;
|
|
1616
|
+
const definition = this.findTriggerDefinition(scheduler, nameOrId, actorConversationPeerId, isAdmin);
|
|
1594
1617
|
if (!definition) {
|
|
1595
1618
|
return { ok: false, error: isAdmin ? `未找到触发器:${nameOrId}` : `未找到触发器 "${nameOrId}",或无权限修改` };
|
|
1596
1619
|
}
|
|
@@ -1768,7 +1791,7 @@ export class CommandHandler {
|
|
|
1768
1791
|
}
|
|
1769
1792
|
async handleRewind(session, agent, turnNum, mode) {
|
|
1770
1793
|
try {
|
|
1771
|
-
if (session
|
|
1794
|
+
if (sessionTopicThreadId(session) && turnNum === 1) {
|
|
1772
1795
|
return '❌ 话题会话暂不支持 /rewind 1,仅开放 N>1';
|
|
1773
1796
|
}
|
|
1774
1797
|
const messages = await agent.getSessionMessages(session.agentSessionId, session.projectPath);
|
|
@@ -1811,10 +1834,11 @@ export class CommandHandler {
|
|
|
1811
1834
|
const ok = await agent.rollbackSessionTurns(session.agentSessionId, session.projectPath, discarded, rewindTarget.assistantUuid);
|
|
1812
1835
|
if (!ok)
|
|
1813
1836
|
return '❌ 对话回退失败';
|
|
1814
|
-
|
|
1837
|
+
const topicThreadId = sessionTopicThreadId(session);
|
|
1838
|
+
if (topicThreadId) {
|
|
1815
1839
|
await this.sessionManager.clearTopicResumeAt({
|
|
1816
1840
|
sessionId: session.id,
|
|
1817
|
-
expectedThreadId:
|
|
1841
|
+
expectedThreadId: topicThreadId,
|
|
1818
1842
|
expectedAgentSessionId: session.agentSessionId,
|
|
1819
1843
|
});
|
|
1820
1844
|
}
|
|
@@ -1825,10 +1849,11 @@ export class CommandHandler {
|
|
|
1825
1849
|
}
|
|
1826
1850
|
}
|
|
1827
1851
|
else if (keepTarget) {
|
|
1828
|
-
|
|
1852
|
+
const topicThreadId = sessionTopicThreadId(session);
|
|
1853
|
+
if (topicThreadId) {
|
|
1829
1854
|
await this.sessionManager.setTopicResumeAt({
|
|
1830
1855
|
sessionId: session.id,
|
|
1831
|
-
expectedThreadId:
|
|
1856
|
+
expectedThreadId: topicThreadId,
|
|
1832
1857
|
expectedAgentSessionId: session.agentSessionId,
|
|
1833
1858
|
resumeAt: keepTarget.assistantUuid,
|
|
1834
1859
|
});
|
|
@@ -1876,7 +1901,7 @@ export class CommandHandler {
|
|
|
1876
1901
|
buildCtlReplyContext(session) {
|
|
1877
1902
|
const ctx = { delivery: deliveryTargetFromSession(session) };
|
|
1878
1903
|
const meta = session.metadata;
|
|
1879
|
-
const threadId = session
|
|
1904
|
+
const threadId = sessionTopicThreadId(session) || meta?.replyContext?.threadId;
|
|
1880
1905
|
if (threadId)
|
|
1881
1906
|
ctx.threadId = threadId;
|
|
1882
1907
|
if (meta?.replyContext?.peerId)
|
|
@@ -1969,7 +1994,7 @@ export class CommandHandler {
|
|
|
1969
1994
|
channelId: conversationId,
|
|
1970
1995
|
chatType: grant.chatType,
|
|
1971
1996
|
conversationId,
|
|
1972
|
-
processOwners:
|
|
1997
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
1973
1998
|
...trustedExecutionIdentityInput(grant),
|
|
1974
1999
|
});
|
|
1975
2000
|
const executeOne = async (fieldArgv) => {
|
|
@@ -1978,7 +2003,7 @@ export class CommandHandler {
|
|
|
1978
2003
|
});
|
|
1979
2004
|
if (!resolved.ok)
|
|
1980
2005
|
return { ok: false, code: resolved.code, error: resolved.reason };
|
|
1981
|
-
const decision =
|
|
2006
|
+
const decision = await authorizeFreshOperation({
|
|
1982
2007
|
source: 'agent-tool',
|
|
1983
2008
|
subject,
|
|
1984
2009
|
intent: {
|
|
@@ -2079,10 +2104,10 @@ export class CommandHandler {
|
|
|
2079
2104
|
channelId: conversationId,
|
|
2080
2105
|
chatType: grant.chatType,
|
|
2081
2106
|
conversationId,
|
|
2082
|
-
processOwners:
|
|
2107
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2083
2108
|
...trustedExecutionIdentityInput(grant),
|
|
2084
2109
|
});
|
|
2085
|
-
const decision =
|
|
2110
|
+
const decision = await authorizeFreshOperation({
|
|
2086
2111
|
source: 'agent-tool',
|
|
2087
2112
|
subject,
|
|
2088
2113
|
intent: {
|
|
@@ -2156,6 +2181,56 @@ export class CommandHandler {
|
|
|
2156
2181
|
: { ok: false, code: result.code, error: result.error, ...(result.data ? { data: result.data } : {}) };
|
|
2157
2182
|
}
|
|
2158
2183
|
/** Agent-managed AID CLI entrypoint. Private key and CA access stay inside the daemon. */
|
|
2184
|
+
async handleOwnershipOperation(argv, sessionId, delegationToken, delegationCommandHash) {
|
|
2185
|
+
const delegation = this.agentDelegationRegistry?.validate(delegationToken, sessionId, delegationCommandHash);
|
|
2186
|
+
if (!delegation?.ok)
|
|
2187
|
+
return { ok: false, code: 'INVALID_DELEGATION', error: 'Valid task delegation is required' };
|
|
2188
|
+
const grant = delegation.grant;
|
|
2189
|
+
if (grant.executionIdentity) {
|
|
2190
|
+
return { ok: false, code: 'NOT_ALLOWED', error: 'Fullaccess execution does not grant protocol Owner binding authority' };
|
|
2191
|
+
}
|
|
2192
|
+
const session = await this.sessionManager.getSessionById(sessionId);
|
|
2193
|
+
if (!session || session.selfAID !== grant.selfAid)
|
|
2194
|
+
return { ok: false, code: 'INVALID_SESSION', error: 'Delegation does not match the session identity' };
|
|
2195
|
+
try {
|
|
2196
|
+
const command = parseOwnershipCommand(argv);
|
|
2197
|
+
const targetAid = command.subjectAid ?? grant.selfAid;
|
|
2198
|
+
ownerResolver.assertLocalSubject(targetAid);
|
|
2199
|
+
if (command.action === 'bind' && ['readonly', 'auto'].includes(grant.permissionMode ?? '')) {
|
|
2200
|
+
return { ok: false, code: 'NOT_ALLOWED', error: 'Binding requires a request or bypass task' };
|
|
2201
|
+
}
|
|
2202
|
+
await refreshOwnershipForAuthorization(targetAid);
|
|
2203
|
+
let conversationId;
|
|
2204
|
+
try {
|
|
2205
|
+
conversationId = parsePeerKey(grant.peerKey).channelId;
|
|
2206
|
+
}
|
|
2207
|
+
catch {
|
|
2208
|
+
return { ok: false, code: 'INVALID_DELEGATION', error: 'Invalid relation key' };
|
|
2209
|
+
}
|
|
2210
|
+
const subject = buildAuthSubject({
|
|
2211
|
+
selfAid: targetAid, actorId: grant.actorId, channel: grant.channel, channelType: grant.channelType,
|
|
2212
|
+
channelId: conversationId, chatType: grant.chatType, conversationId,
|
|
2213
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2214
|
+
});
|
|
2215
|
+
if (targetAid !== grant.selfAid && !subject.isDaemonOwner) {
|
|
2216
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'A different local subject requires the current daemon Owner' };
|
|
2217
|
+
}
|
|
2218
|
+
if (!subject.isDaemonOwner && (command.action === 'bind' ? subject.role !== 'owner' : !isManagementRole(subject.role))) {
|
|
2219
|
+
return { ok: false, code: 'OWNER_REQUIRED', error: 'Ownership binding requires the subject Owner or daemon Owner; first daemon binding uses the local CLI' };
|
|
2220
|
+
}
|
|
2221
|
+
const decision = await authorizeFreshOperation({
|
|
2222
|
+
source: 'agent-tool', subject,
|
|
2223
|
+
intent: { operation: command.action === 'bind' ? 'ec.aid.bind' : 'ec.aid.bind.status', scope: 'agent', source: 'agent-tool', args: { self: targetAid, ...(command.action === 'bind' ? { ownerAid: command.ownerAid } : {}) } },
|
|
2224
|
+
auditMetadata: { taskId: grant.taskId, messageId: grant.messageId },
|
|
2225
|
+
});
|
|
2226
|
+
if (!decision.allow)
|
|
2227
|
+
return { ok: false, code: decision.code, error: decision.reason };
|
|
2228
|
+
return { ok: true, state: await executeOwnershipCommand(command, grant.selfAid) };
|
|
2229
|
+
}
|
|
2230
|
+
catch (error) {
|
|
2231
|
+
return ownershipFailure(error);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2159
2234
|
async handleAidOperation(argv, sessionId, delegationToken, delegationCommandHash) {
|
|
2160
2235
|
if (!this.agentDelegationRegistry) {
|
|
2161
2236
|
return { ok: false, code: 'DELEGATION_REQUIRED', error: 'Task delegation is not configured' };
|
|
@@ -2198,11 +2273,11 @@ export class CommandHandler {
|
|
|
2198
2273
|
channelId: conversationId,
|
|
2199
2274
|
chatType: delegation.grant.chatType,
|
|
2200
2275
|
conversationId,
|
|
2201
|
-
processOwners:
|
|
2276
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2202
2277
|
...trustedExecutionIdentityInput(delegation.grant),
|
|
2203
2278
|
});
|
|
2204
2279
|
const managementRole = isManagementRole(subject.role);
|
|
2205
|
-
const decision =
|
|
2280
|
+
const decision = await authorizeFreshOperation({
|
|
2206
2281
|
source: 'agent-tool',
|
|
2207
2282
|
subject,
|
|
2208
2283
|
intent: {
|
|
@@ -2349,7 +2424,7 @@ export class CommandHandler {
|
|
|
2349
2424
|
channelId: conversationId,
|
|
2350
2425
|
chatType: grant.chatType,
|
|
2351
2426
|
conversationId,
|
|
2352
|
-
processOwners:
|
|
2427
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2353
2428
|
...trustedExecutionIdentityInput(grant),
|
|
2354
2429
|
});
|
|
2355
2430
|
const managementRole = isManagementRole(subject.role) || subject.dataScope === 'daemon';
|
|
@@ -2363,7 +2438,7 @@ export class CommandHandler {
|
|
|
2363
2438
|
&& subject.dataScope !== 'daemon' && subject.role !== 'owner') {
|
|
2364
2439
|
return { ok: false, code: 'ROLE_ACCESS_DENIED', error: `${parsed.command.kind} requires Agent owner permission` };
|
|
2365
2440
|
}
|
|
2366
|
-
const decision =
|
|
2441
|
+
const decision = await authorizeFreshOperation({
|
|
2367
2442
|
source: 'agent-tool',
|
|
2368
2443
|
subject,
|
|
2369
2444
|
intent: {
|
|
@@ -2459,7 +2534,7 @@ export class CommandHandler {
|
|
|
2459
2534
|
try {
|
|
2460
2535
|
return { ok: true, result: await executeManagedGroupOperation(parsed.command, rulesContent, {
|
|
2461
2536
|
defaultThread: grant.chatType === 'group' && conversationId === parsed.command.groupId
|
|
2462
|
-
? session
|
|
2537
|
+
? sessionTopicThreadId(session) ?? 'main' : 'all',
|
|
2463
2538
|
}) };
|
|
2464
2539
|
}
|
|
2465
2540
|
catch (error) {
|
|
@@ -2580,10 +2655,10 @@ export class CommandHandler {
|
|
|
2580
2655
|
chatType: grant.chatType,
|
|
2581
2656
|
conversationId,
|
|
2582
2657
|
...(isSelectorHistory ? { identity: roleToSessionIdentity(grant.issuedRole ?? null) } : {}),
|
|
2583
|
-
processOwners:
|
|
2658
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2584
2659
|
...trustedExecutionIdentityInput(grant),
|
|
2585
2660
|
});
|
|
2586
|
-
const decision =
|
|
2661
|
+
const decision = await authorizeFreshOperation({
|
|
2587
2662
|
source: 'agent-tool',
|
|
2588
2663
|
subject,
|
|
2589
2664
|
intent: {
|
|
@@ -2632,7 +2707,7 @@ export class CommandHandler {
|
|
|
2632
2707
|
};
|
|
2633
2708
|
}
|
|
2634
2709
|
}
|
|
2635
|
-
/** Agent-managed current-group
|
|
2710
|
+
/** Agent-managed filesystem entrypoint for self, current-group, and current-private-peer reads. */
|
|
2636
2711
|
async handleFsOperation(argv, sessionId, delegationToken, delegationCommandHash) {
|
|
2637
2712
|
if (!this.agentDelegationRegistry) {
|
|
2638
2713
|
return { ok: false, code: 'DELEGATION_REQUIRED', error: 'Task delegation is not configured' };
|
|
@@ -2652,9 +2727,21 @@ export class CommandHandler {
|
|
|
2652
2727
|
if (sessionSelfAid && sessionSelfAid !== actorAid) {
|
|
2653
2728
|
return { ok: false, code: 'INVALID_DELEGATION', error: 'Delegation self agent does not match the active session' };
|
|
2654
2729
|
}
|
|
2655
|
-
const
|
|
2730
|
+
const isSelfPersonalTarget = parsed.command.targetAid === actorAid;
|
|
2731
|
+
let currentPrivatePeer;
|
|
2656
2732
|
let currentGroup;
|
|
2657
|
-
if (
|
|
2733
|
+
if (grant.channelType === 'aun' && grant.chatType === 'private') {
|
|
2734
|
+
try {
|
|
2735
|
+
currentPrivatePeer = parsePeerKey(grant.peerKey).channelId;
|
|
2736
|
+
}
|
|
2737
|
+
catch {
|
|
2738
|
+
return { ok: false, code: 'INVALID_DELEGATION', error: 'Delegation contains an invalid relation key' };
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
const isCurrentPrivatePeerCat = parsed.command.kind === 'cat'
|
|
2742
|
+
&& currentPrivatePeer !== undefined
|
|
2743
|
+
&& parsed.command.targetAid === currentPrivatePeer;
|
|
2744
|
+
if (isSelfPersonalTarget) {
|
|
2658
2745
|
if (grant.issuedRole !== 'owner' && !hasTrustedFullAccessDelegation(grant)) {
|
|
2659
2746
|
return { ok: false, code: 'NO_PERMISSION', error: 'Managed personal storage requires the current Agent owner relation' };
|
|
2660
2747
|
}
|
|
@@ -2662,6 +2749,11 @@ export class CommandHandler {
|
|
|
2662
2749
|
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Only the current Agent can access its personal storage' };
|
|
2663
2750
|
}
|
|
2664
2751
|
}
|
|
2752
|
+
else if (isCurrentPrivatePeerCat) {
|
|
2753
|
+
if (parsed.command.actorAid && parsed.command.actorAid !== actorAid) {
|
|
2754
|
+
return { ok: false, code: 'SCOPE_MISMATCH', error: 'Managed fs cannot switch the execution identity with --as' };
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2665
2757
|
else {
|
|
2666
2758
|
const trustedFullAccess = hasTrustedFullAccessDelegation(grant);
|
|
2667
2759
|
if (trustedFullAccess) {
|
|
@@ -2702,26 +2794,27 @@ export class CommandHandler {
|
|
|
2702
2794
|
}
|
|
2703
2795
|
}
|
|
2704
2796
|
const resolvedCommand = parsed.command;
|
|
2705
|
-
resolvedCommand.storageBackend =
|
|
2706
|
-
resolvedCommand.actorAid = hasTrustedFullAccessDelegation(grant) && !
|
|
2797
|
+
resolvedCommand.storageBackend = isSelfPersonalTarget || isCurrentPrivatePeerCat ? 'personal' : 'group';
|
|
2798
|
+
resolvedCommand.actorAid = hasTrustedFullAccessDelegation(grant) && !isSelfPersonalTarget && !isCurrentPrivatePeerCat
|
|
2707
2799
|
? (resolvedCommand.actorAid ?? actorAid)
|
|
2708
2800
|
: actorAid;
|
|
2801
|
+
const relationTarget = currentPrivatePeer ?? currentGroup;
|
|
2709
2802
|
const subject = buildAuthSubject({
|
|
2710
2803
|
selfAid: grant.selfAid,
|
|
2711
2804
|
actorId: grant.actorId,
|
|
2712
2805
|
channel: grant.channel,
|
|
2713
2806
|
channelType: grant.channelType,
|
|
2714
|
-
channelId:
|
|
2807
|
+
channelId: relationTarget ?? actorAid,
|
|
2715
2808
|
chatType: grant.chatType,
|
|
2716
|
-
conversationId:
|
|
2717
|
-
processOwners:
|
|
2809
|
+
conversationId: relationTarget ?? actorAid,
|
|
2810
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2718
2811
|
...trustedExecutionIdentityInput(grant),
|
|
2719
2812
|
});
|
|
2720
2813
|
const intentArgs = {
|
|
2721
2814
|
self: actorAid,
|
|
2722
2815
|
targetId: parsed.command.targetAid,
|
|
2723
|
-
peer:
|
|
2724
|
-
peerKey: formatPeerKey('aun',
|
|
2816
|
+
peer: relationTarget ?? actorAid,
|
|
2817
|
+
peerKey: formatPeerKey('aun', relationTarget ?? actorAid),
|
|
2725
2818
|
path: parsed.command.remotePath,
|
|
2726
2819
|
targetPath: parsed.command.remotePath,
|
|
2727
2820
|
...(parsed.command.remoteSourcePath ? { sourcePath: parsed.command.remoteSourcePath } : {}),
|
|
@@ -2733,12 +2826,12 @@ export class CommandHandler {
|
|
|
2733
2826
|
...(parsed.command.aclPerms ? { aclPerms: parsed.command.aclPerms } : {}),
|
|
2734
2827
|
...(parsed.command.aclRemove !== undefined ? { aclRemove: parsed.command.aclRemove } : {}),
|
|
2735
2828
|
};
|
|
2736
|
-
const decision =
|
|
2829
|
+
const decision = await authorizeFreshOperation({
|
|
2737
2830
|
source: 'agent-tool',
|
|
2738
2831
|
subject,
|
|
2739
2832
|
intent: {
|
|
2740
2833
|
operation: parsed.command.operationId,
|
|
2741
|
-
scope:
|
|
2834
|
+
scope: isSelfPersonalTarget ? 'agent' : 'relation',
|
|
2742
2835
|
source: 'agent-tool',
|
|
2743
2836
|
args: intentArgs,
|
|
2744
2837
|
},
|
|
@@ -2808,6 +2901,68 @@ export class CommandHandler {
|
|
|
2808
2901
|
setAgentDelegationRegistry(registry) {
|
|
2809
2902
|
this.agentDelegationRegistry = registry;
|
|
2810
2903
|
}
|
|
2904
|
+
/** Inject the daemon-owned system-message transport used by thread operations. */
|
|
2905
|
+
setThreadSystemMsgSender(sender) {
|
|
2906
|
+
this.threadSystemMsgSender = sender;
|
|
2907
|
+
}
|
|
2908
|
+
/** Menu actions share the same transport as CLI/thread operations. */
|
|
2909
|
+
getThreadSystemMsgSender() {
|
|
2910
|
+
return this.threadSystemMsgSender;
|
|
2911
|
+
}
|
|
2912
|
+
async executeThreadSummaryCli(input) {
|
|
2913
|
+
const startedAt = Date.now();
|
|
2914
|
+
try {
|
|
2915
|
+
if (!input.selfAid || input.selfAid !== input.authenticatedSelfAid
|
|
2916
|
+
|| !input.peer || !input.threadId) {
|
|
2917
|
+
return {
|
|
2918
|
+
data: {
|
|
2919
|
+
exitCode: 1,
|
|
2920
|
+
stdout: JSON.stringify({ code: 'SCOPE_MISMATCH', message: 'Only the current Agent and a concrete topic can be targeted' }),
|
|
2921
|
+
stderr: '',
|
|
2922
|
+
durationMs: Date.now() - startedAt,
|
|
2923
|
+
},
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
const service = new ThreadService(this.sessionManager);
|
|
2927
|
+
const topic = await service.showThread({
|
|
2928
|
+
selfAid: input.selfAid,
|
|
2929
|
+
peer: input.peer,
|
|
2930
|
+
threadId: input.threadId,
|
|
2931
|
+
});
|
|
2932
|
+
const summaries = service.logSummary(input.selfAid, topic.sessionId);
|
|
2933
|
+
const result = {
|
|
2934
|
+
thread: {
|
|
2935
|
+
peer: topic.peer,
|
|
2936
|
+
threadId: topic.threadId,
|
|
2937
|
+
name: topic.name,
|
|
2938
|
+
topicStatus: topic.topicStatus,
|
|
2939
|
+
label: topic.label ?? null,
|
|
2940
|
+
},
|
|
2941
|
+
currentSummary: service.showSummary(input.selfAid, topic.sessionId) ?? null,
|
|
2942
|
+
summaries,
|
|
2943
|
+
};
|
|
2944
|
+
return {
|
|
2945
|
+
data: {
|
|
2946
|
+
exitCode: 0,
|
|
2947
|
+
stdout: JSON.stringify(result),
|
|
2948
|
+
stderr: '',
|
|
2949
|
+
durationMs: Date.now() - startedAt,
|
|
2950
|
+
},
|
|
2951
|
+
};
|
|
2952
|
+
}
|
|
2953
|
+
catch (error) {
|
|
2954
|
+
const code = error?.code ?? 'THREAD_READ_FAILED';
|
|
2955
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2956
|
+
return {
|
|
2957
|
+
data: {
|
|
2958
|
+
exitCode: 1,
|
|
2959
|
+
stdout: JSON.stringify({ code, message }),
|
|
2960
|
+
stderr: '',
|
|
2961
|
+
durationMs: Date.now() - startedAt,
|
|
2962
|
+
},
|
|
2963
|
+
};
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2811
2966
|
async handleManagedCliOperation(argv, sessionId, grant) {
|
|
2812
2967
|
const invalid = (error) => ({ ok: false, code: 'INVALID_ARGUMENT', error });
|
|
2813
2968
|
if (argv[0] === 'ctl') {
|
|
@@ -2936,13 +3091,13 @@ export class CommandHandler {
|
|
|
2936
3091
|
channelId: conversationId,
|
|
2937
3092
|
chatType: grant.chatType,
|
|
2938
3093
|
conversationId,
|
|
2939
|
-
processOwners:
|
|
3094
|
+
processOwners: ownerResolver.daemonOwners(),
|
|
2940
3095
|
...trustedExecutionIdentityInput(grant),
|
|
2941
3096
|
});
|
|
2942
3097
|
const ctlIntent = this.resolveCtlIntent(cmd, grantSelfAid, grant.peerKey);
|
|
2943
3098
|
if (!ctlIntent)
|
|
2944
3099
|
return { ok: false, code: 'NOT_ALLOWED', error: `不允许的指令: ${inputCmd}` };
|
|
2945
|
-
const ctlDecision =
|
|
3100
|
+
const ctlDecision = await authorizeFreshOperation({
|
|
2946
3101
|
source: 'agent-tool',
|
|
2947
3102
|
subject: ctlSubject,
|
|
2948
3103
|
intent: ctlIntent,
|
|
@@ -3045,7 +3200,7 @@ export class CommandHandler {
|
|
|
3045
3200
|
// 6. 调用现有 handle(),不传 sendMessage 回调(结果直接返回)
|
|
3046
3201
|
try {
|
|
3047
3202
|
const result = await this._handleInternal(cmd, session.channel, session.channelId, undefined, // 不发送消息
|
|
3048
|
-
userId, session
|
|
3203
|
+
userId, sessionTopicThreadId(session), session.chatType, undefined, undefined, session.selfAID, ctlIdentity, ctlSubject);
|
|
3049
3204
|
const text = typeof result === 'string' ? result : (result && 'text' in result ? result.text : '(无输出)');
|
|
3050
3205
|
if (result && typeof result === 'object' && 'kind' in result && result.kind === 'command.error') {
|
|
3051
3206
|
return { ok: false, error: text || '执行失败' };
|
|
@@ -3204,9 +3359,9 @@ export class CommandHandler {
|
|
|
3204
3359
|
const after = parseQueueTimeArg(this.extractArg(args, '--after'));
|
|
3205
3360
|
const before = parseQueueTimeArg(this.extractArg(args, '--before'));
|
|
3206
3361
|
if (this.extractArg(args, '--after') && after === undefined)
|
|
3207
|
-
return { ok: false, error:
|
|
3362
|
+
return { ok: false, error: `❌ --after 不是有效时间(支持 ${TIME_ARG_FORMATS})` };
|
|
3208
3363
|
if (this.extractArg(args, '--before') && before === undefined)
|
|
3209
|
-
return { ok: false, error:
|
|
3364
|
+
return { ok: false, error: `❌ --before 不是有效时间(支持 ${TIME_ARG_FORMATS})` };
|
|
3210
3365
|
if (after !== undefined && before !== undefined && after >= before)
|
|
3211
3366
|
return { ok: false, error: '❌ --after 必须早于 --before' };
|
|
3212
3367
|
// 操作分支
|
|
@@ -3238,10 +3393,7 @@ export class CommandHandler {
|
|
|
3238
3393
|
}
|
|
3239
3394
|
}
|
|
3240
3395
|
function parseQueueTimeArg(value) {
|
|
3241
|
-
|
|
3242
|
-
return undefined;
|
|
3243
|
-
const parsed = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
|
|
3244
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
3396
|
+
return parseTimeArg(value);
|
|
3245
3397
|
}
|
|
3246
3398
|
/**
|
|
3247
3399
|
* ctl 专用渲染:不显示 session 标识列(因为只有一个 session)
|
|
@@ -195,6 +195,7 @@ function contactItem(self, primaryId) {
|
|
|
195
195
|
status: view.status,
|
|
196
196
|
blocked: view.blocked,
|
|
197
197
|
isOwner: view.isOwner,
|
|
198
|
+
...(view.managementRole ? { managementRole: view.managementRole } : {}),
|
|
198
199
|
aliases: view.aliases,
|
|
199
200
|
...(pendingRequest ? {
|
|
200
201
|
pendingRequest: {
|