evolcore 0.0.11 → 0.0.13
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 +44 -0
- package/bin/codex-managed-hook.mjs +80 -0
- package/bin/ec-safe-output.js +26 -7
- package/dist/agents/claude-runner.js +86 -7
- package/dist/agents/codex-app-server-client.js +174 -20
- package/dist/agents/codex-runner.js +375 -92
- package/dist/agents/ecagent-runner.js +39 -4
- package/dist/agents/gemini-runner.js +1 -0
- package/dist/aun/aid/client.js +11 -21
- package/dist/aun/aid/control-aid.js +36 -13
- package/dist/aun/aid/managed-operation.js +107 -0
- package/dist/aun/aid/store.js +13 -7
- package/dist/aun/group-fs-download.js +56 -0
- package/dist/aun/group-identity.js +1 -2
- package/dist/aun/msg/group.js +91 -44
- package/dist/aun/msg/index.js +1 -2
- package/dist/aun/msg/managed-operation.js +865 -0
- package/dist/aun/msg/mention-schema.js +20 -0
- package/dist/aun/msg/p2p.js +7 -0
- package/dist/aun/msg/upload.js +16 -1
- package/dist/aun/outbox.js +31 -2
- package/dist/aun/rpc/client.js +66 -0
- package/dist/aun/rpc/index.js +1 -2
- package/dist/aun/storage/{upload.js → client.js} +11 -2
- package/dist/aun/storage/index.js +1 -2
- package/dist/channels/aun.js +655 -240
- package/dist/channels/daemon.js +13 -0
- package/dist/cli/agent-command.js +56 -8
- package/dist/cli/agent.js +108 -31
- package/dist/cli/aun-commands.js +270 -69
- package/dist/cli/bench.js +12 -3
- package/dist/cli/cli-argv.js +10 -0
- package/dist/cli/config.js +9 -17
- package/dist/cli/ctl-command.js +1 -1
- package/dist/cli/daemon-commands.js +70 -55
- package/dist/cli/fs-command.js +79 -10
- package/dist/cli/handoff-command.js +3 -0
- package/dist/cli/index.js +30 -2
- package/dist/cli/init.js +77 -8
- package/dist/cli/managed-command-guard.js +41 -0
- package/dist/cli/model.js +11 -4
- package/dist/cli/queue-command.js +53 -1
- package/dist/cli/response.js +71 -0
- package/dist/cli/restart-monitor.js +7 -32
- package/dist/cli/trigger-command.js +11 -0
- package/dist/config/access-policy.js +1 -2
- package/dist/config/builtin-roles.js +9 -0
- package/dist/config/config-manager.js +21 -1
- package/dist/config/contact-book-store.js +11 -3
- package/dist/config/contact-request-service.js +161 -15
- package/dist/config/mention-mode.js +8 -24
- package/dist/config/peer-role-resolver.js +6 -2
- package/dist/config/role-migration-startup.js +53 -0
- package/dist/config/role-store.js +1 -1
- package/dist/core/auth/agent-delegation.js +1 -2
- package/dist/core/auth/auth-gateway.js +29 -1
- package/dist/core/auth/authorization-audit.js +15 -0
- package/dist/core/auth/operation-authorizer.js +31 -7
- package/dist/core/auth/operation-catalog.js +196 -25
- package/dist/core/bootstrap-messages.js +25 -0
- package/dist/core/bootstrap-service.js +64 -4
- package/dist/core/capability/providers/claude-capability-provider.js +9 -31
- package/dist/core/capability/providers/codex-capability-provider.js +4 -15
- package/dist/core/capability/skill-discovery.js +55 -0
- package/dist/core/channel-loader.js +1 -1
- package/dist/core/command/cli-intent-parser.js +9 -0
- package/dist/core/command/command-handler.js +650 -42
- package/dist/core/command/connect-menu.js +15 -0
- package/dist/core/command/group-menu.js +4 -4
- package/dist/core/command/menu-catalog.js +370 -0
- package/dist/core/command/menu-handler.js +230 -51
- package/dist/core/command/menu-protocol.js +94 -2
- package/dist/core/command/slash-gate.js +5 -2
- package/dist/core/command/slash-handler.js +99 -31
- package/dist/core/daemon-file-cache.js +2 -1
- package/dist/core/data-migration.js +9 -2
- package/dist/core/event-catalog.js +6 -0
- package/dist/core/evolagent.js +4 -2
- package/dist/core/handoff/dispatcher.js +5 -2
- package/dist/core/handoff/runtime.js +157 -22
- package/dist/core/handoff/store.js +29 -1
- package/dist/core/handoff/types.js +1 -0
- package/dist/core/interaction-router.js +10 -0
- package/dist/core/message/im-renderer.js +19 -0
- package/dist/core/message/logical-queue-bridge.js +1 -0
- package/dist/core/message/mention-schema.js +126 -0
- package/dist/core/message/message-bridge.js +298 -88
- package/dist/core/message/message-log.js +3 -0
- package/dist/core/message/message-queue.js +268 -39
- package/dist/core/message/message-utils.js +81 -4
- package/dist/core/message/response-engine.js +161 -77
- package/dist/core/message/stream-debouncer.js +10 -2
- package/dist/core/permission/approval-gateway.js +1 -0
- package/dist/core/permission/ec-command-parser.js +243 -18
- package/dist/core/permission/index.js +1 -1
- package/dist/core/permission/mode.js +15 -0
- package/dist/core/permission/readonly-shell-query.js +148 -8
- package/dist/core/permission/sandbox-runtime.js +43 -1
- package/dist/core/permission/tool-policy.js +322 -57
- package/dist/core/protected-paths.js +114 -4
- package/dist/core/session/session-manager.js +42 -4
- package/dist/core/session/session-mapper.js +20 -1
- package/dist/eck/detect.js +18 -1
- package/dist/eck/group-rules-sync.js +15 -44
- package/dist/eck/manifest-engine.js +39 -13
- package/dist/index.js +541 -180
- package/dist/ipc.js +232 -10
- package/dist/paths.js +3 -0
- package/dist/response-system/coordinator.js +6 -4
- package/dist/response-system/engines/v1/proactive-flow.js +26 -8
- package/dist/response-system/modes/single-session/index.js +14 -1
- package/dist/response-system/selector.js +6 -5
- package/dist/trigger/anomaly-store.js +4 -0
- package/dist/trigger/feedback.js +64 -11
- package/dist/trigger/manager.js +21 -1
- package/dist/trigger/parser.js +14 -2
- package/dist/trigger/scheduler.js +1 -0
- package/dist/trigger/script-executor.js +1 -0
- package/dist/trigger/validation.js +67 -6
- package/dist/utils/codex-app-server-registry.js +90 -0
- package/dist/utils/codex-cli.js +5 -1
- package/dist/utils/cross-platform.js +15 -0
- package/dist/utils/ecweb-supervisor.js +332 -0
- package/dist/utils/error-utils.js +10 -0
- package/dist/utils/npm-ops.js +5 -12
- package/dist/utils/tool-summary.js +11 -0
- package/kits/docs/channels/aun.md +1 -1
- package/kits/docs/context-assembly.md +2 -2
- package/kits/docs/evolcore/agent.md +11 -6
- package/kits/docs/evolcore/aid.md +14 -0
- package/kits/docs/evolcore/trigger.md +17 -1
- package/kits/docs/prompt-loading-architecture.md +1 -2
- package/kits/docs/venues/group.md +1 -1
- package/kits/eck_manifest.json +0 -12
- package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/05-venue.md +2 -2
- package/kits/schemas/role-config.schema.1.json +1 -0
- package/kits/schemas/single-session.schema.1.json +3 -3
- package/kits/schemas/single-session.schema.2.json +3 -3
- package/kits/templates/roles/admin.json +27 -0
- package/kits/templates/roles/member.json +34 -1
- package/kits/templates/roles/visitor.json +35 -3
- package/kits/templates/system-fragments/bootstrap.md +1 -1
- package/kits/templates/system-fragments/channel.md +1 -1
- package/kits/templates/system-fragments/session.md +1 -1
- package/package.json +2 -2
- package/dist/aun/msg/payload-type.js +0 -27
- package/dist/aun/rpc/caller.js +0 -42
- package/dist/aun/rpc/connection.js +0 -25
- package/dist/aun/storage/manage.js +0 -10
- package/dist/config/access-policy-domain.js +0 -18
- package/dist/config/config-batch-get.js +0 -11
- package/dist/config/owner-policy.js +0 -4
- package/dist/config/role-config-v4-startup.js +0 -32
- package/dist/config/role-config-v5-startup.js +0 -27
- package/dist/core/auth/trigger-authorization.js +0 -15
- package/dist/core/command/evol-menu-version-gate.js +0 -39
- package/dist/core/interaction-registration.js +0 -10
- package/dist/core/permission/execution-sandbox.js +0 -16
- package/dist/core/relation/peer-key.js +0 -1
- package/dist/core/session/session-key.js +0 -24
- package/dist/eck/baseagent-caps.js +0 -18
- package/dist/eck/rules-loader.js +0 -28
|
@@ -6,7 +6,7 @@ import { hasModelSwitcher } from '../../agents/runner-types.js';
|
|
|
6
6
|
import { getCodexEfforts } from '../../agents/codex-runner.js';
|
|
7
7
|
import { execCodexCliSync, resolveCodexCliPath } from '../../utils/codex-cli.js';
|
|
8
8
|
import { resolvePaths, getPackageRoot, daemonControlDir } from '../../paths.js';
|
|
9
|
-
import { buildEnvelope } from '../message/message-utils.js';
|
|
9
|
+
import { buildEnvelope, isDeliveryTarget, isDeliveryTargetForChannel, replyContextFromSession } from '../message/message-utils.js';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import os from 'os';
|
|
@@ -15,7 +15,7 @@ import { execFileSync } from 'child_process';
|
|
|
15
15
|
import { CronExpressionParser } from 'cron-parser';
|
|
16
16
|
import { parseDuration } from '../../trigger/parser.js';
|
|
17
17
|
import { checkLatestVersion, getLocalVersion, isLinkedInstall, compareVersions, resolveGlobalPkg } from '../../utils/npm-ops.js';
|
|
18
|
-
import { commandExists } from '../../utils/cross-platform.js';
|
|
18
|
+
import { commandExists, spawnDetachedNode } from '../../utils/cross-platform.js';
|
|
19
19
|
import { loadDefaults, loadDaemonConfig } from '../../config-store.js';
|
|
20
20
|
import { WEB_PACKAGE_NAME } from '../../product.js';
|
|
21
21
|
import { read as cfgRead, resolveEffective, resolveEffectiveFieldWithSource, routeFieldPath, write as cfgWrite, ConfigTarget, } from '../../config/config-manager.js';
|
|
@@ -28,7 +28,7 @@ import { normalizeCliArgv, parseCliIntent, parseLegacyCliCommand, validateCliArg
|
|
|
28
28
|
import { auditCommandAuthorization, hashArgv } from '../auth/authorization-audit.js';
|
|
29
29
|
import { authorizeOperation, buildAuthSubject } from '../auth/auth-gateway.js';
|
|
30
30
|
import { evaluateRoleOperationCapability } from '../auth/operation-authorizer.js';
|
|
31
|
-
import { splitConfigBatchGetArgv } from '../../
|
|
31
|
+
import { splitConfigBatchGetArgv } from '../../cli/cli-argv.js';
|
|
32
32
|
import { chatmodeFieldForPeer, resolveChatModeForField } from '../message/peer-mode.js';
|
|
33
33
|
import { PUBLIC_PERMISSION_MODES } from '../permission/mode.js';
|
|
34
34
|
import { resolveRuntimePermissionMode, resolveRuntimeStringField, validateRuntimeStringFieldOverride, } from '../role/runtime-policy.js';
|
|
@@ -36,11 +36,12 @@ import { isManagementRole } from '../../config/builtin-roles.js';
|
|
|
36
36
|
import { SYSTEM_CONTROL_CHANNEL } from '../system-channels.js';
|
|
37
37
|
import { logger } from '../../utils/logger.js';
|
|
38
38
|
import { shouldSuppressRealRestart } from '../../utils/restart-safety.js';
|
|
39
|
-
import {
|
|
40
|
-
import { menuFailure, menuSuccess, normalizeMenuError, validateConfigWriteScope, validateMenuRequest } from './menu-protocol.js';
|
|
39
|
+
import { AGENT_DELEGATION_TOKEN_ENV } from '../auth/agent-delegation.js';
|
|
40
|
+
import { evolMenuResponseTransportMetadata, menuFailure, menuCommandForName, menuSuccess, normalizeMenuError, validateConfigWriteScope, validateMenuRequest, } from './menu-protocol.js';
|
|
41
41
|
import { roleMenuAction, roleMenuOperation, roleMenuOptions, roleMenuQuery, roleMenuUpdate, } from './role-menu.js';
|
|
42
42
|
import { handleConnectMenu, connectMenuOperation } from './connect-menu.js';
|
|
43
43
|
import { groupMenuAuthorizationArgs, groupMenuIntent, handleGroupMenu, } from './group-menu.js';
|
|
44
|
+
import { getMenuCatalog, execMenuValueBatch, resolveExplicitMenuExecutionContext, validateMenuCatalogArgs, validateMenuValueBatchArgs } from './menu-catalog.js';
|
|
44
45
|
/**
|
|
45
46
|
* 获取 baseagent CLI 的版本号(claude/gemini/codex)。
|
|
46
47
|
* 失败返回 null(命令不存在或执行失败)。
|
|
@@ -60,6 +61,7 @@ function getBaseagentVersion(cmd) {
|
|
|
60
61
|
encoding: 'utf-8',
|
|
61
62
|
timeout: 3000,
|
|
62
63
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
64
|
+
windowsHide: process.platform === 'win32',
|
|
63
65
|
});
|
|
64
66
|
const versionOutput = String(output).trim();
|
|
65
67
|
// claude: "2.1.187 (Claude Code)" → 提取 "2.1.187"
|
|
@@ -880,7 +882,7 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
880
882
|
if (cmdBase === '/topic')
|
|
881
883
|
return intent('session.topic.current', 'relation');
|
|
882
884
|
if (cmdBase === '/baseagent')
|
|
883
|
-
return intent('agent.baseagent.current', fromControlChannel ? 'agent' : 'relation');
|
|
885
|
+
return intent('agent.baseagent.current', fromControlChannel || args?.scope === 'agent' ? 'agent' : 'relation');
|
|
884
886
|
if (cmdBase === '/file')
|
|
885
887
|
return intent('file.fetch', 'filesystem', { filePath: args?.path });
|
|
886
888
|
if (cmdBase === '/model')
|
|
@@ -938,6 +940,8 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
938
940
|
return intent('permission.current', args?.scope === 'agent' ? 'agent' : 'relation');
|
|
939
941
|
}
|
|
940
942
|
if (verb === 'update') {
|
|
943
|
+
if (cmdBase === '/baseagent')
|
|
944
|
+
return intent('agent.baseagent.update', 'agent', { baseagent: value });
|
|
941
945
|
if (cmdBase === '/model')
|
|
942
946
|
return intent('model.use', modelScope, { model: value });
|
|
943
947
|
if (cmdBase === '/effort')
|
|
@@ -946,6 +950,10 @@ function buildMenuIntent(verb, cmdBase, args, action, value, fromControlChannel
|
|
|
946
950
|
return intent('chatmode.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
947
951
|
if (cmdBase === '/mentionmode')
|
|
948
952
|
return intent('mentionmode.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
953
|
+
if (cmdBase === '/activity')
|
|
954
|
+
return intent('activity.update', args?.scope === 'agent' ? 'agent' : 'relation', { value });
|
|
955
|
+
if (cmdBase === '/observable')
|
|
956
|
+
return intent('observable.update', 'agent', { value });
|
|
949
957
|
if (cmdBase === '/gateway')
|
|
950
958
|
return intent('gateway.write', 'process');
|
|
951
959
|
if (cmdBase === '/config')
|
|
@@ -1006,8 +1014,13 @@ function buildRelationIntentArgs(params) {
|
|
|
1006
1014
|
return out;
|
|
1007
1015
|
}
|
|
1008
1016
|
function buildMenuAuthSubject(owner, params) {
|
|
1009
|
-
if (params.subject)
|
|
1010
|
-
return
|
|
1017
|
+
if (params.subject) {
|
|
1018
|
+
return {
|
|
1019
|
+
...params.subject,
|
|
1020
|
+
...(params.requestId && !params.subject.requestId ? { requestId: params.requestId } : {}),
|
|
1021
|
+
...(params.session?.id && !params.subject.sessionId ? { sessionId: params.session.id } : {}),
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1011
1024
|
const agent = owner.getOwningAgent?.(params.channel);
|
|
1012
1025
|
const selfAid = agent?.aid || params.session?.selfAID;
|
|
1013
1026
|
const channelType = owner.resolveChannelType?.(params.channel) || params.session?.channelType;
|
|
@@ -1018,6 +1031,8 @@ function buildMenuAuthSubject(owner, params) {
|
|
|
1018
1031
|
return buildAuthSubject({
|
|
1019
1032
|
selfAid,
|
|
1020
1033
|
actorId: params.userId,
|
|
1034
|
+
requestId: params.requestId,
|
|
1035
|
+
sessionId: params.session?.id,
|
|
1021
1036
|
channel: params.channel,
|
|
1022
1037
|
channelType: channelType || params.channel.split('#')[0],
|
|
1023
1038
|
channelId: params.channelId,
|
|
@@ -1089,6 +1104,9 @@ function buildRoleMenuContext(owner, channel, subject) {
|
|
|
1089
1104
|
}
|
|
1090
1105
|
const aunAvailable = (owningAgent?.channelInstanceNames?.() ?? [])
|
|
1091
1106
|
.some((channelName) => owner.hasRegisteredChannel?.(channelName, 'aun') === true);
|
|
1107
|
+
const aunChannelName = (owningAgent?.channelInstanceNames?.() ?? [])
|
|
1108
|
+
.find((name) => String(name).split('#', 1)[0].toLowerCase() === 'aun');
|
|
1109
|
+
const contactAdapter = aunChannelName ? owner.getAdapter?.(aunChannelName) : undefined;
|
|
1092
1110
|
return {
|
|
1093
1111
|
self,
|
|
1094
1112
|
actorRole: subject.role,
|
|
@@ -1097,6 +1115,26 @@ function buildRoleMenuContext(owner, channel, subject) {
|
|
|
1097
1115
|
actorAid: subject.actorId,
|
|
1098
1116
|
chatType: subject.chatType,
|
|
1099
1117
|
aunAvailable,
|
|
1118
|
+
...(contactAdapter?.send ? {
|
|
1119
|
+
notifyContactRequestReviewed: async ({ applicantAid, requestId, expiresAt, status }) => {
|
|
1120
|
+
await contactAdapter.send(buildEnvelope({
|
|
1121
|
+
taskId: `contact-request-${requestId}`,
|
|
1122
|
+
channel: contactAdapter.channelName,
|
|
1123
|
+
channelId: applicantAid,
|
|
1124
|
+
agentName: owningAgent?.name ?? '<unknown>',
|
|
1125
|
+
replyContext: { delivery: { chatType: 'private' }, metadata: evolMenuResponseTransportMetadata() },
|
|
1126
|
+
}), {
|
|
1127
|
+
kind: 'custom',
|
|
1128
|
+
channelType: 'aun',
|
|
1129
|
+
payload: {
|
|
1130
|
+
type: 'contact.request.response',
|
|
1131
|
+
status,
|
|
1132
|
+
request_id: requestId,
|
|
1133
|
+
expires_at: expiresAt,
|
|
1134
|
+
},
|
|
1135
|
+
});
|
|
1136
|
+
},
|
|
1137
|
+
} : {}),
|
|
1100
1138
|
availableBaseagents: Array.from(new Set([
|
|
1101
1139
|
...Object.keys(owningAgent?.config?.baseagents ?? {}),
|
|
1102
1140
|
...(owningAgent?.baseagent ? [owningAgent.baseagent] : []),
|
|
@@ -1285,6 +1323,7 @@ export function getMenuItems(role, chatType = 'private', scope = 'agent', authSu
|
|
|
1285
1323
|
fromControlChannel: isControlScope,
|
|
1286
1324
|
}).allow;
|
|
1287
1325
|
};
|
|
1326
|
+
const canReadModel = canOperation('model.list', 'relation') || canOperation('model.current', 'relation');
|
|
1288
1327
|
const canUseModel = canOperation('model.use', 'relation');
|
|
1289
1328
|
const canSetEffort = canOperation('model.effort', 'relation');
|
|
1290
1329
|
const canSetChatmode = canOperation('chatmode.update', 'relation');
|
|
@@ -1293,7 +1332,12 @@ export function getMenuItems(role, chatType = 'private', scope = 'agent', authSu
|
|
|
1293
1332
|
const canUseFile = canOperation('file.fetch', 'filesystem') || canOperation('file.list', 'filesystem');
|
|
1294
1333
|
const canManageProcess = authSubject ? authSubject.isDaemonOwner : isOwner;
|
|
1295
1334
|
const configurableSettings = [
|
|
1296
|
-
...(
|
|
1335
|
+
...(canReadModel ? [{
|
|
1336
|
+
cmd: '/model',
|
|
1337
|
+
label: canUseModel ? '切换模型' : '查看模型',
|
|
1338
|
+
desc: canUseModel ? '切换当前 Agent 使用的模型版本' : '查看当前 Agent 使用的模型版本',
|
|
1339
|
+
next: canUseModel ? { type: 'select', dynamic: true } : undefined,
|
|
1340
|
+
}] : []),
|
|
1297
1341
|
...(canSetEffort ? [{ cmd: '/effort', label: '切换推理强度', desc: '调整模型推理深度,影响响应速度与质量', next: { type: 'select', items: [
|
|
1298
1342
|
{ value: 'low', label: 'Low' },
|
|
1299
1343
|
{ value: 'medium', label: 'Medium' },
|
|
@@ -1729,7 +1773,7 @@ export async function getSubMenuItems(cmd, channel, channelId, userId, args, ove
|
|
|
1729
1773
|
});
|
|
1730
1774
|
if ('error' in target)
|
|
1731
1775
|
throw { code: target.code, message: target.error };
|
|
1732
|
-
const fallback =
|
|
1776
|
+
const fallback = session?.metadata?.mentionMode ?? null;
|
|
1733
1777
|
const currentMode = readMenuMentionMode(target, fallback, fallback === null ? null : 'session').value;
|
|
1734
1778
|
return [
|
|
1735
1779
|
{ value: 'mention-only', label: '@提及时响应', selected: currentMode === 'mention-only' },
|
|
@@ -1755,6 +1799,10 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
1755
1799
|
const cmdBase = cmd.trim().split(' ')[0];
|
|
1756
1800
|
if (!cmdBase)
|
|
1757
1801
|
return { error: '缺少命令', code: 'MISSING_CMD' };
|
|
1802
|
+
const isRequesterRoleQuery = cmdBase === '/role' && args?.view === 'requester';
|
|
1803
|
+
if (isRequesterRoleQuery && Object.keys(args).some(key => key !== 'view')) {
|
|
1804
|
+
return { error: 'role requester query only accepts args.view', code: 'INVALID_ARGUMENT' };
|
|
1805
|
+
}
|
|
1758
1806
|
const gated = gateControlScope.call(this, { cmdBase, args, channel, fromControlChannel });
|
|
1759
1807
|
if (gated)
|
|
1760
1808
|
return gated;
|
|
@@ -1770,6 +1818,18 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
1770
1818
|
fromControlChannel,
|
|
1771
1819
|
subject: authSubject,
|
|
1772
1820
|
});
|
|
1821
|
+
if (isRequesterRoleQuery) {
|
|
1822
|
+
if (!subject.allowAccess) {
|
|
1823
|
+
return { error: `Role ${subject.role} is not allowed to access this agent`, code: 'ROLE_ACCESS_DENIED' };
|
|
1824
|
+
}
|
|
1825
|
+
return {
|
|
1826
|
+
data: {
|
|
1827
|
+
roleId: subject.role,
|
|
1828
|
+
source: subject.roleSource,
|
|
1829
|
+
allowAccess: subject.allowAccess,
|
|
1830
|
+
},
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1773
1833
|
if (cmdBase === '/role') {
|
|
1774
1834
|
const authorized = await authorizeRoleMenu(this, {
|
|
1775
1835
|
kind: 'query', args, identity, subject, session, channel, channelId,
|
|
@@ -2091,8 +2151,7 @@ export async function execMenuQuery(cmd, channel, channelId, userId, args, expli
|
|
|
2091
2151
|
});
|
|
2092
2152
|
if ('error' in target)
|
|
2093
2153
|
return target;
|
|
2094
|
-
|
|
2095
|
-
const fallback = dispatchToMentionMode(session?.metadata?.dispatchMode) ?? null;
|
|
2154
|
+
const fallback = session?.metadata?.mentionMode ?? null;
|
|
2096
2155
|
const current = readMenuMentionMode(target, fallback, fallback === null ? null : 'session');
|
|
2097
2156
|
return {
|
|
2098
2157
|
data: {
|
|
@@ -2605,8 +2664,6 @@ export async function execMenuUpdate(cmd, value, channel, channelId, userId, ove
|
|
|
2605
2664
|
const newMode = modeMap[arg];
|
|
2606
2665
|
if (!newMode)
|
|
2607
2666
|
return { error: `无效模式: ${arg},可选: all / text / none`, code: 'INVALID_VALUE' };
|
|
2608
|
-
if (identity.role !== 'owner')
|
|
2609
|
-
return { error: '中间输出模式切换仅限 owner', code: 'NO_PERMISSION' };
|
|
2610
2667
|
const target = resolveMenuActivityTarget.call(this, {
|
|
2611
2668
|
args,
|
|
2612
2669
|
session,
|
|
@@ -2661,6 +2718,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
2661
2718
|
const subject = buildMenuAuthSubject(this, {
|
|
2662
2719
|
identity: authIdentity,
|
|
2663
2720
|
session: authSession,
|
|
2721
|
+
requestId,
|
|
2664
2722
|
explicitChatType,
|
|
2665
2723
|
channel,
|
|
2666
2724
|
channelId,
|
|
@@ -2878,6 +2936,10 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
2878
2936
|
if (triggerThread !== undefined && triggerThread !== 'per_run' && triggerThread !== 'by_run' && triggerThread !== 'by_trigger') {
|
|
2879
2937
|
return { error: `无效 triggerThread: ${triggerThread}`, code: 'INVALID_ARGS' };
|
|
2880
2938
|
}
|
|
2939
|
+
const targetChatType = args.targetChatType;
|
|
2940
|
+
if (targetChatType !== undefined && targetChatType !== 'private' && targetChatType !== 'group') {
|
|
2941
|
+
return { error: `无效 targetChatType: ${targetChatType}`, code: 'INVALID_ARGS' };
|
|
2942
|
+
}
|
|
2881
2943
|
const parsed = {
|
|
2882
2944
|
scheduleType: args.scheduleType,
|
|
2883
2945
|
scheduleValue: String(args.scheduleValue ?? ''),
|
|
@@ -2888,6 +2950,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
2888
2950
|
name: args.name,
|
|
2889
2951
|
targetChannel: args.targetChannel,
|
|
2890
2952
|
targetChannelId: args.targetChannelId,
|
|
2953
|
+
targetChatType,
|
|
2891
2954
|
targetThreadId: args.targetThreadId,
|
|
2892
2955
|
agentId: args.agentId,
|
|
2893
2956
|
model: args.model,
|
|
@@ -3264,17 +3327,57 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3264
3327
|
}
|
|
3265
3328
|
if (action === 'restart') {
|
|
3266
3329
|
const suppressRealRestart = shouldSuppressRealRestart();
|
|
3330
|
+
let restartReplyContext;
|
|
3331
|
+
try {
|
|
3332
|
+
restartReplyContext = session
|
|
3333
|
+
? replyContextFromSession(session, transportReplyContext)
|
|
3334
|
+
: transportReplyContext;
|
|
3335
|
+
}
|
|
3336
|
+
catch (error) {
|
|
3337
|
+
const code = error?.code;
|
|
3338
|
+
if (channel.split('#', 1)[0].toLowerCase() !== 'aun'
|
|
3339
|
+
|| (code !== 'AUN_OUTBOUND_ROUTE_REQUIRED' && code !== 'AUN_OUTBOUND_ROUTE_MISMATCH')) {
|
|
3340
|
+
throw error;
|
|
3341
|
+
}
|
|
3342
|
+
return {
|
|
3343
|
+
error: '当前 AUN 会话缺少有效的持久化出站路由,请从可信入站上下文重试',
|
|
3344
|
+
code,
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
const restartDelivery = restartReplyContext?.delivery
|
|
3348
|
+
?? (explicitChatType === 'group'
|
|
3349
|
+
? { chatType: 'group', groupId: channelId }
|
|
3350
|
+
: explicitChatType === 'private'
|
|
3351
|
+
? { chatType: 'private' }
|
|
3352
|
+
: undefined);
|
|
3353
|
+
if (channel.split('#', 1)[0].toLowerCase() === 'aun'
|
|
3354
|
+
&& !isDeliveryTargetForChannel(restartDelivery, channelId)) {
|
|
3355
|
+
return {
|
|
3356
|
+
error: '无法确定有效的重启通知出站路由,请从可信会话上下文重试',
|
|
3357
|
+
code: isDeliveryTarget(restartDelivery)
|
|
3358
|
+
? 'AUN_OUTBOUND_ROUTE_MISMATCH'
|
|
3359
|
+
: 'AUN_OUTBOUND_ROUTE_REQUIRED',
|
|
3360
|
+
};
|
|
3361
|
+
}
|
|
3267
3362
|
if (!suppressRealRestart) {
|
|
3268
|
-
const restartInfo = {
|
|
3363
|
+
const restartInfo = {
|
|
3364
|
+
channel,
|
|
3365
|
+
channelId,
|
|
3366
|
+
timestamp: Date.now(),
|
|
3367
|
+
...(restartDelivery ? { delivery: restartDelivery } : {}),
|
|
3368
|
+
};
|
|
3269
3369
|
const controlDir = daemonControlDir();
|
|
3270
3370
|
fs.mkdirSync(controlDir, { recursive: true });
|
|
3271
3371
|
fs.writeFileSync(path.join(controlDir, 'restart-pending.json'), JSON.stringify(restartInfo));
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3372
|
+
// Use the canonical CLI restart path so the restart itself performs
|
|
3373
|
+
// the version check and automatic upgrades before replacing the daemon.
|
|
3374
|
+
// Do not inherit managed-session credentials: otherwise cmdRestart can
|
|
3375
|
+
// delegate back to this daemon and recursively enqueue another restart.
|
|
3376
|
+
spawnDetachedNode([path.join(getPackageRoot(), 'dist', 'cli', 'index.js'), 'restart'], {
|
|
3377
|
+
EVOLCORE_HOME: resolvePaths().root,
|
|
3378
|
+
EVOLCORE_SESSION_ID: '',
|
|
3379
|
+
[AGENT_DELEGATION_TOKEN_ENV]: '',
|
|
3380
|
+
});
|
|
3278
3381
|
}
|
|
3279
3382
|
else {
|
|
3280
3383
|
logger.info('[System] Suppressed real menu restart in test runtime');
|
|
@@ -3310,7 +3413,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3310
3413
|
data: {
|
|
3311
3414
|
devMode,
|
|
3312
3415
|
evolcore: { local: localEvolcore, remote: evolcoreRemote, hasUpdate: cmp(localEvolcore, evolcoreRemote) },
|
|
3313
|
-
fastaun: { local: localFastaun, remote: fastaunRemote, hasUpdate: cmp(localFastaun, fastaunRemote) },
|
|
3416
|
+
fastaun: { local: localFastaun, remote: fastaunRemote, hasUpdate: cmp(localFastaun, fastaunRemote), managedBy: 'evolcore' },
|
|
3314
3417
|
// ecweb 本地版本由 ECWeb 进程自身注入(data.ecwebVersion),此处仅给 remote
|
|
3315
3418
|
ecweb: { remote: ecwebRemote },
|
|
3316
3419
|
},
|
|
@@ -3340,6 +3443,17 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3340
3443
|
? (session?.metadata?.groupId || channelId)
|
|
3341
3444
|
: userId;
|
|
3342
3445
|
const cliPeerKey = cliChannelType && cliPeerKeyId ? formatPeerKey(cliChannelType, cliPeerKeyId) : undefined;
|
|
3446
|
+
const subject = buildMenuAuthSubject(this, {
|
|
3447
|
+
identity,
|
|
3448
|
+
session,
|
|
3449
|
+
requestId,
|
|
3450
|
+
explicitChatType,
|
|
3451
|
+
channel,
|
|
3452
|
+
channelId,
|
|
3453
|
+
userId,
|
|
3454
|
+
fromControlChannel: fromControlChannel ?? false,
|
|
3455
|
+
subject: authSubject,
|
|
3456
|
+
});
|
|
3343
3457
|
if (Array.isArray(args?.argv)) {
|
|
3344
3458
|
argv = withDefaultRelationContext(argv, { self: cliSelfAid, peer: cliPeerKey });
|
|
3345
3459
|
}
|
|
@@ -3358,6 +3472,8 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3358
3472
|
await auditCommandAuthorization({
|
|
3359
3473
|
ts: Date.now(), source: 'menu.cli', operation: parsed.intent.operation,
|
|
3360
3474
|
scope: parsed.intent.scope, dangerous: true, actorId: userId,
|
|
3475
|
+
requestId, sessionId: subject.sessionId, agentAid: subject.selfAid,
|
|
3476
|
+
permissionMode: subject.permissionMode,
|
|
3361
3477
|
channel, channelId, role: identity.role, decision: 'deny', code: 'NOT_ALLOWED',
|
|
3362
3478
|
reason: 'Unrecognized CLI command', taskId: requestId, argvHash: hashArgv(intentArgv),
|
|
3363
3479
|
name: 'cli', action: 'exec', args: { argv: [...requestedArgv] },
|
|
@@ -3366,16 +3482,6 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3366
3482
|
}
|
|
3367
3483
|
parsedCommands.push(parsed);
|
|
3368
3484
|
}
|
|
3369
|
-
const subject = buildMenuAuthSubject(this, {
|
|
3370
|
-
identity,
|
|
3371
|
-
session,
|
|
3372
|
-
explicitChatType,
|
|
3373
|
-
channel,
|
|
3374
|
-
channelId,
|
|
3375
|
-
userId,
|
|
3376
|
-
fromControlChannel: fromControlChannel ?? false,
|
|
3377
|
-
subject: authSubject,
|
|
3378
|
-
});
|
|
3379
3485
|
const selfAid = subject.selfAid;
|
|
3380
3486
|
const peerKey = subject.peerKey;
|
|
3381
3487
|
const isDaemonOwner = subject.isDaemonOwner;
|
|
@@ -3400,6 +3506,10 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3400
3506
|
allowExplicitRelationTarget: true,
|
|
3401
3507
|
auditAllowed: false,
|
|
3402
3508
|
auditMetadata: {
|
|
3509
|
+
requestId,
|
|
3510
|
+
sessionId: subject.sessionId,
|
|
3511
|
+
agentAid: subject.selfAid,
|
|
3512
|
+
permissionMode: subject.permissionMode,
|
|
3403
3513
|
taskId: requestId,
|
|
3404
3514
|
argvHash: hashArgv(authArgv),
|
|
3405
3515
|
name: 'cli',
|
|
@@ -3420,6 +3530,8 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3420
3530
|
ts: Date.now(), source: 'menu.cli', operation: parsed.intent.operation,
|
|
3421
3531
|
scope: parsed.intent.scope, dangerous: parsed.intent.dangerous ?? false,
|
|
3422
3532
|
actorId: userId, selfAid, peerKey,
|
|
3533
|
+
requestId, sessionId: subject.sessionId, agentAid: selfAid,
|
|
3534
|
+
permissionMode: subject.permissionMode,
|
|
3423
3535
|
channel, channelId, role: identity.role, isDaemonOwner,
|
|
3424
3536
|
fromControlChannel: fromControlChannel ?? false, decision: 'allow',
|
|
3425
3537
|
matchedRule: decision.command?.matchedRule, taskId: requestId, argvHash: hashArgv(argv),
|
|
@@ -3463,7 +3575,7 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3463
3575
|
return { error: '通道不存在', code: 'EXEC_FAILED' };
|
|
3464
3576
|
if (!adapter.capabilities?.file)
|
|
3465
3577
|
return { error: '通道不支持文件发送', code: 'NOT_SUPPORTED' };
|
|
3466
|
-
const sessionReplyContext = session ? this.getReplyContext(session) : undefined;
|
|
3578
|
+
const sessionReplyContext = session ? replyContextFromSession(session, this.getReplyContext(session)) : undefined;
|
|
3467
3579
|
const replyCtx = transportReplyContext
|
|
3468
3580
|
? {
|
|
3469
3581
|
...(sessionReplyContext ?? {}),
|
|
@@ -3491,16 +3603,6 @@ export async function execMenuAction(cmd, action, args, channel, channelId, user
|
|
|
3491
3603
|
}
|
|
3492
3604
|
return { error: `不支持 action: ${cmdBase}`, code: 'NOT_SUPPORTED' };
|
|
3493
3605
|
}
|
|
3494
|
-
const SYSTEM_CONTROL_NAME_MAP = {
|
|
3495
|
-
pwd: '/pwd', session: '/session', baseagent: '/baseagent', model: '/model',
|
|
3496
|
-
topic: '/topic',
|
|
3497
|
-
effort: '/effort', chatmode: '/chatmode', mentionmode: '/mentionmode',
|
|
3498
|
-
permission: '/perm', activity: '/activity', system: '/system',
|
|
3499
|
-
observable: '/observable',
|
|
3500
|
-
agent: '/agent', trigger: '/trigger', file: '/file', gateway: '/gateway',
|
|
3501
|
-
config: '/config', capability: '/capability', role: '/role',
|
|
3502
|
-
group: '/group', connect: '/connect',
|
|
3503
|
-
};
|
|
3504
3606
|
function menuCommandToken(cmd) {
|
|
3505
3607
|
if (typeof cmd !== 'string')
|
|
3506
3608
|
return undefined;
|
|
@@ -3511,6 +3613,13 @@ function isProcessLevelMenu(name, cmd) {
|
|
|
3511
3613
|
return name === 'system' || name === 'agent' || name === 'gateway' || name === 'config'
|
|
3512
3614
|
|| cmdToken === '/system' || cmdToken === '/agent' || cmdToken === '/gateway' || cmdToken === '/config';
|
|
3513
3615
|
}
|
|
3616
|
+
function isProcessContextMenu(payload) {
|
|
3617
|
+
const isCatalog = payload?.type === 'menu.list' && payload?.args?.view === 'catalog';
|
|
3618
|
+
const isValueBatch = payload?.type === 'menu.query'
|
|
3619
|
+
&& payload?.name === 'menu'
|
|
3620
|
+
&& payload?.args?.view === 'values';
|
|
3621
|
+
return (isCatalog || isValueBatch) && payload?.args?.context?.kind === 'process';
|
|
3622
|
+
}
|
|
3514
3623
|
async function execMenuForSystemControl(payload, context) {
|
|
3515
3624
|
const id = payload?.id ?? '';
|
|
3516
3625
|
const name = payload?.name;
|
|
@@ -3531,13 +3640,15 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
3531
3640
|
: 'cli 不在控制 channel 范围';
|
|
3532
3641
|
return { type: 'menu.response', id, name, error: { code: 'NOT_SUPPORTED', message } };
|
|
3533
3642
|
}
|
|
3534
|
-
const isProcessLevel = isProcessLevelMenu(name, payload?.cmd);
|
|
3643
|
+
const isProcessLevel = isProcessLevelMenu(name, payload?.cmd) || isProcessContextMenu(payload);
|
|
3644
|
+
const requestedContextKind = payload?.args?.context?.kind;
|
|
3535
3645
|
const isRoleRequest = name === 'role' || compatCmd === '/role';
|
|
3536
3646
|
const isConnectRequest = name === 'connect' || compatCmd === '/connect';
|
|
3537
3647
|
const requiresAgentTarget = isRoleRequest || isConnectRequest || [
|
|
3538
3648
|
'observable', 'baseagent', 'model', 'effort', 'trigger', 'capability', 'group',
|
|
3539
3649
|
].includes(name)
|
|
3540
|
-
|| ['/observable', '/baseagent', '/model', '/effort', '/trigger', '/capability', '/group'].includes(compatCmd ?? '')
|
|
3650
|
+
|| ['/observable', '/baseagent', '/model', '/effort', '/trigger', '/capability', '/group'].includes(compatCmd ?? '')
|
|
3651
|
+
|| (!isProcessLevel && requestedContextKind !== undefined && requestedContextKind !== 'process');
|
|
3541
3652
|
const target = isProcessLevel
|
|
3542
3653
|
? { channel: SYSTEM_CONTROL_CHANNEL }
|
|
3543
3654
|
: resolveExternalMenuAgentChannel(this, payload, SYSTEM_CONTROL_CHANNEL, requiresAgentTarget);
|
|
@@ -3548,6 +3659,7 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
3548
3659
|
const trustedSubject = buildAuthSubject({
|
|
3549
3660
|
selfAid: targetAid,
|
|
3550
3661
|
actorId: context.actorAid,
|
|
3662
|
+
requestId: id !== undefined && id !== null && String(id) ? String(id) : undefined,
|
|
3551
3663
|
channel: targetChannel,
|
|
3552
3664
|
channelType: 'aun',
|
|
3553
3665
|
channelId: context.actorAid || SYSTEM_CONTROL_CHANNEL,
|
|
@@ -3558,21 +3670,71 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
3558
3670
|
fromControlChannel: true,
|
|
3559
3671
|
});
|
|
3560
3672
|
const trustedIdentity = trustedSubject.identity;
|
|
3561
|
-
const cmd = name ? (
|
|
3673
|
+
const cmd = name ? (menuCommandForName(name) ?? payload.cmd) : payload.cmd;
|
|
3562
3674
|
try {
|
|
3563
3675
|
switch (payload?.type) {
|
|
3564
3676
|
case 'menu.list':
|
|
3677
|
+
if (payload?.args?.view === 'catalog') {
|
|
3678
|
+
validateMenuCatalogArgs(payload.args);
|
|
3679
|
+
const data = await getMenuCatalog({
|
|
3680
|
+
subject: trustedSubject,
|
|
3681
|
+
channelType: 'aun',
|
|
3682
|
+
channelScope: 'control',
|
|
3683
|
+
channelId: targetChannel,
|
|
3684
|
+
request: payload.args.context,
|
|
3685
|
+
});
|
|
3686
|
+
return menuSuccess({ id, ...(name ? { name } : {}) }, data);
|
|
3687
|
+
}
|
|
3688
|
+
if (payload?.args?.view !== undefined)
|
|
3689
|
+
return ecwebErr(id, name, 'NOT_SUPPORTED', `Unsupported menu.list view: ${String(payload.args.view)}`);
|
|
3565
3690
|
return menuSuccess({ id }, this.getMenuItems(trustedIdentity.role, 'private', 'control', trustedSubject));
|
|
3566
3691
|
case 'menu.query': {
|
|
3692
|
+
if (name === 'menu' && payload?.args?.view === 'values') {
|
|
3693
|
+
validateMenuValueBatchArgs(payload.args);
|
|
3694
|
+
const data = await execMenuValueBatch({
|
|
3695
|
+
subject: trustedSubject,
|
|
3696
|
+
channelType: 'aun',
|
|
3697
|
+
channelScope: 'control',
|
|
3698
|
+
channelId: targetChannel,
|
|
3699
|
+
request: payload.args.context,
|
|
3700
|
+
items: payload.args.items,
|
|
3701
|
+
schemaVersion: payload.args.schemaVersion,
|
|
3702
|
+
consistency: payload.args.consistency,
|
|
3703
|
+
execQuery: async (entryCmd, resolvedChannelId, queryArgs, catalogContext) => this.execMenuQuery(entryCmd, targetChannel, resolvedChannelId, catalogContext.subject.actorId, queryArgs, catalogContext.subject.chatType, true, catalogContext.subject.identity, catalogContext.subject, context.source),
|
|
3704
|
+
});
|
|
3705
|
+
return menuSuccess({ id, ...(name ? { name } : {}) }, data);
|
|
3706
|
+
}
|
|
3707
|
+
if (name === 'menu')
|
|
3708
|
+
return ecwebErr(id, name, 'NOT_SUPPORTED', `Unsupported menu.query view: ${String(payload?.args?.view)}`);
|
|
3567
3709
|
if (!cmd)
|
|
3568
3710
|
return ecwebErr(id, name, 'MISSING_CMD', '缺少 name/cmd');
|
|
3569
|
-
const
|
|
3711
|
+
const hasExplicitContext = !!payload?.args && Object.prototype.hasOwnProperty.call(payload.args, 'context');
|
|
3712
|
+
const execution = await resolveExplicitMenuExecutionContext({
|
|
3713
|
+
subject: trustedSubject,
|
|
3714
|
+
channelType: 'aun',
|
|
3715
|
+
channelScope: 'control',
|
|
3716
|
+
channelId: targetChannel,
|
|
3717
|
+
args: payload.args,
|
|
3718
|
+
});
|
|
3719
|
+
const r = hasExplicitContext
|
|
3720
|
+
? await this.execMenuQuery(cmd, targetChannel, execution.channelId, execution.subject.actorId, execution.args, execution.subject.chatType, true, execution.subject.identity, execution.subject, context.source)
|
|
3721
|
+
: await this.execMenuQuery(cmd, targetChannel, targetChannel, context.actorAid, payload.args, undefined, true, trustedIdentity, trustedSubject, context.source);
|
|
3570
3722
|
return ecwebResp(id, name, r);
|
|
3571
3723
|
}
|
|
3572
3724
|
case 'menu.options': {
|
|
3573
3725
|
if (!cmd)
|
|
3574
3726
|
return ecwebErr(id, name, 'MISSING_CMD', '缺少 name/cmd');
|
|
3575
|
-
const
|
|
3727
|
+
const hasExplicitContext = !!payload?.args && Object.prototype.hasOwnProperty.call(payload.args, 'context');
|
|
3728
|
+
const execution = await resolveExplicitMenuExecutionContext({
|
|
3729
|
+
subject: trustedSubject,
|
|
3730
|
+
channelType: 'aun',
|
|
3731
|
+
channelScope: 'control',
|
|
3732
|
+
channelId: targetChannel,
|
|
3733
|
+
args: payload.args,
|
|
3734
|
+
});
|
|
3735
|
+
const data = hasExplicitContext
|
|
3736
|
+
? await this.getSubMenuItems(cmd, targetChannel, execution.channelId, execution.subject.actorId, execution.args, execution.subject.identity, execution.subject.chatType, true, execution.subject, context.source) ?? []
|
|
3737
|
+
: await this.getSubMenuItems(cmd, targetChannel, targetChannel, context.actorAid, payload.args, trustedIdentity, undefined, true, trustedSubject, context.source) ?? [];
|
|
3576
3738
|
return menuSuccess({ id, ...(name ? { name } : {}) }, data);
|
|
3577
3739
|
}
|
|
3578
3740
|
case 'menu.update': {
|
|
@@ -3580,7 +3742,14 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
3580
3742
|
return ecwebErr(id, name, 'MISSING_CMD', '缺少 name/cmd');
|
|
3581
3743
|
if (!payload.value)
|
|
3582
3744
|
return ecwebErr(id, name, 'MISSING_VALUE', '缺少 value');
|
|
3583
|
-
const
|
|
3745
|
+
const execution = await resolveExplicitMenuExecutionContext({
|
|
3746
|
+
subject: trustedSubject,
|
|
3747
|
+
channelType: 'aun',
|
|
3748
|
+
channelScope: 'control',
|
|
3749
|
+
channelId: targetChannel,
|
|
3750
|
+
args: payload.args,
|
|
3751
|
+
});
|
|
3752
|
+
const r = await this.execMenuUpdate(cmd, payload.value, targetChannel, execution.channelId, execution.subject.actorId, execution.subject.identity, true, execution.args, execution.subject, context.source);
|
|
3584
3753
|
return ecwebResp(id, name, r);
|
|
3585
3754
|
}
|
|
3586
3755
|
case 'menu.action': {
|
|
@@ -3588,7 +3757,17 @@ async function execMenuForSystemControl(payload, context) {
|
|
|
3588
3757
|
return ecwebErr(id, name, 'MISSING_CMD', '缺少 name/cmd');
|
|
3589
3758
|
if (!payload.action)
|
|
3590
3759
|
return ecwebErr(id, name, 'MISSING_VALUE', '缺少 action');
|
|
3591
|
-
const
|
|
3760
|
+
const hasExplicitContext = !!payload?.args && Object.prototype.hasOwnProperty.call(payload.args, 'context');
|
|
3761
|
+
const execution = await resolveExplicitMenuExecutionContext({
|
|
3762
|
+
subject: trustedSubject,
|
|
3763
|
+
channelType: 'aun',
|
|
3764
|
+
channelScope: 'control',
|
|
3765
|
+
channelId: targetChannel,
|
|
3766
|
+
args: payload.args,
|
|
3767
|
+
});
|
|
3768
|
+
const r = hasExplicitContext
|
|
3769
|
+
? await this.execMenuAction(cmd, payload.action, execution.args, targetChannel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.chatType, id, true, execution.subject, context.source)
|
|
3770
|
+
: await this.execMenuAction(cmd, payload.action, payload.args, targetChannel, targetChannel, context.actorAid, trustedIdentity, undefined, id, true, trustedSubject, context.source);
|
|
3592
3771
|
return ecwebResp(id, name, r);
|
|
3593
3772
|
}
|
|
3594
3773
|
default:
|
|
@@ -3606,7 +3785,7 @@ export async function execMenuForEcweb(payload, trusted) {
|
|
|
3606
3785
|
const validationError = validateMenuRequest(payload ?? {});
|
|
3607
3786
|
if (validationError)
|
|
3608
3787
|
return menuFailure({ id, ...(name ? { name } : {}) }, validationError);
|
|
3609
|
-
const isProcessLevel = isProcessLevelMenu(name, payload?.cmd);
|
|
3788
|
+
const isProcessLevel = isProcessLevelMenu(name, payload?.cmd) || isProcessContextMenu(payload);
|
|
3610
3789
|
const owners = loadDaemonConfig().owners ?? [];
|
|
3611
3790
|
if (isProcessLevel && owners.length === 0) {
|
|
3612
3791
|
return { type: 'menu.response', id, name, error: { code: 'FORBIDDEN', message: '请在 daemon.json 配置 owners 后使用进程级操作' } };
|