evolcore 0.0.12 → 0.0.14
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 +37 -0
- package/bin/codex-managed-hook.mjs +4 -1
- package/bin/ec-safe-output.js +26 -7
- package/bin/install-codex-managed-hooks.mjs +201 -0
- package/dist/agents/claude-runner.js +105 -11
- package/dist/agents/codex-app-server-client.js +176 -7
- package/dist/agents/codex-runner.js +248 -84
- package/dist/agents/ecagent-runner.js +21 -2
- package/dist/agents/gemini-runner.js +9 -4
- package/dist/aun/aid/control-aid.js +36 -13
- 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 +11 -33
- package/dist/aun/msg/index.js +1 -2
- package/dist/aun/msg/managed-operation.js +176 -55
- 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 +514 -150
- package/dist/channels/daemon.js +2 -0
- package/dist/cli/agent.js +9 -96
- package/dist/cli/aun-commands.js +1 -1
- 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 +39 -24
- package/dist/cli/fs-command.js +65 -19
- package/dist/cli/init.js +77 -8
- package/dist/cli/queue-command.js +42 -0
- package/dist/cli/restart-monitor.js +3 -14
- package/dist/cli/task-context.js +172 -0
- package/dist/cli/trigger-command.js +7 -0
- package/dist/config/access-policy.js +1 -2
- package/dist/config/builtin-roles.js +7 -0
- package/dist/config/config-manager.js +27 -3
- package/dist/config/contact-book-store.js +7 -2
- 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 -1
- package/dist/core/auth/auth-gateway.js +30 -1
- package/dist/core/auth/authorization-audit.js +47 -0
- package/dist/core/auth/operation-authorizer.js +1 -0
- package/dist/core/auth/operation-catalog.js +10 -1
- package/dist/core/bootstrap-messages.js +9 -2
- package/dist/core/bootstrap-service.js +8 -1
- package/dist/core/command/command-handler.js +201 -51
- package/dist/core/command/menu-catalog.js +4 -0
- package/dist/core/command/menu-handler.js +85 -18
- package/dist/core/command/menu-protocol.js +23 -2
- package/dist/core/command/slash-handler.js +58 -10
- package/dist/core/event-catalog.js +8 -0
- package/dist/core/handoff/runtime.js +12 -1
- package/dist/core/handoff/store.js +5 -1
- package/dist/core/interaction-router.js +10 -0
- package/dist/core/message/im-renderer.js +34 -1
- package/dist/core/message/message-bridge.js +68 -13
- package/dist/core/message/message-log.js +2 -0
- package/dist/core/message/message-queue.js +267 -39
- package/dist/core/message/message-utils.js +81 -4
- package/dist/core/message/response-engine.js +242 -48
- 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 +649 -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 +21 -0
- package/dist/core/permission/tool-policy.js +266 -56
- package/dist/core/protected-paths.js +107 -2
- package/dist/core/runtime-lock.js +101 -0
- package/dist/core/session/session-manager.js +21 -2
- 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/index.js +191 -89
- package/dist/ipc.js +16 -3
- package/dist/paths.js +3 -0
- package/dist/response-system/engines/v1/proactive-flow.js +92 -8
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +64 -11
- package/dist/trigger/history.js +42 -7
- package/dist/trigger/manager.js +21 -1
- package/dist/trigger/parser.js +14 -2
- package/dist/trigger/scheduler.js +1 -0
- package/dist/trigger/validation.js +67 -6
- package/dist/utils/ecweb-supervisor.js +332 -0
- package/dist/utils/error-utils.js +17 -0
- package/dist/utils/logger.js +37 -4
- package/kits/docs/evolcore/trigger.md +17 -1
- package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
- package/kits/schemas/role-config.schema.1.json +1 -0
- package/kits/templates/roles/admin.json +7 -0
- package/kits/templates/roles/member.json +8 -1
- package/kits/templates/roles/visitor.json +2 -0
- package/package.json +1 -1
- 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/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
|
@@ -600,7 +600,7 @@ export class MessageBridge {
|
|
|
600
600
|
channelId: route.approverOperatorId,
|
|
601
601
|
agentName: owningAgent?.name ?? selfAid,
|
|
602
602
|
chatmode: 'interactive',
|
|
603
|
-
replyContext: { metadata: { source: 'handoff', chatmode: 'interactive' } },
|
|
603
|
+
replyContext: { delivery: { chatType: 'private' }, metadata: { source: 'handoff', chatmode: 'interactive' } },
|
|
604
604
|
});
|
|
605
605
|
const sent = await sendInteractionPayload(route.adapter, envelope, interaction, renderActionAsText(interaction), envelope.replyContext);
|
|
606
606
|
if (!sent)
|
|
@@ -615,14 +615,14 @@ export class MessageBridge {
|
|
|
615
615
|
: code === 'request-stale' ? '申请已更新或已被处理。'
|
|
616
616
|
: code === 'revision-conflict' ? '联系人列表已变化,请从联系人列表重新审核。'
|
|
617
617
|
: '当前无审核权限。';
|
|
618
|
-
await adapter.send(buildEnvelope({ channel: adapter.channelName, channelId: ownerAid, agentName: agentName ?? '<unknown>' }), { kind: 'system.notice', text, subtype: 'contact-review' });
|
|
618
|
+
await adapter.send(buildEnvelope({ channel: adapter.channelName, channelId: ownerAid, agentName: agentName ?? '<unknown>', delivery: { chatType: 'private' } }), { kind: 'system.notice', text, subtype: 'contact-review' });
|
|
619
619
|
}
|
|
620
620
|
async notifyContactApplicant(adapter, applicantAid, code, requestId, expiresAt, agentName) {
|
|
621
621
|
await adapter.send(buildEnvelope({
|
|
622
622
|
channel: adapter.channelName,
|
|
623
623
|
channelId: applicantAid,
|
|
624
624
|
agentName: agentName ?? '<unknown>',
|
|
625
|
-
replyContext: { metadata: evolMenuResponseTransportMetadata() },
|
|
625
|
+
replyContext: { delivery: { chatType: 'private' }, metadata: evolMenuResponseTransportMetadata() },
|
|
626
626
|
}), {
|
|
627
627
|
kind: 'custom',
|
|
628
628
|
channelType: 'aun',
|
|
@@ -687,11 +687,23 @@ export class MessageBridge {
|
|
|
687
687
|
onMessage(async (msg) => {
|
|
688
688
|
try {
|
|
689
689
|
let content = msg.content.trim();
|
|
690
|
+
// Channels that expose adapter receive time (notably AUN) must keep
|
|
691
|
+
// that timestamp through session resolution and queue processing.
|
|
692
|
+
// The fallback is only for legacy adapters that do not provide it.
|
|
693
|
+
const receivedAt = msg.receivedAt ?? Date.now();
|
|
690
694
|
const channelKey = adapter?.channelKey || channelName;
|
|
691
695
|
const owningAgent = this.agentRegistry?.resolveByChannel(channelKey)
|
|
692
696
|
?? this.agentRegistry?.resolveByChannel(channelName);
|
|
693
697
|
const parsedChannelKey = tryParseChannelKey(channelKey);
|
|
694
698
|
const chatType = msg.chatType || 'private';
|
|
699
|
+
const delivery = chatType === 'group'
|
|
700
|
+
? { chatType: 'group', groupId: msg.groupId || msg.channelId }
|
|
701
|
+
: { chatType: 'private' };
|
|
702
|
+
msg.groupId = delivery.chatType === 'group' ? delivery.groupId : undefined;
|
|
703
|
+
msg.replyContext = {
|
|
704
|
+
...(msg.replyContext ?? {}),
|
|
705
|
+
delivery,
|
|
706
|
+
};
|
|
695
707
|
const actorId = msg.peerId;
|
|
696
708
|
const conversationId = chatType === 'group' ? (msg.groupId || msg.channelId) : msg.peerId;
|
|
697
709
|
const selfAid = msg.selfAID || owningAgent?.aid || parsedChannelKey?.selfAID;
|
|
@@ -860,7 +872,7 @@ export class MessageBridge {
|
|
|
860
872
|
return;
|
|
861
873
|
}
|
|
862
874
|
// 普通消息保留原始日志;控制 payload 使用脱敏元数据日志。
|
|
863
|
-
logger.channelIn({ channel: channelName, channelId: msg.channelId, peerId: msg.peerId, peerName: msg.peerName, chatType: msg.chatType, msgId: msg.messageId, threadId: msg.threadId, content, images: msg.images?.length ?? 0, mentions: msg.mentions, replyContext: msg.replyContext });
|
|
875
|
+
logger.channelIn({ channel: channelName, channelId: msg.channelId, selfAid: msg.selfAID, peerId: msg.peerId, peerName: msg.peerName, chatType: msg.chatType, msgId: msg.messageId, correlationId: msg.messageId, threadId: msg.threadId, content, images: msg.images?.length ?? 0, mentions: msg.mentions, replyContext: msg.replyContext });
|
|
864
876
|
const accessDecision = authorizeAccess(authSubject);
|
|
865
877
|
if (!accessDecision.allow) {
|
|
866
878
|
logger.warn(`[MessageBridge] Access denied before command routing: channel=${channelName} channelId=${msg.channelId} actor=${actorId ?? '<none>'} role=${identity.role} reason=${accessDecision.reason}`);
|
|
@@ -925,7 +937,9 @@ export class MessageBridge {
|
|
|
925
937
|
content: msg.messageLogContent ?? content,
|
|
926
938
|
replyTo: inboundReplyTo,
|
|
927
939
|
permMode: null,
|
|
928
|
-
timestamp:
|
|
940
|
+
timestamp: receivedAt,
|
|
941
|
+
receivedAt,
|
|
942
|
+
gatewaySeq: msg.gatewaySeq,
|
|
929
943
|
encrypt: inboundEncrypt,
|
|
930
944
|
chatmode: inboundChatmode,
|
|
931
945
|
peerName: msg.peerName,
|
|
@@ -940,7 +954,8 @@ export class MessageBridge {
|
|
|
940
954
|
}
|
|
941
955
|
}
|
|
942
956
|
if (msg.source !== 'handoff' && await this.handleCommand(cmdContent, channelName, msg.channelId, (text) => {
|
|
943
|
-
|
|
957
|
+
const taskId = `cmd-${msg.messageId || Date.now()}`;
|
|
958
|
+
logger.channelOut({ channel: channelName, channelId: msg.channelId, taskId, correlationId: taskId, sessionId: msg.replyContext?.sessionId, agentAid: msg.selfAID, payload: { kind: 'command.result', text } });
|
|
944
959
|
return sendReply(msg.channelId, text, msg.replyContext);
|
|
945
960
|
}, msg.peerId, msg.threadId, msg.chatType, msg.source, msg.replyContext, msg.messageId, msg.selfAID, authSubject))
|
|
946
961
|
return;
|
|
@@ -1017,9 +1032,12 @@ export class MessageBridge {
|
|
|
1017
1032
|
channelType: msg.channelType || effectiveChannelType,
|
|
1018
1033
|
channelId: msg.channelId, content,
|
|
1019
1034
|
selfAID: msg.selfAID,
|
|
1035
|
+
groupId: msg.groupId,
|
|
1020
1036
|
baseagent: session.baseagent,
|
|
1021
1037
|
chatType,
|
|
1022
|
-
images: msg.images, timestamp:
|
|
1038
|
+
images: msg.images, timestamp: receivedAt,
|
|
1039
|
+
receivedAt,
|
|
1040
|
+
gatewaySeq: msg.gatewaySeq,
|
|
1023
1041
|
peerId: msg.peerId, peerName: msg.peerName,
|
|
1024
1042
|
peerType: msg.peerType,
|
|
1025
1043
|
sameDevice: msg.sameDevice,
|
|
@@ -1062,6 +1080,8 @@ export class MessageBridge {
|
|
|
1062
1080
|
replyTo: inboundReplyTo,
|
|
1063
1081
|
permMode: session.identity?.role ?? null,
|
|
1064
1082
|
timestamp: fullMessage.timestamp,
|
|
1083
|
+
receivedAt: msg.receivedAt,
|
|
1084
|
+
gatewaySeq: msg.gatewaySeq,
|
|
1065
1085
|
encrypt: inboundEncrypt,
|
|
1066
1086
|
chatmode: inboundChatmode,
|
|
1067
1087
|
peerName: msg.peerName,
|
|
@@ -1200,6 +1220,31 @@ export class MessageBridge {
|
|
|
1200
1220
|
if (!hasValidMenuId(parsed))
|
|
1201
1221
|
return;
|
|
1202
1222
|
const header = { id: parsed.id, ...(parsed.name?.trim() ? { name: parsed.name } : {}) };
|
|
1223
|
+
// Menu IDs are the protocol's stable correlation key. Bind it, together
|
|
1224
|
+
// with the active EvolCore session, before authorization so every
|
|
1225
|
+
// CommandAudit record and denial can be joined to the same request.
|
|
1226
|
+
let activeSession;
|
|
1227
|
+
if (msg.threadId && typeof this.sessionManager.getThreadSession === 'function') {
|
|
1228
|
+
try {
|
|
1229
|
+
activeSession = await this.sessionManager.getThreadSession(channel, msg.channelId, msg.threadId);
|
|
1230
|
+
}
|
|
1231
|
+
catch {
|
|
1232
|
+
activeSession = undefined;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
if (!activeSession && typeof this.sessionManager.getActiveSession === 'function') {
|
|
1236
|
+
try {
|
|
1237
|
+
activeSession = await this.sessionManager.getActiveSession(channel, msg.channelId);
|
|
1238
|
+
}
|
|
1239
|
+
catch {
|
|
1240
|
+
activeSession = undefined;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
const menuAuthSubject = {
|
|
1244
|
+
...authSubject,
|
|
1245
|
+
requestId: parsed.id,
|
|
1246
|
+
...(activeSession?.id ? { sessionId: activeSession.id } : {}),
|
|
1247
|
+
};
|
|
1203
1248
|
const isTokenRequest = parsed.type === 'menu.token.request';
|
|
1204
1249
|
if (isTokenRequest) {
|
|
1205
1250
|
if (msg.chatType !== 'private') {
|
|
@@ -1218,7 +1263,7 @@ export class MessageBridge {
|
|
|
1218
1263
|
}
|
|
1219
1264
|
}
|
|
1220
1265
|
if (!isTokenRequest) {
|
|
1221
|
-
const access = authorizeAccess(
|
|
1266
|
+
const access = authorizeAccess(menuAuthSubject);
|
|
1222
1267
|
if (!access.allow) {
|
|
1223
1268
|
this.logMenuDiagnostic('access-denied', channel, msg, parsed, access.code);
|
|
1224
1269
|
await this.sendMenuResponse(adapter, channel, msg, menuFailure(header, {
|
|
@@ -1233,7 +1278,7 @@ export class MessageBridge {
|
|
|
1233
1278
|
let afterResponse;
|
|
1234
1279
|
const deduped = await this.menuDeduper.execute(dedupKey, menuPayloadFingerprint(parsed.raw), () => isTokenRequest
|
|
1235
1280
|
? this.issueMenuTokenResponse(header, channel, msg)
|
|
1236
|
-
: this.dispatchMenuRequest(parsed.request, header, channel, msg,
|
|
1281
|
+
: this.dispatchMenuRequest(parsed.request, header, channel, msg, menuAuthSubject, effect => { afterResponse = effect; }));
|
|
1237
1282
|
if ('conflict' in deduped) {
|
|
1238
1283
|
this.logMenuDiagnostic('request-conflict', channel, msg, parsed, 'CONFLICT');
|
|
1239
1284
|
await this.sendMenuResponse(adapter, channel, msg, menuFailure(header, {
|
|
@@ -1244,6 +1289,8 @@ export class MessageBridge {
|
|
|
1244
1289
|
}
|
|
1245
1290
|
if (deduped.replayed)
|
|
1246
1291
|
this.logMenuDiagnostic('request-replay', channel, msg, parsed);
|
|
1292
|
+
if (deduped.retry)
|
|
1293
|
+
this.logMenuDiagnostic('request-retry', channel, msg, parsed);
|
|
1247
1294
|
const response = responseWarning && 'data' in deduped.value
|
|
1248
1295
|
? { ...deduped.value, warning: responseWarning }
|
|
1249
1296
|
: deduped.value;
|
|
@@ -1380,6 +1427,10 @@ export class MessageBridge {
|
|
|
1380
1427
|
...evolMenuResponseTransportMetadata(),
|
|
1381
1428
|
},
|
|
1382
1429
|
};
|
|
1430
|
+
if (msg.channelType === 'aun' && !replyContext.delivery) {
|
|
1431
|
+
logger.warn(`[MessageBridge] dropping AUN menu response without trusted delivery route: channel=${channel} channelId=${msg.channelId}`);
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1383
1434
|
const envelope = buildEnvelope({
|
|
1384
1435
|
taskId: `menu-${randomBytes(4).toString('hex')}`,
|
|
1385
1436
|
channel,
|
|
@@ -1418,9 +1469,11 @@ export class MessageBridge {
|
|
|
1418
1469
|
logger.channelIn({
|
|
1419
1470
|
channel,
|
|
1420
1471
|
channelId: this.shortHash(msg.channelId),
|
|
1472
|
+
selfAid: msg.selfAID,
|
|
1421
1473
|
peerId: this.shortHash(msg.peerId),
|
|
1422
1474
|
chatType: msg.chatType,
|
|
1423
1475
|
msgId: msg.messageId,
|
|
1476
|
+
correlationId: msg.messageId,
|
|
1424
1477
|
control: {
|
|
1425
1478
|
id: parsed.id,
|
|
1426
1479
|
type: parsed.type,
|
|
@@ -1438,6 +1491,8 @@ export class MessageBridge {
|
|
|
1438
1491
|
logger.warn(`[MenuControl] category=${category} request=${parsed.id || '<missing>'}`
|
|
1439
1492
|
+ ` type=${parsed.type} name=${parsed.name || '<none>'} action=${parsed.action || '<none>'}`
|
|
1440
1493
|
+ ` transport=${channel} scope=${this.shortHash(scope)} sender=${this.shortHash(msg.peerId)}`
|
|
1494
|
+
+ (category === 'request-replay' ? ' replay=true' : '')
|
|
1495
|
+
+ (category === 'request-retry' ? ' retry=true' : '')
|
|
1441
1496
|
+ `${code ? ` code=${code}` : ''}${decision.suppressed ? ` suppressed=${decision.suppressed}` : ''}`);
|
|
1442
1497
|
}
|
|
1443
1498
|
shortHash(value) {
|
|
@@ -1556,17 +1611,17 @@ export class MessageBridge {
|
|
|
1556
1611
|
* 撤回消息:先查 debounce 窗口,再查 message queue,最后查正在执行的任务。
|
|
1557
1612
|
* @returns true 如果找到并取消/中断
|
|
1558
1613
|
*/
|
|
1559
|
-
cancel(messageId) {
|
|
1614
|
+
cancel(messageId, selfAID) {
|
|
1560
1615
|
// 阶段 1: debounce 窗口(尚未入队)
|
|
1561
1616
|
for (const d of this.debouncers.values()) {
|
|
1562
|
-
if (d.cancel(messageId))
|
|
1617
|
+
if (d.cancel(messageId, selfAID))
|
|
1563
1618
|
return true;
|
|
1564
1619
|
}
|
|
1565
1620
|
// 阶段 2: 已入队但未处理(合并后 messageId 可能是逗号分隔的多个 id)
|
|
1566
|
-
if (this.messageQueue.cancel(messageId))
|
|
1621
|
+
if (this.messageQueue.cancel(messageId, selfAID))
|
|
1567
1622
|
return true;
|
|
1568
1623
|
// 阶段 3: 正在执行的任务 → 触发 interrupt
|
|
1569
|
-
return this.messageQueue.cancelActive(messageId);
|
|
1624
|
+
return this.messageQueue.cancelActive(messageId, selfAID);
|
|
1570
1625
|
}
|
|
1571
1626
|
/** 清理资源 */
|
|
1572
1627
|
dispose() {
|
|
@@ -289,6 +289,8 @@ export function buildInboundEntry(opts) {
|
|
|
289
289
|
const isCommand = isCommandCapable && opts.content.startsWith('/');
|
|
290
290
|
return {
|
|
291
291
|
ts,
|
|
292
|
+
...(opts.receivedAt !== undefined ? { receivedAt: opts.receivedAt } : {}),
|
|
293
|
+
...(opts.gatewaySeq !== undefined ? { gatewaySeq: opts.gatewaySeq } : {}),
|
|
292
294
|
time: formatTimestampMs(ts),
|
|
293
295
|
sessionId: opts.sessionId,
|
|
294
296
|
threadId: opts.threadId ?? null,
|