@agentconnect.md/daemon 1.0.0-rc.280 → 1.0.0-rc.282
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/dist/{acp-host-CrjtbS3A.js → acp-host-C-4zFhF8.js} +2 -2
- package/dist/{acp-host-CrjtbS3A.js.map → acp-host-C-4zFhF8.js.map} +1 -1
- package/dist/{agent-list-DRSg2Fhd.js → agent-list-BK1xbKJd.js} +2 -2
- package/dist/{agent-list-DRSg2Fhd.js.map → agent-list-BK1xbKJd.js.map} +1 -1
- package/dist/{chat-4Is9zl7L.js → chat-B8VEWuix.js} +3 -3
- package/dist/{chat-4Is9zl7L.js.map → chat-B8VEWuix.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/{load-agents-Amic2B8b.js → load-agents-DzCnR0cj.js} +150 -1
- package/dist/load-agents-DzCnR0cj.js.map +1 -0
- package/dist/{login-CzDsJwym.js → login-OT3DwN02.js} +3 -3
- package/dist/{login-CzDsJwym.js.map → login-OT3DwN02.js.map} +1 -1
- package/dist/{run-foreground-1y1IF3Dc.js → run-foreground-BV2scayf.js} +401 -61
- package/dist/{run-foreground-1y1IF3Dc.js.map → run-foreground-BV2scayf.js.map} +1 -1
- package/dist/run-foreground-Cz_WXUfg.js +2 -0
- package/package.json +1 -1
- package/dist/load-agents-Amic2B8b.js.map +0 -1
- package/dist/run-foreground-CfLjjwW7.js +0 -2
|
@@ -3,9 +3,9 @@ import { n as require_ms, t as require_src$3 } from "./src-DDtlVutj.js";
|
|
|
3
3
|
import { n as init_esm_shims, t as __dirname } from "./esm-shims-DxGcm4Hw.js";
|
|
4
4
|
import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
5
5
|
import { C as _coercedNumber, T as NEVER, a as array, d as literal, f as looseObject, i as any, m as object, o as boolean, p as number$1, t as ZodNumber, v as string, x as url$4 } from "./schemas-CQkO9hC5.js";
|
|
6
|
-
import { C as ZodIssueCode, S as RESERVED_MCP_SERVER_NAME, _ as buildEnvelope, a as agentChildEnv, b as MAX_FRAME_BYTES, c as persistRelays, d as normalizeGitUrl, f as RELAY_DAEMON_SUBPROTOCOL, g as SHARED_CONFIG_ACTION_ID, h as decodeRelayDaemonFrame, i as selectAgent, m as buildRelayDaemonFrame, n as findAgentFiles, o as loadConfig, p as RELAY_DAEMON_WS_PATH, r as loadAgents, s as persistDaemonId, v as decodeEnvelope, y as encode } from "./load-agents-
|
|
6
|
+
import { C as ZodIssueCode, S as RESERVED_MCP_SERVER_NAME, _ as buildEnvelope, a as agentChildEnv, b as MAX_FRAME_BYTES, c as persistRelays, d as normalizeGitUrl, f as RELAY_DAEMON_SUBPROTOCOL, g as SHARED_CONFIG_ACTION_ID, h as decodeRelayDaemonFrame, i as selectAgent, m as buildRelayDaemonFrame, n as findAgentFiles, o as loadConfig, p as RELAY_DAEMON_WS_PATH, r as loadAgents, s as persistDaemonId, v as decodeEnvelope, y as encode } from "./load-agents-DzCnR0cj.js";
|
|
7
7
|
import { l as resolveRoot, o as mcpSocketPath, u as statePath } from "./paths-DEcUO8lC.js";
|
|
8
|
-
import { S as resolveRuntimes, _ as writeMemoryFile, a as initGitInjection, b as cachedRuntimeNames, c as simpleGit, d as memoryProviderFor, f as MemoryConflictError, g as resolveInMemoryDir, h as listMemory, i as prepareWorkspace, l as createMemoryProvider, m as MemoryTooLargeError, n as installedRuntimes, o as probeGitVersion, p as MemoryPathError, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as memoryKindOf, v as MEMORY_TOOL_NAMES, x as cachedRuntimeVersions, y as toolsForIntegrations } from "./acp-host-
|
|
8
|
+
import { S as resolveRuntimes, _ as writeMemoryFile, a as initGitInjection, b as cachedRuntimeNames, c as simpleGit, d as memoryProviderFor, f as MemoryConflictError, g as resolveInMemoryDir, h as listMemory, i as prepareWorkspace, l as createMemoryProvider, m as MemoryTooLargeError, n as installedRuntimes, o as probeGitVersion, p as MemoryPathError, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as memoryKindOf, v as MEMORY_TOOL_NAMES, x as cachedRuntimeVersions, y as toolsForIntegrations } from "./acp-host-C-4zFhF8.js";
|
|
9
9
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-CMC80O_1.js";
|
|
10
10
|
import { B as ToolListChangedNotificationSchema, D as ListPromptsResultSchema, E as ListChangedOptionsBaseSchema, F as PromptListChangedNotificationSchema, G as isZ4Schema, H as isJSONRPCRequest, I as ReadResourceResultSchema, J as encodeFrame, K as safeParse, L as ResourceListChangedNotificationSchema, M as ListToolsResultSchema, O as ListResourceTemplatesResultSchema, P as McpError, R as SUPPORTED_PROTOCOL_VERSIONS, S as InitializeResultSchema, T as LATEST_PROTOCOL_VERSION, U as isJSONRPCResultResponse, V as isInitializedNotification, W as getObjectShape, _ as ElicitResultSchema, a as AjvJsonSchemaValidator, b as GetPromptResultSchema, c as mergeCapabilities, d as CompleteResultSchema, f as CreateMessageRequestSchema, g as ElicitRequestSchema, h as CreateTaskResultSchema, i as assertToolsCallTaskCapability, k as ListResourcesResultSchema, m as CreateMessageResultWithToolsSchema, n as serializeMessage, o as require_fast_deep_equal, p as CreateMessageResultSchema, q as decodeFrames, r as assertClientRequestTaskCapability, s as Protocol, t as ReadBuffer, u as CallToolResultSchema, v as EmptyResultSchema, w as JSONRPCMessageSchema, y as ErrorCode } from "./stdio-DnS8WcXi.js";
|
|
11
11
|
import { URL as URL$1 } from "url";
|
|
@@ -4516,6 +4516,9 @@ var CpClient = class {
|
|
|
4516
4516
|
case "relay/roster":
|
|
4517
4517
|
this.deps.configApply.applyRelayRoster(frame.payload.relays);
|
|
4518
4518
|
return;
|
|
4519
|
+
case "collaboration/routes":
|
|
4520
|
+
this.deps.configApply.applyCollabRoutes(frame.payload);
|
|
4521
|
+
return;
|
|
4519
4522
|
case "agent/upsert": {
|
|
4520
4523
|
const u = frame.payload;
|
|
4521
4524
|
this.deps.configApply.applyAgentUpsert(u.agentId, u.spec);
|
|
@@ -197213,6 +197216,18 @@ var RelayClient = class {
|
|
|
197213
197216
|
isReady() {
|
|
197214
197217
|
return this.state === "READY";
|
|
197215
197218
|
}
|
|
197219
|
+
/**
|
|
197220
|
+
* Send a cross-daemon agent-call to the relay (`rd/agentmsg` REQ, agent-collaboration
|
|
197221
|
+
* §2.3/§6.4) and resolve with the relay's admission verdict. `claimedFromAgentId` is
|
|
197222
|
+
* this daemon's trusted caller — the relay re-validates it against the socket's
|
|
197223
|
+
* authenticated daemonId. Rejects (retryable) if the socket isn't READY.
|
|
197224
|
+
*/
|
|
197225
|
+
async sendAgentMsg(payload) {
|
|
197226
|
+
if (this.state !== "READY") throw new WireError("INTERNAL", `rd link not ready (${this.state})`, true);
|
|
197227
|
+
const rep = await this.sendRequest(buildRelayDaemonFrame("rd/agentmsg", payload));
|
|
197228
|
+
if (rep.type !== "rd/agentmsg/ack") throw new WireError("INTERNAL", `expected rd/agentmsg/ack, got ${rep.type}`, false);
|
|
197229
|
+
return rep.payload;
|
|
197230
|
+
}
|
|
197216
197231
|
async attemptConnect() {
|
|
197217
197232
|
if (this.stopped || this.fatal) return;
|
|
197218
197233
|
const daemonId = this.deps.daemonId();
|
|
@@ -197264,6 +197279,10 @@ var RelayClient = class {
|
|
|
197264
197279
|
this.handleMsg(frame.id, frame.payload);
|
|
197265
197280
|
return;
|
|
197266
197281
|
}
|
|
197282
|
+
if (frame.type === "rd/agentmsg/fwd") {
|
|
197283
|
+
this.handleAgentMsgFwd(frame.id, frame.payload);
|
|
197284
|
+
return;
|
|
197285
|
+
}
|
|
197267
197286
|
this.deps.log.debug(`relay(${this.relayId}): ignoring ${frame.type}`);
|
|
197268
197287
|
}
|
|
197269
197288
|
/** An inbound rd/msg: dispatch it, reply `rd/ack`; only a webchat op streams
|
|
@@ -197274,7 +197293,22 @@ var RelayClient = class {
|
|
|
197274
197293
|
const ack = this.deps.onRelayMsg(msg, chat);
|
|
197275
197294
|
this.transport?.send(JSON.stringify(buildRelayDaemonFrame("rd/ack", ack, { corr: reqId })));
|
|
197276
197295
|
}
|
|
197277
|
-
/**
|
|
197296
|
+
/** A forwarded cross-daemon agent-call: terminal-verify + dispatch, reply the typed
|
|
197297
|
+
* admission verdict (`rd/agentmsg/ack`, corr = the relay's fwd id). */
|
|
197298
|
+
async handleAgentMsgFwd(reqId, msg) {
|
|
197299
|
+
let ack;
|
|
197300
|
+
try {
|
|
197301
|
+
ack = await this.deps.onRelayAgentMsg(msg);
|
|
197302
|
+
} catch (err) {
|
|
197303
|
+
this.deps.log.error(`relay(${this.relayId}): rd/agentmsg/fwd handler threw: ${err.message}`);
|
|
197304
|
+
ack = {
|
|
197305
|
+
deliveryId: msg.deliveryId,
|
|
197306
|
+
delivered: false,
|
|
197307
|
+
reason: "offline"
|
|
197308
|
+
};
|
|
197309
|
+
}
|
|
197310
|
+
this.transport?.send(JSON.stringify(buildRelayDaemonFrame("rd/agentmsg/ack", ack, { corr: reqId })));
|
|
197311
|
+
}
|
|
197278
197312
|
sendChat(chatId, event) {
|
|
197279
197313
|
const seq = (this.seqByChat.get(chatId) ?? 0) + 1;
|
|
197280
197314
|
this.seqByChat.set(chatId, seq);
|
|
@@ -197346,6 +197380,45 @@ var RelayManager = class {
|
|
|
197346
197380
|
size() {
|
|
197347
197381
|
return this.clients.size;
|
|
197348
197382
|
}
|
|
197383
|
+
/**
|
|
197384
|
+
* Send a cross-daemon agent-call over ANY READY relay (agent-collaboration §2.3/§6.4).
|
|
197385
|
+
* The all-to-all roster means any relay this daemon holds can route the call to the
|
|
197386
|
+
* target's owning daemon via the CP's collaboration snapshot — so we pick the first
|
|
197387
|
+
* READY client. Throws if none is READY (the caller reports the call undeliverable).
|
|
197388
|
+
*/
|
|
197389
|
+
async sendAgentMsg(payload) {
|
|
197390
|
+
for (const client of this.clients.values()) if (client.isReady()) return client.sendAgentMsg(payload);
|
|
197391
|
+
throw new Error("no READY relay to route agent-call");
|
|
197392
|
+
}
|
|
197393
|
+
};
|
|
197394
|
+
//#endregion
|
|
197395
|
+
//#region src/cp/cp-collab-routes.ts
|
|
197396
|
+
var CpCollabRoutes = class {
|
|
197397
|
+
generation = -1;
|
|
197398
|
+
channels = /* @__PURE__ */ new Map();
|
|
197399
|
+
key(orgId, platform, channelId) {
|
|
197400
|
+
return orgId + "\0" + platform + "\0" + channelId;
|
|
197401
|
+
}
|
|
197402
|
+
/** FULL-REPLACE from a CP snapshot (converge-don't-diff); ignore an older generation.
|
|
197403
|
+
* Tolerates an absent snapshot (a pre-collab CP / hand-built test fixture) as a no-op. */
|
|
197404
|
+
replace(snap) {
|
|
197405
|
+
if (!snap) return;
|
|
197406
|
+
if (snap.generation < this.generation) return;
|
|
197407
|
+
this.generation = snap.generation;
|
|
197408
|
+
this.channels.clear();
|
|
197409
|
+
for (const ch of snap.channels) {
|
|
197410
|
+
const byAgent = /* @__PURE__ */ new Map();
|
|
197411
|
+
for (const a of ch.agents) byAgent.set(a.agentId, {
|
|
197412
|
+
...a,
|
|
197413
|
+
orgId: ch.orgId
|
|
197414
|
+
});
|
|
197415
|
+
this.channels.set(this.key(ch.orgId, ch.platform, ch.channelId), byAgent);
|
|
197416
|
+
}
|
|
197417
|
+
}
|
|
197418
|
+
/** The placement of `agentId` in `(orgId,platform,channel)`, or undefined. */
|
|
197419
|
+
resolve(orgId, platform, channelId, agentId) {
|
|
197420
|
+
return this.channels.get(this.key(orgId, platform, channelId))?.get(agentId);
|
|
197421
|
+
}
|
|
197349
197422
|
};
|
|
197350
197423
|
//#endregion
|
|
197351
197424
|
//#region src/slack/permalink.ts
|
|
@@ -213861,6 +213934,26 @@ function formatErr(err) {
|
|
|
213861
213934
|
return e?.stack ?? String(err);
|
|
213862
213935
|
}
|
|
213863
213936
|
const MAX_QUEUED_PER_SESSION = 10;
|
|
213937
|
+
/** Thrown to a `dispatch()` caller when the per-session admission queue is at its depth
|
|
213938
|
+
* cap (§4.4 backpressure): the message is fast-failed, not buffered. Carries a stable
|
|
213939
|
+
* `reason` so an agent-call source (P1/P2) can surface a typed `queue_full`. */
|
|
213940
|
+
var QueueFullError = class extends Error {
|
|
213941
|
+
reason = "queue_full";
|
|
213942
|
+
constructor(sessionKey) {
|
|
213943
|
+
super(`admission queue full for session ${sessionKey}`);
|
|
213944
|
+
this.name = "QueueFullError";
|
|
213945
|
+
}
|
|
213946
|
+
};
|
|
213947
|
+
/** Thrown to the `dispatch()` callers of the messages still queued behind a turn that
|
|
213948
|
+
* FAILED (§6.9 #378 fail-stop): the daemon does not auto-run buffered work onto a broken
|
|
213949
|
+
* session, so each follow-up is rejected rather than silently dropped or force-run. */
|
|
213950
|
+
var FailStopError = class extends Error {
|
|
213951
|
+
reason = "fail_stop";
|
|
213952
|
+
constructor(sessionKey) {
|
|
213953
|
+
super(`turn failed for session ${sessionKey}; queued messages were not auto-run`);
|
|
213954
|
+
this.name = "FailStopError";
|
|
213955
|
+
}
|
|
213956
|
+
};
|
|
213864
213957
|
const SELECT_KIND_CODE = {
|
|
213865
213958
|
model: "m",
|
|
213866
213959
|
effort: "e",
|
|
@@ -213897,6 +213990,10 @@ const IDLE_FLUSH_MS = 2e3;
|
|
|
213897
213990
|
/** Public Web App console origin used for session deep links when neither a local
|
|
213898
213991
|
* `webAppUrl` config nor a CP-provided one is set — so "View session" always resolves. */
|
|
213899
213992
|
const DEFAULT_WEB_APP_URL = "https://app.agentconnect.md";
|
|
213993
|
+
/** Per-in-flight-turn rendering state, keyed by ACP sessionId in `this.pending`. */
|
|
213994
|
+
/** Cap on agent→agent hop depth (design §2.4/§4.5) — reject a `messageAgent` that
|
|
213995
|
+
* would push the outgoing hopCount past this, so an A↔B wake loop can't run away. */
|
|
213996
|
+
const MAX_AGENT_CALL_HOPS = 8;
|
|
213900
213997
|
/** Build the wire SessionKey (protocol §5) for a pending turn — what `drain/done`
|
|
213901
213998
|
* reports as released so the CP may reassign it. Uses the real `thread` (absent for
|
|
213902
213999
|
* a channel-root message), NOT `statusThread` (which falls back to msgId): the CP
|
|
@@ -213972,6 +214069,7 @@ var Daemon = class Daemon {
|
|
|
213972
214069
|
cpIntegrations;
|
|
213973
214070
|
botUserIds = {};
|
|
213974
214071
|
cpRouting;
|
|
214072
|
+
cpCollab = new CpCollabRoutes();
|
|
213975
214073
|
clock;
|
|
213976
214074
|
requestExit;
|
|
213977
214075
|
draining = false;
|
|
@@ -214871,8 +214969,10 @@ var Daemon = class Daemon {
|
|
|
214871
214969
|
* NO mute) shared by the Slack status-bar Cancel button. No-op if nothing is running. */
|
|
214872
214970
|
cancelSessionByKey(key) {
|
|
214873
214971
|
const rec = this.store.getSession(key);
|
|
214874
|
-
if (!
|
|
214875
|
-
|
|
214972
|
+
if (!this.inflight.has(key)) return;
|
|
214973
|
+
const agentId = rec?.agentId ?? this.serialQueue.get(key)?.[0]?.agentId;
|
|
214974
|
+
if (!agentId) return;
|
|
214975
|
+
this.interruptTurn(agentId, key, "cancel", rec?.acpSessionId ?? void 0);
|
|
214876
214976
|
}
|
|
214877
214977
|
/** Switch a session's reasoning effort by its local key — the effort counterpart of
|
|
214878
214978
|
* {@link setModelByKey}. Records the sticky override and, if the ACP session is warm,
|
|
@@ -214944,9 +215044,16 @@ var Daemon = class Daemon {
|
|
|
214944
215044
|
* Resolved by conversationId (the op carries no agentId). No-op when idle. */
|
|
214945
215045
|
handleWebchatCancel(conversationId) {
|
|
214946
215046
|
for (const [acpSessionId, p] of this.pending) if (p.webchat?.conversationId === conversationId) {
|
|
214947
|
-
this.interruptTurn(p.agentId,
|
|
215047
|
+
this.interruptTurn(p.agentId, p.sessionKey, "cancel", acpSessionId);
|
|
214948
215048
|
return;
|
|
214949
215049
|
}
|
|
215050
|
+
for (const [key, entries] of this.serialQueue) {
|
|
215051
|
+
const hit = entries.find((e) => e.webchat?.conversationId === conversationId);
|
|
215052
|
+
if (hit) {
|
|
215053
|
+
this.interruptTurn(hit.agentId, key, "cancel");
|
|
215054
|
+
return;
|
|
215055
|
+
}
|
|
215056
|
+
}
|
|
214950
215057
|
this.log.debug(`webchat cancel: no in-flight turn for conversation ${conversationId}`);
|
|
214951
215058
|
}
|
|
214952
215059
|
relayMsgAcks = /* @__PURE__ */ new Map();
|
|
@@ -214998,6 +215105,74 @@ var Daemon = class Daemon {
|
|
|
214998
215105
|
accepted: true
|
|
214999
215106
|
};
|
|
215000
215107
|
}
|
|
215108
|
+
relayAgentMsgAcks = /* @__PURE__ */ new Map();
|
|
215109
|
+
/**
|
|
215110
|
+
* TARGET side of a cross-daemon `messageAgent` (agent-collaboration §2.3/§6.2, P2) —
|
|
215111
|
+
* the mirror of {@link handleRelayIm} for a relay-forwarded `rd/agentmsg/fwd`. The
|
|
215112
|
+
* relay already validated the caller and minted a TRUSTED claim
|
|
215113
|
+
* (`trustedFromAgentId` + org/channel assertion), but we TERMINAL-VERIFY it against
|
|
215114
|
+
* our OWN local snapshot/spec (defense in depth, §2.5 #4) before dispatching — never
|
|
215115
|
+
* blindly trusting the relay. The ACK is returned on durable ADMISSION (the P4-gate
|
|
215116
|
+
* enqueue), NOT after the model turn (§6.4).
|
|
215117
|
+
*/
|
|
215118
|
+
async handleRelayAgentMsg(msg) {
|
|
215119
|
+
const nak = (reason) => ({
|
|
215120
|
+
deliveryId: msg.deliveryId,
|
|
215121
|
+
delivered: false,
|
|
215122
|
+
...reason ? { reason } : {}
|
|
215123
|
+
});
|
|
215124
|
+
const dedupKey = `${msg.trustedFromAgentId}:${msg.deliveryId}`;
|
|
215125
|
+
const prior = this.relayAgentMsgAcks.get(dedupKey);
|
|
215126
|
+
if (prior) return prior;
|
|
215127
|
+
const record = (ack) => {
|
|
215128
|
+
if (this.relayAgentMsgAcks.size >= 2e3) this.relayAgentMsgAcks.clear();
|
|
215129
|
+
this.relayAgentMsgAcks.set(dedupKey, ack);
|
|
215130
|
+
return ack;
|
|
215131
|
+
};
|
|
215132
|
+
if (msg.hopCount > MAX_AGENT_CALL_HOPS) return record(nak("hop_limit"));
|
|
215133
|
+
const { platform, channel, thread } = msg.coords;
|
|
215134
|
+
if (!this.agents.get(msg.toAgentId)) return record(nak("not_found"));
|
|
215135
|
+
const target = this.cpCollab.resolve(msg.orgId, platform, channel, msg.toAgentId);
|
|
215136
|
+
const caller = this.cpCollab.resolve(msg.orgId, platform, channel, msg.trustedFromAgentId);
|
|
215137
|
+
if (!target || !caller) {
|
|
215138
|
+
this.log.warn(`relay: rd/agentmsg/fwd terminal-verify failed (no placement) for ${msg.toAgentId} — fail closed`);
|
|
215139
|
+
return record(nak("not_allowed"));
|
|
215140
|
+
}
|
|
215141
|
+
if (target.callPolicy === "selected" && !target.allowedCallerAgentIds.includes(msg.trustedFromAgentId)) {
|
|
215142
|
+
this.log.info(`relay: rd/agentmsg/fwd not_allowed — ${msg.trustedFromAgentId} → ${msg.toAgentId} (selected)`);
|
|
215143
|
+
return record(nak("not_allowed"));
|
|
215144
|
+
}
|
|
215145
|
+
const callMeta = {
|
|
215146
|
+
callFrom: msg.trustedFromAgentId,
|
|
215147
|
+
...msg.correlationId !== void 0 ? { correlationId: msg.correlationId } : {},
|
|
215148
|
+
hopCount: msg.hopCount,
|
|
215149
|
+
deliveryId: msg.deliveryId
|
|
215150
|
+
};
|
|
215151
|
+
const narrowed = this.narrowPlatform(platform);
|
|
215152
|
+
const resolved = this.resolveCpAgent(msg.toAgentId);
|
|
215153
|
+
const integrationId = msg.integrationId ?? resolved?.integrationId;
|
|
215154
|
+
const normalized = {
|
|
215155
|
+
msgId: `agentcall:${channel}:${msg.deliveryId}`,
|
|
215156
|
+
traceId: msg.deliveryId,
|
|
215157
|
+
source: "agent",
|
|
215158
|
+
platform: narrowed,
|
|
215159
|
+
channel,
|
|
215160
|
+
...thread !== void 0 ? { thread } : {},
|
|
215161
|
+
sender: {
|
|
215162
|
+
id: msg.trustedFromAgentId,
|
|
215163
|
+
isBot: true
|
|
215164
|
+
},
|
|
215165
|
+
text: `@${msg.trustedFromAgentId} asked:\n${msg.text}`,
|
|
215166
|
+
mentionedBots: resolved?.botUserId ? [resolved.botUserId] : [],
|
|
215167
|
+
isDm: false
|
|
215168
|
+
};
|
|
215169
|
+
this.dispatch(msg.toAgentId, normalized, integrationId, void 0, callMeta).catch((err) => this.log.error(`relay agentmsg dispatch failed for agent "${msg.toAgentId}": ${formatErr(err)}`));
|
|
215170
|
+
this.log.info(`relay: rd/agentmsg/fwd ${msg.trustedFromAgentId} → ${msg.toAgentId} delivery=${msg.deliveryId}`);
|
|
215171
|
+
return record({
|
|
215172
|
+
deliveryId: msg.deliveryId,
|
|
215173
|
+
delivered: true
|
|
215174
|
+
});
|
|
215175
|
+
}
|
|
215001
215176
|
/**
|
|
215002
215177
|
* Same-daemon agent→agent delivery — the impl behind the `messageAgent` MCP tool
|
|
215003
215178
|
* (design §2.2/§2.3, P1). Wakes `toAgentId` by constructing a NormalizedMessage at
|
|
@@ -215032,11 +215207,16 @@ var Daemon = class Daemon {
|
|
|
215032
215207
|
return result;
|
|
215033
215208
|
};
|
|
215034
215209
|
const target = this.agents.get(req.toAgentId);
|
|
215035
|
-
if (!target)
|
|
215036
|
-
|
|
215037
|
-
|
|
215038
|
-
|
|
215039
|
-
|
|
215210
|
+
if (!target) {
|
|
215211
|
+
const coordPlatform = platform === "hook" ? "slack" : platform;
|
|
215212
|
+
return record(await this.routeAgentMsgCrossDaemon(req, {
|
|
215213
|
+
platform: coordPlatform,
|
|
215214
|
+
channel,
|
|
215215
|
+
thread,
|
|
215216
|
+
deliveryId,
|
|
215217
|
+
targetSession
|
|
215218
|
+
}));
|
|
215219
|
+
}
|
|
215040
215220
|
if (target.callPolicy === "selected" && !target.allowedCallerAgentIds.includes(req.callerAgentId)) {
|
|
215041
215221
|
this.log.info(`messageAgent: ${req.callerAgentId} not allowed to call ${req.toAgentId} (policy=selected)`);
|
|
215042
215222
|
return record({
|
|
@@ -215077,6 +215257,53 @@ var Daemon = class Daemon {
|
|
|
215077
215257
|
targetSession
|
|
215078
215258
|
});
|
|
215079
215259
|
}
|
|
215260
|
+
/**
|
|
215261
|
+
* Route a cross-daemon `messageAgent` over the relay data plane (agent-collaboration
|
|
215262
|
+
* §2.3/§6.2/§6.4, P2) and map the relay's typed admission verdict to a
|
|
215263
|
+
* {@link MessageAgentResult}. The `claimedFromAgentId` is our trusted caller — the
|
|
215264
|
+
* relay re-validates it against our authenticated daemonId (a forged claim is
|
|
215265
|
+
* rejected there). `hopCount` is the source turn's depth (0 in P1's minimal
|
|
215266
|
+
* cross-turn model); the relay increments it (+1, cap 8). The body never touches
|
|
215267
|
+
* the CP — only the relay.
|
|
215268
|
+
*/
|
|
215269
|
+
async routeAgentMsgCrossDaemon(req, ctx) {
|
|
215270
|
+
if (!this.relays) return {
|
|
215271
|
+
delivered: false,
|
|
215272
|
+
targetSession: ctx.targetSession,
|
|
215273
|
+
reason: "not_local"
|
|
215274
|
+
};
|
|
215275
|
+
try {
|
|
215276
|
+
const ack = await this.relays.sendAgentMsg({
|
|
215277
|
+
claimedFromAgentId: req.callerAgentId,
|
|
215278
|
+
toAgentId: req.toAgentId,
|
|
215279
|
+
text: req.text,
|
|
215280
|
+
coords: {
|
|
215281
|
+
platform: ctx.platform,
|
|
215282
|
+
channel: ctx.channel,
|
|
215283
|
+
...ctx.thread !== void 0 ? { thread: ctx.thread } : {}
|
|
215284
|
+
},
|
|
215285
|
+
...req.correlationId !== void 0 ? { correlationId: req.correlationId } : {},
|
|
215286
|
+
hopCount: 0,
|
|
215287
|
+
deliveryId: ctx.deliveryId
|
|
215288
|
+
});
|
|
215289
|
+
if (ack.delivered) return {
|
|
215290
|
+
delivered: true,
|
|
215291
|
+
targetSession: ctx.targetSession
|
|
215292
|
+
};
|
|
215293
|
+
return {
|
|
215294
|
+
delivered: false,
|
|
215295
|
+
targetSession: ctx.targetSession,
|
|
215296
|
+
...ack.reason ? { reason: ack.reason } : {}
|
|
215297
|
+
};
|
|
215298
|
+
} catch (err) {
|
|
215299
|
+
this.log.warn(`messageAgent: cross-daemon route failed for ${req.toAgentId}: ${formatErr(err)}`);
|
|
215300
|
+
return {
|
|
215301
|
+
delivered: false,
|
|
215302
|
+
targetSession: ctx.targetSession,
|
|
215303
|
+
reason: "offline"
|
|
215304
|
+
};
|
|
215305
|
+
}
|
|
215306
|
+
}
|
|
215080
215307
|
/** Narrow the trusted session-context platform string to the NormalizedMessage union;
|
|
215081
215308
|
* falls back to 'slack' for an unrecognized value (coords still resolve — the union is
|
|
215082
215309
|
* a routing/key detail, not the trust basis). */
|
|
@@ -215308,7 +215535,8 @@ var Daemon = class Daemon {
|
|
|
215308
215535
|
};
|
|
215309
215536
|
});
|
|
215310
215537
|
}
|
|
215311
|
-
|
|
215538
|
+
inflight = /* @__PURE__ */ new Set();
|
|
215539
|
+
serialQueue = /* @__PURE__ */ new Map();
|
|
215312
215540
|
/**
|
|
215313
215541
|
* Resolve a command's target from the channel's latest session when the routing ladder
|
|
215314
215542
|
* couldn't (no mention entity / thread / dm rule matched — e.g. a group `/status@bot`).
|
|
@@ -215357,7 +215585,7 @@ var Daemon = class Daemon {
|
|
|
215357
215585
|
}
|
|
215358
215586
|
}
|
|
215359
215587
|
const acpSessionId = rec?.acpSessionId;
|
|
215360
|
-
const inflight =
|
|
215588
|
+
const inflight = this.inflight.has(key);
|
|
215361
215589
|
const tgReplyTo = this.telegramReplyTarget(msg);
|
|
215362
215590
|
const reply = (text) => {
|
|
215363
215591
|
if (!conn) return;
|
|
@@ -215371,7 +215599,7 @@ var Daemon = class Daemon {
|
|
|
215371
215599
|
reply(rec ? `🔇 Nothing is running. ${muteNote}` : "Nothing is running to stop.");
|
|
215372
215600
|
return;
|
|
215373
215601
|
}
|
|
215374
|
-
this.interruptTurn(target.agentId,
|
|
215602
|
+
this.interruptTurn(target.agentId, key, "stop", acpSessionId ?? void 0);
|
|
215375
215603
|
reply(`🛑 Stopped. ${muteNote}`);
|
|
215376
215604
|
return;
|
|
215377
215605
|
}
|
|
@@ -215380,7 +215608,7 @@ var Daemon = class Daemon {
|
|
|
215380
215608
|
reply("Nothing is running to cancel.");
|
|
215381
215609
|
return;
|
|
215382
215610
|
}
|
|
215383
|
-
this.interruptTurn(target.agentId,
|
|
215611
|
+
this.interruptTurn(target.agentId, key, "cancel", acpSessionId ?? void 0);
|
|
215384
215612
|
reply("🛑 Cancelled.");
|
|
215385
215613
|
return;
|
|
215386
215614
|
}
|
|
@@ -215446,21 +215674,23 @@ var Daemon = class Daemon {
|
|
|
215446
215674
|
text: command.text,
|
|
215447
215675
|
thread
|
|
215448
215676
|
};
|
|
215449
|
-
if (
|
|
215450
|
-
this.log.
|
|
215451
|
-
this.dispatch(target.agentId, payload, target.integrationId).catch((err) => this.log.error(`queued dispatch failed for agent "${target.agentId}": ${err.stack ?? err}`));
|
|
215452
|
-
return;
|
|
215453
|
-
}
|
|
215454
|
-
const q = this.queued.get(acpSessionId) ?? [];
|
|
215455
|
-
if (q.length >= MAX_QUEUED_PER_SESSION) {
|
|
215456
|
-
this.log.warn(`command: queue → agent "${target.agentId}" session ${acpSessionId} full (${q.length}), rejected`);
|
|
215677
|
+
if (inflight && (this.serialQueue.get(key)?.length ?? 0) >= MAX_QUEUED_PER_SESSION) {
|
|
215678
|
+
this.log.warn(`command: queue → agent "${target.agentId}" session ${key} full, rejected`);
|
|
215457
215679
|
reply(`Queue is full (${MAX_QUEUED_PER_SESSION} pending) — wait for the current turn to finish.`);
|
|
215458
215680
|
return;
|
|
215459
215681
|
}
|
|
215460
|
-
|
|
215461
|
-
|
|
215462
|
-
|
|
215463
|
-
|
|
215682
|
+
this.dispatch(target.agentId, payload, target.integrationId, void 0, void 0, { isQueueCmd: true }).catch((err) => {
|
|
215683
|
+
if (err instanceof QueueFullError) return;
|
|
215684
|
+
this.log.error(`queued dispatch failed for agent "${target.agentId}": ${err.stack ?? err}`);
|
|
215685
|
+
});
|
|
215686
|
+
if (!inflight) {
|
|
215687
|
+
this.log.info(`command: queue → agent "${target.agentId}" idle, dispatching now`);
|
|
215688
|
+
reply(`▶️ Running now — the session was idle.`);
|
|
215689
|
+
} else {
|
|
215690
|
+
const depth = this.serialQueue.get(key)?.length ?? 0;
|
|
215691
|
+
this.log.info(`command: queue → agent "${target.agentId}" session ${key} (depth ${depth})`);
|
|
215692
|
+
reply(`📥 Queued (#${depth}) — will run when the current turn finishes.`);
|
|
215693
|
+
}
|
|
215464
215694
|
}
|
|
215465
215695
|
selectLabel(kind) {
|
|
215466
215696
|
return kind === "model" ? "Model" : kind === "effort" ? "Reasoning effort" : "Permission mode";
|
|
@@ -215591,15 +215821,6 @@ var Daemon = class Daemon {
|
|
|
215591
215821
|
acpSessionId: latest.acpSessionId ?? void 0
|
|
215592
215822
|
};
|
|
215593
215823
|
}
|
|
215594
|
-
/** Drain one buffered message for a session whose turn just finished (FIFO). */
|
|
215595
|
-
flushQueued(agentId, sessionId, integrationId) {
|
|
215596
|
-
const q = this.queued.get(sessionId);
|
|
215597
|
-
if (!q || q.length === 0) return;
|
|
215598
|
-
const next = q.shift();
|
|
215599
|
-
if (q.length === 0) this.queued.delete(sessionId);
|
|
215600
|
-
this.log.info(`queue: dispatching buffered message to agent "${agentId}" session ${sessionId} (${q.length} left)`);
|
|
215601
|
-
this.dispatch(agentId, next, integrationId).catch((err) => this.log.error(`queued dispatch failed for agent "${agentId}": ${err.stack ?? err}`));
|
|
215602
|
-
}
|
|
215603
215824
|
/** Local layer (agent.json) ∪ resolved CP layer; unservable CP rules are dropped + warn-logged. */
|
|
215604
215825
|
mergedRules() {
|
|
215605
215826
|
const local = [...this.agents.values()].flatMap((a) => rulesFromAgent(a, this.botUserIds));
|
|
@@ -215646,21 +215867,116 @@ var Daemon = class Daemon {
|
|
|
215646
215867
|
ctx.replyConn.postMessage(ctx.channel, `⚠️ Agent failed to respond: ${reason}`, ctx.thread);
|
|
215647
215868
|
}
|
|
215648
215869
|
}
|
|
215649
|
-
|
|
215650
|
-
|
|
215651
|
-
|
|
215652
|
-
|
|
215870
|
+
/**
|
|
215871
|
+
* Terminate a QUEUED entry's webchat sink when it is gate-dropped/rejected without ever
|
|
215872
|
+
* entering dispatchOne (drain/pause gate-drop, fail-stop of the queued rest, `!cancel`/`!stop`
|
|
215873
|
+
* queue drop, shutdown). A webchat turn signals its client via the WebchatSink terminal
|
|
215874
|
+
* `done` frame, NOT the dispatch() promise — so settling the promise alone leaves the browser
|
|
215875
|
+
* UI spinning forever. Mirrors surfaceTurnFailure's webchat branch. No-op for non-webchat
|
|
215876
|
+
* entries. Pass an `error` for reject/cancel/shutdown; omit it for a clean gate-drop.
|
|
215877
|
+
*/
|
|
215878
|
+
terminateQueuedSink(entry, error) {
|
|
215879
|
+
if (!entry.webchat) return;
|
|
215880
|
+
entry.webchat.sink.done({
|
|
215881
|
+
conversationId: entry.webchat.conversationId,
|
|
215882
|
+
turnId: entry.webchat.turnId,
|
|
215883
|
+
...error ? { error } : {}
|
|
215884
|
+
});
|
|
215885
|
+
}
|
|
215886
|
+
dispatch(agentId, msg, integrationId, webchat, callMeta, opts) {
|
|
215887
|
+
return new Promise((resolve, reject) => {
|
|
215888
|
+
if (this.draining || this.drainingAgents.has(agentId)) {
|
|
215889
|
+
this.log.debug(`dispatch: skipped for agent "${agentId}" (draining)`);
|
|
215890
|
+
resolve(null);
|
|
215891
|
+
return;
|
|
215892
|
+
}
|
|
215893
|
+
if (this.agents.get(agentId).pause) {
|
|
215894
|
+
this.log.info(`dispatch: skipped for agent "${agentId}" (paused)`);
|
|
215895
|
+
resolve(null);
|
|
215896
|
+
return;
|
|
215897
|
+
}
|
|
215898
|
+
const key = sessionKey(msg.platform, msg.channel, msg.thread ?? msg.msgId, agentId);
|
|
215899
|
+
const entry = {
|
|
215900
|
+
agentId,
|
|
215901
|
+
msg,
|
|
215902
|
+
...integrationId !== void 0 ? { integrationId } : {},
|
|
215903
|
+
...webchat ? { webchat } : {},
|
|
215904
|
+
...callMeta ? { callMeta } : {},
|
|
215905
|
+
...opts?.isQueueCmd ? { isQueueCmd: true } : {},
|
|
215906
|
+
resolve,
|
|
215907
|
+
reject
|
|
215908
|
+
};
|
|
215909
|
+
if (this.inflight.has(key)) {
|
|
215910
|
+
const q = this.serialQueue.get(key) ?? [];
|
|
215911
|
+
if (q.length >= MAX_QUEUED_PER_SESSION) {
|
|
215912
|
+
this.log.warn(`dispatch: queue full for session ${key} (${q.length}) — rejecting (queue_full)`);
|
|
215913
|
+
reject(new QueueFullError(key));
|
|
215914
|
+
return;
|
|
215915
|
+
}
|
|
215916
|
+
q.push(entry);
|
|
215917
|
+
this.serialQueue.set(key, q);
|
|
215918
|
+
this.log.debug(`dispatch: queued behind in-flight turn for session ${key} (depth ${q.length})`);
|
|
215919
|
+
return;
|
|
215920
|
+
}
|
|
215921
|
+
this.inflight.add(key);
|
|
215922
|
+
this.runLoop(key, entry);
|
|
215923
|
+
});
|
|
215924
|
+
}
|
|
215925
|
+
/**
|
|
215926
|
+
* Own a sessionKey's serial gate: run its head turn to completion, settle that entry's
|
|
215927
|
+
* own promise, then drain the queue in FIFO order WITHOUT releasing ownership between
|
|
215928
|
+
* turns (§6.9 #390 — deleting `inflight` then dequeuing would reopen the FIFO race).
|
|
215929
|
+
* Ownership is released only once the queue is confirmed empty in the same synchronous
|
|
215930
|
+
* tick. Fail-stop is the default (§6.9 #378): if a turn throws, the rest of the queue is
|
|
215931
|
+
* NOT auto-run — each remaining entry is rejected with a notice and the queue cleared,
|
|
215932
|
+
* so buffered work never chains onto a broken session.
|
|
215933
|
+
*/
|
|
215934
|
+
paused(agentId) {
|
|
215935
|
+
return this.agents.get(agentId)?.pause === true;
|
|
215936
|
+
}
|
|
215937
|
+
async runLoop(key, firstEntry) {
|
|
215938
|
+
let entry = firstEntry;
|
|
215939
|
+
while (entry) {
|
|
215940
|
+
if (entry !== firstEntry && (this.draining || this.drainingAgents.has(entry.agentId) || this.paused(entry.agentId))) {
|
|
215941
|
+
this.terminateQueuedSink(entry);
|
|
215942
|
+
entry.resolve(null);
|
|
215943
|
+
const rest = this.serialQueue.get(key) ?? [];
|
|
215944
|
+
this.serialQueue.delete(key);
|
|
215945
|
+
for (const e of rest) {
|
|
215946
|
+
this.terminateQueuedSink(e);
|
|
215947
|
+
e.resolve(null);
|
|
215948
|
+
}
|
|
215949
|
+
this.inflight.delete(key);
|
|
215950
|
+
return;
|
|
215951
|
+
}
|
|
215952
|
+
try {
|
|
215953
|
+
const sessionId = await this.dispatchOne(entry, key);
|
|
215954
|
+
entry.resolve(sessionId);
|
|
215955
|
+
} catch (err) {
|
|
215956
|
+
entry.reject(err);
|
|
215957
|
+
const rest = this.serialQueue.get(key) ?? [];
|
|
215958
|
+
this.serialQueue.delete(key);
|
|
215959
|
+
for (const e of rest) {
|
|
215960
|
+
const failStop = new FailStopError(key);
|
|
215961
|
+
this.terminateQueuedSink(e, failStop.message);
|
|
215962
|
+
e.reject(failStop);
|
|
215963
|
+
}
|
|
215964
|
+
this.inflight.delete(key);
|
|
215965
|
+
return;
|
|
215966
|
+
}
|
|
215967
|
+
const q = this.serialQueue.get(key);
|
|
215968
|
+
entry = q?.shift();
|
|
215969
|
+
if (q && q.length === 0) this.serialQueue.delete(key);
|
|
215653
215970
|
}
|
|
215971
|
+
this.inflight.delete(key);
|
|
215972
|
+
}
|
|
215973
|
+
async dispatchOne(entry, key) {
|
|
215974
|
+
const { agentId, msg, integrationId, webchat, callMeta } = entry;
|
|
215654
215975
|
const agent = this.agents.get(agentId);
|
|
215655
|
-
if (agent.pause) {
|
|
215656
|
-
this.log.info(`dispatch: skipped for agent "${agentId}" (paused)`);
|
|
215657
|
-
return null;
|
|
215658
|
-
}
|
|
215659
215976
|
const rec = new TranscriptRecorder();
|
|
215660
215977
|
const replyConn = msg.headless || webchat ? void 0 : this.replyConnFor(agentId, integrationId);
|
|
215661
215978
|
const wasRunning = this.hostStarts.has(agentId);
|
|
215662
215979
|
const statusThread = msg.thread ?? msg.msgId;
|
|
215663
|
-
const key = sessionKey(msg.platform, msg.channel, statusThread, agentId);
|
|
215664
215980
|
const mode = this.store.getOutputModeOverride(key) ?? agent.output.mode;
|
|
215665
215981
|
const conv = msg.platform === "telegram" ? new TelegramConverger(mode) : msg.platform === "discord" ? new DiscordConverger(mode) : new OutputConverger(mode);
|
|
215666
215982
|
this.showActivity(replyConn, msg.channel, statusThread, wasRunning ? "is thinking…" : "is starting up…");
|
|
@@ -215799,18 +216115,28 @@ var Daemon = class Daemon {
|
|
|
215799
216115
|
this.clearCancelBackstop(sessionId);
|
|
215800
216116
|
p.resolveDone();
|
|
215801
216117
|
}
|
|
215802
|
-
this.flushQueued(agentId, sessionId, integrationId);
|
|
215803
216118
|
return sessionId;
|
|
215804
216119
|
}
|
|
215805
|
-
/** Interrupt
|
|
215806
|
-
* drop anything queued behind it
|
|
215807
|
-
*
|
|
215808
|
-
*
|
|
215809
|
-
|
|
215810
|
-
|
|
216120
|
+
/** Interrupt a session by its LOGICAL sessionKey (shared by `!stop`, `!cancel`, and
|
|
216121
|
+
* webchat cancel): reject+drop anything queued behind it in the serial gate, then — if
|
|
216122
|
+
* a turn is actually in flight (ACP session live) — release any unanswered cards, mark
|
|
216123
|
+
* it `cancelling`, send ACP `session/cancel`, and arm the force backstop. Works for a
|
|
216124
|
+
* queued-but-not-yet-started or cold session too (§6.9 #390): draining the queue is
|
|
216125
|
+
* enough, no ACP id required. Muting is the CALLER's concern — `!stop` mutes,
|
|
216126
|
+
* `!cancel`/webchat-cancel do not. */
|
|
216127
|
+
interruptTurn(agentId, key, reason, acpSessionId) {
|
|
216128
|
+
const queued = this.serialQueue.get(key);
|
|
216129
|
+
if (queued && queued.length > 0) {
|
|
216130
|
+
this.serialQueue.delete(key);
|
|
216131
|
+
for (const e of queued) {
|
|
216132
|
+
this.terminateQueuedSink(e, reason);
|
|
216133
|
+
e.reject(new FailStopError(key));
|
|
216134
|
+
}
|
|
216135
|
+
}
|
|
216136
|
+
this.log.info(`command: ${reason} → agent "${agentId}" session ${key}${acpSessionId ? ` (${acpSessionId})` : ""}`);
|
|
216137
|
+
if (!acpSessionId || !this.pending.has(acpSessionId)) return;
|
|
215811
216138
|
this.releasePermissions(acpSessionId);
|
|
215812
216139
|
this.releaseElicits(acpSessionId);
|
|
215813
|
-
this.log.info(`command: ${reason} → agent "${agentId}" session ${acpSessionId}`);
|
|
215814
216140
|
this.store.setSessionState(key, "cancelling", this.clock.now());
|
|
215815
216141
|
this.hosts.get(agentId)?.cancel(acpSessionId).catch((err) => this.log.error(`command ${reason}: cancel failed: ${err.message}`));
|
|
215816
216142
|
this.armCancelBackstop(agentId, acpSessionId, key);
|
|
@@ -216723,13 +217049,24 @@ var Daemon = class Daemon {
|
|
|
216723
217049
|
async drainForShutdown() {
|
|
216724
217050
|
this.draining = true;
|
|
216725
217051
|
const live = [...this.pending.values()];
|
|
216726
|
-
if (live.length
|
|
216727
|
-
|
|
216728
|
-
|
|
216729
|
-
|
|
216730
|
-
|
|
216731
|
-
|
|
217052
|
+
if (live.length > 0) {
|
|
217053
|
+
const deadlineMs = this.cfg.limits.shutdownDrainMs;
|
|
217054
|
+
this.log.info(`shutdown: draining ${live.length} in-flight turn(s) (deadline ${Math.round(deadlineMs / 1e3)}s)`);
|
|
217055
|
+
if (await this.raceDeadline(Promise.all(live.map((p) => p.done)), deadlineMs) === "timeout") {
|
|
217056
|
+
this.log.warn(`shutdown: deadline hit with ${this.pending.size} turn(s) still in flight — cancelling`);
|
|
217057
|
+
for (const [sid, p] of this.pending) await this.hosts.get(p.agentId)?.cancel(sid).catch(() => {});
|
|
217058
|
+
}
|
|
217059
|
+
}
|
|
217060
|
+
this.settleQueuedForShutdown();
|
|
217061
|
+
}
|
|
217062
|
+
/** Reject and clear every entry still in the serial gate's queues (shutdown/teardown),
|
|
217063
|
+
* so no admitted-but-unrun message leaves an unsettled dispatch() promise. */
|
|
217064
|
+
settleQueuedForShutdown() {
|
|
217065
|
+
for (const [key, entries] of this.serialQueue) for (const e of entries) {
|
|
217066
|
+
this.terminateQueuedSink(e, "daemon shutting down");
|
|
217067
|
+
e.reject(new FailStopError(key));
|
|
216732
217068
|
}
|
|
217069
|
+
this.serialQueue.clear();
|
|
216733
217070
|
}
|
|
216734
217071
|
/** daemon/restart + daemon/upgrade (§8.3): ack now, then drain + stop + exit so
|
|
216735
217072
|
* the supervisor relaunches (the new binary, for upgrade). */
|
|
@@ -216762,6 +217099,7 @@ var Daemon = class Daemon {
|
|
|
216762
217099
|
this.cpAgents?.converge(snap.agents);
|
|
216763
217100
|
this.cpIntegrations?.converge(snap.integrations);
|
|
216764
217101
|
this.convergeRelays(snap.relays);
|
|
217102
|
+
this.cpCollab.replace(snap.collabRoutes);
|
|
216765
217103
|
for (const id of snap.drop.crons) this.cpCrons?.remove(id);
|
|
216766
217104
|
this.cpCrons?.converge(snap.crons);
|
|
216767
217105
|
this.cpRouting?.converge({
|
|
@@ -216790,6 +217128,7 @@ var Daemon = class Daemon {
|
|
|
216790
217128
|
applyRouteAssign: (a) => this.cpRouting?.upsertAssign(a),
|
|
216791
217129
|
applyRouteUpdate: (u) => this.cpRouting?.applyUpdate(u),
|
|
216792
217130
|
applyRelayRoster: (relays) => this.convergeRelays(relays),
|
|
217131
|
+
applyCollabRoutes: (snap) => this.cpCollab.replace(snap),
|
|
216793
217132
|
applyAgentLaunch: async (launch) => {
|
|
216794
217133
|
const agent = this.agents.get(launch.agentId);
|
|
216795
217134
|
if (!agent) throw new Error(`agent/launch: unknown agent ${launch.agentId}`);
|
|
@@ -216926,7 +217265,8 @@ var Daemon = class Daemon {
|
|
|
216926
217265
|
path: RELAY_DAEMON_WS_PATH
|
|
216927
217266
|
}),
|
|
216928
217267
|
log: this.log,
|
|
216929
|
-
onRelayMsg: (msg, chat) => this.handleRelayMsg(msg, chat)
|
|
217268
|
+
onRelayMsg: (msg, chat) => this.handleRelayMsg(msg, chat),
|
|
217269
|
+
onRelayAgentMsg: (msg) => this.handleRelayAgentMsg(msg)
|
|
216930
217270
|
});
|
|
216931
217271
|
if (this.cfg.relays.length) this.relays.converge(this.cfg.relays);
|
|
216932
217272
|
this.cpClient = new CpClient({
|
|
@@ -217133,4 +217473,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
217133
217473
|
//#endregion
|
|
217134
217474
|
export { ClientTransport as i, CP_SUBPROTOCOL as n, CP_WS_PATH as r, runForeground as t };
|
|
217135
217475
|
|
|
217136
|
-
//# sourceMappingURL=run-foreground-
|
|
217476
|
+
//# sourceMappingURL=run-foreground-BV2scayf.js.map
|