evolcore 0.0.20 → 0.0.21
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 +22 -0
- package/README.md +58 -9
- package/dist/agents/baseagent.js +10 -6
- package/dist/agents/claude-runner.js +379 -108
- package/dist/agents/codex-app-server-client.js +10 -2
- package/dist/agents/codex-runner.js +402 -135
- package/dist/agents/ecagent-runner.js +171 -61
- package/dist/agents/gemini-runner.js +130 -30
- package/dist/agents/request-identity.js +25 -0
- package/dist/agents/runner-types.js +19 -0
- package/dist/aun/aid/agentmd.js +59 -2
- package/dist/aun/aid/identity.js +4 -1
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/msg/group.js +72 -6
- package/dist/aun/msg/history.js +213 -36
- package/dist/aun/msg/managed-operation.js +58 -9
- package/dist/aun/msg/p2p.js +5 -0
- package/dist/aun/outbox.js +182 -80
- package/dist/aun/service-proxy.js +43 -25
- package/dist/channels/aun.js +409 -88
- package/dist/channels/daemon.js +6 -1
- package/dist/cli/agent-command.js +4 -3
- package/dist/cli/agent.js +66 -56
- package/dist/cli/aun-commands.js +177 -42
- package/dist/cli/command-log.js +10 -11
- package/dist/cli/contact.js +1 -0
- package/dist/cli/daemon-commands.js +69 -115
- package/dist/cli/init.js +27 -15
- package/dist/cli/task-context.js +46 -0
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-logs.js +10 -3
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-field-policy.js +16 -5
- package/dist/config/config-manager.js +135 -17
- package/dist/config/contact-operation-service.js +32 -1
- package/dist/config/contact-request-service.js +44 -0
- package/dist/config/daemon-services.js +186 -0
- package/dist/config/gateway-config.js +20 -9
- package/dist/config/role-service.js +54 -3
- package/dist/config/schema-migration.js +550 -0
- package/dist/config-store.js +151 -9
- package/dist/core/agent-application-service.js +279 -0
- package/dist/core/audit/log-integrity.js +102 -0
- package/dist/core/auth/agent-delegation.js +31 -1
- package/dist/core/auth/auth-gateway.js +33 -4
- package/dist/core/auth/authorization-audit.js +150 -2
- package/dist/core/auth/operation-authorizer.js +41 -1
- package/dist/core/auth/operation-catalog.js +9 -1
- package/dist/core/bootstrap-service.js +6 -2
- package/dist/core/causation/aun-association.js +7 -4
- package/dist/core/command/agent-control.js +56 -16
- package/dist/core/command/command-handler.js +290 -44
- package/dist/core/command/connect-menu.js +3 -4
- package/dist/core/command/group-menu.js +5 -7
- package/dist/core/command/menu-handler.js +279 -80
- package/dist/core/command/role-menu.js +21 -11
- package/dist/core/command/slash-gate.js +85 -18
- package/dist/core/command/slash-handler.js +350 -32
- package/dist/core/event-catalog.js +5 -0
- package/dist/core/evolagent.js +4 -0
- package/dist/core/handoff/dispatcher.js +4 -0
- package/dist/core/handoff/runtime.js +10 -0
- package/dist/core/handoff/store.js +32 -9
- package/dist/core/inference/text-inference.js +7 -15
- package/dist/core/message/im-renderer.js +83 -84
- package/dist/core/message/{inbound-admission.js → message-admission.js} +51 -1
- package/dist/core/message/message-bridge.js +124 -10
- package/dist/core/message/message-log.js +14 -7
- package/dist/core/message/message-queue.js +206 -16
- package/dist/core/message/message-utils.js +12 -5
- package/dist/core/message/response-engine.js +486 -68
- package/dist/core/message/send-receipt.js +1 -0
- package/dist/core/message/stream-debouncer.js +9 -2
- package/dist/core/model/model-catalog.js +23 -15
- package/dist/core/model/model-diagnostics.js +28 -10
- package/dist/core/permission/approval-gateway.js +180 -6
- package/dist/core/permission/ec-command-parser.js +410 -54
- package/dist/core/permission/mode.js +18 -3
- package/dist/core/{protected-paths.js → permission/protected-paths.js} +17 -5
- package/dist/core/permission/readonly-shell-query.js +263 -9
- package/dist/core/permission/sandbox-runtime.js +159 -1
- package/dist/core/permission/tool-policy.js +575 -21
- package/dist/core/session/session-fs-store.js +154 -5
- package/dist/core/session/session-manager.js +299 -30
- package/dist/core/session/session-renew.js +19 -12
- package/dist/core/session/session-turn-coordinator.js +11 -4
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/index.js +253 -46
- package/dist/ipc.js +374 -24
- package/dist/paths.js +64 -7
- package/dist/response-system/context-builder.js +1 -7
- package/dist/trigger/anomaly-store.js +1 -0
- package/dist/trigger/feedback.js +56 -5
- package/dist/trigger/history.js +79 -4
- package/dist/trigger/legacy-session-history.js +2 -2
- package/dist/trigger/parser.js +3 -2
- package/dist/trigger/validation.js +6 -1
- package/dist/utils/atomic-write.js +27 -0
- package/dist/utils/ecweb-utils.js +16 -2
- package/dist/utils/error-utils.js +4 -1
- package/dist/utils/logger.js +21 -2
- package/dist/utils/process-tree-stats.js +24 -4
- package/dist/utils/process-tree-worker.js +31 -0
- package/dist/utils/project-path.js +1 -2
- package/kits/docs/INDEX.md +1 -1
- package/kits/docs/evolcore/INDEX.md +1 -1
- package/kits/docs/evolcore/contact.md +7 -1
- package/kits/docs/evolcore/msg.md +16 -0
- package/kits/schemas/_meta.json +4 -2
- package/kits/schemas/agent-config.schema.11.json +13 -0
- package/kits/schemas/daemon.schema.5.json +0 -1
- package/kits/schemas/daemon.schema.6.json +131 -0
- package/kits/schemas/defaults.schema.5.json +15 -3
- package/kits/schemas/migrations/README.md +3 -1
- package/kits/schemas/relation-config.schema.8.json +13 -0
- package/kits/schemas/role-config.schema.1.json +1 -2
- package/kits/schemas/single-session.schema.3.json +32 -0
- package/kits/templates/roles/admin.json +1 -0
- package/kits/templates/roles/member.json +1 -0
- package/kits/templates/roles/visitor.json +1 -0
- package/package.json +6 -3
- package/skills/eclink/SKILL.md +2 -0
- package/dist/config/aun-gateway-config.js +0 -2
package/dist/cli/aun-commands.js
CHANGED
|
@@ -5,6 +5,7 @@ import { isExplicitGroupId } from '../aun/group-identity.js';
|
|
|
5
5
|
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
6
6
|
import { ipcQuery } from '../ipc.js';
|
|
7
7
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
8
|
+
import { readBestTaskRuntimeContext } from './task-context.js';
|
|
8
9
|
// ==================== AID ====================
|
|
9
10
|
function resolveAunPath(args) {
|
|
10
11
|
const idx = args.indexOf('--aun-path');
|
|
@@ -98,6 +99,14 @@ async function runManagedAid(args, formatJson) {
|
|
|
98
99
|
if (!delegationToken) {
|
|
99
100
|
failManagedAid(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
|
|
100
101
|
}
|
|
102
|
+
const { resolveManagedAidOperation } = await import('../aun/aid/managed-operation.js');
|
|
103
|
+
const parsed = resolveManagedAidOperation(['aid', ...args]);
|
|
104
|
+
if (!parsed.ok)
|
|
105
|
+
failManagedAid(formatJson, parsed.code, parsed.reason);
|
|
106
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
107
|
+
if (runtime?.selfAid && parsed.command.aid !== runtime.selfAid.replace(/^@/, '')) {
|
|
108
|
+
failManagedAid(formatJson, 'SCOPE_MISMATCH', `托管任务只能操作当前 self AID:${runtime.selfAid}`);
|
|
109
|
+
}
|
|
101
110
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
102
111
|
type: 'aid.op',
|
|
103
112
|
argv: ['aid', ...args],
|
|
@@ -153,6 +162,12 @@ async function runManagedGroup(args, formatJson) {
|
|
|
153
162
|
if (args.includes('--aun-path') || args.includes('--app')) {
|
|
154
163
|
failManagedGroup(formatJson, 'NOT_ALLOWED', '--aun-path and --app are not allowed in a managed task');
|
|
155
164
|
}
|
|
165
|
+
const { resolveManagedGroupOperation } = await import('../aun/msg/managed-operation.js');
|
|
166
|
+
const parsed = resolveManagedGroupOperation(['group', ...args]);
|
|
167
|
+
if (!parsed.ok)
|
|
168
|
+
failManagedGroup(formatJson, parsed.code, parsed.reason);
|
|
169
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
170
|
+
validateManagedGroupScope(parsed.command.from, parsed.command.groupId, runtime, formatJson);
|
|
156
171
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
157
172
|
type: 'group.op',
|
|
158
173
|
argv: ['group', ...args],
|
|
@@ -174,6 +189,33 @@ async function runManagedMsg(args, formatJson) {
|
|
|
174
189
|
if (!delegationToken) {
|
|
175
190
|
failManagedGroup(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
|
|
176
191
|
}
|
|
192
|
+
const { resolveManagedMsgOperation } = await import('../aun/msg/managed-operation.js');
|
|
193
|
+
const parsed = resolveManagedMsgOperation(['msg', ...args]);
|
|
194
|
+
if (!parsed.ok)
|
|
195
|
+
failManagedGroup(formatJson, parsed.code, parsed.reason);
|
|
196
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
197
|
+
if (runtime?.selfAid
|
|
198
|
+
&& parsed.command.from !== runtime.selfAid.replace(/^@/, '')) {
|
|
199
|
+
failManagedGroup(formatJson, 'SCOPE_MISMATCH', `托管任务只能使用当前 self AID:${runtime.selfAid}`);
|
|
200
|
+
}
|
|
201
|
+
const isSelectorHistory = parsed.command.kind === 'history'
|
|
202
|
+
&& !!parsed.command.channelKey
|
|
203
|
+
&& !!parsed.command.peerId;
|
|
204
|
+
if (isSelectorHistory) {
|
|
205
|
+
// Trigger tasks retain their originating channel in runtime.channel. The
|
|
206
|
+
// daemon-created session route is the stable, non-spoofable discriminator.
|
|
207
|
+
if (runtime && !runtime.channelId?.startsWith('trigger:')) {
|
|
208
|
+
failManagedGroup(formatJson, 'SCOPE_MISMATCH', '跨渠道 history selector 仅允许可信 Trigger 会话使用');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
if (runtime && (runtime.channel !== 'aun' || runtime.chatType !== 'private')) {
|
|
213
|
+
failManagedGroup(formatJson, 'SCOPE_MISMATCH', 'ec msg history/online 只能读取当前 AUN 私聊关系');
|
|
214
|
+
}
|
|
215
|
+
if (runtime?.channelId && parsed.command.target !== runtime.channelId.replace(/^@/, '')) {
|
|
216
|
+
failManagedGroup(formatJson, 'SCOPE_MISMATCH', `只能读取当前 AUN 私聊对端:${runtime.channelId}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
177
219
|
const response = await ipcQuery(resolvePaths().socket, {
|
|
178
220
|
type: 'msg.op',
|
|
179
221
|
argv: ['msg', ...args],
|
|
@@ -187,6 +229,21 @@ async function runManagedMsg(args, formatJson) {
|
|
|
187
229
|
}
|
|
188
230
|
return response.result;
|
|
189
231
|
}
|
|
232
|
+
function validateManagedGroupScope(from, groupId, runtime, formatJson) {
|
|
233
|
+
if (!runtime)
|
|
234
|
+
return;
|
|
235
|
+
if (runtime.selfAid && from !== runtime.selfAid.replace(/^@/, '')) {
|
|
236
|
+
failManagedGroup(formatJson, 'SCOPE_MISMATCH', `托管任务只能使用当前 self AID:${runtime.selfAid}`);
|
|
237
|
+
}
|
|
238
|
+
if (!groupId || (runtime.peerRole !== 'member' && runtime.peerRole !== 'visitor'))
|
|
239
|
+
return;
|
|
240
|
+
if (runtime.channel !== 'aun' || runtime.chatType !== 'group') {
|
|
241
|
+
failManagedGroup(formatJson, 'ARGUMENT_MISMATCH', `当前角色 ${runtime.peerRole} 只能在 AUN 群聊任务中操作当前群`);
|
|
242
|
+
}
|
|
243
|
+
if (!runtime.channelId || groupId !== runtime.channelId) {
|
|
244
|
+
failManagedGroup(formatJson, 'ARGUMENT_MISMATCH', `当前角色 ${runtime.peerRole} 只能操作当前群 ${runtime.channelId ?? '<unknown>'},不能操作 ${groupId}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
190
247
|
function renderManagedMsgResult(sub, result, formatJson) {
|
|
191
248
|
if (formatJson) {
|
|
192
249
|
console.log(JSON.stringify(result));
|
|
@@ -992,7 +1049,7 @@ Commands:
|
|
|
992
1049
|
ack <from> <seq> [--app <name>] 确认已读
|
|
993
1050
|
recall <from> <message-id> [<message-id>...] 撤回消息
|
|
994
1051
|
online <from> <target-aid> [<target-aid>...] 查询在线状态
|
|
995
|
-
history <from> <target-aid
|
|
1052
|
+
history <from> [<target-aid>|selector] [筛选选项] 查询本地消息历史
|
|
996
1053
|
|
|
997
1054
|
Options:
|
|
998
1055
|
--text-from-file <path> 从文件读取文本(UTF-8),用于超长消息或避免 Shell 转义
|
|
@@ -1008,6 +1065,8 @@ Options:
|
|
|
1008
1065
|
--direction <value> 历史方向:in|out|all
|
|
1009
1066
|
--channel <type> 历史渠道:aun|feishu|wechat|dingtalk|qqbot|wecom
|
|
1010
1067
|
--channel-name <name> 历史渠道实例名(非 AUN 渠道必须匹配 Agent 配置)
|
|
1068
|
+
--channel-key <key> 非 AUN 已落盘渠道的完整实例键(与 --peer-id 成对)
|
|
1069
|
+
--peer-id <id> 非 AUN 渠道的原生对端 ID(与 --channel-key 成对)
|
|
1011
1070
|
--return <none|required> 跨会话发送必填:none=仅补充目标上下文,required=回答回流来源
|
|
1012
1071
|
--content-type <mime> 显式覆盖 MIME(仅 --file 模式)
|
|
1013
1072
|
--as <type> 附件类型:image|video|voice|file(仅 --file 模式)
|
|
@@ -1029,13 +1088,16 @@ Options:
|
|
|
1029
1088
|
ec msg ack alice.agentid.pub 42 --app my-bot
|
|
1030
1089
|
ec msg recall alice.agentid.pub msg-uuid-1 msg-uuid-2
|
|
1031
1090
|
ec msg online alice.agentid.pub bob.agentid.pub carol.agentid.pub
|
|
1032
|
-
ec msg history alice.agentid.pub bob.agentid.pub --session latest --limit 50
|
|
1091
|
+
ec msg history alice.agentid.pub bob.agentid.pub --session latest --limit 50
|
|
1092
|
+
ec msg history alice.agentid.pub --channel-key feishu#alice.agentid.pub#main --peer-id ou_xxx --session all --format json`);
|
|
1033
1093
|
return;
|
|
1034
1094
|
}
|
|
1035
1095
|
if (sub === 'history' && wantsHelp(args)) {
|
|
1036
|
-
console.log(`用法: ec msg history <self-aid> <target-aid> [options]
|
|
1096
|
+
console.log(`用法: ec msg history <self-aid> [<target-aid> | --channel-key <key> --peer-id <id>] [options]
|
|
1097
|
+
|
|
1098
|
+
查询指定会话对的本地历史,不调用 message.pull,也不影响收件箱游标。非 AUN selector 按已落盘的 session metadata、完整 channelKey 与原生 peer ID 精确读取,不能传入文件路径。
|
|
1037
1099
|
|
|
1038
|
-
|
|
1100
|
+
托管会话限制:普通会话只能使用当前 self AID 和当前 AUN 私聊对端;可信 daemon Trigger 可用精确的 --channel-key/--peer-id selector 读取已落盘的非 AUN 私聊历史。托管任务不支持 --channel、--channel-name、--aun-path 或 --app。
|
|
1039
1101
|
|
|
1040
1102
|
Options:
|
|
1041
1103
|
--session <latest|all|id> 默认 latest;all 查询全部;也可指定会话 ID
|
|
@@ -1043,16 +1105,16 @@ Options:
|
|
|
1043
1105
|
--before <time> 开区间;epoch 毫秒或 ISO 时间
|
|
1044
1106
|
--after <time> 开区间;epoch 毫秒或 ISO 时间
|
|
1045
1107
|
--direction <value> in|out|all(默认 all)
|
|
1046
|
-
--channel <
|
|
1047
|
-
--
|
|
1108
|
+
--channel-key <key> 非 AUN 已落盘渠道完整键;必须与 --peer-id 同时给出
|
|
1109
|
+
--peer-id <id> 原生私聊对端 ID;必须与 --channel-key 同时给出
|
|
1048
1110
|
--format <text|json> 输出格式(默认 text)
|
|
1049
1111
|
|
|
1050
1112
|
示例:
|
|
1051
1113
|
ec msg history alice.agentid.pub bob.agentid.pub
|
|
1052
1114
|
ec msg history alice.agentid.pub bob.agentid.pub --session latest
|
|
1053
1115
|
ec msg history alice.agentid.pub bob.agentid.pub --session all
|
|
1054
|
-
ec msg history alice.agentid.pub
|
|
1055
|
-
ec msg history alice.agentid.pub
|
|
1116
|
+
ec msg history alice.agentid.pub bob.agentid.pub --session meta_20260713_1783920000000 --format json
|
|
1117
|
+
ec msg history alice.agentid.pub --channel-key feishu#alice.agentid.pub#main --peer-id ou_xxx --session all --format json`);
|
|
1056
1118
|
return;
|
|
1057
1119
|
}
|
|
1058
1120
|
const from = args[1];
|
|
@@ -1073,14 +1135,12 @@ Options:
|
|
|
1073
1135
|
const { msgSend, msgPull, msgAck, msgRecall, msgOnline, msgHistory } = await import('../aun/msg/index.js');
|
|
1074
1136
|
const commonOpts = { aunPath, slotId: appSlot };
|
|
1075
1137
|
if (sub === 'history') {
|
|
1076
|
-
const target = args[2];
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
const historyValueFlags = new Set(['--session', '--limit', '--before', '--after', '--direction', '--channel', '--channel-name', '--format']);
|
|
1138
|
+
const target = args[2] && !args[2].startsWith('--') ? args[2] : undefined;
|
|
1139
|
+
const historyValueFlags = new Set([
|
|
1140
|
+
'--session', '--limit', '--before', '--after', '--direction', '--channel', '--channel-name', '--format', '--channel-key', '--peer-id',
|
|
1141
|
+
]);
|
|
1082
1142
|
const seenHistoryFlags = new Set();
|
|
1083
|
-
for (let index = 3; index < args.length; index++) {
|
|
1143
|
+
for (let index = target ? 3 : 2; index < args.length; index++) {
|
|
1084
1144
|
const flag = args[index];
|
|
1085
1145
|
if (!historyValueFlags.has(flag)) {
|
|
1086
1146
|
console.error(`❌ 未知 history 参数: ${flag}`);
|
|
@@ -1117,25 +1177,47 @@ Options:
|
|
|
1117
1177
|
console.error(`❌ --after 必须是 epoch 毫秒或有效时间: ${afterRaw}`);
|
|
1118
1178
|
process.exit(1);
|
|
1119
1179
|
}
|
|
1120
|
-
const
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1180
|
+
const channelKey = getArgValue(args, '--channel-key');
|
|
1181
|
+
const peerId = getArgValue(args, '--peer-id');
|
|
1182
|
+
const usesSelector = channelKey !== undefined || peerId !== undefined;
|
|
1183
|
+
if (usesSelector && (channelKey === undefined || peerId === undefined)) {
|
|
1184
|
+
console.error('❌ --channel-key 与 --peer-id 必须同时提供');
|
|
1124
1185
|
process.exit(1);
|
|
1125
1186
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1187
|
+
if (usesSelector && target) {
|
|
1188
|
+
console.error('❌ --channel-key/--peer-id 不能与 positional target 同时使用');
|
|
1189
|
+
process.exit(1);
|
|
1129
1190
|
}
|
|
1130
|
-
|
|
1131
|
-
console.error(
|
|
1191
|
+
if (usesSelector && (getArgValue(args, '--channel') !== undefined || getArgValue(args, '--channel-name') !== undefined)) {
|
|
1192
|
+
console.error('❌ --channel-key/--peer-id 不能与 --channel 或 --channel-name 同时使用');
|
|
1132
1193
|
process.exit(1);
|
|
1133
1194
|
}
|
|
1195
|
+
if (!usesSelector && !target) {
|
|
1196
|
+
console.error('用法: ec msg history <self-aid> <target-aid> [options]');
|
|
1197
|
+
process.exit(1);
|
|
1198
|
+
}
|
|
1199
|
+
let channel;
|
|
1200
|
+
let channelName;
|
|
1201
|
+
if (!usesSelector) {
|
|
1202
|
+
channel = getArgValue(args, '--channel') ?? 'aun';
|
|
1203
|
+
const channelTypes = new Set(['aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom']);
|
|
1204
|
+
if (!channelTypes.has(channel)) {
|
|
1205
|
+
console.error(`❌ 不支持的 channel: ${channel}`);
|
|
1206
|
+
process.exit(1);
|
|
1207
|
+
}
|
|
1208
|
+
try {
|
|
1209
|
+
channelName = resolveHistoryChannelName(from, channel, getArgValue(args, '--channel-name'));
|
|
1210
|
+
}
|
|
1211
|
+
catch (error) {
|
|
1212
|
+
console.error(`❌ ${error instanceof Error ? error.message : String(error)}`);
|
|
1213
|
+
process.exit(1);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1134
1216
|
const result = msgHistory({
|
|
1135
1217
|
from,
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1218
|
+
...(usesSelector
|
|
1219
|
+
? { channelKey: channelKey, peerId: peerId }
|
|
1220
|
+
: { target: target, channel: channel, channelName }),
|
|
1139
1221
|
session: getArgValue(args, '--session'),
|
|
1140
1222
|
limit,
|
|
1141
1223
|
before,
|
|
@@ -1555,23 +1637,25 @@ Options:
|
|
|
1555
1637
|
// 收集 --mention(可多次;每次的值支持逗号分隔多个 aid)
|
|
1556
1638
|
const collectMentions = () => {
|
|
1557
1639
|
const mentions = [];
|
|
1640
|
+
const optionsEnd = args.indexOf('--');
|
|
1641
|
+
const optionArgs = optionsEnd >= 0 ? args.slice(0, optionsEnd) : args;
|
|
1558
1642
|
for (let i = 0; i < args.length; i++) {
|
|
1643
|
+
if (args[i] === '--')
|
|
1644
|
+
break;
|
|
1559
1645
|
if (args[i] !== '--mention')
|
|
1560
1646
|
continue;
|
|
1561
1647
|
const val = args[i + 1];
|
|
1562
1648
|
if (val === undefined || val.startsWith('--')) {
|
|
1563
|
-
|
|
1564
|
-
process.exit(1);
|
|
1649
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '--mention 后面缺少 <aid>');
|
|
1565
1650
|
}
|
|
1566
1651
|
for (const aid of val.split(',').map(s => s.trim()).filter(Boolean)) {
|
|
1567
1652
|
if (!isValidAid(aid)) {
|
|
1568
|
-
|
|
1569
|
-
process.exit(1);
|
|
1653
|
+
failManagedGroup(formatJson, 'INVALID_AID', `--mention 的 aid 无效: ${aid}`);
|
|
1570
1654
|
}
|
|
1571
1655
|
mentions.push({ aid });
|
|
1572
1656
|
}
|
|
1573
1657
|
}
|
|
1574
|
-
if (
|
|
1658
|
+
if (optionArgs.includes('--mention-all')) {
|
|
1575
1659
|
mentions.push({ scope: 'all' });
|
|
1576
1660
|
}
|
|
1577
1661
|
return mentions;
|
|
@@ -1638,17 +1722,61 @@ Options:
|
|
|
1638
1722
|
// ---- 消息 ----
|
|
1639
1723
|
if (sub === 'send') {
|
|
1640
1724
|
const groupId = requireGroupId();
|
|
1641
|
-
|
|
1642
|
-
|
|
1725
|
+
// Group sends use the dedicated AUN message daemon route rather than the
|
|
1726
|
+
// managed group-operation IPC parser. Apply the same task scope checks
|
|
1727
|
+
// before building or uploading the payload, so a bad target fails locally
|
|
1728
|
+
// instead of reaching the transport layer first.
|
|
1729
|
+
if (process.env.EVOLCORE_SESSION_ID) {
|
|
1730
|
+
if (args.includes('--aun-path') || args.includes('--app')) {
|
|
1731
|
+
failManagedGroup(formatJson, 'NOT_ALLOWED', '--aun-path and --app are not allowed in a managed task');
|
|
1732
|
+
}
|
|
1733
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
1734
|
+
validateManagedGroupScope(from, groupId, runtime, formatJson);
|
|
1735
|
+
}
|
|
1736
|
+
const optionsEnd = args.indexOf('--', 3);
|
|
1737
|
+
const optionArgs = optionsEnd >= 0 ? args.slice(0, optionsEnd) : args;
|
|
1738
|
+
const getSendArgValue = (flag) => getArgValue(optionArgs, flag);
|
|
1739
|
+
const fileVal = getSendArgValue('--file');
|
|
1740
|
+
const payloadVal = getSendArgValue('--payload');
|
|
1741
|
+
const bodyPositionals = collectPositional(args, 3);
|
|
1742
|
+
const bodyFlags = ['--file', '--payload', '--as', '--content-type', '--text', '--transcript', '--thread', '--return'];
|
|
1743
|
+
for (let index = 3; index < args.length; index++) {
|
|
1744
|
+
const flag = args[index];
|
|
1745
|
+
if (flag === '--')
|
|
1746
|
+
break;
|
|
1747
|
+
if (bodyFlags.includes(flag)) {
|
|
1748
|
+
if (index + 1 >= args.length || args[index + 1].startsWith('--')) {
|
|
1749
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', `${flag} 后面缺少值`);
|
|
1750
|
+
}
|
|
1751
|
+
index++;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
if (optionArgs.includes('--encrypt') && optionArgs.includes('--no-encrypt')) {
|
|
1755
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '--encrypt 与 --no-encrypt 不能同时使用');
|
|
1756
|
+
}
|
|
1757
|
+
if (fileVal && payloadVal) {
|
|
1758
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '--file and --payload are mutually exclusive');
|
|
1759
|
+
}
|
|
1760
|
+
if ((fileVal || payloadVal) && bodyPositionals.length > 0) {
|
|
1761
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '文本正文不能与 --file 或 --payload 同时使用');
|
|
1762
|
+
}
|
|
1643
1763
|
let body;
|
|
1644
1764
|
if (fileVal) {
|
|
1765
|
+
const attachmentType = getSendArgValue('--as');
|
|
1766
|
+
if (attachmentType && !['image', 'video', 'voice', 'file'].includes(attachmentType)) {
|
|
1767
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', `--as 仅支持 image|video|voice|file: ${attachmentType}`);
|
|
1768
|
+
}
|
|
1769
|
+
const transcript = getSendArgValue('--transcript');
|
|
1770
|
+
if (transcript !== undefined && attachmentType !== 'voice') {
|
|
1771
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '--transcript 仅能与 --as voice 一起使用');
|
|
1772
|
+
}
|
|
1645
1773
|
body = {
|
|
1646
1774
|
mode: 'file',
|
|
1647
1775
|
filePath: fileVal,
|
|
1648
|
-
as:
|
|
1649
|
-
contentType:
|
|
1650
|
-
text:
|
|
1651
|
-
transcript
|
|
1776
|
+
as: attachmentType,
|
|
1777
|
+
contentType: getSendArgValue('--content-type'),
|
|
1778
|
+
text: getSendArgValue('--text'),
|
|
1779
|
+
transcript,
|
|
1652
1780
|
};
|
|
1653
1781
|
}
|
|
1654
1782
|
else if (payloadVal) {
|
|
@@ -1660,9 +1788,17 @@ Options:
|
|
|
1660
1788
|
console.error(`❌ --payload 解析失败: ${e.message}`);
|
|
1661
1789
|
process.exit(1);
|
|
1662
1790
|
}
|
|
1791
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
1792
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', '--payload 必须是 JSON 对象');
|
|
1793
|
+
}
|
|
1663
1794
|
body = { mode: 'payload', payload: parsed };
|
|
1664
1795
|
}
|
|
1665
1796
|
else {
|
|
1797
|
+
const fileOnlyFlags = ['--as', '--content-type', '--text', '--transcript']
|
|
1798
|
+
.filter(flag => optionArgs.includes(flag));
|
|
1799
|
+
if (fileOnlyFlags.length > 0) {
|
|
1800
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', `${fileOnlyFlags.join(', ')} 仅能与 --file 一起使用`);
|
|
1801
|
+
}
|
|
1666
1802
|
const text = collectPositional(args, 3).join(' ');
|
|
1667
1803
|
if (!text) {
|
|
1668
1804
|
console.error('❌ 缺少消息内容(文本或 --file/--payload)');
|
|
@@ -1675,11 +1811,10 @@ Options:
|
|
|
1675
1811
|
const encryptGroup = args.includes('--no-encrypt')
|
|
1676
1812
|
? false
|
|
1677
1813
|
: args.includes('--encrypt') ? true : undefined;
|
|
1678
|
-
const thread =
|
|
1679
|
-
const returnPolicyRaw =
|
|
1814
|
+
const thread = getSendArgValue('--thread');
|
|
1815
|
+
const returnPolicyRaw = getSendArgValue('--return');
|
|
1680
1816
|
if (returnPolicyRaw && returnPolicyRaw !== 'required' && returnPolicyRaw !== 'none') {
|
|
1681
|
-
|
|
1682
|
-
process.exit(1);
|
|
1817
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', `--return 仅支持 required|none: ${returnPolicyRaw}`);
|
|
1683
1818
|
}
|
|
1684
1819
|
const result = await groupSend({
|
|
1685
1820
|
from,
|
package/dist/cli/command-log.js
CHANGED
|
@@ -5,17 +5,16 @@
|
|
|
5
5
|
* 挂在唯一 choke-point(src/cli/index.ts 的 main() 第一行),所有子命令必经,
|
|
6
6
|
* 无需改动任何具体命令集代码。
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - per-agent 日志 agents/<aid>/logs/commands-YYYYMMDD.jsonl:能同步解析出 self-AID 时
|
|
12
|
-
* 额外再记一份,便于单独查看某个 agent。
|
|
8
|
+
* 统一落盘到 $EVOLCORE_HOME/logs/commands-YYYYMMDD.jsonl。所有命令(不论有无
|
|
9
|
+
* AID)都记一份;记录带 selfAid,可直接按 agent 过滤。Agent 业务数据目录不存放
|
|
10
|
+
* 审计或诊断日志。
|
|
13
11
|
*
|
|
14
12
|
* 原则:日志写失败静默降级,绝不影响命令执行(沿用 log-writer.ts 的取舍)。
|
|
15
13
|
*/
|
|
16
14
|
import fs from 'fs';
|
|
17
15
|
import path from 'path';
|
|
18
|
-
import {
|
|
16
|
+
import { resolvePaths } from '../paths.js';
|
|
17
|
+
import { migrateLegacyAgentJsonlLogs } from '../core/audit/log-integrity.js';
|
|
19
18
|
import { getArgValue } from './help.js';
|
|
20
19
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
21
20
|
/** Keep path derivation from accepting arbitrary option values. */
|
|
@@ -52,6 +51,10 @@ function resolveSelfAid(args) {
|
|
|
52
51
|
* @param args 完整 argv 原样
|
|
53
52
|
*/
|
|
54
53
|
export function logCliCommand(cmd, args) {
|
|
54
|
+
const paths = resolvePaths();
|
|
55
|
+
// This entry point runs for every CLI command, including status/help commands
|
|
56
|
+
// that do not otherwise call ensureDataDirs().
|
|
57
|
+
migrateLegacyAgentJsonlLogs(paths.agentsDir, paths.logs);
|
|
55
58
|
const selfAid = resolveSelfAid(args);
|
|
56
59
|
const line = JSON.stringify({
|
|
57
60
|
ts: localTimestamp(),
|
|
@@ -62,11 +65,7 @@ export function logCliCommand(cmd, args) {
|
|
|
62
65
|
sessionId: process.env.EVOLCORE_SESSION_ID || undefined,
|
|
63
66
|
}) + '\n';
|
|
64
67
|
const fileName = `commands-${dayTag()}.jsonl`;
|
|
65
|
-
|
|
66
|
-
appendLine(resolvePaths().logs, fileName, line);
|
|
67
|
-
// per-agent 日志:有 AID 时再额外记一份到该 agent 自己的 logs/,便于单独查看。
|
|
68
|
-
if (selfAid)
|
|
69
|
-
appendLine(agentLogsDir(selfAid), fileName, line);
|
|
68
|
+
appendLine(paths.logs, fileName, line);
|
|
70
69
|
}
|
|
71
70
|
/** 本地时间字符串 YYYY-MM-DD HH:mm:ss(不含时区偏移,直接可读)。 */
|
|
72
71
|
function localTimestamp() {
|
package/dist/cli/contact.js
CHANGED
|
@@ -59,6 +59,7 @@ function fail(message, code = 'INVALID_ARGUMENT', data) {
|
|
|
59
59
|
}
|
|
60
60
|
function printHelp() {
|
|
61
61
|
console.log(`Usage:
|
|
62
|
+
ec contact add <primaryId> --self <agent-aid>
|
|
62
63
|
ec contact block <primaryId> --self <agent-aid>
|
|
63
64
|
ec contact unblock <primaryId> --self <agent-aid>
|
|
64
65
|
ec contact list --blocked --self <agent-aid>
|