@agentconnect.md/daemon 1.0.0-rc.289 → 1.0.0-rc.290
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-BlkeNrQB.js → acp-host-B91pZ6PG.js} +2 -2
- package/dist/{acp-host-BlkeNrQB.js.map → acp-host-B91pZ6PG.js.map} +1 -1
- package/dist/{agent-list-DS3NGUJO.js → agent-list-jSv0GQn-.js} +2 -2
- package/dist/{agent-list-DS3NGUJO.js.map → agent-list-jSv0GQn-.js.map} +1 -1
- package/dist/{chat-Nq98n5LI.js → chat-DRFrVRfQ.js} +3 -3
- package/dist/{chat-Nq98n5LI.js.map → chat-DRFrVRfQ.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/{load-agents-BLNSM987.js → load-agents-CZJD_fRG.js} +139 -112
- package/dist/load-agents-CZJD_fRG.js.map +1 -0
- package/dist/{login-B4KagoWu.js → login-DP6dWldB.js} +3 -3
- package/dist/{login-B4KagoWu.js.map → login-DP6dWldB.js.map} +1 -1
- package/dist/{run-foreground-D4TMcwTn.js → run-foreground-BMjqIzg4.js} +663 -55
- package/dist/{run-foreground-D4TMcwTn.js.map → run-foreground-BMjqIzg4.js.map} +1 -1
- package/dist/run-foreground-B_jAVnV3.js +2 -0
- package/package.json +1 -1
- package/dist/load-agents-BLNSM987.js.map +0 -1
- package/dist/run-foreground-COW0zak6.js +0 -2
|
@@ -3,19 +3,19 @@ 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-CZJD_fRG.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-B91pZ6PG.js";
|
|
9
9
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-Dhp-tyEI.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";
|
|
12
12
|
import * as tls from "tls";
|
|
13
13
|
import * as net$5 from "net";
|
|
14
14
|
import * as path$16 from "node:path";
|
|
15
|
-
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
15
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
16
16
|
import * as http$8 from "http";
|
|
17
17
|
import { Agent } from "https";
|
|
18
|
-
import { chmodSync, existsSync, mkdirSync, mkdtempSync, promises, readFileSync, rmSync, stat, unwatchFile, watch, watchFile, writeFileSync } from "node:fs";
|
|
18
|
+
import { chmodSync, existsSync, mkdirSync, mkdtempSync, promises, readFileSync, readdirSync, renameSync, rmSync, stat, unwatchFile, watch, watchFile, writeFileSync } from "node:fs";
|
|
19
19
|
import { EventEmitter } from "node:events";
|
|
20
20
|
import process$1 from "node:process";
|
|
21
21
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
@@ -4527,6 +4527,12 @@ var CpClient = class {
|
|
|
4527
4527
|
case "agent/remove":
|
|
4528
4528
|
this.deps.configApply.applyAgentRemove(frame.payload.agentId);
|
|
4529
4529
|
return;
|
|
4530
|
+
case "agent/detach":
|
|
4531
|
+
this.deps.configApply.applyAgentDetach(frame.payload).then((ack) => this.reply(frame, "ack", ack)).catch((err) => this.sendError(frame.id, "INTERNAL", `agent/detach failed: ${err.message}`, false));
|
|
4532
|
+
return;
|
|
4533
|
+
case "agent/activate":
|
|
4534
|
+
this.deps.configApply.applyAgentActivate(frame.payload).then((ack) => this.reply(frame, "ack", ack)).catch((err) => this.sendError(frame.id, "INTERNAL", `agent/activate failed: ${err.message}`, false));
|
|
4535
|
+
return;
|
|
4530
4536
|
case "integration/upsert":
|
|
4531
4537
|
this.deps.configApply.applyIntegrationUpsert(frame.payload);
|
|
4532
4538
|
return;
|
|
@@ -198188,6 +198194,227 @@ async function fetchHeadMtime(root) {
|
|
|
198188
198194
|
* without the key leaves the local value alone — hand-authored agent.json keeps
|
|
198189
198195
|
* working).
|
|
198190
198196
|
*/
|
|
198197
|
+
const DETACHED_DIR = ".detached";
|
|
198198
|
+
const STAGED_DIR = ".staged";
|
|
198199
|
+
const DETACHED_DATA_DIR = "agent";
|
|
198200
|
+
const DETACHED_META_FILE = "metadata.json";
|
|
198201
|
+
const MOVE_META_FILE = "metadata.json";
|
|
198202
|
+
/** Stable cold-move archive root. It is hidden, so agent discovery ignores it. */
|
|
198203
|
+
function detachedAgentDir(agentsDir, agentId) {
|
|
198204
|
+
return join(agentsDir, DETACHED_DIR, agentId);
|
|
198205
|
+
}
|
|
198206
|
+
function stagedAgentDir(agentsDir, agentId) {
|
|
198207
|
+
return join(agentsDir, STAGED_DIR, agentId);
|
|
198208
|
+
}
|
|
198209
|
+
function writeMoveStage(agentsDir, agentId, metadata) {
|
|
198210
|
+
const root = stagedAgentDir(agentsDir, agentId);
|
|
198211
|
+
const file = join(root, MOVE_META_FILE);
|
|
198212
|
+
const temp = join(root, `${MOVE_META_FILE}.tmp`);
|
|
198213
|
+
mkdirSync(root, { recursive: true });
|
|
198214
|
+
try {
|
|
198215
|
+
writeFileSync(temp, JSON.stringify(metadata, null, 2) + "\n");
|
|
198216
|
+
renameSync(temp, file);
|
|
198217
|
+
} catch (err) {
|
|
198218
|
+
rmSync(temp, { force: true });
|
|
198219
|
+
throw err;
|
|
198220
|
+
}
|
|
198221
|
+
}
|
|
198222
|
+
/** Durable fail-closed tombstone: a new move atomically supersedes the old id/state. */
|
|
198223
|
+
function stageAgentMove(agentsDir, agentId, moveId) {
|
|
198224
|
+
writeMoveStage(agentsDir, agentId, {
|
|
198225
|
+
moveId,
|
|
198226
|
+
state: "staging"
|
|
198227
|
+
});
|
|
198228
|
+
}
|
|
198229
|
+
function readAgentMoveStage(agentsDir, agentId) {
|
|
198230
|
+
const root = stagedAgentDir(agentsDir, agentId);
|
|
198231
|
+
if (!existsSync(root)) return void 0;
|
|
198232
|
+
try {
|
|
198233
|
+
const raw = JSON.parse(readFileSync(join(root, MOVE_META_FILE), "utf8"));
|
|
198234
|
+
if (typeof raw.moveId === "string" && (raw.state === "staging" || raw.state === "committed")) return {
|
|
198235
|
+
moveId: raw.moveId,
|
|
198236
|
+
state: raw.state
|
|
198237
|
+
};
|
|
198238
|
+
} catch {}
|
|
198239
|
+
return {
|
|
198240
|
+
moveId: "",
|
|
198241
|
+
state: "staging"
|
|
198242
|
+
};
|
|
198243
|
+
}
|
|
198244
|
+
function commitAgentMove(agentsDir, agentId, moveId) {
|
|
198245
|
+
const current = readAgentMoveStage(agentsDir, agentId);
|
|
198246
|
+
if (!current || current.moveId !== moveId) throw new Error(`cannot commit move "${moveId}" for agent "${agentId}": staging fence changed`);
|
|
198247
|
+
if (current.state === "committed") return;
|
|
198248
|
+
writeMoveStage(agentsDir, agentId, {
|
|
198249
|
+
moveId,
|
|
198250
|
+
state: "committed"
|
|
198251
|
+
});
|
|
198252
|
+
}
|
|
198253
|
+
function clearAgentMoveStage(agentsDir, agentId) {
|
|
198254
|
+
rmSync(stagedAgentDir(agentsDir, agentId), {
|
|
198255
|
+
recursive: true,
|
|
198256
|
+
force: true
|
|
198257
|
+
});
|
|
198258
|
+
}
|
|
198259
|
+
function agentMoveStages(agentsDir) {
|
|
198260
|
+
const root = join(agentsDir, STAGED_DIR);
|
|
198261
|
+
const out = /* @__PURE__ */ new Map();
|
|
198262
|
+
if (!existsSync(root)) return out;
|
|
198263
|
+
try {
|
|
198264
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
198265
|
+
if (!entry.isDirectory()) continue;
|
|
198266
|
+
const metadata = readAgentMoveStage(agentsDir, entry.name);
|
|
198267
|
+
if (metadata) out.set(entry.name, metadata);
|
|
198268
|
+
}
|
|
198269
|
+
} catch {}
|
|
198270
|
+
return out;
|
|
198271
|
+
}
|
|
198272
|
+
function detachedDataDir(agentsDir, agentId) {
|
|
198273
|
+
return join(detachedAgentDir(agentsDir, agentId), DETACHED_DATA_DIR);
|
|
198274
|
+
}
|
|
198275
|
+
function scrubAgentIntegrations(file) {
|
|
198276
|
+
const original = readFileSync(file, "utf8");
|
|
198277
|
+
const raw = JSON.parse(original);
|
|
198278
|
+
if (Array.isArray(raw.integrations) && raw.integrations.length === 0) return original;
|
|
198279
|
+
raw.integrations = [];
|
|
198280
|
+
writeFileSync(file, JSON.stringify(raw, null, 2) + "\n");
|
|
198281
|
+
return original;
|
|
198282
|
+
}
|
|
198283
|
+
/**
|
|
198284
|
+
* Move an active agent root out of the discovery tree without deleting any of
|
|
198285
|
+
* its daemon-local state. The metadata preserves custom/nested directory names
|
|
198286
|
+
* so a later activate or upsert can restore the exact original location.
|
|
198287
|
+
*/
|
|
198288
|
+
function archiveAgent(agentsDir, agentId) {
|
|
198289
|
+
const file = findAgentFileById(agentsDir, agentId);
|
|
198290
|
+
const archived = detachedDataDir(agentsDir, agentId);
|
|
198291
|
+
if (!file) {
|
|
198292
|
+
if (!existsSync(archived)) return "missing";
|
|
198293
|
+
const archivedFile = findAgentFileById(archived, agentId);
|
|
198294
|
+
if (!archivedFile) throw new Error(`cannot detach agent "${agentId}": detached archive is incomplete`);
|
|
198295
|
+
scrubAgentIntegrations(archivedFile);
|
|
198296
|
+
return "already-detached";
|
|
198297
|
+
}
|
|
198298
|
+
const base = resolve(agentsDir);
|
|
198299
|
+
const activeDir = resolve(dirname(file));
|
|
198300
|
+
const relativePath = relative(base, activeDir);
|
|
198301
|
+
if (!relativePath || isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(`..${sep}`)) throw new Error(`cannot detach agent "${agentId}": its root is not a child of agentsDir`);
|
|
198302
|
+
const archiveRoot = detachedAgentDir(agentsDir, agentId);
|
|
198303
|
+
if (existsSync(archiveRoot)) if (!existsSync(archived)) rmSync(archiveRoot, {
|
|
198304
|
+
recursive: true,
|
|
198305
|
+
force: true
|
|
198306
|
+
});
|
|
198307
|
+
else throw new Error(`cannot detach agent "${agentId}": an archive already exists while the agent is active`);
|
|
198308
|
+
const metadata = {
|
|
198309
|
+
agentId,
|
|
198310
|
+
relativePath
|
|
198311
|
+
};
|
|
198312
|
+
const originalAgentJson = readFileSync(file, "utf8");
|
|
198313
|
+
try {
|
|
198314
|
+
mkdirSync(archiveRoot, { recursive: true });
|
|
198315
|
+
scrubAgentIntegrations(file);
|
|
198316
|
+
writeFileSync(join(archiveRoot, DETACHED_META_FILE), JSON.stringify(metadata, null, 2) + "\n");
|
|
198317
|
+
renameSync(activeDir, archived);
|
|
198318
|
+
} catch (err) {
|
|
198319
|
+
if (existsSync(file)) writeFileSync(file, originalAgentJson);
|
|
198320
|
+
rmSync(archiveRoot, {
|
|
198321
|
+
recursive: true,
|
|
198322
|
+
force: true
|
|
198323
|
+
});
|
|
198324
|
+
throw err;
|
|
198325
|
+
}
|
|
198326
|
+
return "archived";
|
|
198327
|
+
}
|
|
198328
|
+
/** Restore a cold-move archive to its exact former relative location. */
|
|
198329
|
+
function restoreArchivedAgent(agentsDir, agentId) {
|
|
198330
|
+
const archiveRoot = detachedAgentDir(agentsDir, agentId);
|
|
198331
|
+
const archived = detachedDataDir(agentsDir, agentId);
|
|
198332
|
+
if (!existsSync(archiveRoot)) return false;
|
|
198333
|
+
if (!existsSync(archived)) throw new Error(`cannot activate agent "${agentId}": detached archive is incomplete`);
|
|
198334
|
+
let metadata;
|
|
198335
|
+
try {
|
|
198336
|
+
metadata = JSON.parse(readFileSync(join(archiveRoot, DETACHED_META_FILE), "utf8"));
|
|
198337
|
+
} catch {
|
|
198338
|
+
throw new Error(`cannot activate agent "${agentId}": detached archive metadata is invalid`);
|
|
198339
|
+
}
|
|
198340
|
+
if (metadata.agentId !== agentId || typeof metadata.relativePath !== "string" || !metadata.relativePath) throw new Error(`cannot activate agent "${agentId}": detached archive metadata does not match`);
|
|
198341
|
+
const base = resolve(agentsDir);
|
|
198342
|
+
const target = resolve(base, metadata.relativePath);
|
|
198343
|
+
if (target === base || !target.startsWith(base + sep)) throw new Error(`cannot activate agent "${agentId}": detached archive path escapes agentsDir`);
|
|
198344
|
+
if (existsSync(target)) throw new Error(`cannot activate agent "${agentId}": original path is already occupied`);
|
|
198345
|
+
if (!findAgentFileById(archived, agentId)) throw new Error(`cannot activate agent "${agentId}": detached archive does not contain the agent`);
|
|
198346
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
198347
|
+
renameSync(archived, target);
|
|
198348
|
+
rmSync(archiveRoot, {
|
|
198349
|
+
recursive: true,
|
|
198350
|
+
force: true
|
|
198351
|
+
});
|
|
198352
|
+
return true;
|
|
198353
|
+
}
|
|
198354
|
+
/**
|
|
198355
|
+
* Exact-set the CP-owned dependents restored from a move-back archive BEFORE
|
|
198356
|
+
* the agent becomes visible to reconcile. CP crons are explicitly tagged and
|
|
198357
|
+
* can coexist with hand-authored entries. Integrations historically have no
|
|
198358
|
+
* ownership marker, so move activation deliberately treats the CP list as
|
|
198359
|
+
* authoritative/fail-closed and removes every non-listed integration; retaining
|
|
198360
|
+
* an unknown stale bot credential would be the less safe ambiguity.
|
|
198361
|
+
*/
|
|
198362
|
+
function pruneMovedAgentDependents(agentsDir, agentId, desired) {
|
|
198363
|
+
const file = findAgentFileById(agentsDir, agentId);
|
|
198364
|
+
if (!file) return false;
|
|
198365
|
+
const raw = JSON.parse(readFileSync(file, "utf8"));
|
|
198366
|
+
const integrationIds = new Set(desired.integrationIds);
|
|
198367
|
+
const cronIds = new Set(desired.cronIds);
|
|
198368
|
+
let changed = false;
|
|
198369
|
+
if (Array.isArray(raw.integrations)) {
|
|
198370
|
+
const seen = /* @__PURE__ */ new Set();
|
|
198371
|
+
const next = raw.integrations.filter((integration) => {
|
|
198372
|
+
if (typeof integration !== "object" || integration === null) return false;
|
|
198373
|
+
const id = integration.id;
|
|
198374
|
+
if (typeof id !== "string" || !integrationIds.has(id) || seen.has(id)) return false;
|
|
198375
|
+
seen.add(id);
|
|
198376
|
+
return true;
|
|
198377
|
+
});
|
|
198378
|
+
if (JSON.stringify(next) !== JSON.stringify(raw.integrations)) {
|
|
198379
|
+
raw.integrations = next;
|
|
198380
|
+
changed = true;
|
|
198381
|
+
}
|
|
198382
|
+
}
|
|
198383
|
+
const localCronCollisions = /* @__PURE__ */ new Set();
|
|
198384
|
+
if (Array.isArray(raw.crons)) {
|
|
198385
|
+
const seenCp = /* @__PURE__ */ new Set();
|
|
198386
|
+
const next = raw.crons.filter((cron) => {
|
|
198387
|
+
if (typeof cron !== "object" || cron === null) return true;
|
|
198388
|
+
const item = cron;
|
|
198389
|
+
if (item.origin !== "cp") {
|
|
198390
|
+
if (typeof item.id === "string" && cronIds.has(item.id)) localCronCollisions.add(item.id);
|
|
198391
|
+
return true;
|
|
198392
|
+
}
|
|
198393
|
+
if (typeof item.id !== "string" || !cronIds.has(item.id) || seenCp.has(item.id)) return false;
|
|
198394
|
+
seenCp.add(item.id);
|
|
198395
|
+
return true;
|
|
198396
|
+
});
|
|
198397
|
+
if (JSON.stringify(next) !== JSON.stringify(raw.crons)) {
|
|
198398
|
+
raw.crons = next;
|
|
198399
|
+
changed = true;
|
|
198400
|
+
}
|
|
198401
|
+
}
|
|
198402
|
+
if (changed) writeFileSync(file, JSON.stringify(raw, null, 2) + "\n");
|
|
198403
|
+
const finalIntegrations = new Set((Array.isArray(raw.integrations) ? raw.integrations : []).flatMap((integration) => {
|
|
198404
|
+
if (typeof integration !== "object" || integration === null) return [];
|
|
198405
|
+
const id = integration.id;
|
|
198406
|
+
return typeof id === "string" ? [id] : [];
|
|
198407
|
+
}));
|
|
198408
|
+
const finalCpCrons = new Set((Array.isArray(raw.crons) ? raw.crons : []).flatMap((cron) => {
|
|
198409
|
+
if (typeof cron !== "object" || cron === null) return [];
|
|
198410
|
+
const item = cron;
|
|
198411
|
+
return item.origin === "cp" && typeof item.id === "string" ? [item.id] : [];
|
|
198412
|
+
}));
|
|
198413
|
+
const missingIntegrations = desired.integrationIds.filter((id) => !finalIntegrations.has(id));
|
|
198414
|
+
const missingCrons = desired.cronIds.filter((id) => !finalCpCrons.has(id));
|
|
198415
|
+
if (missingIntegrations.length || missingCrons.length || localCronCollisions.size) throw new Error(`cannot activate agent "${agentId}": authoritative dependent bundle did not persist (missing integrations: ${missingIntegrations.join(", ") || "none"}; missing crons: ${missingCrons.join(", ") || "none"}; local cron collisions: ${[...localCronCollisions].join(", ") || "none"})`);
|
|
198416
|
+
return changed;
|
|
198417
|
+
}
|
|
198191
198418
|
/** Map a CP workspace mode onto the daemon's AgentSchema workspace mode. */
|
|
198192
198419
|
function mapWorkspaceMode(mode) {
|
|
198193
198420
|
return mode === "scratch" ? "from-scratch" : "git-repo";
|
|
@@ -198267,7 +198494,8 @@ function applySpecFields(raw, spec, opts) {
|
|
|
198267
198494
|
* from-scratch, path daemon-generated.
|
|
198268
198495
|
*/
|
|
198269
198496
|
function writeAgentSpec(agentsDir, agentId, spec, deps) {
|
|
198270
|
-
|
|
198497
|
+
let existingFile = findAgentFileById(agentsDir, agentId);
|
|
198498
|
+
if (!existingFile && restoreArchivedAgent(agentsDir, agentId)) existingFile = findAgentFileById(agentsDir, agentId);
|
|
198271
198499
|
if (existingFile) {
|
|
198272
198500
|
const raw = JSON.parse(readFileSync(existingFile, "utf8"));
|
|
198273
198501
|
applySpecFields(raw, spec, {
|
|
@@ -198317,6 +198545,11 @@ function removeAgent(agentsDir, agentId) {
|
|
|
198317
198545
|
recursive: true,
|
|
198318
198546
|
force: true
|
|
198319
198547
|
});
|
|
198548
|
+
rmSync(detachedAgentDir(agentsDir, agentId), {
|
|
198549
|
+
recursive: true,
|
|
198550
|
+
force: true
|
|
198551
|
+
});
|
|
198552
|
+
clearAgentMoveStage(agentsDir, agentId);
|
|
198320
198553
|
}
|
|
198321
198554
|
//#endregion
|
|
198322
198555
|
//#region src/agents/write-cron.ts
|
|
@@ -198461,6 +198694,20 @@ var CpAgentRegistry = class {
|
|
|
198461
198694
|
removeAgent(this.agentsDir, agentId);
|
|
198462
198695
|
this.onChange();
|
|
198463
198696
|
}
|
|
198697
|
+
/** Non-destructively move an agent root out of the active discovery tree. */
|
|
198698
|
+
detach(agentId) {
|
|
198699
|
+
const result = archiveAgent(this.agentsDir, agentId);
|
|
198700
|
+
if (result !== "missing") this.onChange();
|
|
198701
|
+
return result;
|
|
198702
|
+
}
|
|
198703
|
+
/** Restore a detached root in place. Idempotent while already active. */
|
|
198704
|
+
activate(agentId, desired) {
|
|
198705
|
+
const alreadyActive = !!findAgentFileById(this.agentsDir, agentId);
|
|
198706
|
+
if (!alreadyActive && !restoreArchivedAgent(this.agentsDir, agentId)) return "missing";
|
|
198707
|
+
const pruned = pruneMovedAgentDependents(this.agentsDir, agentId, desired);
|
|
198708
|
+
if (!alreadyActive || pruned) this.onChange();
|
|
198709
|
+
return alreadyActive ? "already-active" : "restored";
|
|
198710
|
+
}
|
|
198464
198711
|
/**
|
|
198465
198712
|
* Apply the register/ok reconcile roster: create-or-merge EACH entry and
|
|
198466
198713
|
* NOTHING else. Never prunes agents absent from the roster (deletion is only
|
|
@@ -214428,10 +214675,18 @@ var Daemon = class Daemon {
|
|
|
214428
214675
|
requestExit;
|
|
214429
214676
|
draining = false;
|
|
214430
214677
|
drainingAgents = /* @__PURE__ */ new Set();
|
|
214678
|
+
moveStagedAgents = /* @__PURE__ */ new Set();
|
|
214679
|
+
moveStageMetadata = /* @__PURE__ */ new Map();
|
|
214680
|
+
activatingAgents = /* @__PURE__ */ new Set();
|
|
214681
|
+
agentMoveTails = /* @__PURE__ */ new Map();
|
|
214682
|
+
agentMoveInFlight = /* @__PURE__ */ new Map();
|
|
214683
|
+
activeDispatchesByAgent = /* @__PURE__ */ new Map();
|
|
214684
|
+
activeReplyConnectionUses = /* @__PURE__ */ new Map();
|
|
214431
214685
|
hostStopping = /* @__PURE__ */ new Map();
|
|
214432
214686
|
idleSweepTimer;
|
|
214433
214687
|
cancelTimers = /* @__PURE__ */ new Map();
|
|
214434
214688
|
slackRetryTimers = /* @__PURE__ */ new Map();
|
|
214689
|
+
slackRetryRuns = /* @__PURE__ */ new Map();
|
|
214435
214690
|
constructor(opts = {}) {
|
|
214436
214691
|
this.opts = opts;
|
|
214437
214692
|
this.clock = opts.clock ?? systemClock;
|
|
@@ -214476,12 +214731,16 @@ var Daemon = class Daemon {
|
|
|
214476
214731
|
this.log.info(`starting daemon (root=${root})`);
|
|
214477
214732
|
this.log.info(`control plane: ${cfg.controlPlane?.enabled ? `enabled (${cfg.controlPlane.url ?? "no url"})` : "disabled — running local"}`);
|
|
214478
214733
|
this.agentsDir = cfg.agentsDir;
|
|
214479
|
-
|
|
214480
|
-
this.
|
|
214734
|
+
this.moveStageMetadata = agentMoveStages(this.agentsDir);
|
|
214735
|
+
this.moveStagedAgents = new Set([...this.moveStageMetadata].filter(([, metadata]) => metadata.state === "staging").map(([agentId]) => agentId));
|
|
214736
|
+
for (const agentId of this.moveStagedAgents) this.drainingAgents.add(agentId);
|
|
214737
|
+
const discoveredAgents = this.loadAgentList();
|
|
214738
|
+
const agents = discoveredAgents.filter((agent) => !this.moveStagedAgents.has(agent.id));
|
|
214739
|
+
this.fileAgents = new Map(discoveredAgents.map((a) => [a.id, a]));
|
|
214481
214740
|
this.log.info(`loaded ${agents.length} agent(s) from ${this.agentsDir}${agents.length ? `: ${agents.map((a) => a.id).join(", ")}` : ""}`);
|
|
214482
214741
|
this.root = root;
|
|
214483
214742
|
const resolvedRuntimes = await resolveRuntimes(cfg, root, {
|
|
214484
|
-
neededRuntimes:
|
|
214743
|
+
neededRuntimes: discoveredAgents.map((a) => a.runtime),
|
|
214485
214744
|
mode: "cache-first"
|
|
214486
214745
|
});
|
|
214487
214746
|
this.runtimes = installedRuntimes(resolvedRuntimes);
|
|
@@ -214628,7 +214887,7 @@ var Daemon = class Daemon {
|
|
|
214628
214887
|
this.log.warn(`slack: connection failed for appToken — retrying in 60s: ${formatErr(err)}`);
|
|
214629
214888
|
const timer = this.clock.setTimeout(() => {
|
|
214630
214889
|
if (this.draining) return;
|
|
214631
|
-
this.
|
|
214890
|
+
this.startSlackRetry(group.appToken);
|
|
214632
214891
|
}, 6e4);
|
|
214633
214892
|
this.slackRetryTimers.set(group.appToken, timer);
|
|
214634
214893
|
}
|
|
@@ -214642,7 +214901,7 @@ var Daemon = class Daemon {
|
|
|
214642
214901
|
this.watcher = watch$1(this.agentsDir, {
|
|
214643
214902
|
ignoreInitial: true,
|
|
214644
214903
|
depth: 4,
|
|
214645
|
-
ignored: (p) => /[\\/](node_modules|\.git)([\\/]|$)/.test(p)
|
|
214904
|
+
ignored: (p) => /[\\/](node_modules|\.git|\.detached|\.staged)([\\/]|$)/.test(p)
|
|
214646
214905
|
});
|
|
214647
214906
|
const debounced = () => {
|
|
214648
214907
|
clearTimeout(this.debounceTimer);
|
|
@@ -214671,7 +214930,7 @@ var Daemon = class Daemon {
|
|
|
214671
214930
|
* routing (all of which read `agent.integrations`) see one merged view.
|
|
214672
214931
|
*/
|
|
214673
214932
|
effectiveAgents() {
|
|
214674
|
-
return [...this.fileAgents.values()];
|
|
214933
|
+
return [...this.fileAgents.values()].filter((agent) => !this.moveStagedAgents.has(agent.id));
|
|
214675
214934
|
}
|
|
214676
214935
|
/**
|
|
214677
214936
|
* Converge the running set to the desired effective agents. Driven by both the
|
|
@@ -214726,6 +214985,7 @@ var Daemon = class Daemon {
|
|
|
214726
214985
|
this.agents.delete(id);
|
|
214727
214986
|
this.scheduler.unregister(id);
|
|
214728
214987
|
}
|
|
214988
|
+
let connectionsDirty = toStart.length > 0 || toStop.length > 0;
|
|
214729
214989
|
for (const change of toChange) {
|
|
214730
214990
|
const a = change.agent;
|
|
214731
214991
|
this.agents.set(a.id, a);
|
|
@@ -214739,20 +214999,19 @@ var Daemon = class Daemon {
|
|
|
214739
214999
|
this.hostStarts.delete(a.id);
|
|
214740
215000
|
}
|
|
214741
215001
|
if (change.workspace) this.prefetchClone(a);
|
|
214742
|
-
if (change.integrations)
|
|
214743
|
-
await this.reconcileSlackConnections();
|
|
214744
|
-
await this.reconcileTelegramConnections();
|
|
214745
|
-
await this.reconcileDiscordConnections();
|
|
214746
|
-
}
|
|
215002
|
+
if (change.integrations) connectionsDirty = true;
|
|
214747
215003
|
}
|
|
214748
215004
|
for (const a of toStart) {
|
|
214749
215005
|
this.agents.set(a.id, a);
|
|
214750
215006
|
this.prefetchClone(a);
|
|
214751
215007
|
this.scheduler.sync(a.id, a.crons);
|
|
214752
215008
|
}
|
|
214753
|
-
if (
|
|
214754
|
-
|
|
214755
|
-
|
|
215009
|
+
if (connectionsDirty) {
|
|
215010
|
+
await this.closeUnusedPlatformConnections();
|
|
215011
|
+
await this.reconcileSlackConnections();
|
|
215012
|
+
await this.reconcileTelegramConnections();
|
|
215013
|
+
await this.reconcileDiscordConnections();
|
|
215014
|
+
}
|
|
214756
215015
|
}
|
|
214757
215016
|
/**
|
|
214758
215017
|
* Fire-and-forget eager clone of a git-repo workspace so the checkout is warm
|
|
@@ -214765,6 +215024,93 @@ var Daemon = class Daemon {
|
|
|
214765
215024
|
prefetchWorkspace(agent).catch((err) => this.log.warn(`workspace: prefetch clone for "${agent.id}" failed (will retry at first session): ${formatErr(err)}`));
|
|
214766
215025
|
}
|
|
214767
215026
|
/**
|
|
215027
|
+
* Close platform clients whose credential key has no reference in the FINAL
|
|
215028
|
+
* active-agent roster, and evict every derived index that points at a removed
|
|
215029
|
+
* or re-keyed integration. Consolidation maps are the reference counts: direct
|
|
215030
|
+
* Slack is keyed by appToken; shared Slack, Telegram and Discord by botToken.
|
|
215031
|
+
*
|
|
215032
|
+
* A captured connection on a live turn is a temporary reference too. Detach
|
|
215033
|
+
* drains its own dispatch leases before reaching this method; the guard also
|
|
215034
|
+
* keeps ordinary concurrent reconcile safe for unrelated in-flight turns.
|
|
215035
|
+
*/
|
|
215036
|
+
async closeUnusedPlatformConnections() {
|
|
215037
|
+
const agents = [...this.agents.values()];
|
|
215038
|
+
const direct = consolidate(agents);
|
|
215039
|
+
const shared = consolidateShared(agents);
|
|
215040
|
+
const telegram = consolidateTelegram(agents);
|
|
215041
|
+
const discord = consolidateDiscord(agents);
|
|
215042
|
+
const directByIntegration = /* @__PURE__ */ new Map();
|
|
215043
|
+
for (const group of direct.values()) for (const { integrationId } of group.integrations) directByIntegration.set(integrationId, {
|
|
215044
|
+
appToken: group.appToken,
|
|
215045
|
+
botToken: group.botToken
|
|
215046
|
+
});
|
|
215047
|
+
const sharedByIntegration = /* @__PURE__ */ new Map();
|
|
215048
|
+
for (const group of shared.values()) for (const { integrationId } of group.integrations) sharedByIntegration.set(integrationId, group.botToken);
|
|
215049
|
+
const telegramByIntegration = /* @__PURE__ */ new Map();
|
|
215050
|
+
for (const group of telegram.values()) for (const { integrationId } of group.integrations) telegramByIntegration.set(integrationId, group.botToken);
|
|
215051
|
+
const discordByIntegration = /* @__PURE__ */ new Map();
|
|
215052
|
+
for (const group of discord.values()) for (const { integrationId } of group.integrations) discordByIntegration.set(integrationId, group.botToken);
|
|
215053
|
+
const allDesiredIds = /* @__PURE__ */ new Set([
|
|
215054
|
+
...directByIntegration.keys(),
|
|
215055
|
+
...sharedByIntegration.keys(),
|
|
215056
|
+
...telegramByIntegration.keys(),
|
|
215057
|
+
...discordByIntegration.keys()
|
|
215058
|
+
]);
|
|
215059
|
+
const dropIdentity = (integrationId) => {
|
|
215060
|
+
delete this.botUserIds[integrationId];
|
|
215061
|
+
this.channelSnapshots.delete(integrationId);
|
|
215062
|
+
};
|
|
215063
|
+
for (const integrationId of Object.keys(this.botUserIds)) if (!allDesiredIds.has(integrationId)) dropIdentity(integrationId);
|
|
215064
|
+
for (const integrationId of [...this.channelSnapshots.keys()]) if (!allDesiredIds.has(integrationId)) this.channelSnapshots.delete(integrationId);
|
|
215065
|
+
for (const [integrationId, conn] of this.connByIntegration) {
|
|
215066
|
+
const expectedDirect = directByIntegration.get(integrationId);
|
|
215067
|
+
const expectedShared = sharedByIntegration.get(integrationId);
|
|
215068
|
+
if (!(expectedDirect ? conn.appToken === expectedDirect.appToken && conn.botToken === expectedDirect.botToken : expectedShared !== void 0 ? conn.appToken === "" && conn.botToken === expectedShared : false)) {
|
|
215069
|
+
this.connByIntegration.delete(integrationId);
|
|
215070
|
+
dropIdentity(integrationId);
|
|
215071
|
+
}
|
|
215072
|
+
}
|
|
215073
|
+
for (const [integrationId, conn] of this.tgConnByIntegration) if (conn.botToken !== telegramByIntegration.get(integrationId)) {
|
|
215074
|
+
this.tgConnByIntegration.delete(integrationId);
|
|
215075
|
+
dropIdentity(integrationId);
|
|
215076
|
+
}
|
|
215077
|
+
for (const [integrationId, conn] of this.dcConnByIntegration) if (conn.botToken !== discordByIntegration.get(integrationId)) {
|
|
215078
|
+
this.dcConnByIntegration.delete(integrationId);
|
|
215079
|
+
dropIdentity(integrationId);
|
|
215080
|
+
}
|
|
215081
|
+
for (const [appToken, timer] of this.slackRetryTimers) {
|
|
215082
|
+
if (direct.has(appToken)) continue;
|
|
215083
|
+
this.clock.clearTimeout(timer);
|
|
215084
|
+
this.slackRetryTimers.delete(appToken);
|
|
215085
|
+
}
|
|
215086
|
+
const retryRuns = [...this.slackRetryRuns].filter(([appToken, run]) => direct.get(appToken)?.botToken !== run.botToken).map(([, run]) => run.promise);
|
|
215087
|
+
if (retryRuns.length) await Promise.all(retryRuns);
|
|
215088
|
+
for (const conn of [...this.connections]) {
|
|
215089
|
+
if (direct.get(conn.appToken)?.botToken === conn.botToken) continue;
|
|
215090
|
+
await this.waitForConnectionUses(conn);
|
|
215091
|
+
await conn.stop();
|
|
215092
|
+
this.connections = this.connections.filter((candidate) => candidate !== conn);
|
|
215093
|
+
}
|
|
215094
|
+
for (const [botToken, conn] of [...this.sharedSlackConns]) {
|
|
215095
|
+
if (shared.has(botToken)) continue;
|
|
215096
|
+
await this.waitForConnectionUses(conn);
|
|
215097
|
+
await conn.stop();
|
|
215098
|
+
this.sharedSlackConns.delete(botToken);
|
|
215099
|
+
}
|
|
215100
|
+
for (const conn of [...this.telegramConns]) {
|
|
215101
|
+
if (telegram.has(conn.botToken)) continue;
|
|
215102
|
+
await this.waitForConnectionUses(conn);
|
|
215103
|
+
await conn.stop();
|
|
215104
|
+
this.telegramConns = this.telegramConns.filter((candidate) => candidate !== conn);
|
|
215105
|
+
}
|
|
215106
|
+
for (const conn of [...this.discordConns]) {
|
|
215107
|
+
if (discord.has(conn.botToken)) continue;
|
|
215108
|
+
await this.waitForConnectionUses(conn);
|
|
215109
|
+
await conn.stop();
|
|
215110
|
+
this.discordConns = this.discordConns.filter((candidate) => candidate !== conn);
|
|
215111
|
+
}
|
|
215112
|
+
}
|
|
215113
|
+
/**
|
|
214768
215114
|
* Reconcile the connection-derived Slack state (`botUserIds`, `connByIntegration`,
|
|
214769
215115
|
* open sockets) against the live `this.agents` set. Routing itself is rebuilt
|
|
214770
215116
|
* implicitly each message (mergedRules reads this.agents) — this only maintains the
|
|
@@ -214777,18 +215123,14 @@ var Daemon = class Daemon {
|
|
|
214777
215123
|
* - NEW integration reusing an ALREADY-OPEN appToken → no socket churn; just
|
|
214778
215124
|
* backfill botUserIds/connByIntegration from the existing conn (mention routing
|
|
214779
215125
|
* for the new bot would otherwise silently never match).
|
|
214780
|
-
* - REMOVED
|
|
214781
|
-
*
|
|
214782
|
-
* the one genuinely dangerous op; it is left as a logged deferred-close TODO so
|
|
214783
|
-
* a stale socket simply lingers (harmless) rather than risking the daemon.
|
|
215126
|
+
* - REMOVED/re-keyed appToken → closed by closeUnusedPlatformConnections first,
|
|
215127
|
+
* after checking the final roster and captured-turn connection leases.
|
|
214784
215128
|
*/
|
|
214785
215129
|
async reconcileSlackConnections() {
|
|
214786
215130
|
const groups = consolidate([...this.agents.values()]);
|
|
214787
|
-
new Set([...this.connByIntegration.values()].map((c) => c.appToken));
|
|
214788
215131
|
for (const group of groups.values()) {
|
|
214789
|
-
const existing =
|
|
215132
|
+
const existing = this.connections.find((c) => c.appToken === group.appToken && c.botToken === group.botToken);
|
|
214790
215133
|
if (existing) {
|
|
214791
|
-
if (existing.botToken !== group.botToken) this.log.warn(`slack: botToken changed for appToken (socket bot user ${existing.botUserId}) — deferred: the live socket keeps the old botToken until it is closed+reopened`);
|
|
214792
215134
|
let bound = false;
|
|
214793
215135
|
for (const { integrationId } of group.integrations) if (this.connByIntegration.get(integrationId) !== existing) {
|
|
214794
215136
|
this.botUserIds[integrationId] = existing.botUserId;
|
|
@@ -214848,12 +215190,6 @@ var Daemon = class Daemon {
|
|
|
214848
215190
|
async openSharedSlackConnections(agents) {
|
|
214849
215191
|
const groups = consolidateShared(agents);
|
|
214850
215192
|
for (const group of groups.values()) {
|
|
214851
|
-
const staleDirect = this.connections.find((c) => c.botToken === group.botToken && c.appToken !== "");
|
|
214852
|
-
if (staleDirect) {
|
|
214853
|
-
this.log.info(`slack: bot flipped to shared — stopping its direct socket (bot ${staleDirect.botUserId})`);
|
|
214854
|
-
await staleDirect.stop().catch(() => {});
|
|
214855
|
-
this.connections = this.connections.filter((c) => c !== staleDirect);
|
|
214856
|
-
}
|
|
214857
215193
|
let conn = this.sharedSlackConns.get(group.botToken);
|
|
214858
215194
|
if (!conn) {
|
|
214859
215195
|
conn = new SlackConnection({
|
|
@@ -214892,7 +215228,7 @@ var Daemon = class Daemon {
|
|
|
214892
215228
|
* tgConnByIntegration for every integrationId on that token. A failed start
|
|
214893
215229
|
* is logged and leaves existing connections intact (never throws out).
|
|
214894
215230
|
* - integration reusing an ALREADY-OPEN token → bind it onto the live conn.
|
|
214895
|
-
* - REMOVED token →
|
|
215231
|
+
* - REMOVED token → closed by closeUnusedPlatformConnections before this opener.
|
|
214896
215232
|
*/
|
|
214897
215233
|
async reconcileTelegramConnections() {
|
|
214898
215234
|
const groups = consolidateTelegram([...this.agents.values()]);
|
|
@@ -214938,8 +215274,7 @@ var Daemon = class Daemon {
|
|
|
214938
215274
|
* Parallel to reconcileTelegramConnections (one Gateway per bot token), but
|
|
214939
215275
|
* mention-routing matches the bot's numeric user id (normalize's `mentionedBots`
|
|
214940
215276
|
* are Discord user ids). A failed start is logged and leaves other connections
|
|
214941
|
-
* intact (never throws out);
|
|
214942
|
-
* close reasoning as Slack/Telegram).
|
|
215277
|
+
* intact (never throws out); removed tokens are closed by the shared close phase.
|
|
214943
215278
|
*/
|
|
214944
215279
|
async reconcileDiscordConnections() {
|
|
214945
215280
|
const groups = consolidateDiscord([...this.agents.values()]);
|
|
@@ -215037,9 +215372,26 @@ var Daemon = class Daemon {
|
|
|
215037
215372
|
* at a slow, fixed interval — never gives up, so a temporary network outage
|
|
215038
215373
|
* self-heals without manual daemon restart.
|
|
215039
215374
|
*/
|
|
215040
|
-
|
|
215375
|
+
startSlackRetry(appToken) {
|
|
215376
|
+
if (this.slackRetryRuns.has(appToken)) return;
|
|
215377
|
+
const group = consolidate([...this.agents.values()]).get(appToken);
|
|
215378
|
+
if (!group) return;
|
|
215379
|
+
const run = this.retrySlackConnection(appToken).catch((err) => this.log.error(`slack: retry loop error: ${formatErr(err)}`)).finally(() => {
|
|
215380
|
+
if (this.slackRetryRuns.get(appToken)?.promise === run) this.slackRetryRuns.delete(appToken);
|
|
215381
|
+
});
|
|
215382
|
+
this.slackRetryRuns.set(appToken, {
|
|
215383
|
+
botToken: group.botToken,
|
|
215384
|
+
promise: run
|
|
215385
|
+
});
|
|
215386
|
+
}
|
|
215387
|
+
async retrySlackConnection(appToken) {
|
|
215041
215388
|
if (this.draining) return;
|
|
215042
|
-
|
|
215389
|
+
const group = consolidate([...this.agents.values()]).get(appToken);
|
|
215390
|
+
if (!group) {
|
|
215391
|
+
this.slackRetryTimers.delete(appToken);
|
|
215392
|
+
return;
|
|
215393
|
+
}
|
|
215394
|
+
if (this.connections.some((c) => c.appToken === group.appToken && c.botToken === group.botToken)) {
|
|
215043
215395
|
this.slackRetryTimers.delete(group.appToken);
|
|
215044
215396
|
return;
|
|
215045
215397
|
}
|
|
@@ -215061,9 +215413,15 @@ var Daemon = class Daemon {
|
|
|
215061
215413
|
});
|
|
215062
215414
|
try {
|
|
215063
215415
|
await conn.start();
|
|
215416
|
+
const currentGroup = consolidate([...this.agents.values()]).get(appToken);
|
|
215417
|
+
if (this.draining || !currentGroup || currentGroup.botToken !== group.botToken) {
|
|
215418
|
+
await conn.stop().catch(() => {});
|
|
215419
|
+
this.slackRetryTimers.delete(appToken);
|
|
215420
|
+
return;
|
|
215421
|
+
}
|
|
215064
215422
|
this.log.info(`slack: background retry succeeded — connected as bot user ${conn.botUserId}`);
|
|
215065
215423
|
this.slackRetryTimers.delete(group.appToken);
|
|
215066
|
-
for (const { integrationId } of
|
|
215424
|
+
for (const { integrationId } of currentGroup.integrations) {
|
|
215067
215425
|
this.botUserIds[integrationId] = conn.botUserId;
|
|
215068
215426
|
this.connByIntegration.set(integrationId, conn);
|
|
215069
215427
|
}
|
|
@@ -215071,10 +215429,14 @@ var Daemon = class Daemon {
|
|
|
215071
215429
|
this.refreshChannels(conn);
|
|
215072
215430
|
} catch (err) {
|
|
215073
215431
|
await conn.stop().catch(() => {});
|
|
215432
|
+
if (this.draining || !consolidate([...this.agents.values()]).has(appToken)) {
|
|
215433
|
+
this.slackRetryTimers.delete(appToken);
|
|
215434
|
+
return;
|
|
215435
|
+
}
|
|
215074
215436
|
this.log.warn(`slack: background retry failed — scheduling next attempt in 60s: ${formatErr(err)}`);
|
|
215075
215437
|
const timer = this.clock.setTimeout(() => {
|
|
215076
215438
|
if (this.draining) return;
|
|
215077
|
-
this.
|
|
215439
|
+
this.startSlackRetry(appToken);
|
|
215078
215440
|
}, 6e4);
|
|
215079
215441
|
this.slackRetryTimers.set(group.appToken, timer);
|
|
215080
215442
|
}
|
|
@@ -216587,6 +216949,45 @@ var Daemon = class Daemon {
|
|
|
216587
216949
|
paused(agentId) {
|
|
216588
216950
|
return this.agents.get(agentId)?.pause === true;
|
|
216589
216951
|
}
|
|
216952
|
+
beginActiveDispatch(agentId) {
|
|
216953
|
+
let resolveDone;
|
|
216954
|
+
const done = new Promise((resolve) => resolveDone = resolve);
|
|
216955
|
+
const active = this.activeDispatchesByAgent.get(agentId) ?? /* @__PURE__ */ new Set();
|
|
216956
|
+
active.add(done);
|
|
216957
|
+
this.activeDispatchesByAgent.set(agentId, active);
|
|
216958
|
+
let released = false;
|
|
216959
|
+
return () => {
|
|
216960
|
+
if (released) return;
|
|
216961
|
+
released = true;
|
|
216962
|
+
active.delete(done);
|
|
216963
|
+
if (active.size === 0) this.activeDispatchesByAgent.delete(agentId);
|
|
216964
|
+
resolveDone();
|
|
216965
|
+
};
|
|
216966
|
+
}
|
|
216967
|
+
holdReplyConnection(conn) {
|
|
216968
|
+
if (!conn) return () => {};
|
|
216969
|
+
let resolveDone;
|
|
216970
|
+
const done = new Promise((resolve) => resolveDone = resolve);
|
|
216971
|
+
const uses = this.activeReplyConnectionUses.get(conn) ?? /* @__PURE__ */ new Set();
|
|
216972
|
+
uses.add(done);
|
|
216973
|
+
this.activeReplyConnectionUses.set(conn, uses);
|
|
216974
|
+
let released = false;
|
|
216975
|
+
return () => {
|
|
216976
|
+
if (released) return;
|
|
216977
|
+
released = true;
|
|
216978
|
+
uses.delete(done);
|
|
216979
|
+
if (uses.size === 0) this.activeReplyConnectionUses.delete(conn);
|
|
216980
|
+
resolveDone();
|
|
216981
|
+
};
|
|
216982
|
+
}
|
|
216983
|
+
async waitForConnectionUses(conn) {
|
|
216984
|
+
while (true) {
|
|
216985
|
+
const leases = [...this.activeReplyConnectionUses.get(conn) ?? []];
|
|
216986
|
+
const pending = [...this.pending.values()].filter((turn) => turn.conn === conn).map((turn) => turn.done);
|
|
216987
|
+
if (leases.length === 0 && pending.length === 0) return;
|
|
216988
|
+
await Promise.all([...leases, ...pending]);
|
|
216989
|
+
}
|
|
216990
|
+
}
|
|
216590
216991
|
async runLoop(key, firstEntry) {
|
|
216591
216992
|
let entry = firstEntry;
|
|
216592
216993
|
while (entry) {
|
|
@@ -216605,7 +217006,13 @@ var Daemon = class Daemon {
|
|
|
216605
217006
|
return;
|
|
216606
217007
|
}
|
|
216607
217008
|
try {
|
|
216608
|
-
const
|
|
217009
|
+
const releaseDispatch = this.beginActiveDispatch(entry.agentId);
|
|
217010
|
+
let sessionId;
|
|
217011
|
+
try {
|
|
217012
|
+
sessionId = await this.dispatchOne(entry, key);
|
|
217013
|
+
} finally {
|
|
217014
|
+
releaseDispatch();
|
|
217015
|
+
}
|
|
216609
217016
|
this.removeInbox(entry);
|
|
216610
217017
|
entry.resolve(sessionId);
|
|
216611
217018
|
} catch (err) {
|
|
@@ -216639,18 +217046,23 @@ var Daemon = class Daemon {
|
|
|
216639
217046
|
const mode = this.store.getOutputModeOverride(key) ?? agent.output.mode;
|
|
216640
217047
|
const conv = msg.platform === "telegram" ? new TelegramConverger(mode) : msg.platform === "discord" ? new DiscordConverger(mode) : new OutputConverger(mode);
|
|
216641
217048
|
this.showActivity(replyConn, msg.channel, statusThread, wasRunning ? "is thinking…" : "is starting up…");
|
|
217049
|
+
const releaseReplyConn = this.holdReplyConnection(replyConn);
|
|
216642
217050
|
let handled;
|
|
216643
217051
|
try {
|
|
216644
217052
|
handled = await this.sessions.handle(agentId, msg);
|
|
216645
217053
|
} catch (err) {
|
|
216646
|
-
|
|
216647
|
-
|
|
216648
|
-
|
|
216649
|
-
|
|
216650
|
-
|
|
216651
|
-
|
|
216652
|
-
|
|
216653
|
-
|
|
217054
|
+
try {
|
|
217055
|
+
this.store.setSessionState(key, "idle", this.clock.now());
|
|
217056
|
+
this.surfaceTurnFailure(err, {
|
|
217057
|
+
webchat,
|
|
217058
|
+
replyConn,
|
|
217059
|
+
channel: msg.channel,
|
|
217060
|
+
thread: msg.thread,
|
|
217061
|
+
statusThread
|
|
217062
|
+
});
|
|
217063
|
+
} finally {
|
|
217064
|
+
releaseReplyConn();
|
|
217065
|
+
}
|
|
216654
217066
|
throw err;
|
|
216655
217067
|
}
|
|
216656
217068
|
const { sessionId, blocks, created } = handled;
|
|
@@ -216760,6 +217172,7 @@ var Daemon = class Daemon {
|
|
|
216760
217172
|
finalPhase = "problem";
|
|
216761
217173
|
throw err;
|
|
216762
217174
|
} finally {
|
|
217175
|
+
releaseReplyConn();
|
|
216763
217176
|
this.clearIdle(p);
|
|
216764
217177
|
this.releasePermissions(sessionId);
|
|
216765
217178
|
this.releaseElicits(sessionId);
|
|
@@ -217722,6 +218135,50 @@ var Daemon = class Daemon {
|
|
|
217722
218135
|
agentId
|
|
217723
218136
|
}, this.cfg.limits.shutdownDrainMs);
|
|
217724
218137
|
await this.stopHost(agentId);
|
|
218138
|
+
while (this.activeDispatchesByAgent.get(agentId)?.size) await Promise.all([...this.activeDispatchesByAgent.get(agentId)]);
|
|
218139
|
+
await this.stopHost(agentId);
|
|
218140
|
+
}
|
|
218141
|
+
/** Await the single-flight reconcile and any coalesced trailing pass. Registry
|
|
218142
|
+
* callbacks fire a background reconcile before lifecycle handlers explicitly
|
|
218143
|
+
* await it, so one plain `await reconcile()` can otherwise observe only the
|
|
218144
|
+
* current pass rather than the queued final-roster pass. */
|
|
218145
|
+
async flushReconcile() {
|
|
218146
|
+
await this.reconcile();
|
|
218147
|
+
await Promise.resolve();
|
|
218148
|
+
while (this.reconcileRun || this.reconcilePending) {
|
|
218149
|
+
if (this.reconcileRun) await this.reconcileRun;
|
|
218150
|
+
else await this.reconcile();
|
|
218151
|
+
await Promise.resolve();
|
|
218152
|
+
}
|
|
218153
|
+
}
|
|
218154
|
+
queueAgentMove(kind, agentId, moveId, work) {
|
|
218155
|
+
const key = `${kind}:${agentId}:${moveId}`;
|
|
218156
|
+
const duplicate = this.agentMoveInFlight.get(key);
|
|
218157
|
+
if (duplicate) return duplicate;
|
|
218158
|
+
const run = (this.agentMoveTails.get(agentId) ?? Promise.resolve()).catch(() => {}).then(work);
|
|
218159
|
+
const tail = run.then(() => void 0, () => void 0);
|
|
218160
|
+
this.agentMoveInFlight.set(key, run);
|
|
218161
|
+
this.agentMoveTails.set(agentId, tail);
|
|
218162
|
+
run.then(() => {
|
|
218163
|
+
if (this.agentMoveInFlight.get(key) === run) this.agentMoveInFlight.delete(key);
|
|
218164
|
+
if (this.agentMoveTails.get(agentId) === tail) this.agentMoveTails.delete(agentId);
|
|
218165
|
+
}, () => {
|
|
218166
|
+
if (this.agentMoveInFlight.get(key) === run) this.agentMoveInFlight.delete(key);
|
|
218167
|
+
if (this.agentMoveTails.get(agentId) === tail) this.agentMoveTails.delete(agentId);
|
|
218168
|
+
});
|
|
218169
|
+
return run;
|
|
218170
|
+
}
|
|
218171
|
+
activationCapabilityError(agent) {
|
|
218172
|
+
const model = agent.runtimeOverrides?.model;
|
|
218173
|
+
const offeredModels = this.runtimeModels.get(agent.runtime) ?? [];
|
|
218174
|
+
if (model && offeredModels.length > 0 && !offeredModels.includes(model)) return `model "${model}" is not offered by runtime "${agent.runtime}"`;
|
|
218175
|
+
const caps = this.runtimeMcpCaps.get(agent.runtime);
|
|
218176
|
+
for (const name of agent.mcpServers) {
|
|
218177
|
+
if (name === "agentconnect") return `MCP server name "${name}" is reserved`;
|
|
218178
|
+
const def = this.mcpServerDefs[name];
|
|
218179
|
+
if (!def) return `MCP server "${name}" is not configured on this daemon`;
|
|
218180
|
+
if (def.transport !== "stdio" && caps && !caps[def.transport]) return `MCP server "${name}" needs unsupported ${def.transport} transport on runtime "${agent.runtime}"`;
|
|
218181
|
+
}
|
|
217725
218182
|
}
|
|
217726
218183
|
/** §2.5 SIGTERM / daemon shutdown: gate new turns, then await in-flight turns up
|
|
217727
218184
|
* to `shutdownDrainMs`, cancelling stragglers. Safe to call repeatedly. */
|
|
@@ -217818,12 +218275,12 @@ var Daemon = class Daemon {
|
|
|
217818
218275
|
if (ignored.length) this.log.warn(`cp: ignored config keys: ${ignored.join(", ")}`);
|
|
217819
218276
|
},
|
|
217820
218277
|
applyReconcileSnapshot: (snap) => {
|
|
217821
|
-
this.cpAgents?.converge(snap.agents);
|
|
217822
|
-
this.cpIntegrations?.converge(snap.integrations);
|
|
218278
|
+
this.cpAgents?.converge((snap.agents ?? []).filter((agent) => !this.moveStagedAgents.has(agent.agentId)));
|
|
218279
|
+
this.cpIntegrations?.converge((snap.integrations ?? []).filter((integration) => !this.moveStagedAgents.has(integration.agentId)));
|
|
217823
218280
|
this.convergeRelays(snap.relays);
|
|
217824
218281
|
this.cpCollab.replace(snap.collabRoutes);
|
|
217825
218282
|
for (const id of snap.drop.crons) this.cpCrons?.remove(id);
|
|
217826
|
-
this.cpCrons?.converge(snap.crons);
|
|
218283
|
+
this.cpCrons?.converge((snap.crons ?? []).filter((cron) => !this.moveStagedAgents.has(cron.agentId)));
|
|
217827
218284
|
this.cpRouting?.converge({
|
|
217828
218285
|
routingEpoch: snap.routingEpoch,
|
|
217829
218286
|
assignments: snap.assignments,
|
|
@@ -217835,16 +218292,164 @@ var Daemon = class Daemon {
|
|
|
217835
218292
|
if (snap.integrations?.length) this.log.debug(`cp: converged ${snap.integrations.length} integration(s)`);
|
|
217836
218293
|
},
|
|
217837
218294
|
applyAgentUpsert: (agentId, spec) => {
|
|
218295
|
+
if (this.moveStagedAgents.has(agentId)) return;
|
|
217838
218296
|
this.gitCreds?.clearDenied(agentId);
|
|
217839
218297
|
this.cpAgents?.upsert(agentId, spec);
|
|
217840
218298
|
},
|
|
217841
218299
|
applyAgentRemove: (agentId) => {
|
|
217842
218300
|
this.gitCreds?.remove(agentId);
|
|
217843
218301
|
this.cpAgents?.remove(agentId);
|
|
218302
|
+
this.moveStageMetadata.delete(agentId);
|
|
218303
|
+
this.moveStagedAgents.delete(agentId);
|
|
218304
|
+
this.drainingAgents.delete(agentId);
|
|
218305
|
+
},
|
|
218306
|
+
applyAgentDetach: (detach) => {
|
|
218307
|
+
const { agentId, moveId } = detach;
|
|
218308
|
+
return this.queueAgentMove("detach", agentId, moveId, async () => {
|
|
218309
|
+
if (this.opts.agentName) return {
|
|
218310
|
+
ok: false,
|
|
218311
|
+
reason: "agent move is unavailable in --agent single-agent mode"
|
|
218312
|
+
};
|
|
218313
|
+
const previous = this.moveStageMetadata.get(agentId);
|
|
218314
|
+
if (previous?.moveId === moveId && previous.state === "committed") return { ok: true };
|
|
218315
|
+
stageAgentMove(this.agentsDir, agentId, moveId);
|
|
218316
|
+
this.moveStageMetadata.set(agentId, {
|
|
218317
|
+
moveId,
|
|
218318
|
+
state: "staging"
|
|
218319
|
+
});
|
|
218320
|
+
this.moveStagedAgents.add(agentId);
|
|
218321
|
+
this.drainingAgents.add(agentId);
|
|
218322
|
+
await this.stopAgent(agentId);
|
|
218323
|
+
const fence = this.moveStageMetadata.get(agentId);
|
|
218324
|
+
if (fence?.moveId !== moveId || fence.state !== "staging") return {
|
|
218325
|
+
ok: false,
|
|
218326
|
+
reason: "agent/detach: move was superseded"
|
|
218327
|
+
};
|
|
218328
|
+
this.gitCreds?.remove(agentId);
|
|
218329
|
+
this.cpAgents?.detach(agentId);
|
|
218330
|
+
await this.flushReconcile();
|
|
218331
|
+
await this.closeUnusedPlatformConnections();
|
|
218332
|
+
const finalFence = this.moveStageMetadata.get(agentId);
|
|
218333
|
+
if (finalFence?.moveId !== moveId || finalFence.state !== "staging") return {
|
|
218334
|
+
ok: false,
|
|
218335
|
+
reason: "agent/detach: move was superseded"
|
|
218336
|
+
};
|
|
218337
|
+
return { ok: true };
|
|
218338
|
+
});
|
|
218339
|
+
},
|
|
218340
|
+
applyAgentActivate: (activate) => {
|
|
218341
|
+
const { agentId } = activate;
|
|
218342
|
+
return this.queueAgentMove("activate", agentId, activate.moveId, async () => {
|
|
218343
|
+
if (this.opts.agentName) return {
|
|
218344
|
+
ok: false,
|
|
218345
|
+
reason: "agent move is unavailable in --agent single-agent mode"
|
|
218346
|
+
};
|
|
218347
|
+
const stage = this.moveStageMetadata.get(agentId);
|
|
218348
|
+
if (stage?.moveId === activate.moveId && stage.state === "committed") return { ok: true };
|
|
218349
|
+
if (stage?.moveId !== activate.moveId || stage.state !== "staging" || !this.moveStagedAgents.has(agentId) || !this.drainingAgents.has(agentId)) return {
|
|
218350
|
+
ok: false,
|
|
218351
|
+
reason: "agent/activate: staging fence is missing or superseded"
|
|
218352
|
+
};
|
|
218353
|
+
const capacityUsed = this.agents.size + this.activatingAgents.size;
|
|
218354
|
+
if (this.cfg.limits.maxAgents > 0 && capacityUsed >= this.cfg.limits.maxAgents) return {
|
|
218355
|
+
ok: false,
|
|
218356
|
+
reason: `agent/activate: daemon capacity ${capacityUsed}/${this.cfg.limits.maxAgents} is full`
|
|
218357
|
+
};
|
|
218358
|
+
this.activatingAgents.add(agentId);
|
|
218359
|
+
try {
|
|
218360
|
+
if (activate.integrations.some((integration) => integration.agentId !== agentId)) return {
|
|
218361
|
+
ok: false,
|
|
218362
|
+
reason: "agent/activate: integration bundle contains a different agentId"
|
|
218363
|
+
};
|
|
218364
|
+
if (activate.crons.some((cron) => cron.agentId !== agentId)) return {
|
|
218365
|
+
ok: false,
|
|
218366
|
+
reason: "agent/activate: cron bundle contains a different agentId"
|
|
218367
|
+
};
|
|
218368
|
+
this.gitCreds?.clearDenied(agentId);
|
|
218369
|
+
this.cpAgents?.upsert(agentId, activate.spec);
|
|
218370
|
+
for (const integration of activate.integrations) this.cpIntegrations?.upsert(integration);
|
|
218371
|
+
for (const cron of activate.crons) this.cpCrons?.upsert(cron);
|
|
218372
|
+
if ((this.cpAgents?.activate(agentId, {
|
|
218373
|
+
integrationIds: activate.integrations.map((integration) => integration.integrationId),
|
|
218374
|
+
cronIds: activate.crons.map((cron) => cron.cronId)
|
|
218375
|
+
}) ?? "missing") === "missing") return {
|
|
218376
|
+
ok: false,
|
|
218377
|
+
reason: `agent/activate: unknown agent ${agentId}`
|
|
218378
|
+
};
|
|
218379
|
+
this.moveStagedAgents.delete(agentId);
|
|
218380
|
+
try {
|
|
218381
|
+
await this.flushReconcile();
|
|
218382
|
+
} catch (err) {
|
|
218383
|
+
this.moveStagedAgents.add(agentId);
|
|
218384
|
+
await this.stopHost(agentId).catch(() => {});
|
|
218385
|
+
await this.flushReconcile().catch(() => {});
|
|
218386
|
+
throw err;
|
|
218387
|
+
}
|
|
218388
|
+
const agent = this.agents.get(agentId);
|
|
218389
|
+
if (!agent) {
|
|
218390
|
+
this.moveStagedAgents.add(agentId);
|
|
218391
|
+
await this.flushReconcile();
|
|
218392
|
+
return {
|
|
218393
|
+
ok: false,
|
|
218394
|
+
reason: `agent/activate: agent ${agentId} did not reconcile`
|
|
218395
|
+
};
|
|
218396
|
+
}
|
|
218397
|
+
if (!this.runtimes[agent.runtime]) {
|
|
218398
|
+
this.moveStagedAgents.add(agentId);
|
|
218399
|
+
await this.flushReconcile();
|
|
218400
|
+
return {
|
|
218401
|
+
ok: false,
|
|
218402
|
+
reason: `agent/activate: runtime "${agent.runtime}" is unavailable`
|
|
218403
|
+
};
|
|
218404
|
+
}
|
|
218405
|
+
const capabilityError = this.activationCapabilityError(agent);
|
|
218406
|
+
if (capabilityError) {
|
|
218407
|
+
this.moveStagedAgents.add(agentId);
|
|
218408
|
+
await this.flushReconcile();
|
|
218409
|
+
return {
|
|
218410
|
+
ok: false,
|
|
218411
|
+
reason: `agent/activate: ${capabilityError}`
|
|
218412
|
+
};
|
|
218413
|
+
}
|
|
218414
|
+
try {
|
|
218415
|
+
await this.ensureHostAsync(agentId);
|
|
218416
|
+
} catch (err) {
|
|
218417
|
+
this.moveStagedAgents.add(agentId);
|
|
218418
|
+
await this.stopHost(agentId).catch(() => {});
|
|
218419
|
+
await this.flushReconcile().catch(() => {});
|
|
218420
|
+
return {
|
|
218421
|
+
ok: false,
|
|
218422
|
+
reason: `agent/activate: ${err.message}`
|
|
218423
|
+
};
|
|
218424
|
+
}
|
|
218425
|
+
try {
|
|
218426
|
+
commitAgentMove(this.agentsDir, agentId, activate.moveId);
|
|
218427
|
+
} catch (err) {
|
|
218428
|
+
this.moveStagedAgents.add(agentId);
|
|
218429
|
+
await this.flushReconcile().catch(() => {});
|
|
218430
|
+
return {
|
|
218431
|
+
ok: false,
|
|
218432
|
+
reason: `agent/activate: failed to commit staging fence: ${err.message}`
|
|
218433
|
+
};
|
|
218434
|
+
}
|
|
218435
|
+
this.moveStageMetadata.set(agentId, {
|
|
218436
|
+
moveId: activate.moveId,
|
|
218437
|
+
state: "committed"
|
|
218438
|
+
});
|
|
218439
|
+
this.drainingAgents.delete(agentId);
|
|
218440
|
+
return { ok: true };
|
|
218441
|
+
} finally {
|
|
218442
|
+
this.activatingAgents.delete(agentId);
|
|
218443
|
+
}
|
|
218444
|
+
});
|
|
218445
|
+
},
|
|
218446
|
+
applyIntegrationUpsert: (spec) => {
|
|
218447
|
+
if (!this.moveStagedAgents.has(spec.agentId)) this.cpIntegrations?.upsert(spec);
|
|
217844
218448
|
},
|
|
217845
|
-
applyIntegrationUpsert: (spec) => this.cpIntegrations?.upsert(spec),
|
|
217846
218449
|
applyIntegrationRemove: (integrationId) => this.cpIntegrations?.remove(integrationId),
|
|
217847
|
-
upsertCron: (cron) =>
|
|
218450
|
+
upsertCron: (cron) => {
|
|
218451
|
+
if (!this.moveStagedAgents.has(cron.agentId)) this.cpCrons.upsert(cron);
|
|
218452
|
+
},
|
|
217848
218453
|
removeCron: (cronId) => this.cpCrons.remove(cronId),
|
|
217849
218454
|
runCron: (cronId) => this.runCronNow(cronId),
|
|
217850
218455
|
applyRouteAssign: (a) => this.cpRouting?.upsertAssign(a),
|
|
@@ -217852,6 +218457,7 @@ var Daemon = class Daemon {
|
|
|
217852
218457
|
applyRelayRoster: (relays) => this.convergeRelays(relays),
|
|
217853
218458
|
applyCollabRoutes: (snap) => this.cpCollab.replace(snap),
|
|
217854
218459
|
applyAgentLaunch: async (launch) => {
|
|
218460
|
+
if (this.moveStagedAgents.has(launch.agentId)) throw new Error(`agent/launch: agent ${launch.agentId} is staged for a daemon move`);
|
|
217855
218461
|
const agent = this.agents.get(launch.agentId);
|
|
217856
218462
|
if (!agent) throw new Error(`agent/launch: unknown agent ${launch.agentId}`);
|
|
217857
218463
|
this.drainingAgents.delete(launch.agentId);
|
|
@@ -218031,7 +218637,7 @@ var Daemon = class Daemon {
|
|
|
218031
218637
|
],
|
|
218032
218638
|
runtimes: Object.keys(this.runtimes).map((id) => this.runtimeNames[id] ?? id),
|
|
218033
218639
|
acp: true,
|
|
218034
|
-
features: []
|
|
218640
|
+
features: this.opts.agentName ? [] : ["agent-move-v1"]
|
|
218035
218641
|
}),
|
|
218036
218642
|
runtimeProfiles: () => Object.keys(this.runtimes).map((id) => this.runtimeProfileFor(id)),
|
|
218037
218643
|
mcpServerFacts: () => this.mcpServerFacts,
|
|
@@ -218165,7 +218771,9 @@ var Daemon = class Daemon {
|
|
|
218165
218771
|
this.scheduler?.stop();
|
|
218166
218772
|
await Promise.resolve(this.cpClient?.stop()).catch((e) => errors.push(e));
|
|
218167
218773
|
await Promise.resolve(this.relays?.stop()).catch((e) => errors.push(e));
|
|
218774
|
+
for (const run of [...this.slackRetryRuns.values()]) await Promise.resolve(run.promise).catch((e) => errors.push(e));
|
|
218168
218775
|
for (const c of this.connections) await Promise.resolve(c.stop()).catch((e) => errors.push(e));
|
|
218776
|
+
for (const c of this.sharedSlackConns.values()) await Promise.resolve(c.stop()).catch((e) => errors.push(e));
|
|
218169
218777
|
for (const c of this.telegramConns) await Promise.resolve(c.stop()).catch((e) => errors.push(e));
|
|
218170
218778
|
for (const c of this.discordConns) await Promise.resolve(c.stop()).catch((e) => errors.push(e));
|
|
218171
218779
|
for (const h of this.hosts.values()) await Promise.resolve(h.stop()).catch((e) => errors.push(e));
|
|
@@ -218208,4 +218816,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
218208
218816
|
//#endregion
|
|
218209
218817
|
export { ClientTransport as i, CP_SUBPROTOCOL as n, CP_WS_PATH as r, runForeground as t };
|
|
218210
218818
|
|
|
218211
|
-
//# sourceMappingURL=run-foreground-
|
|
218819
|
+
//# sourceMappingURL=run-foreground-BMjqIzg4.js.map
|