evolcore 0.0.31 → 0.0.32
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 +11 -0
- package/dist/agents/codex-runner.js +28 -5
- package/dist/agents/ecagent-runner.js +4 -0
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +10 -135
- package/dist/cli/agent-command.js +6 -7
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +15 -69
- package/dist/cli/aun-commands.js +149 -5
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +1 -1
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +15 -5
- package/dist/cli/memory-command.js +85 -11
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +46 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/skill-command.js +9 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +15 -0
- package/dist/cli/trigger-command.js +73 -49
- package/dist/config/builtin-roles.js +8 -7
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +17 -1
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-catalog.js +11 -3
- package/dist/core/command/command-handler.js +164 -21
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/ipc-registration.js +71 -7
- package/dist/core/message/aun-ipc-sender.js +48 -4
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/response-engine.js +30 -2
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/index.js +2 -2
- package/dist/ipc.js +146 -8
- package/dist/trigger/authorization.js +2 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/script-sandbox.js +58 -77
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/evolcore/INDEX.md +2 -2
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/06-channel.md +7 -1
- package/kits/templates/system-fragments/commands.md +1 -1
- package/package.json +1 -1
package/dist/channels/aun.js
CHANGED
|
@@ -5,7 +5,6 @@ import { performance } from 'node:perf_hooks';
|
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import os from 'os';
|
|
8
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
|
9
8
|
import { logger, localTimestamp } from '../utils/logger.js';
|
|
10
9
|
import { LogWriter } from '../utils/log-writer.js';
|
|
11
10
|
import { middleOutputModePolicy, resolveShowActivities, showActivitiesPolicy } from '../core/channel-loader.js';
|
|
@@ -19,7 +18,7 @@ import { chatDirPath } from '../core/session/session-fs-store.js';
|
|
|
19
18
|
import { readTopicLabel, readTopicStatus } from '../core/session/session-mapper.js';
|
|
20
19
|
import { appendHintAddDetailed, appendHintRemoveDetailed, appendHintPromoteDetailed, parseInjectRequest, peekHints, withHintTargetLock } from '../core/message/pending-hints.js';
|
|
21
20
|
import { appendAidLifecycle } from '../aun/aid/identity.js';
|
|
22
|
-
import {
|
|
21
|
+
import { getAidStore, loadClient, SLOT } from '../aun/aid/store.js';
|
|
23
22
|
import { MAX_AUN_ATTACHMENT_SIZE, uploadBufferAndBuildPayload, uploadFileAndBuildPayload } from '../aun/msg/upload.js';
|
|
24
23
|
import { loadAgent } from '../config-store.js';
|
|
25
24
|
import { resolveAgentLifecycle } from '../config/lifecycle.js';
|
|
@@ -653,7 +652,6 @@ export class AUNChannel {
|
|
|
653
652
|
return this.managedMenuClient.request(options);
|
|
654
653
|
}
|
|
655
654
|
client = null;
|
|
656
|
-
localSenderInstallation;
|
|
657
655
|
store = null;
|
|
658
656
|
/** 实际连接的网关 URL(来自 authenticate() 返回值 / connection.state 事件),替代旧 (client as any)._gatewayUrl。 */
|
|
659
657
|
gatewayUrl = '';
|
|
@@ -1343,7 +1341,7 @@ export class AUNChannel {
|
|
|
1343
1341
|
// boundary while the command handler uses /mention internally.
|
|
1344
1342
|
return stripped.replace(/^\/mentionmode(?=\s|$)/, '/mention');
|
|
1345
1343
|
}
|
|
1346
|
-
parsePayloadMentionsOrReject(payload, context, messageId
|
|
1344
|
+
parsePayloadMentionsOrReject(payload, context, messageId) {
|
|
1347
1345
|
const raw = payload && typeof payload === 'object' && !Array.isArray(payload)
|
|
1348
1346
|
? payload.mentions
|
|
1349
1347
|
: undefined;
|
|
@@ -1351,7 +1349,6 @@ export class AUNChannel {
|
|
|
1351
1349
|
return normalizeAunMentionEntries(raw);
|
|
1352
1350
|
}
|
|
1353
1351
|
catch (error) {
|
|
1354
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
1355
1352
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1356
1353
|
const code = error?.code ?? 'INVALID_MENTION_SCHEMA';
|
|
1357
1354
|
logger.error(`${this.logPrefix()} Dropped ${context}: invalid payload.mentions (${detail}) code=${code} mid=${messageId}`);
|
|
@@ -1452,12 +1449,9 @@ export class AUNChannel {
|
|
|
1452
1449
|
else {
|
|
1453
1450
|
logger.debug(`${this.logPrefix()} Duplicate inbound message dropped: namespace=${namespace} mid=${messageId} seq=${seq ?? 'unknown'}`);
|
|
1454
1451
|
}
|
|
1455
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
1456
1452
|
return false;
|
|
1457
1453
|
}
|
|
1458
1454
|
this.inboundSeenMessages.set(dedupeKey, { seenAt: Date.now(), seq });
|
|
1459
|
-
if (seq !== undefined)
|
|
1460
|
-
this.messageSeqMap.set(messageId, seq);
|
|
1461
1455
|
this.appendInboundDedupe(dedupeKey, messageId, kind, seq);
|
|
1462
1456
|
setTimeout(() => this.inboundSeenMessages.delete(dedupeKey), AUN_INBOUND_DEDUP_TTL_MS);
|
|
1463
1457
|
return true;
|
|
@@ -1524,12 +1518,6 @@ export class AUNChannel {
|
|
|
1524
1518
|
logger.warn(`${this.logPrefix()} Failed to compact inbound dedup: ${error instanceof Error ? error.message : String(error)}`);
|
|
1525
1519
|
}
|
|
1526
1520
|
}
|
|
1527
|
-
acknowledgeImmediately(messageId, _seq) {
|
|
1528
|
-
// SDK internally manages seq tracking and ack — do not call message.ack RPC directly,
|
|
1529
|
-
// as it corrupts the SDK's seqTracker state and breaks V2 e2ee message pull.
|
|
1530
|
-
if (messageId)
|
|
1531
|
-
this.messageSeqMap.delete(messageId);
|
|
1532
|
-
}
|
|
1533
1521
|
shouldEncrypt(_peerId) {
|
|
1534
1522
|
return this.config.defaultEncrypt ?? true;
|
|
1535
1523
|
}
|
|
@@ -1543,7 +1531,7 @@ export class AUNChannel {
|
|
|
1543
1531
|
/**
|
|
1544
1532
|
* Inbound application dedupe. The AUN SDK may redeliver the same message
|
|
1545
1533
|
* with a different transport sequence, so message_id is the identity and
|
|
1546
|
-
* seq is only retained for
|
|
1534
|
+
* seq is only retained for ordering and conflict diagnostics. Claiming happens at
|
|
1547
1535
|
* the event handler boundary, before payload/slash/mention parsing.
|
|
1548
1536
|
*/
|
|
1549
1537
|
inboundSeenMessages = new Map();
|
|
@@ -1551,7 +1539,6 @@ export class AUNChannel {
|
|
|
1551
1539
|
groupNameCache = new Map(); // groupId → 群显示名(进程内缓存,群名极少变)
|
|
1552
1540
|
peerInfoCache = new Map();
|
|
1553
1541
|
peerInfoRevision = 0;
|
|
1554
|
-
messageSeqMap = new Map(); // messageId → seq (for ack/diagnostics)
|
|
1555
1542
|
sentCount = new Map(); // "channelId\0threadId" → 本轮已发消息计数(seqInTurn/turnMessageCount 用)
|
|
1556
1543
|
peerE2ee = new Map();
|
|
1557
1544
|
static E2EE_PROBE_TTL = 10 * 60 * 1000; // 10min
|
|
@@ -1737,27 +1724,6 @@ export class AUNChannel {
|
|
|
1737
1724
|
this.initInProgress = false;
|
|
1738
1725
|
}
|
|
1739
1726
|
}
|
|
1740
|
-
/** Optional local compatibility code is never required by a clean checkout or npm install. */
|
|
1741
|
-
async loadLocalSenderInstallation(client) {
|
|
1742
|
-
this.localSenderInstallation = undefined;
|
|
1743
|
-
const currentFile = fileURLToPath(import.meta.url);
|
|
1744
|
-
const modulePath = path.join(path.dirname(currentFile), '..', 'aun', `sender-installation${path.extname(currentFile)}`);
|
|
1745
|
-
if (!fs.existsSync(modulePath))
|
|
1746
|
-
return;
|
|
1747
|
-
try {
|
|
1748
|
-
// Use a runtime URL so TypeScript can build when the local file is absent.
|
|
1749
|
-
const extension = await import(pathToFileURL(modulePath).href);
|
|
1750
|
-
if (typeof extension.enableAunSenderInstallation !== 'function'
|
|
1751
|
-
|| typeof extension.aunSenderInstallation !== 'function') {
|
|
1752
|
-
throw new Error('Invalid local sender installation module');
|
|
1753
|
-
}
|
|
1754
|
-
extension.enableAunSenderInstallation(client);
|
|
1755
|
-
this.localSenderInstallation = extension;
|
|
1756
|
-
}
|
|
1757
|
-
catch (error) {
|
|
1758
|
-
logger.warn(`${this.logPrefix()} Optional local sender installation disabled: ${error instanceof Error ? error.message : String(error)}`);
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
1727
|
async _initClientInner() {
|
|
1762
1728
|
this.observerGroupMembers.clear();
|
|
1763
1729
|
for (const groupId of new Set([
|
|
@@ -1805,9 +1771,6 @@ export class AUNChannel {
|
|
|
1805
1771
|
});
|
|
1806
1772
|
this.store = store;
|
|
1807
1773
|
const client = await loadClient(store, aidName);
|
|
1808
|
-
enableFullGroupPullPagination(client);
|
|
1809
|
-
enableReliableMessageDelivery(client);
|
|
1810
|
-
await this.loadLocalSenderInstallation(client);
|
|
1811
1774
|
this.client = client;
|
|
1812
1775
|
// A reconnect replaces the SDK client. Late events from the retired
|
|
1813
1776
|
// instance must not mutate the new instance's health or message state.
|
|
@@ -1939,7 +1902,7 @@ export class AUNChannel {
|
|
|
1939
1902
|
client.on('message.recalled', (data) => {
|
|
1940
1903
|
if (!isCurrentClient())
|
|
1941
1904
|
return;
|
|
1942
|
-
this.handleMessageRecalled(data
|
|
1905
|
+
this.handleMessageRecalled(data);
|
|
1943
1906
|
});
|
|
1944
1907
|
client.on('message.undecryptable', (data) => {
|
|
1945
1908
|
if (!isCurrentClient())
|
|
@@ -2017,13 +1980,14 @@ export class AUNChannel {
|
|
|
2017
1980
|
// max_attempts=0 = 无限重试(与 Go/Python 对齐),交由 SDK 自己跑指数退避
|
|
2018
1981
|
// initial_delay=1s,max_delay=300s(5min 封顶)
|
|
2019
1982
|
auto_reconnect: true,
|
|
1983
|
+
background_sync: true,
|
|
2020
1984
|
retry_max_attempts: 0,
|
|
2021
1985
|
retry_initial_delay: 1.0,
|
|
2022
1986
|
retry_max_delay: 300.0,
|
|
2023
1987
|
});
|
|
2024
1988
|
this.trace('OUT', 'client.connect.ok', { aid: client.aid });
|
|
2025
1989
|
this._aid = this.client.aid ?? undefined;
|
|
2026
|
-
const deviceId =
|
|
1990
|
+
const deviceId = client.currentAid?.deviceId ?? '';
|
|
2027
1991
|
this._chatId = this._aid ? `${this._aid}:${deviceId}:` : '';
|
|
2028
1992
|
// 控制 AID 也有标准 host agent.md。发布在后台执行,短暂的 Name
|
|
2029
1993
|
// Service/Gateway 故障不能把控制通道判定为连接失败。
|
|
@@ -2056,25 +2020,6 @@ export class AUNChannel {
|
|
|
2056
2020
|
logger.warn(`${this.logPrefix()} Group invitation recovery failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2057
2021
|
});
|
|
2058
2022
|
}
|
|
2059
|
-
// AUN seq_tracker is transport-scoped, while this channel's durable
|
|
2060
|
-
// dedup log is application-scoped. A diagnostic consumer can advance
|
|
2061
|
-
// the former without the application having seen those messages. On a
|
|
2062
|
-
// reconnect, repair only the in-memory P2P cursor to the last message
|
|
2063
|
-
// the application actually claimed, then force a Forward pull. The SDK
|
|
2064
|
-
// persists cursors monotonically, so this does not rewrite SQLite and
|
|
2065
|
-
// the normal pull will restore the high watermark after delivery.
|
|
2066
|
-
this.scheduleInboundP2PCursorRepair(client, isCurrentClient);
|
|
2067
|
-
// Workaround: SDK e2ee uses _identity.cert for sender_cert_fingerprint;
|
|
2068
|
-
// if cert is missing, it falls back to public key SPKI fingerprint which
|
|
2069
|
-
// causes peer cert lookup failures. Backfill from keystore if needed.
|
|
2070
|
-
const clientAny = this.client;
|
|
2071
|
-
if (clientAny._identity && !clientAny._identity.cert) {
|
|
2072
|
-
const cert = clientAny._keystore?.loadCert?.(aidName);
|
|
2073
|
-
if (cert) {
|
|
2074
|
-
clientAny._identity.cert = cert;
|
|
2075
|
-
logger.info(`${this.logPrefix()} Backfilled identity.cert from keystore for e2ee fingerprint`);
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
2023
|
logger.info(`${this.logPrefix()} Connected as ${this._aid}`);
|
|
2079
2024
|
appendAidEvent({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.gatewayUrl });
|
|
2080
2025
|
appendAidLifecycle({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.gatewayUrl });
|
|
@@ -2161,47 +2106,7 @@ export class AUNChannel {
|
|
|
2161
2106
|
const aid = this.config.aid.replace(/^@/, '');
|
|
2162
2107
|
return bindPostBootstrapWelcomeOutboxSession(aid, sessionId, owner);
|
|
2163
2108
|
}
|
|
2164
|
-
|
|
2165
|
-
const tracker = client?._seqTracker;
|
|
2166
|
-
const repair = tracker?.repairContiguousSeq;
|
|
2167
|
-
const pull = client?._pullV2;
|
|
2168
|
-
if (typeof repair !== 'function' || typeof pull !== 'function')
|
|
2169
|
-
return;
|
|
2170
|
-
if (this.inboundP2PCursorRepairTimer)
|
|
2171
|
-
clearTimeout(this.inboundP2PCursorRepairTimer);
|
|
2172
|
-
const ns = `p2p:${this.config.aid}`;
|
|
2173
|
-
let appSeq = 0;
|
|
2174
|
-
for (const [key, value] of this.inboundSeenMessages) {
|
|
2175
|
-
// Group sequence spaces are independent from the P2P space.
|
|
2176
|
-
if (!key.includes(':aun:private'))
|
|
2177
|
-
continue;
|
|
2178
|
-
const seq = Number(value.seq);
|
|
2179
|
-
if (Number.isSafeInteger(seq) && seq > appSeq)
|
|
2180
|
-
appSeq = seq;
|
|
2181
|
-
}
|
|
2182
|
-
if (appSeq <= 0)
|
|
2183
|
-
return;
|
|
2184
|
-
this.inboundP2PCursorRepairTimer = setTimeout(() => {
|
|
2185
|
-
this.inboundP2PCursorRepairTimer = null;
|
|
2186
|
-
if (!isCurrentClient() || !this.connected)
|
|
2187
|
-
return;
|
|
2188
|
-
const transportSeq = Number(tracker.getContiguousSeq?.(ns) ?? 0);
|
|
2189
|
-
if (!Number.isSafeInteger(transportSeq) || transportSeq <= appSeq + 1)
|
|
2190
|
-
return;
|
|
2191
|
-
try {
|
|
2192
|
-
repair.call(tracker, ns, appSeq);
|
|
2193
|
-
logger.warn(`${this.logPrefix()} Rewinding in-memory P2P cursor for application recovery: transport=${transportSeq}, app=${appSeq}`);
|
|
2194
|
-
Promise.resolve(pull.call(client, appSeq, 50, { force: true }))
|
|
2195
|
-
.then(() => logger.info(`${this.logPrefix()} Replayed P2P messages after cursor mismatch: after_seq=${appSeq}`))
|
|
2196
|
-
.catch((error) => logger.warn(`${this.logPrefix()} P2P cursor recovery pull failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
2197
|
-
}
|
|
2198
|
-
catch (error) {
|
|
2199
|
-
logger.warn(`${this.logPrefix()} P2P cursor repair failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2200
|
-
}
|
|
2201
|
-
}, 250);
|
|
2202
|
-
}
|
|
2203
|
-
inboundP2PCursorRepairTimer = null;
|
|
2204
|
-
handleMessageRecalled(data, client, isCurrentClient) {
|
|
2109
|
+
handleMessageRecalled(data) {
|
|
2205
2110
|
this.trace('IN', 'message.recalled', data);
|
|
2206
2111
|
if (data && typeof data === 'object') {
|
|
2207
2112
|
const ids = data.message_ids;
|
|
@@ -2214,9 +2119,6 @@ export class AUNChannel {
|
|
|
2214
2119
|
}
|
|
2215
2120
|
}
|
|
2216
2121
|
}
|
|
2217
|
-
// A recall tombstone may arrive at a high transport sequence and advance
|
|
2218
|
-
// the SDK cursor past messages that were never delivered to the app.
|
|
2219
|
-
this.scheduleInboundP2PCursorRepair(client, isCurrentClient);
|
|
2220
2122
|
}
|
|
2221
2123
|
pendingPostBootstrapWelcomeOwners() {
|
|
2222
2124
|
return pendingPostBootstrapWelcomeOwners(this.config.aid);
|
|
@@ -2525,7 +2427,6 @@ export class AUNChannel {
|
|
|
2525
2427
|
const env = (msg.envelope && typeof msg.envelope === 'object') ? msg.envelope : {};
|
|
2526
2428
|
const fromAid = typeof env.from === 'string' ? env.from.trim() : '';
|
|
2527
2429
|
if (!messageId || !fromAid) {
|
|
2528
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2529
2430
|
const now = Date.now();
|
|
2530
2431
|
if (now - this.invalidInboundEnvelopeLastLogAt >= 60_000) {
|
|
2531
2432
|
this.invalidInboundEnvelopeLastLogAt = now;
|
|
@@ -2541,15 +2442,13 @@ export class AUNChannel {
|
|
|
2541
2442
|
const protectedHeaders = verifiedProtectedHeaders(msg, env);
|
|
2542
2443
|
const payload = msg.payload ?? '';
|
|
2543
2444
|
if (this.managedMenuClient.accept(fromAid, payload, !!env.encrypted)) {
|
|
2544
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2545
2445
|
return;
|
|
2546
2446
|
}
|
|
2547
2447
|
if (payloadTypeForObserver(msg) === 'observer.forward') {
|
|
2548
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2549
2448
|
logger.debug(`${this.logPrefix()} P2P dropped observer.forward control envelope: mid=${messageId}`);
|
|
2550
2449
|
return;
|
|
2551
2450
|
}
|
|
2552
|
-
const mentions = this.parsePayloadMentionsOrReject(payload, 'p2p.inbound', messageId
|
|
2451
|
+
const mentions = this.parsePayloadMentionsOrReject(payload, 'p2p.inbound', messageId);
|
|
2553
2452
|
if (!mentions)
|
|
2554
2453
|
return;
|
|
2555
2454
|
const causationRef = payload && typeof payload === 'object' && typeof payload._evolcore_causation_ref === 'string'
|
|
@@ -2570,7 +2469,6 @@ export class AUNChannel {
|
|
|
2570
2469
|
const inboundType = (payload && typeof payload === 'object') ? payload.type : undefined;
|
|
2571
2470
|
// 终态错误只作为展示信号,不能进入 Agent,也不能被 observer 再次传播。
|
|
2572
2471
|
if (inboundType === 'error') {
|
|
2573
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2574
2472
|
logger.info(`${this.logPrefix()} P2P dropped terminal error: from=${fromAid || 'unknown'} mid=${messageId}`);
|
|
2575
2473
|
return;
|
|
2576
2474
|
}
|
|
@@ -2582,14 +2480,12 @@ export class AUNChannel {
|
|
|
2582
2480
|
void this.forwardInbound(msg);
|
|
2583
2481
|
}
|
|
2584
2482
|
if (inboundType === 'observer.inject.status' || inboundType === 'observer.inject.ack') {
|
|
2585
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2586
2483
|
return;
|
|
2587
2484
|
}
|
|
2588
2485
|
// 回声过滤:自己发出的消息会被 gateway fanout 回来,
|
|
2589
2486
|
// 只有 from_aid == self 且 chat_id 不匹配时才丢弃(说明是其它实例发的)
|
|
2590
2487
|
const msgChatId = typeof payload === 'object' && payload !== null && payload.chat_id;
|
|
2591
2488
|
if (this._aid && fromAid === this._aid && (!msgChatId || !this._chatId || msgChatId !== this._chatId)) {
|
|
2592
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2593
2489
|
logger.debug(`${this.logPrefix()} P2P dropped: echo from self (from=${fromAid} mid=${messageId})`);
|
|
2594
2490
|
return;
|
|
2595
2491
|
}
|
|
@@ -2632,18 +2528,14 @@ export class AUNChannel {
|
|
|
2632
2528
|
if (p2pPayloadType.startsWith('menu.')
|
|
2633
2529
|
|| p2pPayloadType === AUNChannel.CONTACT_REQUEST_QUERY_TYPE
|
|
2634
2530
|
|| p2pPayloadType === AUNChannel.CONTACT_REQUEST_SUBMIT_TYPE) {
|
|
2635
|
-
const installation = p2pPayloadType.startsWith('menu.')
|
|
2636
|
-
? this.localSenderInstallation?.aunSenderInstallation(msg) : undefined;
|
|
2637
2531
|
const peerDeviceId = p2pPayloadType.startsWith('menu.')
|
|
2638
2532
|
? menuSenderDeviceId(msg.sender_device_id) : undefined;
|
|
2639
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2640
2533
|
this.appendInboundPayloadJsonl(chatId, fromAid, messageId, msgEncrypted, false, logDescriptor, threadId, receivedAt, seq);
|
|
2641
2534
|
this.dispatchMessage({
|
|
2642
2535
|
channelId: chatId, userId: fromAid,
|
|
2643
2536
|
text: JSON.stringify(payload),
|
|
2644
2537
|
chatType: 'private', messageId, seq, receivedAt, receivedAtMono, gatewaySeq: seq,
|
|
2645
2538
|
peerDeviceId,
|
|
2646
|
-
peerSlotId: installation?.slotId,
|
|
2647
2539
|
threadId,
|
|
2648
2540
|
peerName: displayName || undefined,
|
|
2649
2541
|
peerType: peerIdentity.type,
|
|
@@ -2669,7 +2561,6 @@ export class AUNChannel {
|
|
|
2669
2561
|
// observer.inject:owner 插话。鉴权 from∈owners 后,以 target.channel_id 选 agent↔对端 会话,
|
|
2670
2562
|
// observer 插话(v0.3):只落盘到 pending-hints,不进 Agent、不回 owner。详见 docs/observer-insert-design.md。
|
|
2671
2563
|
if (p2pPayloadType === AUNChannel.INJECT_REQUEST_TYPE) {
|
|
2672
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2673
2564
|
void Promise.resolve(this.handleObserverInject(fromAid, payload, displayName, peerIdentity.type)).catch(error => {
|
|
2674
2565
|
logger.error(`${this.logPrefix()} observer.inject failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2675
2566
|
});
|
|
@@ -2679,7 +2570,6 @@ export class AUNChannel {
|
|
|
2679
2570
|
// 由控制 AID 的 onMessage 处理器(BindService.handleRequest)解析并回 bind.response。
|
|
2680
2571
|
// 透传 encrypted:bind.response 须与请求的加密/明文对称(见 onMessage 处理)。
|
|
2681
2572
|
if (p2pPayloadType === AUNChannel.BIND_REQUEST_TYPE) {
|
|
2682
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2683
2573
|
this.appendInboundPayloadJsonl(chatId, fromAid, messageId, msgEncrypted, false, logDescriptor, threadId, receivedAt, seq);
|
|
2684
2574
|
this.dispatchMessage({
|
|
2685
2575
|
channelId: chatId, userId: fromAid,
|
|
@@ -2700,7 +2590,6 @@ export class AUNChannel {
|
|
|
2700
2590
|
}
|
|
2701
2591
|
// payload 类型白名单:信号类消息(status / event / thought 等)不进 Agent
|
|
2702
2592
|
if (p2pPayloadType && !AUNChannel.PROACTIVE_ALLOW_TYPES.has(p2pPayloadType)) {
|
|
2703
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2704
2593
|
this.appendInboundPayloadJsonl(chatId, fromAid, messageId, msgEncrypted, false, logDescriptor, threadId, receivedAt, seq);
|
|
2705
2594
|
logger.info(`${this.logPrefix()} P2P dropped (type deny): type=${p2pPayloadType} from=${shortAid}(${displayName}) mid=${messageId}`);
|
|
2706
2595
|
return;
|
|
@@ -2758,11 +2647,10 @@ export class AUNChannel {
|
|
|
2758
2647
|
const payload = msg.payload ?? '';
|
|
2759
2648
|
const inboundType = (payload && typeof payload === 'object') ? payload.type : undefined;
|
|
2760
2649
|
if (inboundType === 'observer.forward' || (typeof inboundType === 'string' && inboundType.startsWith('observer.inject'))) {
|
|
2761
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2762
2650
|
logger.debug(`${this.logPrefix()} Group dropped observer control envelope: mid=${messageId}`);
|
|
2763
2651
|
return;
|
|
2764
2652
|
}
|
|
2765
|
-
const payloadMentionEntries = this.parsePayloadMentionsOrReject(payload, 'group.inbound', messageId
|
|
2653
|
+
const payloadMentionEntries = this.parsePayloadMentionsOrReject(payload, 'group.inbound', messageId);
|
|
2766
2654
|
if (!payloadMentionEntries)
|
|
2767
2655
|
return;
|
|
2768
2656
|
const payloadMentionAids = mentionEntryAids(payloadMentionEntries);
|
|
@@ -2774,7 +2662,6 @@ export class AUNChannel {
|
|
|
2774
2662
|
: undefined;
|
|
2775
2663
|
// 终态错误只作为展示信号,不能进入 Agent,也不能被 observer 再次传播。
|
|
2776
2664
|
if (inboundType === 'error') {
|
|
2777
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2778
2665
|
logger.info(`${this.logPrefix()} Group dropped terminal error: group=${groupId || 'unknown'} sender=${senderAid || 'unknown'} mid=${messageId}`);
|
|
2779
2666
|
return;
|
|
2780
2667
|
}
|
|
@@ -2783,7 +2670,6 @@ export class AUNChannel {
|
|
|
2783
2670
|
void this.forwardInbound(msg);
|
|
2784
2671
|
logger.debug(`${this.logPrefix()}[DIAG-GRP] full_msg=${JSON.stringify(msg).substring(0, 500)}`);
|
|
2785
2672
|
if (!groupId || !senderAid) {
|
|
2786
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2787
2673
|
logger.debug(`${this.logPrefix()} Group dropped: missing groupId or senderAid (mid=${messageId})`);
|
|
2788
2674
|
return;
|
|
2789
2675
|
}
|
|
@@ -2795,7 +2681,6 @@ export class AUNChannel {
|
|
|
2795
2681
|
&& typeof handoffMarker === 'string'
|
|
2796
2682
|
&& /^h-[A-Za-z0-9._-]+$/.test(handoffMarker);
|
|
2797
2683
|
if (this._aid && senderAid === this._aid && !isOwnHandoff) {
|
|
2798
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2799
2684
|
logger.debug(`${this.logPrefix()} Group dropped: own message (group=${groupId} mid=${messageId})`);
|
|
2800
2685
|
return;
|
|
2801
2686
|
}
|
|
@@ -2804,7 +2689,6 @@ export class AUNChannel {
|
|
|
2804
2689
|
const firstLineFast = text.split('\n')[0] || '';
|
|
2805
2690
|
const hasEvolCoreTrace = /\[EvolCore\.(receive|reply|agent)\]/.test(text);
|
|
2806
2691
|
if (/echo/i.test(firstLineFast) && firstLineFast.trim().length <= 10 && !hasEvolCoreTrace) {
|
|
2807
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2808
2692
|
const msgEncryptedFast = !!env.encrypted;
|
|
2809
2693
|
const msgChatmodeFast = (payload && typeof payload === 'object') ? payload.chatmode : undefined;
|
|
2810
2694
|
const peerInfo = this.peerInfoCached(senderAid);
|
|
@@ -2843,12 +2727,10 @@ export class AUNChannel {
|
|
|
2843
2727
|
const payloadType = typeof payloadObj?.type === 'string' ? payloadObj.type : '';
|
|
2844
2728
|
// Menu control requests are private-only, including token issuance.
|
|
2845
2729
|
if (payloadType.startsWith('menu.')) {
|
|
2846
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2847
2730
|
logger.debug(`${this.logPrefix()} Group Menu dropped: code=MENU_PRIVATE_ONLY mid=${messageId}`);
|
|
2848
2731
|
return;
|
|
2849
2732
|
}
|
|
2850
2733
|
if (payloadType && !AUNChannel.PROACTIVE_ALLOW_TYPES.has(payloadType)) {
|
|
2851
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2852
2734
|
this.appendInboundPayloadJsonl(groupId, senderAid, messageId, !!env.encrypted, true, logDescriptor, threadId, receivedAt, seq);
|
|
2853
2735
|
logger.info(`${this.logPrefix()} Group dropped (type deny): type=${payloadType} group=${groupId} sender=${senderAid} mid=${messageId}`);
|
|
2854
2736
|
return;
|
|
@@ -2906,7 +2788,6 @@ export class AUNChannel {
|
|
|
2906
2788
|
}
|
|
2907
2789
|
else if (/echo/i.test(firstLineGroup) && hasEvolCoreTraceGroup) {
|
|
2908
2790
|
// 回声炸弹:已被任何 EvolCore 节点 trace 过的 echo,直接丢弃
|
|
2909
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2910
2791
|
logger.info(`${this.logPrefix()} Group dropped: echo bomb (already-traced group=${groupId} sender=${senderAid} mid=${messageId})`);
|
|
2911
2792
|
return;
|
|
2912
2793
|
}
|
|
@@ -2934,7 +2815,6 @@ export class AUNChannel {
|
|
|
2934
2815
|
logger.warn(`${this.logPrefix()} Deferred group message was not recorded; awaiting redelivery: ${error}`);
|
|
2935
2816
|
return;
|
|
2936
2817
|
}
|
|
2937
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2938
2818
|
const dropReason = commandTargetsAnotherAgent ? 'command-targeted-other-agent' : 'unmentioned';
|
|
2939
2819
|
logger.info(`${this.logPrefix()} Group dropped: ${dropReason} (group=${groupId} sender=${senderAid} mid=${messageId} mentionMode=${mentionMode} slashRequireMentions=${groupSlashRequireMentions} isCommand=${isCommandMsg} commandMentionAids=${JSON.stringify(commandMentionAids)} textPreview=${JSON.stringify(text.slice(0, 80))})`);
|
|
2940
2820
|
return;
|
|
@@ -2950,7 +2830,6 @@ export class AUNChannel {
|
|
|
2950
2830
|
const hasAttachments = rawAttachments.length > 0;
|
|
2951
2831
|
// Allow through if there's text OR attachments; both-empty messages are silently dropped
|
|
2952
2832
|
if (!strippedText && !hasAttachments) {
|
|
2953
|
-
this.acknowledgeImmediately(messageId, seq);
|
|
2954
2833
|
logger.debug(`${this.logPrefix()} Group dropped: empty text and no attachments (group=${groupId} sender=${senderAid} mid=${messageId})`);
|
|
2955
2834
|
return;
|
|
2956
2835
|
}
|
|
@@ -6022,11 +5901,7 @@ export class AUNChannel {
|
|
|
6022
5901
|
logger.warn(`${this.logPrefix()} Repaired bootstrap outbox route to private Owner delivery: entry=${entry.id} owner=${owner}`);
|
|
6023
5902
|
}
|
|
6024
5903
|
}
|
|
6025
|
-
acknowledge(
|
|
6026
|
-
// Gateway auto-delivery-ack is sufficient; skip explicit message.ack RPC
|
|
6027
|
-
// to avoid duplicate "已送达" at the sender CLI
|
|
6028
|
-
this.messageSeqMap.delete(messageId);
|
|
6029
|
-
}
|
|
5904
|
+
acknowledge(_messageId) { }
|
|
6030
5905
|
sendProcessingStatus(channelId, status, sessionId, taskId, context, extraMeta) {
|
|
6031
5906
|
let delivery;
|
|
6032
5907
|
try {
|
|
@@ -148,8 +148,7 @@ Options:
|
|
|
148
148
|
process.exitCode = 1;
|
|
149
149
|
return;
|
|
150
150
|
}
|
|
151
|
-
const
|
|
152
|
-
const result = await runManagedAgentOperation(managedArgs);
|
|
151
|
+
const result = await runManagedAgentOperation(args);
|
|
153
152
|
if (!result.ok) {
|
|
154
153
|
if (formatJson)
|
|
155
154
|
console.log(JSON.stringify(result));
|
|
@@ -671,7 +670,7 @@ Options:
|
|
|
671
670
|
process.exitCode = 1;
|
|
672
671
|
return;
|
|
673
672
|
}
|
|
674
|
-
const result = await agentPersona(aid, { text, file });
|
|
673
|
+
const result = await agentPersona(aid, { text, file, argv: args });
|
|
675
674
|
if (!result.ok) {
|
|
676
675
|
if (formatJson)
|
|
677
676
|
console.log(JSON.stringify(result));
|
|
@@ -720,7 +719,7 @@ Options:
|
|
|
720
719
|
process.exitCode = 1;
|
|
721
720
|
return;
|
|
722
721
|
}
|
|
723
|
-
const result = await agentWelcome(aid, { text });
|
|
722
|
+
const result = await agentWelcome(aid, { text, argv: args });
|
|
724
723
|
if (!result.ok) {
|
|
725
724
|
if (formatJson)
|
|
726
725
|
console.log(JSON.stringify(result));
|
|
@@ -756,7 +755,7 @@ Options:
|
|
|
756
755
|
console.error('用法: ec agent get <aid> <key>');
|
|
757
756
|
process.exit(1);
|
|
758
757
|
}
|
|
759
|
-
const result = await agentGet(aid, key);
|
|
758
|
+
const result = await agentGet(aid, key, { argv: args });
|
|
760
759
|
if (!result.ok) {
|
|
761
760
|
if (formatJson) {
|
|
762
761
|
console.log(JSON.stringify(result));
|
|
@@ -797,7 +796,7 @@ Options:
|
|
|
797
796
|
console.error('用法: ec agent set <aid> <key> <value>');
|
|
798
797
|
process.exit(1);
|
|
799
798
|
}
|
|
800
|
-
const result = await agentSet(aid, key, val);
|
|
799
|
+
const result = await agentSet(aid, key, val, { argv: args });
|
|
801
800
|
if (!result.ok) {
|
|
802
801
|
if (formatJson) {
|
|
803
802
|
console.log(JSON.stringify(result));
|
|
@@ -828,7 +827,7 @@ Options:
|
|
|
828
827
|
console.error('用法: ec agent ready <aid>');
|
|
829
828
|
process.exit(1);
|
|
830
829
|
}
|
|
831
|
-
const result = await agentReady(aid);
|
|
830
|
+
const result = await agentReady(aid, args);
|
|
832
831
|
if (!result.ok) {
|
|
833
832
|
if (formatJson) {
|
|
834
833
|
console.log(JSON.stringify(result));
|
package/dist/cli/agent-create.js
CHANGED
|
@@ -20,6 +20,7 @@ import { atomicWriteJson } from '../utils/atomic-write.js';
|
|
|
20
20
|
import { isHClassPath, isLClassPath, isSameOrDescendant } from '../core/permission/protected-paths.js';
|
|
21
21
|
import { MAIN_CLI_BIN } from '../product.js';
|
|
22
22
|
import { uploadAvatarFile, uploadAvatarUrl } from '../utils/avatar-upload.js';
|
|
23
|
+
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
23
24
|
/** Parse the current Agent's Bootstrap welcome subcommand. */
|
|
24
25
|
export function parseAgentWelcomeArgs(args) {
|
|
25
26
|
const tail = args.at(-2) === '--format' && args.at(-1) === 'json' ? args.slice(0, -2) : args;
|
|
@@ -190,9 +191,9 @@ function projectSlug(project) {
|
|
|
190
191
|
.replace(/-+$/g, '');
|
|
191
192
|
return slug || 'agent';
|
|
192
193
|
}
|
|
193
|
-
export function resolveAgentCreatePlan(options) {
|
|
194
|
+
export function resolveAgentCreatePlan(options, projectCwd = process.cwd()) {
|
|
194
195
|
const aid = options.aid.trim();
|
|
195
|
-
const project = path.resolve(options.project ||
|
|
196
|
+
const project = path.resolve(projectCwd, options.project || '.');
|
|
196
197
|
const metadata = readProjectMetadata(project);
|
|
197
198
|
const defaults = loadDefaults();
|
|
198
199
|
const daemon = loadDaemonConfig();
|
|
@@ -940,6 +941,20 @@ export class AgentInitializationService {
|
|
|
940
941
|
await this.running.get(aid);
|
|
941
942
|
}
|
|
942
943
|
async settle(aid) { await this.running.get(aid); }
|
|
944
|
+
async wait(aid, seconds) {
|
|
945
|
+
const work = this.running.get(aid);
|
|
946
|
+
if (work && seconds > 0) {
|
|
947
|
+
let timer;
|
|
948
|
+
try {
|
|
949
|
+
await Promise.race([work, new Promise(resolve => { timer = setTimeout(resolve, seconds * 1000); })]);
|
|
950
|
+
}
|
|
951
|
+
finally {
|
|
952
|
+
if (timer)
|
|
953
|
+
clearTimeout(timer);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return this.status(aid);
|
|
957
|
+
}
|
|
943
958
|
launch(r) {
|
|
944
959
|
const aid = r.plan.aid;
|
|
945
960
|
const work = Promise.resolve().then(() => this.run(r)).catch(error => {
|
|
@@ -1167,33 +1182,37 @@ export function parseInitializationArgs(args) {
|
|
|
1167
1182
|
throw new Error('--wait must be an integer from 0 to 300');
|
|
1168
1183
|
return { aid: args[1], resume, dryRun: seen.has('--dry-run'), wait, values };
|
|
1169
1184
|
}
|
|
1170
|
-
export function resolveInitializationPlan(args) {
|
|
1185
|
+
export function resolveInitializationPlan(args, context) {
|
|
1171
1186
|
const parsed = parseInitializationArgs(args);
|
|
1172
1187
|
if (parsed.resume)
|
|
1173
1188
|
throw new Error('A resume request cannot supply a new plan');
|
|
1174
1189
|
const v = parsed.values;
|
|
1175
1190
|
if (v['--avatar-file'] !== undefined && v['--avatar-url'] !== undefined)
|
|
1176
1191
|
throw new Error('--avatar-file and --avatar-url are mutually exclusive');
|
|
1177
|
-
if (v['--avatar-file']?.startsWith('attachment:') && !process.env.EVOLCORE_SESSION_ID) {
|
|
1192
|
+
if (v['--avatar-file']?.startsWith('attachment:') && !context && !process.env.EVOLCORE_SESSION_ID) {
|
|
1178
1193
|
throw new Error('attachment:<id> avatar sources require a managed Agent task');
|
|
1179
1194
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1195
|
+
const persona = v['--persona-file'] !== undefined
|
|
1196
|
+
? readInitializationPersona(v['--persona-file'], !!context, context)
|
|
1197
|
+
: v['--persona-text'];
|
|
1182
1198
|
const p = resolveAgentCreatePlan({
|
|
1183
1199
|
aid: parsed.aid, project: v['--project'], baseagent: v['--baseagent'], ...parseAgentOwnerArgs(args),
|
|
1184
1200
|
avatarFile: v['--avatar-file'], avatarUrl: v['--avatar-url'],
|
|
1185
1201
|
name: v['--name'], description: v['--description'], tags: parseAgentTags(v['--tags']), type: v['--type'],
|
|
1186
|
-
});
|
|
1202
|
+
}, context?.projectCwd);
|
|
1187
1203
|
return {
|
|
1188
1204
|
aid: p.aid, project: p.project, baseagent: p.baseagent ?? '', owners: p.owners ?? (p.owner ? [p.owner] : []),
|
|
1189
1205
|
name: p.name, description: p.description, tags: p.tags, type: p.type,
|
|
1190
|
-
...(
|
|
1206
|
+
...(persona !== undefined ? { persona } : {}),
|
|
1191
1207
|
...(v['--avatar-file'] !== undefined ? { avatarFile: v['--avatar-file'] } : {}),
|
|
1192
1208
|
...(v['--avatar-url'] !== undefined ? { avatarUrl: v['--avatar-url'] } : {}),
|
|
1193
1209
|
};
|
|
1194
1210
|
}
|
|
1195
|
-
export function readInitializationPersona(file, managed
|
|
1196
|
-
|
|
1211
|
+
export function readInitializationPersona(file, managed, context = {
|
|
1212
|
+
projectCwd: managed ? readTaskRuntimeContextFromEnv()?.projectPath ?? process.cwd() : process.cwd(),
|
|
1213
|
+
tempDir: process.env.TMPDIR,
|
|
1214
|
+
}) {
|
|
1215
|
+
const resolved = path.resolve(context.projectCwd, file);
|
|
1197
1216
|
if (!/\.(md|txt)$/i.test(resolved))
|
|
1198
1217
|
throw new Error('persona file must be .md or .txt');
|
|
1199
1218
|
const stat = fs.lstatSync(resolved);
|
|
@@ -1201,8 +1220,8 @@ export function readInitializationPersona(file, managed) {
|
|
|
1201
1220
|
throw new Error('persona must be a regular text file of at most 64 KiB');
|
|
1202
1221
|
if (managed) {
|
|
1203
1222
|
const real = fs.realpathSync(resolved);
|
|
1204
|
-
const roots = [
|
|
1205
|
-
const allowed = roots.some(root => isSameOrDescendant(real, fs.realpathSync(root)));
|
|
1223
|
+
const roots = [context.projectCwd, context.tempDir].filter((root) => !!root && path.isAbsolute(root));
|
|
1224
|
+
const allowed = roots.some(root => fs.existsSync(root) && isSameOrDescendant(real, fs.realpathSync(root)));
|
|
1206
1225
|
if (!allowed || isHClassPath(real) || isLClassPath(real))
|
|
1207
1226
|
throw new Error('persona file must be inside the project or current TMPDIR');
|
|
1208
1227
|
}
|
|
@@ -1216,27 +1235,24 @@ export async function runInitializationCommand(args) {
|
|
|
1216
1235
|
const parsed = parseInitializationArgs(args);
|
|
1217
1236
|
const managed = !!process.env.EVOLCORE_SESSION_ID;
|
|
1218
1237
|
const argv = [...args];
|
|
1219
|
-
if (parsed.values['--persona-file'] !== undefined) {
|
|
1238
|
+
if (parsed.values['--persona-file'] !== undefined && !managed) {
|
|
1239
|
+
const persona = readInitializationPersona(parsed.values['--persona-file'], managed);
|
|
1220
1240
|
const at = argv.indexOf('--persona-file');
|
|
1221
|
-
argv.splice(at, 2, '--persona-text',
|
|
1241
|
+
argv.splice(at, 2, '--persona-text', persona);
|
|
1222
1242
|
}
|
|
1223
|
-
if (!parsed.resume) {
|
|
1243
|
+
if (!managed && !parsed.resume) {
|
|
1224
1244
|
const at = argv.indexOf('--project');
|
|
1225
1245
|
if (at < 0)
|
|
1226
1246
|
argv.push('--project', process.cwd());
|
|
1227
1247
|
else
|
|
1228
1248
|
argv[at + 1] = path.resolve(argv[at + 1]);
|
|
1229
1249
|
}
|
|
1250
|
+
if (managed) {
|
|
1251
|
+
const { runManagedAgentOperation } = await import('./agent.js');
|
|
1252
|
+
const result = await runManagedAgentOperation(argv, (parsed.wait + 10) * 1000);
|
|
1253
|
+
return initializationCommandResult(result);
|
|
1254
|
+
}
|
|
1230
1255
|
const request = async (poll) => {
|
|
1231
|
-
if (managed) {
|
|
1232
|
-
const { runManagedAgentOperation } = await import('./agent.js');
|
|
1233
|
-
const r = await runManagedAgentOperation(poll ? ['show', parsed.aid, '--format', 'json'] : argv);
|
|
1234
|
-
if (!poll || !r.ok || !r.initialization)
|
|
1235
|
-
return r;
|
|
1236
|
-
const init = r.initialization;
|
|
1237
|
-
return { ...init, ok: !['failed', 'cancelled'].includes(init.status), aid: parsed.aid,
|
|
1238
|
-
accepted: true, lifecycle: r.lifecycle, usable: init.complete && r.connection?.status === 'connected' };
|
|
1239
|
-
}
|
|
1240
1256
|
return await ipcQuery(resolvePaths().socket, {
|
|
1241
1257
|
type: 'evolagent.initialize', argv, poll,
|
|
1242
1258
|
}, 10_000) ?? { ok: false, code: 'DAEMON_UNAVAILABLE', error: 'Initialization requires a running daemon' };
|
|
@@ -1249,6 +1265,9 @@ export async function runInitializationCommand(args) {
|
|
|
1249
1265
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
1250
1266
|
result = await request(true);
|
|
1251
1267
|
}
|
|
1268
|
+
return initializationCommandResult(result);
|
|
1269
|
+
}
|
|
1270
|
+
function initializationCommandResult(result) {
|
|
1252
1271
|
if (result.ok && !result.complete && result.accepted)
|
|
1253
1272
|
return { ...result, ok: false, code: 'INITIALIZE_PENDING', error: 'Initialization is still running; inspect agent show' };
|
|
1254
1273
|
if (result.complete && !result.usable)
|