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
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 【重要】最先加载环境变量,确保后续模块初始化时可用
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir, daemonControlDir, daemonQueuePath } from './paths.js';
|
|
4
|
+
import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir, daemonControlDir, daemonQueuePath, daemonMessageDedupPath } from './paths.js';
|
|
5
5
|
// 立即加载 .env 文件(在其他模块导入之前)
|
|
6
6
|
try {
|
|
7
7
|
dotenv.config({ path: path.join(resolvePaths().root, '.env') });
|
|
@@ -14,16 +14,13 @@ import { CodexSessionFileAdapter } from './core/session/adapters/codex-session-f
|
|
|
14
14
|
import { GeminiSessionFileAdapter } from './core/session/adapters/gemini-session-file-adapter.js';
|
|
15
15
|
import { EcagentSessionFileAdapter } from './core/session/adapters/ecagent-session-file-adapter.js';
|
|
16
16
|
import { loadDefaults, loadAllAgents, migrateIdentitiesIfNeeded, loadDaemonConfig, initializeEckSnapshotsConfig } from './config-store.js';
|
|
17
|
-
import { ConfigTarget, initConfigManager, onConfigWrite, read as readConfig } from './config/config-manager.js';
|
|
18
|
-
import { ensureRoleConfigV4OnStartup } from './config/role-
|
|
19
|
-
import { ensureRoleConfigV5OnStartup } from './config/role-config-v5-startup.js';
|
|
17
|
+
import { ConfigTarget, initConfigManager, onConfigWrite, read as readConfig, shouldFailFastForMissingOwners } from './config/config-manager.js';
|
|
18
|
+
import { ensureRoleConfigV4OnStartup, ensureRoleConfigV5OnStartup } from './config/role-migration-startup.js';
|
|
20
19
|
import { ensureContactBookV2OnStartup } from './config/contact-book-v2-startup.js';
|
|
21
20
|
import { resolvePeerDisplayLabel } from './config/contact-book.js';
|
|
22
21
|
import { expirePendingContactRequests } from './config/contact-request-service.js';
|
|
23
|
-
import { shouldFailFastForMissingOwners } from './config/owner-policy.js';
|
|
24
22
|
import { isManagementRole } from './config/builtin-roles.js';
|
|
25
23
|
import { checkRoleAccess, getFirstStaticAgentOwner, resolvePeerRoleDetail, roleToSessionIdentity } from './config/peer-role-resolver.js';
|
|
26
|
-
import { isCrossAgentTriggerOperationAllowed, isCrossAgentTriggerReadOperation } from './core/auth/trigger-authorization.js';
|
|
27
24
|
import { ensureStartupConfigSnapshot, isConfigSnapshotsEnabled, retentionCleanup, readCurrent, readWVersion, diffWorkingVsVersion, paramDiff, incrementSuccessCount } from './config/snapshot.js';
|
|
28
25
|
import { appendBootLog, selfDiagnose } from './config/boot-log.js';
|
|
29
26
|
import { CONFIG_SCHEMA_VERSION } from './types.js';
|
|
@@ -41,7 +38,7 @@ import { BindService } from './utils/aid-bind.js';
|
|
|
41
38
|
import { DingtalkChannelPlugin, registerPendingDingtalkContactBind } from './channels/dingtalk.js';
|
|
42
39
|
import { QQBotChannelPlugin, registerPendingQQBotContactBind } from './channels/qqbot.js';
|
|
43
40
|
import { WecomChannelPlugin, registerPendingWecomContactBind } from './channels/wecom.js';
|
|
44
|
-
import { buildEnvelope } from './core/message/message-utils.js';
|
|
41
|
+
import { buildEnvelope, isDeliveryTargetForChannel, replyContextFromSession } from './core/message/message-utils.js';
|
|
45
42
|
import { ResponseEngine } from './core/message/response-engine.js';
|
|
46
43
|
import { MessageQueue } from './core/message/message-queue.js';
|
|
47
44
|
import { MessageBridge } from './core/message/message-bridge.js';
|
|
@@ -58,10 +55,9 @@ import { getEventCatalog } from './core/event-catalog.js';
|
|
|
58
55
|
import { StatsCollector } from './utils/stats.js';
|
|
59
56
|
import { AidStatsCollector } from './utils/stats.js';
|
|
60
57
|
import { PermissionGateway } from './core/permission/approval-gateway.js';
|
|
61
|
-
import { InteractionRouter } from './core/interaction-router.js';
|
|
62
|
-
import { registerAdapterInteractions } from './core/interaction-registration.js';
|
|
58
|
+
import { InteractionRouter, registerAdapterInteractions } from './core/interaction-router.js';
|
|
63
59
|
import { AgentDelegationRegistry, authorizeDelegatedAunMsgSend } from './core/auth/agent-delegation.js';
|
|
64
|
-
import { authorizeOperation, buildAuthSubject } from './core/auth/auth-gateway.js';
|
|
60
|
+
import { authorizeOperation, buildAuthSubject, isCrossAgentTriggerOperationAllowed, isCrossAgentTriggerReadOperation, } from './core/auth/auth-gateway.js';
|
|
65
61
|
import { parsePeerKey } from './core/relation/peer-identity.js';
|
|
66
62
|
import { isHClassPath } from './core/protected-paths.js';
|
|
67
63
|
import { ChannelLoader, tryParseChannelKey } from './core/channel-loader.js';
|
|
@@ -72,7 +68,8 @@ import { AgentReloadBusyError, AgentReloadCoordinator } from './core/agent-reloa
|
|
|
72
68
|
import { buildReloadHooks } from './core/channel-loader.js';
|
|
73
69
|
import { IpcServer } from './ipc.js';
|
|
74
70
|
import { logger, setLogLevel } from './utils/logger.js';
|
|
75
|
-
import {
|
|
71
|
+
import { fetchEcwebPairCode } from './utils/ecweb-utils.js';
|
|
72
|
+
import { createEcwebSupervisor } from './utils/ecweb-supervisor.js';
|
|
76
73
|
import { writeMain, removeAll, isMainWinner, scanInstances } from './utils/instance-registry.js';
|
|
77
74
|
import { detectDuplicates } from './core/evolagent-registry.js';
|
|
78
75
|
import { loadKitManifest, cleanEckDebug, invalidateKitCache } from './eck/kit-renderer.js';
|
|
@@ -90,14 +87,13 @@ import { applyTriggerPatch } from './trigger/patch.js';
|
|
|
90
87
|
import { validateModelSelectionForRole } from './core/model/model-permission.js';
|
|
91
88
|
import { constrainRuntimePermissionMode, validateRuntimeStringFieldOverride, } from './core/role/runtime-policy.js';
|
|
92
89
|
import { atomicWriteJson } from './core/session/session-fs-store.js';
|
|
90
|
+
import { ensureProcessManagedTempDir } from './cli/task-context.js';
|
|
93
91
|
import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
|
|
94
92
|
import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
|
|
95
93
|
import { MAIN_PACKAGE_NAME } from './product.js';
|
|
96
94
|
import fs from 'fs';
|
|
97
95
|
import crypto from 'crypto';
|
|
98
96
|
import { fileURLToPath } from 'url';
|
|
99
|
-
import { spawn } from 'child_process';
|
|
100
|
-
import * as platform from './utils/cross-platform.js';
|
|
101
97
|
const controlMenuDeduper = new MenuRequestDeduper();
|
|
102
98
|
/** 出站 payload 摘要(用于 channel-out.log) */
|
|
103
99
|
function summarizeOutboundPayload(payload) {
|
|
@@ -176,6 +172,61 @@ function normalizeMessageSource(value) {
|
|
|
176
172
|
? value
|
|
177
173
|
: 'daemon';
|
|
178
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Preserve the authenticated AUN inbound route for control-plane replies.
|
|
177
|
+
* Control callbacks must not reconstruct group/private semantics from an AID.
|
|
178
|
+
*/
|
|
179
|
+
function controlReplyContext(opts, metadata) {
|
|
180
|
+
const supplied = opts.replyContext?.delivery;
|
|
181
|
+
if (supplied) {
|
|
182
|
+
const matchesInbound = opts.chatType === 'group'
|
|
183
|
+
? supplied.chatType === 'group' && supplied.groupId === opts.groupId
|
|
184
|
+
: supplied.chatType === 'private';
|
|
185
|
+
if (!matchesInbound) {
|
|
186
|
+
throw Object.assign(new Error('AUN control reply route does not match its authenticated inbound context'), {
|
|
187
|
+
code: 'AUN_OUTBOUND_ROUTE_MISMATCH',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const delivery = supplied
|
|
192
|
+
?? (opts.chatType === 'group'
|
|
193
|
+
? (opts.groupId ? { chatType: 'group', groupId: opts.groupId } : undefined)
|
|
194
|
+
: { chatType: 'private' });
|
|
195
|
+
if (!delivery)
|
|
196
|
+
throw Object.assign(new Error('AUN control reply is missing a trusted groupId'), { code: 'AUN_OUTBOUND_ROUTE_REQUIRED' });
|
|
197
|
+
return {
|
|
198
|
+
...(opts.replyContext ?? {}),
|
|
199
|
+
delivery,
|
|
200
|
+
metadata: {
|
|
201
|
+
...(opts.replyContext?.metadata ?? {}),
|
|
202
|
+
...(opts.encrypted === undefined ? {} : { encrypted: opts.encrypted }),
|
|
203
|
+
...(opts.protectedHeaders ? { protectedHeaders: opts.protectedHeaders } : {}),
|
|
204
|
+
...(metadata ?? {}),
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function isValidAunDeliveryForChannel(delivery, channelId) {
|
|
209
|
+
return isDeliveryTargetForChannel(delivery, channelId);
|
|
210
|
+
}
|
|
211
|
+
function restartChannelType(channel) {
|
|
212
|
+
return channel?.split('#', 1)[0].toLowerCase();
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Restore a persisted restart route without inferring AUN group semantics from
|
|
216
|
+
* an address. Legacy non-AUN entries may remain route-less; AUN entries do not.
|
|
217
|
+
*/
|
|
218
|
+
export function resolvePersistedRestartDelivery(opts) {
|
|
219
|
+
const requiresAunRoute = restartChannelType(opts.channel) === 'aun'
|
|
220
|
+
|| restartChannelType(opts.adapterChannel) === 'aun';
|
|
221
|
+
if (!requiresAunRoute) {
|
|
222
|
+
return isDeliveryTargetForChannel(opts.delivery, opts.channelId)
|
|
223
|
+
? { valid: true, delivery: opts.delivery }
|
|
224
|
+
: { valid: true };
|
|
225
|
+
}
|
|
226
|
+
return isDeliveryTargetForChannel(opts.delivery, opts.channelId)
|
|
227
|
+
? { valid: true, delivery: opts.delivery }
|
|
228
|
+
: { valid: false };
|
|
229
|
+
}
|
|
179
230
|
function daemonConversationWatchdogMs(settings) {
|
|
180
231
|
const idleTimeoutSec = settings.idleMonitor?.timeout;
|
|
181
232
|
const idleMs = typeof idleTimeoutSec === 'number' && Number.isFinite(idleTimeoutSec) && idleTimeoutSec > 0
|
|
@@ -205,6 +256,10 @@ function originFromActorSession(session, authenticatedPeerId, authenticatedChann
|
|
|
205
256
|
threadId: sameConversation && !isGroup ? (session.threadId || undefined) : undefined,
|
|
206
257
|
peerId,
|
|
207
258
|
sessionKey: sameConversation && !isGroup ? session.sessionKey : undefined,
|
|
259
|
+
// A group-created trigger intentionally feeds back to the authenticated
|
|
260
|
+
// actor's private conversation (the origin channelId is peerId), so the
|
|
261
|
+
// route remains explicit even though the source session was a group.
|
|
262
|
+
delivery: { chatType: 'private' },
|
|
208
263
|
};
|
|
209
264
|
}
|
|
210
265
|
function seedUpgradeCheckTrigger(manager, owner) {
|
|
@@ -402,6 +457,20 @@ export async function sendSystemPayload(adapter, envelope, payload) {
|
|
|
402
457
|
}
|
|
403
458
|
async function runBindBootstrapDaemon(daemonCfg) {
|
|
404
459
|
logger.warn('[bind-bootstrap] starting control AID + IPC only');
|
|
460
|
+
// Bootstrap exits before the normal trigger scheduler is constructed. Keep
|
|
461
|
+
// the daemon-owned upgrade check present during a fresh installation too;
|
|
462
|
+
// the regular startup path will reseed this definition idempotently.
|
|
463
|
+
const bootstrapControlAid = daemonCfg.aid || '__daemon__';
|
|
464
|
+
try {
|
|
465
|
+
seedUpgradeCheckTrigger(new TriggerDefinitionManager(bootstrapControlAid), {
|
|
466
|
+
aid: bootstrapControlAid,
|
|
467
|
+
originPeerId: bootstrapControlAid,
|
|
468
|
+
baseagent: 'codex',
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
logger.warn(`[bind-bootstrap] failed to seed daemon upgrade trigger: ${error instanceof Error ? error.message : String(error)}`);
|
|
473
|
+
}
|
|
405
474
|
const bindService = new BindService({
|
|
406
475
|
receiverAid: daemonCfg.aid,
|
|
407
476
|
getAvailableBaseagents: detectAvailableBaseagentsForBind,
|
|
@@ -437,7 +506,7 @@ async function runBindBootstrapDaemon(daemonCfg) {
|
|
|
437
506
|
}
|
|
438
507
|
const response = parsed ? await bindService.handleRequest(parsed, opts.peerId) : null;
|
|
439
508
|
if (response) {
|
|
440
|
-
await controlChannel.sendMessage(opts.channelId, JSON.stringify(response));
|
|
509
|
+
await controlChannel.sendMessage(opts.channelId, JSON.stringify(response), controlReplyContext(opts));
|
|
441
510
|
}
|
|
442
511
|
});
|
|
443
512
|
const controlToken = crypto.randomBytes(32).toString('base64url');
|
|
@@ -595,6 +664,9 @@ function readFastaunVersion() {
|
|
|
595
664
|
}
|
|
596
665
|
}
|
|
597
666
|
async function main() {
|
|
667
|
+
// Service managers do not necessarily export TMPDIR. Establish the private
|
|
668
|
+
// managed root before any runner or task runtime is initialized.
|
|
669
|
+
ensureProcessManagedTempDir();
|
|
598
670
|
// 启动信息:目录类型 + 版本号 + 代码最新时间戳
|
|
599
671
|
{
|
|
600
672
|
const pkgRoot = getPackageRoot();
|
|
@@ -789,6 +861,23 @@ async function main() {
|
|
|
789
861
|
'如需远程管理,请在 daemon.json 配置 owners: [<你的 AID>]');
|
|
790
862
|
}
|
|
791
863
|
const paths = resolvePaths();
|
|
864
|
+
// ECWeb has one lifecycle owner: the daemon. The CLI may have started an
|
|
865
|
+
// instance just before spawning us; the supervisor adopts it when healthy,
|
|
866
|
+
// otherwise starts one and keeps it alive for the daemon's lifetime.
|
|
867
|
+
let ecwebSupervisor = null;
|
|
868
|
+
if (daemonCfg.ecweb?.enabled) {
|
|
869
|
+
ecwebSupervisor = createEcwebSupervisor({
|
|
870
|
+
port: daemonCfg.ecweb.port ?? 42705,
|
|
871
|
+
logger,
|
|
872
|
+
});
|
|
873
|
+
try {
|
|
874
|
+
await ecwebSupervisor.start();
|
|
875
|
+
onShutdown(() => ecwebSupervisor?.stop());
|
|
876
|
+
}
|
|
877
|
+
catch (error) {
|
|
878
|
+
logger.warn(`ECWeb supervisor 启动失败(不影响 daemon 主流程): ${error?.message || error}`);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
792
881
|
if (bindBootstrapMode && daemonCfg.aid && loadAllAgents().agents.length === 0) {
|
|
793
882
|
await runBindBootstrapDaemon(daemonCfg);
|
|
794
883
|
return;
|
|
@@ -1091,7 +1180,7 @@ async function main() {
|
|
|
1091
1180
|
if (!adapter)
|
|
1092
1181
|
return;
|
|
1093
1182
|
if (text) {
|
|
1094
|
-
await adapter.send(buildEnvelope({ channel: adapter.channelName, channelId: id, replyContext: opts }), { kind: 'system.notice', text, subtype: 'health' });
|
|
1183
|
+
await adapter.send(buildEnvelope({ channel: adapter.channelName, channelId: id, delivery: opts?.delivery, replyContext: opts }), { kind: 'system.notice', text, subtype: 'health' });
|
|
1095
1184
|
}
|
|
1096
1185
|
};
|
|
1097
1186
|
return cmdHandler.handle(content, channel, channelId, sendFn, userId, threadId);
|
|
@@ -1120,6 +1209,7 @@ async function main() {
|
|
|
1120
1209
|
await processor.processMessage(message);
|
|
1121
1210
|
}, {
|
|
1122
1211
|
persistencePath: daemonQueuePath(),
|
|
1212
|
+
dedupPath: daemonMessageDedupPath(),
|
|
1123
1213
|
});
|
|
1124
1214
|
// 设置中断回调(精确中断正在处理的 agent)
|
|
1125
1215
|
messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
|
|
@@ -1160,12 +1250,20 @@ async function main() {
|
|
|
1160
1250
|
source: 'msg',
|
|
1161
1251
|
handoffTrace: { version: 2, handoff_id: handoff.handoff_id },
|
|
1162
1252
|
};
|
|
1163
|
-
const
|
|
1253
|
+
const delivery = handoff.request.delivery;
|
|
1254
|
+
if (!isValidAunDeliveryForChannel(delivery, targetSession.channelId)) {
|
|
1255
|
+
return {
|
|
1256
|
+
ok: false,
|
|
1257
|
+
error: 'handoff is missing a valid immutable AUN delivery route',
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
const result = delivery.chatType === 'group'
|
|
1164
1261
|
? typeof channel.sendDaemonGroupMsg === 'function'
|
|
1165
1262
|
? await channel.sendDaemonGroupMsg({
|
|
1166
|
-
groupId:
|
|
1263
|
+
groupId: delivery.groupId,
|
|
1167
1264
|
payload: { ...handoff.request.payload, [AUN_HANDOFF_MARKER_FIELD]: handoff.handoff_id },
|
|
1168
1265
|
encrypt: handoff.request.encrypt,
|
|
1266
|
+
causation: handoff.causation,
|
|
1169
1267
|
log,
|
|
1170
1268
|
})
|
|
1171
1269
|
: { ok: false, error: 'AUN channel does not support daemon group sends' }
|
|
@@ -1279,6 +1377,14 @@ async function main() {
|
|
|
1279
1377
|
if (target && !getTriggerChannel(definition.agentAid, target.channelKey)) {
|
|
1280
1378
|
throw new Error(`agent ${definition.agentAid} has no configured channel ${target.channelKey}`);
|
|
1281
1379
|
}
|
|
1380
|
+
const channelType = tryParseChannelKey(target?.channelKey ?? '')?.type
|
|
1381
|
+
?? (target?.channelKey?.split('#', 1)[0] || undefined);
|
|
1382
|
+
const validAunRoute = definition.feedback.strategy === 'target'
|
|
1383
|
+
? definition.feedback.target?.chatType === 'private' || definition.feedback.target?.chatType === 'group'
|
|
1384
|
+
: !!definition.origin && isValidAunDeliveryForChannel(definition.origin.delivery, definition.origin.channelId);
|
|
1385
|
+
if (target && channelType === 'aun' && !validAunRoute) {
|
|
1386
|
+
throw Object.assign(new Error('AUN trigger feedback target requires a valid explicit delivery route'), { code: 'AUN_OUTBOUND_ROUTE_REQUIRED' });
|
|
1387
|
+
}
|
|
1282
1388
|
};
|
|
1283
1389
|
const validateTriggerDefinitionForActor = (definition, actor) => {
|
|
1284
1390
|
if (definition.execution.type === 'script' && !actor.management) {
|
|
@@ -1520,9 +1626,13 @@ async function main() {
|
|
|
1520
1626
|
&& (candidate.adapter.channelKey === target.channelKey || candidate.adapter.channelName === target.channelKey)
|
|
1521
1627
|
&& tryParseChannelKey(candidate.adapter.channelKey)?.selfAID === input.trigger.agentAid));
|
|
1522
1628
|
const channel = inst?.channel;
|
|
1523
|
-
if (!channel
|
|
1629
|
+
if (!channel)
|
|
1630
|
+
return null;
|
|
1631
|
+
// Trigger targets carry their transport classification explicitly. A
|
|
1632
|
+
// channelId is only an address and is never parsed to choose the RPC.
|
|
1633
|
+
const targetChatType = target.chatType;
|
|
1634
|
+
if (!targetChatType)
|
|
1524
1635
|
return null;
|
|
1525
|
-
const targetChatType = channel.isGroupId(target.channelId) ? 'group' : 'private';
|
|
1526
1636
|
if (targetChatType === 'group' && typeof channel.sendDaemonGroupMsg !== 'function')
|
|
1527
1637
|
return null;
|
|
1528
1638
|
if (targetChatType === 'private' && typeof channel.sendDaemonMsg !== 'function')
|
|
@@ -1634,11 +1744,20 @@ async function main() {
|
|
|
1634
1744
|
// 0. 包装 adapter.send,记录所有出站到 channel-out.log
|
|
1635
1745
|
const originalSend = inst.adapter.send.bind(inst.adapter);
|
|
1636
1746
|
inst.adapter.send = async (envelope, payload) => {
|
|
1637
|
-
|
|
1747
|
+
const owningAgent = agentRegistry.resolveByChannel(inst.adapter.channelKey)
|
|
1748
|
+
?? agentRegistry.resolveByChannel(inst.adapter.channelName);
|
|
1749
|
+
logger.channelOut({
|
|
1750
|
+
channel: inst.adapter.channelName,
|
|
1751
|
+
channelId: envelope.channelId,
|
|
1752
|
+
taskId: envelope.taskId,
|
|
1753
|
+
correlationId: envelope.operationId ?? envelope.taskId,
|
|
1754
|
+
sessionId: envelope.sessionId,
|
|
1755
|
+
agentAid: owningAgent?.aid,
|
|
1756
|
+
agentName: envelope.agentName,
|
|
1757
|
+
payload: summarizeOutboundPayload(payload),
|
|
1758
|
+
});
|
|
1638
1759
|
const result = await originalSend(envelope, payload);
|
|
1639
1760
|
if (shouldCountSentPayload(payload)) {
|
|
1640
|
-
const owningAgent = agentRegistry.resolveByChannel(inst.adapter.channelKey)
|
|
1641
|
-
?? agentRegistry.resolveByChannel(inst.adapter.channelName);
|
|
1642
1761
|
if ((inst.channelType || inst.adapter.channelName) !== 'aun') {
|
|
1643
1762
|
try {
|
|
1644
1763
|
const logPayload = outboundPayloadToLogText(payload);
|
|
@@ -1748,8 +1867,8 @@ async function main() {
|
|
|
1748
1867
|
});
|
|
1749
1868
|
}
|
|
1750
1869
|
// 5. 撤回消息 → 中断执行中任务
|
|
1751
|
-
inst.channel.onRecall?.((messageId) => {
|
|
1752
|
-
msgBridge.cancel(messageId);
|
|
1870
|
+
inst.channel.onRecall?.((messageId, selfAID) => {
|
|
1871
|
+
msgBridge.cancel(messageId, selfAID);
|
|
1753
1872
|
});
|
|
1754
1873
|
}
|
|
1755
1874
|
// ── 注册所有渠道实例 ──
|
|
@@ -1858,6 +1977,7 @@ async function main() {
|
|
|
1858
1977
|
channel: adapter.channelName,
|
|
1859
1978
|
channelId: ownerAid,
|
|
1860
1979
|
agentName,
|
|
1980
|
+
delivery: { chatType: 'private' },
|
|
1861
1981
|
});
|
|
1862
1982
|
sendSystemPayload(adapter, envelope, {
|
|
1863
1983
|
kind: 'system.notice',
|
|
@@ -1896,16 +2016,31 @@ async function main() {
|
|
|
1896
2016
|
logger.info(`[Restart] Pending notification waits for channel connection: ${pending.channel}`);
|
|
1897
2017
|
return;
|
|
1898
2018
|
}
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
:
|
|
2019
|
+
const pendingDelivery = pending.delivery;
|
|
2020
|
+
const restartDelivery = resolvePersistedRestartDelivery({
|
|
2021
|
+
channel: pending.channel,
|
|
2022
|
+
adapterChannel: adapter.channelName,
|
|
2023
|
+
channelId: pending.channelId,
|
|
2024
|
+
delivery: pendingDelivery,
|
|
2025
|
+
});
|
|
2026
|
+
if (!restartDelivery.valid) {
|
|
2027
|
+
logger.warn(`[Restart] Discarding pending notification without a valid persisted delivery route: channel=${pending.channel} channelId=${pending.channelId}`);
|
|
2028
|
+
fs.rmSync(pendingFile, { force: true });
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
const pendingRouteContext = restartDelivery.delivery ? { delivery: restartDelivery.delivery } : {};
|
|
2032
|
+
const replyContext = {
|
|
2033
|
+
...(pendingRouteContext ?? {}),
|
|
2034
|
+
...(pending.rootId ? { replyToMessageId: pending.rootId, replyInThread: !!pending.threadId } : {}),
|
|
2035
|
+
};
|
|
1902
2036
|
const owningAgent = agentRegistry.resolveByChannel(adapter.channelKey);
|
|
1903
2037
|
const envelope = buildEnvelope({
|
|
1904
2038
|
taskId: `system-restart-${process.pid}`,
|
|
1905
2039
|
channel: adapter.channelKey,
|
|
1906
2040
|
channelId: pending.channelId,
|
|
1907
2041
|
agentName: owningAgent?.aid || 'evolcore',
|
|
1908
|
-
|
|
2042
|
+
...(restartDelivery.delivery ? { delivery: restartDelivery.delivery } : {}),
|
|
2043
|
+
replyContext: Object.keys(replyContext).length > 0 ? replyContext : undefined,
|
|
1909
2044
|
});
|
|
1910
2045
|
await sendSystemPayload(adapter, envelope, {
|
|
1911
2046
|
kind: 'system.notice',
|
|
@@ -2115,53 +2250,6 @@ async function main() {
|
|
|
2115
2250
|
catch (e) {
|
|
2116
2251
|
logger.warn(`控制 AID 首连失败(后台自动重连,不影响 daemon 主流程): ${e?.message || e}`);
|
|
2117
2252
|
}
|
|
2118
|
-
// ── ECWeb 自动启动 ──
|
|
2119
|
-
// 如果 config.ecweb.enabled,自动拉起 ecweb 服务
|
|
2120
|
-
if (daemonCfg.ecweb?.enabled) {
|
|
2121
|
-
const ecwebPath = path.join(resolvePaths().root, 'ecweb');
|
|
2122
|
-
const ecwebEntry = path.join(ecwebPath, 'dist', 'index.js');
|
|
2123
|
-
if (fs.existsSync(ecwebEntry)) {
|
|
2124
|
-
let ecwebVersion;
|
|
2125
|
-
try {
|
|
2126
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(ecwebPath, 'package.json'), 'utf-8'));
|
|
2127
|
-
ecwebVersion = pkg.version;
|
|
2128
|
-
}
|
|
2129
|
-
catch { }
|
|
2130
|
-
const versionError = ecwebVersionRequirementError(ecwebVersion);
|
|
2131
|
-
if (versionError) {
|
|
2132
|
-
logger.error(`ECWeb 未启动: ${versionError}`);
|
|
2133
|
-
}
|
|
2134
|
-
else {
|
|
2135
|
-
try {
|
|
2136
|
-
const ecwebProc = spawn(process.execPath, [ecwebEntry], {
|
|
2137
|
-
cwd: ecwebPath,
|
|
2138
|
-
detached: true,
|
|
2139
|
-
stdio: 'ignore',
|
|
2140
|
-
windowsHide: platform.isWindows,
|
|
2141
|
-
env: { ...process.env, EVOLCORE_HOME: resolvePaths().root }
|
|
2142
|
-
});
|
|
2143
|
-
ecwebProc.unref();
|
|
2144
|
-
logger.info(`✓ ECWeb 已启动 (PID: ${ecwebProc.pid})`);
|
|
2145
|
-
onShutdown(() => {
|
|
2146
|
-
try {
|
|
2147
|
-
if (ecwebProc.pid)
|
|
2148
|
-
platform.killProcess(ecwebProc.pid, true);
|
|
2149
|
-
logger.info(`✓ ECWeb 已停止`);
|
|
2150
|
-
}
|
|
2151
|
-
catch { }
|
|
2152
|
-
});
|
|
2153
|
-
}
|
|
2154
|
-
catch (e) {
|
|
2155
|
-
logger.warn(`ECWeb 启动失败: ${e?.message || e}`);
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
else {
|
|
2160
|
-
// 正式安装时 ECWeb 是独立的全局 ec-web 包,由 ec start/restart 的
|
|
2161
|
-
// 启动链路管理;runtime 目录没有内嵌构建产物是正常状态。
|
|
2162
|
-
logger.debug(`ECWeb runtime entry absent (managed externally): ${ecwebEntry}`);
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
2253
|
// 控制 AID 接收 owner 指令:
|
|
2166
2254
|
// 1. /pair — ECWeb 配对码(文本快路径)
|
|
2167
2255
|
// 2. menu.* JSON — 路由到 cmdHandler.execMenuForControl(进程级 + 全量权限)
|
|
@@ -2176,22 +2264,20 @@ async function main() {
|
|
|
2176
2264
|
catch {
|
|
2177
2265
|
parsed = null;
|
|
2178
2266
|
}
|
|
2267
|
+
const menuResponseContext = () => controlReplyContext(opts, evolMenuResponseTransportMetadata());
|
|
2179
2268
|
if (bindService && parsed?.type === 'bind.request') {
|
|
2180
2269
|
const response = await bindService.handleRequest(parsed, opts.peerId);
|
|
2181
2270
|
if (response) {
|
|
2182
2271
|
// 用 sendStructured 直发 typed payload(payload.type='bind.response'),
|
|
2183
2272
|
// 不能用 sendMessage——它会把内容包成 {type:'text', text:...},App 无法识别。
|
|
2184
2273
|
// encrypted 跟随入站请求:bind.response 与 bind.request 的加密/明文对称。
|
|
2185
|
-
await controlChannel.sendStructured(opts.channelId, response,
|
|
2274
|
+
await controlChannel.sendStructured(opts.channelId, response, controlReplyContext(opts));
|
|
2186
2275
|
}
|
|
2187
2276
|
return;
|
|
2188
2277
|
}
|
|
2189
2278
|
const menuControl = parseMenuControl(text);
|
|
2190
2279
|
const isRoleMenu = menuControl.isMenu
|
|
2191
2280
|
&& (menuControl.name === 'role' || menuControl.request.cmd === '/role');
|
|
2192
|
-
const menuResponseContext = () => ({
|
|
2193
|
-
metadata: evolMenuResponseTransportMetadata(),
|
|
2194
|
-
});
|
|
2195
2281
|
if (menuControl.isMenu && !hasValidMenuId(menuControl)) {
|
|
2196
2282
|
logger.warn(`[ControlMenu] dropped malformed request without id type=${menuControl.type}`);
|
|
2197
2283
|
return;
|
|
@@ -2216,7 +2302,7 @@ async function main() {
|
|
|
2216
2302
|
else {
|
|
2217
2303
|
reply = 'ECWeb 未运行或暂不可达。请在主机运行 ec watch web 启动后重试。';
|
|
2218
2304
|
}
|
|
2219
|
-
await controlChannel.sendMessage(opts.channelId, reply);
|
|
2305
|
+
await controlChannel.sendMessage(opts.channelId, reply, controlReplyContext(opts));
|
|
2220
2306
|
return;
|
|
2221
2307
|
}
|
|
2222
2308
|
// menu.* JSON 路由:owner 已在上方校验,转交 execMenuForControl(fromControlChannel=true)
|
|
@@ -2235,6 +2321,16 @@ async function main() {
|
|
|
2235
2321
|
return;
|
|
2236
2322
|
}
|
|
2237
2323
|
const deduped = await controlMenuDeduper.execute([opts.channelId, opts.peerId, menuControl.id].join('\u001f'), menuPayloadFingerprint(menuControl.raw), () => cmdHandler.execMenuForControl(parsed, opts.peerId));
|
|
2324
|
+
if ('retry' in deduped) {
|
|
2325
|
+
if (deduped.replayed) {
|
|
2326
|
+
logger.warn(`[MenuControl] category=request-replay request=${menuControl.id}`
|
|
2327
|
+
+ ` sender=${opts.peerId} replay=true`);
|
|
2328
|
+
}
|
|
2329
|
+
if (deduped.retry) {
|
|
2330
|
+
logger.warn(`[MenuControl] category=request-retry request=${menuControl.id}`
|
|
2331
|
+
+ ` sender=${opts.peerId} retry=true`);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2238
2334
|
const response = 'conflict' in deduped
|
|
2239
2335
|
? menuFailure({ id: menuControl.id, ...(menuControl.name?.trim() ? { name: menuControl.name } : {}) }, { code: 'CONFLICT', message: 'Request ID was already used with a different payload' })
|
|
2240
2336
|
: deduped.value;
|
|
@@ -2244,7 +2340,7 @@ async function main() {
|
|
|
2244
2340
|
return;
|
|
2245
2341
|
}
|
|
2246
2342
|
// owner 发的其他内容:提示可用指令
|
|
2247
|
-
await controlChannel.sendMessage(opts.channelId, '可用指令:/pair(获取 ECWeb 登录配对码)');
|
|
2343
|
+
await controlChannel.sendMessage(opts.channelId, '可用指令:/pair(获取 ECWeb 登录配对码)', controlReplyContext(opts));
|
|
2248
2344
|
}
|
|
2249
2345
|
catch (e) {
|
|
2250
2346
|
logger.warn(`控制 AID 消息处理失败: ${e?.message || e}`);
|
|
@@ -2296,6 +2392,7 @@ async function main() {
|
|
|
2296
2392
|
channel: other.adapter.channelKey,
|
|
2297
2393
|
channelId: ownerId,
|
|
2298
2394
|
agentName: owningAgent?.aid || 'evolcore',
|
|
2395
|
+
delivery: { chatType: 'private' },
|
|
2299
2396
|
});
|
|
2300
2397
|
sendSystemPayload(other.adapter, envelope, {
|
|
2301
2398
|
kind: 'system.error',
|
|
@@ -2385,11 +2482,13 @@ async function main() {
|
|
|
2385
2482
|
channelType: session.channelType || parsedResumeKey?.type,
|
|
2386
2483
|
selfAID: resumeSelfAID,
|
|
2387
2484
|
channelId: session.channelId,
|
|
2485
|
+
groupId: session.chatType === 'group' ? (session.metadata?.groupId || session.channelId) : undefined,
|
|
2486
|
+
chatType: session.chatType === 'group' ? 'group' : 'private',
|
|
2388
2487
|
content: '服务已重启,请继续之前未完成的任务。',
|
|
2389
2488
|
timestamp: Date.now(),
|
|
2390
2489
|
peerId: '',
|
|
2391
2490
|
threadId: session.threadId || undefined,
|
|
2392
|
-
replyContext: session
|
|
2491
|
+
replyContext: replyContextFromSession(session),
|
|
2393
2492
|
};
|
|
2394
2493
|
// 清除状态后入队(processMessage 会重新标记)
|
|
2395
2494
|
sessionManager.clearProcessing(session.id);
|
|
@@ -2721,10 +2820,9 @@ async function main() {
|
|
|
2721
2820
|
if (!ch) {
|
|
2722
2821
|
return { ok: false, error: `AUN channel not found for ${params.aid}`, code: 'AUN_CHANNEL_NOT_FOUND' };
|
|
2723
2822
|
}
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
}
|
|
2823
|
+
// The IPC command already carries the caller-selected transport scope.
|
|
2824
|
+
// Never reclassify the target by parsing its AID string: a private AID may
|
|
2825
|
+
// look group-like and a group identifier may use a future format.
|
|
2728
2826
|
const encrypt = typeof params.encrypt === 'boolean'
|
|
2729
2827
|
? params.encrypt
|
|
2730
2828
|
: (typeof ch.getDefaultEncrypt === 'function' ? ch.getDefaultEncrypt() : true);
|
|
@@ -3180,7 +3278,7 @@ async function main() {
|
|
|
3180
3278
|
const agentName = handle?.name;
|
|
3181
3279
|
if (!agentName)
|
|
3182
3280
|
return [];
|
|
3183
|
-
return messageQueue.getQueueItemsByAgent(agentName);
|
|
3281
|
+
return messageQueue.getQueueItemsByAgent(agentName, { after: params.after, before: params.before });
|
|
3184
3282
|
});
|
|
3185
3283
|
ipcServer.setQueueActionExecutor(async (params) => {
|
|
3186
3284
|
const handle = agentRegistry.get(params.agent);
|
|
@@ -3261,8 +3359,12 @@ async function main() {
|
|
|
3261
3359
|
const handle = agentRegistry.get(authorization.aid);
|
|
3262
3360
|
if (!handle?.name)
|
|
3263
3361
|
return { ok: false, code: 'AGENT_NOT_FOUND', error: 'current Agent not found' };
|
|
3264
|
-
if (!params.action)
|
|
3265
|
-
return { ok: true, items: messageQueue.getQueueItemsByAgent(handle.name
|
|
3362
|
+
if (!params.action) {
|
|
3363
|
+
return { ok: true, items: messageQueue.getQueueItemsByAgent(handle.name, {
|
|
3364
|
+
after: params.after,
|
|
3365
|
+
before: params.before,
|
|
3366
|
+
}) };
|
|
3367
|
+
}
|
|
3266
3368
|
if (params.action === 'clear')
|
|
3267
3369
|
return { ok: true, cleared: messageQueue.clearByAgent(handle.name) };
|
|
3268
3370
|
if (params.action === 'cancel') {
|
package/dist/ipc.js
CHANGED
|
@@ -15,6 +15,7 @@ import { hashCurrentDelegatedCommand } from './core/auth/agent-delegation.js';
|
|
|
15
15
|
import { normalizeAunMentionEntries } from './aun/msg/mention-schema.js';
|
|
16
16
|
const isWindows = process.platform === 'win32';
|
|
17
17
|
const isNamedPipe = (p) => isWindows && p.startsWith('\\\\.\\pipe\\');
|
|
18
|
+
const finiteTimestamp = (value) => (typeof value === 'number' && Number.isFinite(value) ? value : undefined);
|
|
18
19
|
const LOCAL_CONTROL_COMMANDS = new Set([
|
|
19
20
|
'bind.begin',
|
|
20
21
|
'bind.status',
|
|
@@ -32,6 +33,12 @@ const LOCAL_CONTROL_COMMANDS = new Set([
|
|
|
32
33
|
'menu.exec',
|
|
33
34
|
'monitor-snapshot',
|
|
34
35
|
]);
|
|
36
|
+
function requiresLocalControlToken(cmd) {
|
|
37
|
+
// Managed bootstrap completion is authenticated by the session delegation
|
|
38
|
+
// ticket. A standalone CLI invocation still needs the daemon control token.
|
|
39
|
+
return LOCAL_CONTROL_COMMANDS.has(String(cmd.type ?? ''))
|
|
40
|
+
|| (cmd.type === 'evolagent.bootstrapComplete' && typeof cmd.sessionId !== 'string');
|
|
41
|
+
}
|
|
35
42
|
export function summarizeMonitorAgents(agents, aids) {
|
|
36
43
|
const connectedAgents = new Set(aids.filter(aid => aid.status === 'connected').map(aid => aid.agentName || aid.aid));
|
|
37
44
|
const enabledAgents = agents.filter(agent => agent.status !== 'disabled');
|
|
@@ -379,7 +386,7 @@ export class IpcServer {
|
|
|
379
386
|
}
|
|
380
387
|
}
|
|
381
388
|
async handleCommand(cmd) {
|
|
382
|
-
if (
|
|
389
|
+
if (requiresLocalControlToken(cmd) && !this.hasValidControlToken(cmd.controlToken)) {
|
|
383
390
|
return { ok: false, code: 'INVALID_CONTROL_TOKEN', error: 'valid local control token is required' };
|
|
384
391
|
}
|
|
385
392
|
switch (cmd.type) {
|
|
@@ -520,7 +527,11 @@ export class IpcServer {
|
|
|
520
527
|
// 纯查询
|
|
521
528
|
if (!this.queueSnapshotProvider)
|
|
522
529
|
return { ok: false, error: 'queue-snapshot not configured' };
|
|
523
|
-
return { ok: true, items: this.queueSnapshotProvider({
|
|
530
|
+
return { ok: true, items: this.queueSnapshotProvider({
|
|
531
|
+
agent: cmd.agent,
|
|
532
|
+
after: finiteTimestamp(cmd.after),
|
|
533
|
+
before: finiteTimestamp(cmd.before),
|
|
534
|
+
}) };
|
|
524
535
|
}
|
|
525
536
|
// 操作:clear / cancel / interrupt
|
|
526
537
|
if (!this.queueActionExecutor)
|
|
@@ -546,6 +557,8 @@ export class IpcServer {
|
|
|
546
557
|
action: cmd.action,
|
|
547
558
|
messageId: typeof cmd.messageId === 'string' ? cmd.messageId : undefined,
|
|
548
559
|
sessionKey: typeof cmd.sessionKey === 'string' ? cmd.sessionKey : undefined,
|
|
560
|
+
after: finiteTimestamp(cmd.after),
|
|
561
|
+
before: finiteTimestamp(cmd.before),
|
|
549
562
|
sessionId: cmd.sessionId,
|
|
550
563
|
delegationToken: typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined,
|
|
551
564
|
delegationCommandHash: typeof cmd.delegationCommandHash === 'string' ? cmd.delegationCommandHash : undefined,
|
|
@@ -1037,7 +1050,7 @@ export class IpcServer {
|
|
|
1037
1050
|
export function ipcQuery(socketPath, cmd, timeoutMs = 3000) {
|
|
1038
1051
|
let authenticatedCmd = cmd;
|
|
1039
1052
|
if (!process.env.EVOLCORE_SESSION_ID
|
|
1040
|
-
&&
|
|
1053
|
+
&& requiresLocalControlToken(cmd)
|
|
1041
1054
|
&& typeof cmd.controlToken !== 'string') {
|
|
1042
1055
|
try {
|
|
1043
1056
|
const controlToken = fs.readFileSync(resolvePaths().controlToken, 'utf8').trim();
|
package/dist/paths.js
CHANGED
|
@@ -149,6 +149,9 @@ export function daemonControlDir() {
|
|
|
149
149
|
export function daemonQueuePath() {
|
|
150
150
|
return path.join(daemonDataDir(), 'message-queue.json');
|
|
151
151
|
}
|
|
152
|
+
export function daemonMessageDedupPath() {
|
|
153
|
+
return path.join(daemonDataDir(), 'message-dedup.json');
|
|
154
|
+
}
|
|
152
155
|
export function channelStateDir(channelKey) {
|
|
153
156
|
if (!channelKey || channelKey === '.' || channelKey === '..') {
|
|
154
157
|
throw new Error('channelKey is required');
|