@essentialai/cogent-plugin 3.25.6 → 3.25.7

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.
@@ -1282,8 +1282,8 @@ var init_parseUtil = __esm({
1282
1282
  init_errors();
1283
1283
  init_en();
1284
1284
  makeIssue = (params) => {
1285
- const { data, path: path26, errorMaps, issueData } = params;
1286
- const fullPath = [...path26, ...issueData.path || []];
1285
+ const { data, path: path27, errorMaps, issueData } = params;
1286
+ const fullPath = [...path27, ...issueData.path || []];
1287
1287
  const fullIssue = {
1288
1288
  ...issueData,
1289
1289
  path: fullPath
@@ -1563,11 +1563,11 @@ var init_types = __esm({
1563
1563
  init_parseUtil();
1564
1564
  init_util();
1565
1565
  ParseInputLazyPath = class {
1566
- constructor(parent, value, path26, key) {
1566
+ constructor(parent, value, path27, key) {
1567
1567
  this._cachedPath = [];
1568
1568
  this.parent = parent;
1569
1569
  this.data = value;
1570
- this._path = path26;
1570
+ this._path = path27;
1571
1571
  this._key = key;
1572
1572
  }
1573
1573
  get path() {
@@ -5019,10 +5019,10 @@ function assignProp(target, prop, value) {
5019
5019
  configurable: true
5020
5020
  });
5021
5021
  }
5022
- function getElementAtPath(obj, path26) {
5023
- if (!path26)
5022
+ function getElementAtPath(obj, path27) {
5023
+ if (!path27)
5024
5024
  return obj;
5025
- return path26.reduce((acc, key) => acc?.[key], obj);
5025
+ return path27.reduce((acc, key) => acc?.[key], obj);
5026
5026
  }
5027
5027
  function promiseAllObject(promisesObj) {
5028
5028
  const keys = Object.keys(promisesObj);
@@ -5271,11 +5271,11 @@ function aborted(x, startIndex = 0) {
5271
5271
  }
5272
5272
  return false;
5273
5273
  }
5274
- function prefixIssues(path26, issues) {
5274
+ function prefixIssues(path27, issues) {
5275
5275
  return issues.map((iss) => {
5276
5276
  var _a;
5277
5277
  (_a = iss).path ?? (_a.path = []);
5278
- iss.path.unshift(path26);
5278
+ iss.path.unshift(path27);
5279
5279
  return iss;
5280
5280
  });
5281
5281
  }
@@ -17081,8 +17081,8 @@ var require_utils = __commonJS({
17081
17081
  }
17082
17082
  return ind;
17083
17083
  }
17084
- function removeDotSegments(path26) {
17085
- let input = path26;
17084
+ function removeDotSegments(path27) {
17085
+ let input = path27;
17086
17086
  const output = [];
17087
17087
  let nextSlash = -1;
17088
17088
  let len = 0;
@@ -17281,8 +17281,8 @@ var require_schemes = __commonJS({
17281
17281
  wsComponent.secure = void 0;
17282
17282
  }
17283
17283
  if (wsComponent.resourceName) {
17284
- const [path26, query] = wsComponent.resourceName.split("?");
17285
- wsComponent.path = path26 && path26 !== "/" ? path26 : void 0;
17284
+ const [path27, query] = wsComponent.resourceName.split("?");
17285
+ wsComponent.path = path27 && path27 !== "/" ? path27 : void 0;
17286
17286
  wsComponent.query = query;
17287
17287
  wsComponent.resourceName = void 0;
17288
17288
  }
@@ -20635,12 +20635,12 @@ var require_dist = __commonJS({
20635
20635
  throw new Error(`Unknown format "${name}"`);
20636
20636
  return f;
20637
20637
  };
20638
- function addFormats(ajv, list, fs24, exportName) {
20638
+ function addFormats(ajv, list, fs25, exportName) {
20639
20639
  var _a;
20640
20640
  var _b;
20641
20641
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
20642
20642
  for (const f of list)
20643
- ajv.addFormat(f, fs24[f]);
20643
+ ajv.addFormat(f, fs25[f]);
20644
20644
  }
20645
20645
  module.exports = exports = formatsPlugin;
20646
20646
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -21752,8 +21752,8 @@ var require_parseUtil = __commonJS({
21752
21752
  var errors_js_1 = require_errors2();
21753
21753
  var en_js_1 = __importDefault(require_en());
21754
21754
  var makeIssue2 = (params) => {
21755
- const { data, path: path26, errorMaps, issueData } = params;
21756
- const fullPath = [...path26, ...issueData.path || []];
21755
+ const { data, path: path27, errorMaps, issueData } = params;
21756
+ const fullPath = [...path27, ...issueData.path || []];
21757
21757
  const fullIssue = {
21758
21758
  ...issueData,
21759
21759
  path: fullPath
@@ -21907,11 +21907,11 @@ var require_types2 = __commonJS({
21907
21907
  var parseUtil_js_1 = require_parseUtil();
21908
21908
  var util_js_1 = require_util2();
21909
21909
  var ParseInputLazyPath2 = class {
21910
- constructor(parent, value, path26, key) {
21910
+ constructor(parent, value, path27, key) {
21911
21911
  this._cachedPath = [];
21912
21912
  this.parent = parent;
21913
21913
  this.data = value;
21914
- this._path = path26;
21914
+ this._path = path27;
21915
21915
  this._key = key;
21916
21916
  }
21917
21917
  get path() {
@@ -26412,8 +26412,8 @@ var init_stdio2 = __esm({
26412
26412
  // src/constants.ts
26413
26413
  import { createRequire } from "node:module";
26414
26414
  function resolveVersion() {
26415
- if ("3.25.6") {
26416
- return "3.25.6";
26415
+ if ("3.25.7") {
26416
+ return "3.25.7";
26417
26417
  }
26418
26418
  try {
26419
26419
  const require2 = createRequire(import.meta.url);
@@ -26432,6 +26432,34 @@ var init_constants = __esm({
26432
26432
  }
26433
26433
  });
26434
26434
 
26435
+ // src/instructions.ts
26436
+ var ENV_KEY_NAMES_COMMAND, SERVER_INSTRUCTIONS;
26437
+ var init_instructions = __esm({
26438
+ "src/instructions.ts"() {
26439
+ "use strict";
26440
+ ENV_KEY_NAMES_COMMAND = "grep -noE '^#COGENT[A-Za-z0-9_ -]*|^(CHANNEL|COG[A-Z]*NT)_(CHANNEL_)?(NAME|PASSWORD|ORG_ID|PEER_NAME|PEER_LABEL)=' .env";
26441
+ SERVER_INSTRUCTIONS = [
26442
+ "Cogent connects this agent to a shared channel with other agents and with people in Slack. Follow the steps below only when the user asks you to register, join or get online on Cogent; never read .env or register unprompted.",
26443
+ "To get online:",
26444
+ "1. cogent_join_session { channel, secret, orgId? }. channel is the channel NAME (3-32 characters: lowercase letters, digits, hyphens), never a UUID. If you were given an Org_ID (Team channel) pass it as orgId on every call and never retry without it.",
26445
+ "2. Only if step 1 answers CHANNEL_NOT_FOUND: cogent_create_session { label, secret, orgId? } with the SAME name, password and Org_ID. It creates the channel and joins you. Never change the name. Do not repeat step 1 first: five failed joins lock the name for 15 minutes.",
26446
+ "3. cogent_register_peer { peerId, sessionId, cwd, label }. peerId is the peer name you were given. sessionId is this agent session's own resumable id, not the channel id. Do not call this first.",
26447
+ "Values come from the user's message, else from the project .env: the keys ending in CHANNEL_NAME, CHANNEL_PASSWORD, ORG_ID, PEER_NAME and PEER_LABEL. To find them, list the key NAMES only:",
26448
+ ENV_KEY_NAMES_COMMAND,
26449
+ "Then pass the values straight into the tool call. Do not print them and do not write a script that prints them. A key with a misspelled prefix is still used: report its KEY NAME. If the channel name or peer name is missing, or appears more than once, ask. Never invent either.",
26450
+ "Errors:",
26451
+ "- CHANNEL_NOT_FOUND: do step 2 once. Exception: if you were given an Org_ID and left it out, do step 1 again WITH orgId and create nothing.",
26452
+ "- 'already in use' from create: the channel exists. Do step 1 again with the same name.",
26453
+ "- Invalid credentials or Invalid session secret (HTTP 401): the password or Org_ID is wrong. Stop and ask.",
26454
+ "- RATE_LIMITED or HTTP 429: wait the seconds it states, then repeat the same call once. Change nothing.",
26455
+ "- JOIN_NOT_CONFIRMED: step 1 or 2 has not succeeded in this session. Do it, then register.",
26456
+ "- PEER_NOT_YOURS: your own earlier session holds the name. Retry the SAME peerId when the error says. Never rename.",
26457
+ "- Anything else: report it and stop.",
26458
+ "Never print the channel password or the Org_ID. When online, report the peer name, the channel name, whether you created or joined it, and the Slack command from the tool result with its placeholders left as they are."
26459
+ ].join("\n");
26460
+ }
26461
+ });
26462
+
26435
26463
  // src/logger.ts
26436
26464
  import fs5 from "node:fs";
26437
26465
  import path5 from "node:path";
@@ -26803,6 +26831,7 @@ var init_errors4 = __esm({
26803
26831
  BridgeErrorCode2["DIR_NOT_WRITABLE"] = "DIR_NOT_WRITABLE";
26804
26832
  BridgeErrorCode2["NETWORK_TIMEOUT"] = "NETWORK_TIMEOUT";
26805
26833
  BridgeErrorCode2["JOIN_NOT_CONFIRMED"] = "JOIN_NOT_CONFIRMED";
26834
+ BridgeErrorCode2["CHANNEL_NOT_FOUND"] = "CHANNEL_NOT_FOUND";
26806
26835
  BridgeErrorCode2["PEER_NOT_YOURS"] = "PEER_NOT_YOURS";
26807
26836
  return BridgeErrorCode2;
26808
26837
  })(BridgeErrorCode || {});
@@ -27857,7 +27886,7 @@ var init_http_backend = __esm({
27857
27886
  * in cloud mode we ignore it and use this.sessionId (the cloud session).
27858
27887
  */
27859
27888
  async registerPeer(peerId, _sessionId, cwd, label, clientVersion, mode, _channelSessionId, capabilities, workspaceId, threadId, peerSecret) {
27860
- const path26 = PATHS.peers.replace(":sessionId", this.sessionId);
27889
+ const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
27861
27890
  const body = {
27862
27891
  peerId,
27863
27892
  cwd,
@@ -27888,7 +27917,7 @@ var init_http_backend = __esm({
27888
27917
  if (peerSecret !== void 0 && await relaySupports(this.http, "peer-ownership")) {
27889
27918
  body.peerSecret = peerSecret;
27890
27919
  }
27891
- const peer = await this.http.post(path26, body);
27920
+ const peer = await this.http.post(path27, body);
27892
27921
  const issued = peer?.peerSecret;
27893
27922
  if (issued) {
27894
27923
  try {
@@ -27908,9 +27937,9 @@ var init_http_backend = __esm({
27908
27937
  * local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
27909
27938
  */
27910
27939
  async deregisterPeer(peerId, peerSecret) {
27911
- const path26 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27940
+ const path27 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27912
27941
  try {
27913
- const headers = await this.http.delete(path26, peerSecret ? { peerSecret } : {});
27942
+ const headers = await this.http.delete(path27, peerSecret ? { peerSecret } : {});
27914
27943
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
27915
27944
  return { removed: true, mailboxDeprovisioned };
27916
27945
  } catch (err) {
@@ -27934,8 +27963,8 @@ var init_http_backend = __esm({
27934
27963
  * GET /api/sessions/:sessionId/peers
27935
27964
  */
27936
27965
  async listPeers() {
27937
- const path26 = PATHS.peers.replace(":sessionId", this.sessionId);
27938
- const result = await this.http.get(path26);
27966
+ const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
27967
+ const result = await this.http.get(path27);
27939
27968
  return result.peers;
27940
27969
  }
27941
27970
  /**
@@ -27943,8 +27972,8 @@ var init_http_backend = __esm({
27943
27972
  * Calls the lightweight heartbeat endpoint on the cloud relay server.
27944
27973
  */
27945
27974
  async updateLastSeen(peerId) {
27946
- const path26 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27947
- await this.http.post(path26, { peerId });
27975
+ const path27 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27976
+ await this.http.post(path27, { peerId });
27948
27977
  }
27949
27978
  /**
27950
27979
  * Record a message in the cloud session.
@@ -27955,7 +27984,7 @@ var init_http_backend = __esm({
27955
27984
  * the input record to construct a full MessageRecord.
27956
27985
  */
27957
27986
  async recordMessage(record2) {
27958
- const path26 = PATHS.messages.replace(":sessionId", this.sessionId);
27987
+ const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
27959
27988
  const body = {
27960
27989
  fromPeerId: record2.fromPeerId,
27961
27990
  toPeerId: record2.toPeerId,
@@ -27981,7 +28010,7 @@ var init_http_backend = __esm({
27981
28010
  if (record2.replyExpected === false && await relaySupports(this.http, "terminal-messages")) {
27982
28011
  body.replyExpected = false;
27983
28012
  }
27984
- const resp = await this.http.post(path26, body);
28013
+ const resp = await this.http.post(path27, body);
27985
28014
  return {
27986
28015
  ...record2,
27987
28016
  id: resp.id,
@@ -27995,7 +28024,7 @@ var init_http_backend = __esm({
27995
28024
  * Supports optional peerId filter and limit (default 300).
27996
28025
  */
27997
28026
  async getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes) {
27998
- const path26 = PATHS.messages.replace(":sessionId", this.sessionId);
28027
+ const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
27999
28028
  const query = {};
28000
28029
  if (peerId) {
28001
28030
  query.peerId = peerId;
@@ -28010,7 +28039,7 @@ var init_http_backend = __esm({
28010
28039
  if (dedupInferredEchoes) {
28011
28040
  query.dedupInferredEchoes = "true";
28012
28041
  }
28013
- const result = await this.http.get(path26, query);
28042
+ const result = await this.http.get(path27, query);
28014
28043
  return result.messages;
28015
28044
  }
28016
28045
  /**
@@ -28021,12 +28050,12 @@ var init_http_backend = __esm({
28021
28050
  * so that get-history shows the actual response (not null).
28022
28051
  */
28023
28052
  async updateMessageResponse(messageId, response, durationMs, pending) {
28024
- const path26 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
28053
+ const path27 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
28025
28054
  const body = { response, durationMs };
28026
28055
  if (pending === true) {
28027
28056
  body.pending = true;
28028
28057
  }
28029
- await this.http.patch(path26, body);
28058
+ await this.http.patch(path27, body);
28030
28059
  }
28031
28060
  /**
28032
28061
  * Validate a session.
@@ -28200,8 +28229,8 @@ var init_http_client = __esm({
28200
28229
  * Perform an authenticated GET request.
28201
28230
  * Appends query parameters to the URL if provided.
28202
28231
  */
28203
- async get(path26, query) {
28204
- const url = new URL(path26, this.baseUrl);
28232
+ async get(path27, query) {
28233
+ const url = new URL(path27, this.baseUrl);
28205
28234
  if (query) {
28206
28235
  for (const [k, v] of Object.entries(query)) {
28207
28236
  url.searchParams.set(k, v);
@@ -28216,8 +28245,8 @@ var init_http_client = __esm({
28216
28245
  /**
28217
28246
  * Perform an authenticated POST request with a JSON body.
28218
28247
  */
28219
- async post(path26, body) {
28220
- const url = new URL(path26, this.baseUrl);
28248
+ async post(path27, body) {
28249
+ const url = new URL(path27, this.baseUrl);
28221
28250
  const resp = await this.fetchWithTimeout(url, {
28222
28251
  method: "POST",
28223
28252
  headers: this.headers(),
@@ -28235,8 +28264,8 @@ var init_http_client = __esm({
28235
28264
  * Perform an authenticated PATCH request with a JSON body.
28236
28265
  * Used to update existing resources (e.g., message response fields).
28237
28266
  */
28238
- async patch(path26, body) {
28239
- const url = new URL(path26, this.baseUrl);
28267
+ async patch(path27, body) {
28268
+ const url = new URL(path27, this.baseUrl);
28240
28269
  const resp = await this.fetchWithTimeout(url, {
28241
28270
  method: "PATCH",
28242
28271
  headers: this.headers(),
@@ -28261,8 +28290,8 @@ var init_http_client = __esm({
28261
28290
  * "Malformed JSON in request body" 400 from cogent-server <=3.1.2 when
28262
28291
  * any client (including third-party tools) DELETEd a peer without a body.
28263
28292
  */
28264
- async delete(path26, body) {
28265
- const url = new URL(path26, this.baseUrl);
28293
+ async delete(path27, body) {
28294
+ const url = new URL(path27, this.baseUrl);
28266
28295
  const headers = {
28267
28296
  "Authorization": `Bearer ${this.token}`
28268
28297
  };
@@ -32563,14 +32592,14 @@ var init_ws_client = __esm({
32563
32592
  this.restoreCursor();
32564
32593
  const poll = async () => {
32565
32594
  try {
32566
- const path26 = `/api/sessions/${this.opts.sessionId}/poll`;
32595
+ const path27 = `/api/sessions/${this.opts.sessionId}/poll`;
32567
32596
  const query = {
32568
32597
  peerId: this.opts.peerId
32569
32598
  };
32570
32599
  if (this.lastMessageId) {
32571
32600
  query.lastMessageId = this.lastMessageId;
32572
32601
  }
32573
- const result = await this.opts.http.get(path26, query);
32602
+ const result = await this.opts.http.get(path27, query);
32574
32603
  if (result.messages && result.messages.length > 0) {
32575
32604
  this.opts.onMessages(result.messages);
32576
32605
  this.advanceCursor(result.messages[result.messages.length - 1].id);
@@ -33487,6 +33516,10 @@ import crypto5 from "node:crypto";
33487
33516
  import fs15 from "node:fs";
33488
33517
  import os11 from "node:os";
33489
33518
  import path16 from "node:path";
33519
+ function drainCapMs(timeoutMs) {
33520
+ const t = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e5;
33521
+ return Math.min(INFLIGHT_TIMEOUT_FACTOR * t, INFLIGHT_MAX_MS);
33522
+ }
33490
33523
  function hashCwd3(cwd) {
33491
33524
  return crypto5.createHash("sha256").update(path16.resolve(cwd)).digest("hex").slice(0, 16);
33492
33525
  }
@@ -33813,12 +33846,36 @@ import crypto8 from "node:crypto";
33813
33846
  import fs18 from "node:fs";
33814
33847
  import os14 from "node:os";
33815
33848
  import path19 from "node:path";
33849
+ function agentSessionId(env = process.env) {
33850
+ if (env.COGENT_PLATFORM && env.COGENT_PLATFORM !== "cc") return void 0;
33851
+ const id = env.CLAUDE_CODE_SESSION_ID?.trim();
33852
+ return id && id.length <= 128 ? id : void 0;
33853
+ }
33854
+ function startedWithoutClient() {
33855
+ if (withoutClient === void 0) {
33856
+ try {
33857
+ withoutClient = fs18.fstatSync(0).isCharacterDevice();
33858
+ } catch {
33859
+ withoutClient = false;
33860
+ }
33861
+ }
33862
+ return withoutClient;
33863
+ }
33816
33864
  function hashCwd6(cwd) {
33817
33865
  return crypto8.createHash("sha256").update(path19.resolve(cwd)).digest("hex").slice(0, 16);
33818
33866
  }
33819
33867
  function bridgeDirFor(cwd, peerId) {
33820
33868
  return path19.join(os14.homedir(), ".cogent", "bridges", `${hashCwd6(cwd)}.${safe4(peerId)}`);
33821
33869
  }
33870
+ function isReservedPeerName(peerId) {
33871
+ return safe4(peerId).toLowerCase() === safe4(PROCESS_MARK).toLowerCase();
33872
+ }
33873
+ function registryText(value) {
33874
+ return String(value ?? "").replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64) || "unreadable";
33875
+ }
33876
+ function registryOwnerLabel(o) {
33877
+ return `pid ${registryText(o.pid)} (v${registryText(o.version)}, ${JSON.stringify(String(o.endpoint ?? "").slice(0, 200))})`;
33878
+ }
33822
33879
  function pidAlive(pid) {
33823
33880
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return false;
33824
33881
  if (pid === process.pid) return true;
@@ -33829,7 +33886,7 @@ function pidAlive(pid) {
33829
33886
  return err?.code === "EPERM";
33830
33887
  }
33831
33888
  }
33832
- function announceBridge(cwd, peerId, version2, endpoint) {
33889
+ function announceBridge(cwd, peerId, version2, endpoint, sessionId = agentSessionId()) {
33833
33890
  const dir = bridgeDirFor(cwd, peerId);
33834
33891
  try {
33835
33892
  fs18.mkdirSync(dir, { recursive: true });
@@ -33839,13 +33896,30 @@ function announceBridge(cwd, peerId, version2, endpoint) {
33839
33896
  version: version2,
33840
33897
  peerId,
33841
33898
  endpoint,
33842
- cwd: path19.resolve(cwd)
33899
+ cwd: path19.resolve(cwd),
33900
+ parentPid: process.ppid,
33901
+ ...sessionId ? { sessionId } : {},
33902
+ // 🔴 A headless bridge never had a client to lose (review r7 FIX2-2, SEC2-2): when its launching
33903
+ // shell exited, the changed parent read as "client gone" and any bridge that started took its name.
33904
+ ...startedWithoutClient() ? { noClient: true } : {}
33843
33905
  };
33844
33906
  fs18.writeFileSync(path19.join(dir, `${process.pid}.json`), JSON.stringify(entry));
33845
33907
  } catch (err) {
33846
33908
  logger.debug(`wake-ownership: could not announce this bridge (${err.message})`);
33847
33909
  }
33848
33910
  }
33911
+ function markBridgeDraining(cwd, peerId) {
33912
+ const file = path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`);
33913
+ try {
33914
+ const entry = JSON.parse(fs18.readFileSync(file, "utf-8"));
33915
+ fs18.writeFileSync(file, JSON.stringify({ ...entry, draining: true }));
33916
+ } catch {
33917
+ }
33918
+ }
33919
+ function markBridgeProcess(cwd, version2) {
33920
+ listLiveBridges(cwd, PROCESS_MARK);
33921
+ announceBridge(cwd, PROCESS_MARK, version2, "");
33922
+ }
33849
33923
  function withdrawBridge(cwd, peerId) {
33850
33924
  try {
33851
33925
  fs18.unlinkSync(path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`));
@@ -33882,6 +33956,16 @@ function listLiveBridges(cwd, peerId) {
33882
33956
  live.sort((a, b) => b.startedAt - a.startedAt || b.pid - a.pid);
33883
33957
  return live;
33884
33958
  }
33959
+ function listLiveBridgesInFolder(cwd) {
33960
+ const prefix = `${hashCwd6(cwd)}.`;
33961
+ let dirs;
33962
+ try {
33963
+ dirs = fs18.readdirSync(path19.join(os14.homedir(), ".cogent", "bridges"));
33964
+ } catch {
33965
+ return [];
33966
+ }
33967
+ return dirs.filter((d) => d.startsWith(prefix)).flatMap((d) => listLiveBridges(cwd, d.slice(prefix.length)));
33968
+ }
33885
33969
  function checkWakeOwnership(cwd, peerId) {
33886
33970
  let live;
33887
33971
  try {
@@ -33902,13 +33986,14 @@ function checkWakeOwnership(cwd, peerId) {
33902
33986
  }
33903
33987
  return { isOwner: true, liveCount: live.length + 1 };
33904
33988
  }
33905
- var PROCESS_STARTED_AT, safe4;
33989
+ var PROCESS_STARTED_AT, withoutClient, safe4, PROCESS_MARK;
33906
33990
  var init_wake_ownership = __esm({
33907
33991
  "src/services/wake-ownership.ts"() {
33908
33992
  "use strict";
33909
33993
  init_logger();
33910
33994
  PROCESS_STARTED_AT = Date.now() - Math.floor(process.uptime() * 1e3);
33911
33995
  safe4 = (s) => String(s).replace(/[^A-Za-z0-9._-]/g, "_");
33996
+ PROCESS_MARK = ".process";
33912
33997
  }
33913
33998
  });
33914
33999
 
@@ -33927,6 +34012,39 @@ function versionFromArgv(argv) {
33927
34012
  const m = argv.match(/\/cogent\/(\d+\.\d+\.\d+)\//);
33928
34013
  return m ? m[1] : null;
33929
34014
  }
34015
+ function versionAtLeast(a, b) {
34016
+ const pa = a.split(/[-+]/)[0].split(".").map(Number);
34017
+ const pb = b.split(/[-+]/)[0].split(".").map(Number);
34018
+ for (let i = 0; i < 3; i++) {
34019
+ const x = pa[i] ?? 0;
34020
+ const y = pb[i] ?? 0;
34021
+ if (x !== y) return x > y;
34022
+ }
34023
+ return true;
34024
+ }
34025
+ function bridgeVersion(argv, readFile = (p) => fs19.readFileSync(p, "utf-8")) {
34026
+ const fromPath = versionFromArgv(argv);
34027
+ if (fromPath) return fromPath;
34028
+ const candidates = [];
34029
+ const pkg = argv.match(/(\S*\/@essentialai\/cogent-bridge(?:-bundled)?)\/dist\/(?:cli|index)\.js(?:\s|$)/);
34030
+ if (pkg) candidates.push(path20.join(pkg[1], "package.json"));
34031
+ const bin = argv.match(/(\S*\/node_modules)\/\.bin\/cogent-bridge(?:\s|$)/);
34032
+ if (bin) {
34033
+ for (const name of ["cogent-bridge", "cogent-bridge-bundled"]) {
34034
+ candidates.push(path20.join(bin[1], "@essentialai", name, "package.json"));
34035
+ }
34036
+ }
34037
+ for (const file of candidates) {
34038
+ try {
34039
+ const pj = JSON.parse(readFile(file));
34040
+ if (typeof pj.name === "string" && pj.name.startsWith("@essentialai/cogent-bridge") && typeof pj.version === "string" && /^\d+\.\d+\.\d+/.test(pj.version)) {
34041
+ return pj.version;
34042
+ }
34043
+ } catch {
34044
+ }
34045
+ }
34046
+ return null;
34047
+ }
33930
34048
  function listProcesses() {
33931
34049
  let out;
33932
34050
  try {
@@ -33988,25 +34106,13 @@ function ancestorsOf(pid, procs) {
33988
34106
  }
33989
34107
  return seen;
33990
34108
  }
33991
- function announcedPidsFor(cwd) {
33992
- const pids = /* @__PURE__ */ new Set();
33993
- try {
33994
- const base = path20.dirname(bridgeDirFor(cwd, "x"));
33995
- const prefix = path20.basename(bridgeDirFor(cwd, "x")).split(".")[0];
33996
- for (const dir of fs19.readdirSync(base)) {
33997
- if (!dir.startsWith(`${prefix}.`)) continue;
33998
- const peerId = dir.slice(prefix.length + 1);
33999
- for (const e of listLiveBridges(cwd, peerId)) pids.add(e.pid);
34000
- }
34001
- } catch {
34002
- }
34003
- return pids;
34004
- }
34005
34109
  function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
34110
+ const versionOf = opts.versionOf ?? ((argv) => bridgeVersion(argv));
34006
34111
  const selfPid = opts.selfPid ?? process.pid;
34007
- const selfStartedAt = opts.selfStartedAt ?? Date.now() - Math.floor(process.uptime() * 1e3);
34112
+ const selfStartedAt = opts.selfStartedAt ?? procs.find((p) => p.pid === selfPid)?.startedAt ?? NaN;
34113
+ if (!Number.isFinite(selfStartedAt)) return [];
34008
34114
  const cwdOf = opts.cwdOf ?? processCwd;
34009
- const announced = opts.announced ?? announcedPidsFor(cwd);
34115
+ const announced = opts.announced ?? new Set(listLiveBridgesInFolder(cwd).map((e) => e.pid));
34010
34116
  const target = canonicalPath(cwd);
34011
34117
  const ancestors = ancestorsOf(selfPid, procs);
34012
34118
  const out = [];
@@ -34018,10 +34124,11 @@ function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
34018
34124
  if (!Number.isFinite(p.startedAt) || p.startedAt >= selfStartedAt) continue;
34019
34125
  const theirCwd = cwdOf(p.pid);
34020
34126
  if (!theirCwd || canonicalPath(theirCwd) !== target) continue;
34021
- const ver = versionFromArgv(p.argv);
34127
+ const ver = versionOf(p.argv);
34128
+ if (!ver || versionAtLeast(ver, SELF_SUPERSESSION_VERSION)) continue;
34022
34129
  out.push({
34023
34130
  proc: p,
34024
- reason: `pid ${p.pid}${ver ? ` (plugin ${ver})` : ""} is a cogent bridge in this exact checkout, started ${new Date(p.startedAt).toISOString()} \u2014 before this process \u2014 and has not announced itself, so it predates self-supersession and would keep waking this session forever`
34131
+ reason: `pid ${p.pid} (version ${ver}) is a cogent bridge in this exact checkout, started ${new Date(p.startedAt).toISOString()} \u2014 before this process \u2014 and is not in the bridge registry; version ${ver} predates ${SELF_SUPERSESSION_VERSION} self-supersession and would keep waking this session forever`
34025
34132
  });
34026
34133
  }
34027
34134
  return out;
@@ -34055,21 +34162,25 @@ function reapStaleBridges(cwd, opts = {}) {
34055
34162
  }
34056
34163
  if (reaped.length) {
34057
34164
  logger.warn(
34058
- `Cogent: reaped ${reaped.length} stale bridge process(es) left behind by an earlier plugin version. They could not stand down on their own because they predate 3.23.4.`
34165
+ `Cogent: reaped ${reaped.length} stale bridge process(es) for this checkout, each at a version before ${SELF_SUPERSESSION_VERSION}: they could not stand down on their own.`
34059
34166
  );
34060
34167
  }
34061
34168
  return reaped;
34062
34169
  }
34170
+ var SELF_SUPERSESSION_VERSION;
34063
34171
  var init_stale_bridge_reaper = __esm({
34064
34172
  "src/services/stale-bridge-reaper.ts"() {
34065
34173
  "use strict";
34066
34174
  init_logger();
34067
34175
  init_wake_ownership();
34176
+ SELF_SUPERSESSION_VERSION = "3.23.4";
34068
34177
  }
34069
34178
  });
34070
34179
 
34071
34180
  // src/services/auto-relay.ts
34072
34181
  import { randomUUID as randomUUID2 } from "node:crypto";
34182
+ import fs20 from "node:fs";
34183
+ import path21 from "node:path";
34073
34184
  function buildStatusNotice(status, peerId, traceId) {
34074
34185
  const tail = traceId ? ` (trace ${traceId})` : "";
34075
34186
  if (status === RELAY_STATUS.QUEUED) {
@@ -34196,6 +34307,21 @@ function truncate(s) {
34196
34307
  const flat = s.replace(/\s+/g, " ").trim();
34197
34308
  return flat.length > DIAGNOSTIC_MAX ? `${flat.slice(0, DIAGNOSTIC_MAX - 1)}\u2026` : flat;
34198
34309
  }
34310
+ function isInsideOwnFolder(dir) {
34311
+ try {
34312
+ const real = fs20.realpathSync.native(dir);
34313
+ return real === process.cwd() || real.startsWith(process.cwd() + path21.sep);
34314
+ } catch {
34315
+ return false;
34316
+ }
34317
+ }
34318
+ function isOwnFolder(dir) {
34319
+ try {
34320
+ return fs20.realpathSync.native(dir) === fs20.realpathSync.native(process.cwd());
34321
+ } catch {
34322
+ return false;
34323
+ }
34324
+ }
34199
34325
  var RELAY_STATUS, STATUS_MARKER_RE, DIAGNOSTIC_MAX, EARLY_ACK_TTL_MS, EARLY_ACK_MAX, AutoRelayService, autoRelay;
34200
34326
  var init_auto_relay = __esm({
34201
34327
  "src/services/auto-relay.ts"() {
@@ -34236,6 +34362,8 @@ var init_auto_relay = __esm({
34236
34362
  */
34237
34363
  pinnedSessionId = null;
34238
34364
  localCwd = null;
34365
+ /** Every folder this process announced the current peer name under — what a drain or a stop must cover. */
34366
+ announcedCwds = /* @__PURE__ */ new Set();
34239
34367
  /**
34240
34368
  * Peer participation mode (3.2.0, Phase 17 OBS-03).
34241
34369
  * - "agent" (default): full auto-relay — inbound directed messages run
@@ -34299,6 +34427,7 @@ var init_auto_relay = __esm({
34299
34427
  * successful registration so we know which session to inject into.
34300
34428
  */
34301
34429
  setLocalPeer(peerId, sessionId, cwd, mode, label, pinnedSessionId) {
34430
+ if (this.localPeerId && this.localPeerId !== peerId) this.withdrawAnnouncement();
34302
34431
  this.localPeerId = peerId;
34303
34432
  this.localSessionId = sessionId;
34304
34433
  this.pinnedSessionId = pinnedSessionId ?? sessionId;
@@ -34308,7 +34437,12 @@ var init_auto_relay = __esm({
34308
34437
  logger.info(
34309
34438
  `Auto-relay configured for peer ${peerId} (session: ${sessionId}, pinned: ${this.pinnedSessionId}, mode: ${this.localMode}, label: ${this.localLabel})`
34310
34439
  );
34311
- announceBridge(cwd, peerId, CLIENT_VERSION, getConfig().COGENT_ENDPOINT ?? "local");
34440
+ const dirs = /* @__PURE__ */ new Set([path21.resolve(cwd)]);
34441
+ if (isInsideOwnFolder(path21.resolve(cwd))) dirs.add(process.cwd());
34442
+ for (const dir of dirs) {
34443
+ this.announcedCwds.add(dir);
34444
+ announceBridge(dir, peerId, CLIENT_VERSION, getConfig().COGENT_ENDPOINT ?? "local");
34445
+ }
34312
34446
  this.supersededNotified.clear();
34313
34447
  if (!this.reapedStaleBridges) {
34314
34448
  this.reapedStaleBridges = true;
@@ -34683,10 +34817,13 @@ var init_auto_relay = __esm({
34683
34817
  }
34684
34818
  }
34685
34819
  if (this.localPeerId && this.localCwd) {
34686
- const own = checkWakeOwnership(this.localCwd, this.localPeerId);
34687
- if (!own.isOwner) {
34688
- await this._reportSuperseded(msg, own.owner);
34689
- return;
34820
+ const dirs = /* @__PURE__ */ new Set([path21.resolve(this.localCwd), ...isOwnFolder(this.localCwd) ? [process.cwd()] : []]);
34821
+ for (const dir of dirs) {
34822
+ const own = checkWakeOwnership(dir, this.localPeerId);
34823
+ if (!own.isOwner) {
34824
+ await this._reportSuperseded(msg, own.owner);
34825
+ return;
34826
+ }
34690
34827
  }
34691
34828
  }
34692
34829
  if (this.localPeerId && !this.awarenessOnly.has(msg.id)) {
@@ -34731,7 +34868,7 @@ var init_auto_relay = __esm({
34731
34868
  * notice generator.
34732
34869
  */
34733
34870
  async _reportSuperseded(msg, owner) {
34734
- const who = owner ? `pid ${owner.pid} (v${owner.version}, ${owner.endpoint})` : "a newer bridge";
34871
+ const who = owner ? registryOwnerLabel(owner) : "a newer bridge";
34735
34872
  logger.warn(
34736
34873
  `Auto-relay: NOT waking for ${msg.fromPeerId} \u2014 this bridge (pid ${process.pid}, v${CLIENT_VERSION}) has been superseded for peer "${this.localPeerId}" in this checkout by ${who}. It is a leftover process; the newer bridge is answering. Standing down.`
34737
34874
  );
@@ -35162,6 +35299,24 @@ var init_auto_relay = __esm({
35162
35299
  activeDeliveryAckWaiters: Array.from(this.deliveryAckWaiters.keys())
35163
35300
  };
35164
35301
  }
35302
+ /**
35303
+ * Stop claiming this peer's name for this checkout, WITHOUT stopping work already in flight.
35304
+ * Called the moment the MCP client is gone: a draining bridge serves no agent, and while it
35305
+ * counted as the peer's holder, the restarted agent's new bridge stood by behind it (review r2
35306
+ * NEW-1). The announcement is MARKED, not removed — see markBridgeDraining (R3-2). Idempotent.
35307
+ * 🔴 EVERY announcement, not only the last registered cwd's (review r7 SEC2-1, ABC2-2, FIX2-5):
35308
+ * after a register with another spelling of the folder, the one for the bridge's own folder stayed
35309
+ * unmarked, and the restarted agent waited out the drain or stood by for good.
35310
+ */
35311
+ announceDraining() {
35312
+ if (!this.localPeerId) return;
35313
+ for (const dir of this.announcedCwds) markBridgeDraining(dir, this.localPeerId);
35314
+ }
35315
+ /** Remove this bridge's ownership announcements (graceful shutdown, a rename). Idempotent. */
35316
+ withdrawAnnouncement() {
35317
+ if (this.localPeerId) for (const dir of this.announcedCwds) withdrawBridge(dir, this.localPeerId);
35318
+ this.announcedCwds.clear();
35319
+ }
35165
35320
  /**
35166
35321
  * Stop the auto-relay service: clear queue and reset state.
35167
35322
  */
@@ -35181,7 +35336,7 @@ var init_auto_relay = __esm({
35181
35336
  }
35182
35337
  this.deliveryAckWaiters.clear();
35183
35338
  this.recentAcks.clear();
35184
- if (this.localCwd && this.localPeerId) withdrawBridge(this.localCwd, this.localPeerId);
35339
+ this.withdrawAnnouncement();
35185
35340
  this.queue = [];
35186
35341
  this.awarenessOnly.clear();
35187
35342
  this.supersededNotified.clear();
@@ -35201,6 +35356,63 @@ var init_auto_relay = __esm({
35201
35356
  });
35202
35357
 
35203
35358
  // src/services/peer-presence.ts
35359
+ function holderRelation(holderSession, ownSession) {
35360
+ if (holderSession && ownSession) return holderSession === ownSession ? "same-session" : "other-session";
35361
+ return holderSession || ownSession ? "unknown" : "no-session";
35362
+ }
35363
+ function holderClientGone(holder, procs) {
35364
+ if (holder.noClient === true) return false;
35365
+ const byPid = new Map(procs.map((p) => [p.pid, p]));
35366
+ let cur = byPid.get(holder.pid);
35367
+ if (!cur) return false;
35368
+ if (typeof holder.parentPid === "number") return cur.ppid !== holder.parentPid;
35369
+ for (let hops = 0; hops < 3; hops++) {
35370
+ if (cur.ppid === 1) return true;
35371
+ const parent = byPid.get(cur.ppid);
35372
+ if (!parent) return false;
35373
+ const exe = parent.argv.trim().split(/\s+/)[0] ?? "";
35374
+ if (ORPHAN_PARENT_RE.test(exe.split("/").pop() ?? "")) return true;
35375
+ if (!NPX_WRAPPER_RE.test(parent.argv.trim())) return false;
35376
+ cur = parent;
35377
+ }
35378
+ return false;
35379
+ }
35380
+ function insideCodexWakeTurn(selfPid, procs) {
35381
+ const byPid = new Map(procs.map((p) => [p.pid, p]));
35382
+ const seen = /* @__PURE__ */ new Set();
35383
+ let cur = byPid.get(selfPid)?.ppid;
35384
+ while (cur && cur > 1 && !seen.has(cur)) {
35385
+ seen.add(cur);
35386
+ const p = byPid.get(cur);
35387
+ if (!p) break;
35388
+ if (/(^|[\s/])codex(\.js)?\s+exec\s+resume(\s|$)/.test(p.argv)) return true;
35389
+ cur = p.ppid;
35390
+ }
35391
+ return false;
35392
+ }
35393
+ function otherBridgesInFolder(entries, self, listProcs) {
35394
+ let procs = null;
35395
+ return entries.filter(
35396
+ (e) => e.peerId !== PROCESS_MARK && e.pid !== self.pid && !e.draining && holderRelation(e.sessionId, self.sessionId) !== "same-session" && !holderClientGone(e, procs ??= listProcs())
35397
+ );
35398
+ }
35399
+ function anotherAgentSessionAmong(others, ownSession) {
35400
+ return others.some((o) => holderRelation(o.sessionId, ownSession) === "other-session");
35401
+ }
35402
+ function otherBridgeNotice(others, peerId, verdict, ownSession) {
35403
+ const lines = others.map((o) => {
35404
+ const version2 = registryText(o.version);
35405
+ const who = holderRelation(o.sessionId, ownSession) === "other-session" ? `Another live agent session in this folder (bridge pid ${o.pid}, version ${version2}, agent session ${registryText(o.sessionId)})` : `Another live bridge in this folder (pid ${o.pid}, version ${version2}; its agent session cannot be compared with this one, so it may be this agent's own previous or second bridge)`;
35406
+ if (o.peerId !== peerId) {
35407
+ return `${who} is still registered as '${registryText(o.peerId)}'. It keeps that name while it runs, but the folder's saved identity now points at this bridge ('${peerId}'): after a restart that bridge's agent comes back as '${peerId}' only if this bridge is no longer running then; otherwise it stays out of the channel until it registers again.`;
35408
+ }
35409
+ if (verdict.isOwner) {
35410
+ return `${who} was registered as '${peerId}'. It is now superseded: this bridge holds '${peerId}' and that bridge has stopped answering for it.`;
35411
+ }
35412
+ return `${who} is registered as '${peerId}' too. NOBODY answers for '${peerId}' in this channel now: the bridge that started last (pid ${verdict.owner?.pid ?? "unknown"}) is the one that wakes its agent, but in this channel the relay registration now belongs to this bridge, so the relay refuses that bridge's replies here and this bridge does not wake. It stays that way until that bridge is closed or its agent registers again. If that bridge is registered in another channel, it still answers there.`;
35413
+ });
35414
+ return lines.join(" ") + (anotherAgentSessionAmong(others, ownSession) ? ` Two agents in one folder are not supported yet: each agent needs its own peer name and, for now, its own folder.` : "");
35415
+ }
35204
35416
  function autoPresenceEnabled(env = process.env) {
35205
35417
  const v = env.COGENT_AUTO_PRESENCE;
35206
35418
  if (v === void 0 || v === "") return true;
@@ -35230,11 +35442,42 @@ async function restorePresence(deps) {
35230
35442
  };
35231
35443
  }
35232
35444
  const peerId = creds.peerId;
35233
- if (deps.peerAlreadyServed(peerId)) {
35445
+ if (deps.startedByWakeTurn?.()) {
35234
35446
  return {
35235
- state: "online",
35447
+ state: "deferred",
35236
35448
  restored: false,
35237
- detail: `peer '${peerId}' is already served by a live bridge for this working directory`
35449
+ detail: `this bridge runs inside a codex wake turn ('codex exec resume'); peer '${peerId}' belongs to the agent's own bridge, which started this turn \u2014 nothing to restore here`
35450
+ };
35451
+ }
35452
+ const served = deps.peerAlreadyServed(peerId);
35453
+ if (served) {
35454
+ const session = deps.agentSessionId?.();
35455
+ const holder = holderRelation(served.sessionId, session);
35456
+ const servedBy = {
35457
+ ...served,
35458
+ ...served.version === void 0 ? {} : { version: registryText(served.version) },
35459
+ ...served.sessionId === void 0 ? {} : { sessionId: registryText(served.sessionId) }
35460
+ };
35461
+ const started = Number.isFinite(servedBy.startedAt) ? new Date(servedBy.startedAt).toISOString() : "unknown";
35462
+ const recheck = holder === "same-session";
35463
+ const every = deps.recheckSeconds ? ` (re-checked every ${deps.recheckSeconds}s)` : "";
35464
+ const take = `To take '${peerId}' for this agent now, run /cogent:register (cogent_join_session, then cogent_register_peer)`;
35465
+ const why = {
35466
+ "same-session": `That bridge serves this same agent session (${session})`,
35467
+ "no-session": `Neither bridge records an agent session (codex, gemini), so it cannot be told whether that bridge is this agent's previous one or another agent's. ${take}`,
35468
+ "other-session": `That bridge serves another agent session (${servedBy.sessionId}; ours: ${session}). Two agents in one folder are not supported yet: a second agent needs its own folder and peer name. ${take}`,
35469
+ unknown: `Its agent session cannot be compared with this one (that bridge: ${servedBy.sessionId ?? "not recorded"}; this bridge: ${session ?? "not known"}): it may be this agent's own other bridge of an older version, or another agent's. ${take}`
35470
+ };
35471
+ return {
35472
+ state: "standby",
35473
+ restored: false,
35474
+ peerId,
35475
+ servedBy,
35476
+ holder,
35477
+ recheck,
35478
+ // A final standby is evaluated once, so it says "when this bridge started": the health
35479
+ // check keeps showing this text after that bridge is gone.
35480
+ detail: `peer '${peerId}' ${recheck ? "is already served" : "was already served when this bridge started"} by a live bridge for this working directory (pid ${servedBy.pid}, version ${servedBy.version ?? "unknown"}, started ${started}); this bridge has NOT registered and ` + (recheck ? `restores '${peerId}' by itself once that bridge is gone${every}. ` : `does NOT take '${peerId}' by itself, also after that bridge is gone. `) + why[holder]
35238
35481
  };
35239
35482
  }
35240
35483
  if (!autoPresenceEnabled(deps.env ?? process.env)) {
@@ -35294,15 +35537,22 @@ function logPresence(outcome) {
35294
35537
  );
35295
35538
  } else if (outcome.state === "offline") {
35296
35539
  logger.warn(`Presence: OFFLINE \u2014 ${outcome.detail}.`);
35540
+ } else if (outcome.state === "standby" && outcome.holder === "other-session") {
35541
+ logger.warn(`Presence: STANDBY \u2014 ${outcome.detail}.`);
35542
+ } else if (outcome.state === "standby" || outcome.state === "deferred") {
35543
+ logger.info(`Presence: ${outcome.state.toUpperCase()} \u2014 ${outcome.detail}.`);
35297
35544
  } else {
35298
35545
  logger.debug(`Presence: ${outcome.state} \u2014 ${outcome.detail}.`);
35299
35546
  }
35300
35547
  }
35301
- var lastPresence;
35548
+ var ORPHAN_PARENT_RE, NPX_WRAPPER_RE, lastPresence;
35302
35549
  var init_peer_presence = __esm({
35303
35550
  "src/services/peer-presence.ts"() {
35304
35551
  "use strict";
35305
35552
  init_logger();
35553
+ init_wake_ownership();
35554
+ ORPHAN_PARENT_RE = /^(init|launchd|systemd)$/;
35555
+ NPX_WRAPPER_RE = /^(?:\S*\/)?(?:sh|bash|dash) -c cogent-bridge\b|^npm exec @essentialai\/cogent-bridge/;
35306
35556
  lastPresence = null;
35307
35557
  }
35308
35558
  });
@@ -35550,8 +35800,8 @@ __export(startup_exports, {
35550
35800
  triggerReRegistration: () => triggerReRegistration
35551
35801
  });
35552
35802
  import os15 from "node:os";
35553
- import path21 from "node:path";
35554
- import fs20 from "node:fs/promises";
35803
+ import path22 from "node:path";
35804
+ import fs21 from "node:fs/promises";
35555
35805
  import readline2 from "node:readline";
35556
35806
  import { execFile as execFile5 } from "node:child_process";
35557
35807
  import { promisify as promisify4 } from "node:util";
@@ -35569,7 +35819,7 @@ function bindInboxNotifier() {
35569
35819
  }
35570
35820
  async function loadPersistedConfig() {
35571
35821
  try {
35572
- const raw = await fs20.readFile(PERSIST_PATH, "utf-8");
35822
+ const raw = await fs21.readFile(PERSIST_PATH, "utf-8");
35573
35823
  return JSON.parse(raw);
35574
35824
  } catch {
35575
35825
  return {};
@@ -35577,7 +35827,7 @@ async function loadPersistedConfig() {
35577
35827
  }
35578
35828
  async function savePersistedConfig(config2) {
35579
35829
  try {
35580
- await fs20.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
35830
+ await fs21.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
35581
35831
  } catch (err) {
35582
35832
  const msg = err instanceof Error ? err.message : String(err);
35583
35833
  logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
@@ -35612,11 +35862,11 @@ First run detected. Where should cogent-bridge store its data?
35612
35862
  });
35613
35863
  }
35614
35864
  async function validateStateDir(statePath) {
35615
- await fs20.mkdir(statePath, { recursive: true });
35616
- const testFile = path21.join(statePath, ".write-test");
35865
+ await fs21.mkdir(statePath, { recursive: true });
35866
+ const testFile = path22.join(statePath, ".write-test");
35617
35867
  try {
35618
- await fs20.writeFile(testFile, "test", "utf-8");
35619
- await fs20.unlink(testFile);
35868
+ await fs21.writeFile(testFile, "test", "utf-8");
35869
+ await fs21.unlink(testFile);
35620
35870
  } catch {
35621
35871
  throw new BridgeError(
35622
35872
  "STARTUP_FAILED" /* STARTUP_FAILED */,
@@ -35700,9 +35950,15 @@ function cancelPresenceRetry() {
35700
35950
  if (presenceRetry) clearTimeout(presenceRetry);
35701
35951
  presenceRetry = null;
35702
35952
  }
35703
- function presenceRetryDelayMs(attempt) {
35953
+ function presenceRetryBaseMs() {
35704
35954
  const base = Number(process.env.COGENT_PRESENCE_RETRY_MS);
35705
- return Math.min((Number.isFinite(base) && base > 0 ? base : 3e4) * 2 ** attempt, 3e5);
35955
+ return Number.isFinite(base) && base > 0 ? base : 3e4;
35956
+ }
35957
+ function presenceRetryDelayMs(attempt) {
35958
+ return Math.min(presenceRetryBaseMs() * 2 ** attempt, 3e5);
35959
+ }
35960
+ function standbyRecheckMs() {
35961
+ return Math.max(250, Math.min(presenceRetryBaseMs(), 15e3));
35706
35962
  }
35707
35963
  async function restorePeerPresence(attempt = 0) {
35708
35964
  if (!presenceSupersedeBound) {
@@ -35716,6 +35972,8 @@ async function restorePeerPresence(attempt = 0) {
35716
35972
  }
35717
35973
  const generation = getCloudAttemptGeneration();
35718
35974
  const stillCurrent = () => getCloudAttemptGeneration() === generation;
35975
+ let procs = null;
35976
+ const ps = () => procs ??= listProcesses();
35719
35977
  const outcome = await restorePresence({
35720
35978
  // The endpoint being a relay URL is what makes presence meaningful. We deliberately do
35721
35979
  // NOT gate on the active backend being the cloud one: at startup it is still the
@@ -35728,13 +35986,27 @@ async function restorePeerPresence(attempt = 0) {
35728
35986
  alreadyRegisteredInProcess: () => autoRelay.getDiagnostics().registered,
35729
35987
  peerAlreadyServed: (peerId) => {
35730
35988
  try {
35731
- return listLiveBridges(process.cwd(), peerId).some((b) => b.pid !== process.pid);
35989
+ const holders = listLiveBridges(process.cwd(), peerId).filter((b) => b.pid !== process.pid && !b.draining);
35990
+ const other = holders.find((b) => {
35991
+ if (!holderClientGone(b, ps())) return true;
35992
+ if (!ignoredHolders.has(b.pid)) {
35993
+ ignoredHolders.add(b.pid);
35994
+ logger.info(
35995
+ `Presence: ignoring bridge pid ${b.pid} (${registryText(b.version)}) announced for '${peerId}' \u2014 its MCP client is gone (parent then: ${b.parentPid === void 0 ? "not recorded" : registryText(b.parentPid)}), so it serves no agent`
35996
+ );
35997
+ }
35998
+ return false;
35999
+ });
36000
+ return other ? { pid: other.pid, version: other.version, startedAt: other.startedAt, sessionId: other.sessionId } : null;
35732
36001
  } catch {
35733
- return false;
36002
+ return null;
35734
36003
  }
35735
36004
  },
36005
+ agentSessionId: () => agentSessionId(),
36006
+ startedByWakeTurn: () => insideCodexWakeTurn(process.pid, ps()),
35736
36007
  loadCredentials: () => loadCredentials(),
35737
36008
  cwd: () => process.cwd(),
36009
+ recheckSeconds: Math.round(standbyRecheckMs() / 1e3),
35738
36010
  goOnline: async ({ peerId, endpoint, sessionId, token, cwd, label, peerSecret }) => {
35739
36011
  if (!stillCurrent()) throw new Error(PRESENCE_SUPERSEDED);
35740
36012
  await reinitCloudBackend(endpoint, sessionId, token);
@@ -35754,18 +36026,25 @@ async function restorePeerPresence(attempt = 0) {
35754
36026
  logPresence(superseded);
35755
36027
  return superseded;
35756
36028
  }
36029
+ const prev = getPresence();
35757
36030
  setPresence(outcome);
35758
- logPresence(outcome);
35759
- if (outcome.state === "offline" && outcome.detail.startsWith("presence restore failed")) {
35760
- const delay = presenceRetryDelayMs(attempt);
36031
+ if (outcome.state === "standby" && prev?.state === "standby" && prev.servedBy.pid === outcome.servedBy.pid) {
36032
+ logger.debug(`Presence: STANDBY (unchanged) \u2014 ${outcome.detail}.`);
36033
+ } else {
36034
+ logPresence(outcome);
36035
+ }
36036
+ const failed = outcome.state === "offline" && outcome.detail.startsWith("presence restore failed");
36037
+ const standby = outcome.state === "standby" && outcome.recheck;
36038
+ if (failed || standby) {
36039
+ const delay = standby ? standbyRecheckMs() : presenceRetryDelayMs(attempt);
35761
36040
  cancelPresenceRetry();
35762
36041
  presenceRetry = setTimeout(() => {
35763
36042
  presenceRetry = null;
35764
- void restorePeerPresence(attempt + 1).catch(() => {
36043
+ void restorePeerPresence(standby ? 0 : attempt + 1).catch(() => {
35765
36044
  });
35766
36045
  }, delay);
35767
36046
  presenceRetry.unref?.();
35768
- logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
36047
+ if (failed) logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
35769
36048
  }
35770
36049
  return outcome;
35771
36050
  }
@@ -35899,10 +36178,10 @@ async function runStartup() {
35899
36178
  if (envStatePath) {
35900
36179
  statePath = envStatePath;
35901
36180
  } else {
35902
- const defaultPath = path21.join(os15.homedir(), ".cogent");
36181
+ const defaultPath = path22.join(os15.homedir(), ".cogent");
35903
36182
  statePath = await firstRunPrompt(defaultPath);
35904
36183
  }
35905
- if (!envStatePath && statePath !== path21.join(os15.homedir(), ".cogent")) {
36184
+ if (!envStatePath && statePath !== path22.join(os15.homedir(), ".cogent")) {
35906
36185
  process.env.COGENT_STATE_PATH = statePath;
35907
36186
  } else if (!envStatePath) {
35908
36187
  process.env.COGENT_STATE_PATH = statePath;
@@ -35966,7 +36245,7 @@ async function runStartup() {
35966
36245
  }
35967
36246
  initLogger(
35968
36247
  config2.COGENT_LOG_LEVEL,
35969
- path21.join(config2.COGENT_STATE_PATH, "logs")
36248
+ path22.join(config2.COGENT_STATE_PATH, "logs")
35970
36249
  );
35971
36250
  if (isCloud && effectiveSessionId && effectiveToken) {
35972
36251
  cloudInbox = new MessageInbox();
@@ -36006,7 +36285,7 @@ async function runPreflights() {
36006
36285
  await preflightClaude(config2.COGENT_CLAUDE_PATH);
36007
36286
  }
36008
36287
  }
36009
- var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve;
36288
+ var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, ignoredHolders, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve;
36010
36289
  var init_startup = __esm({
36011
36290
  "src/startup.ts"() {
36012
36291
  "use strict";
@@ -36022,6 +36301,7 @@ var init_startup = __esm({
36022
36301
  init_auto_relay();
36023
36302
  init_peer_presence();
36024
36303
  init_wake_ownership();
36304
+ init_stale_bridge_reaper();
36025
36305
  init_heartbeat();
36026
36306
  init_codex_preflight();
36027
36307
  init_codex_cli();
@@ -36030,7 +36310,7 @@ var init_startup = __esm({
36030
36310
  init_auto_relay();
36031
36311
  UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
36032
36312
  execFileAsync3 = promisify4(execFile5);
36033
- PERSIST_PATH = path21.join(os15.homedir(), ".cogent-config.json");
36313
+ PERSIST_PATH = path22.join(os15.homedir(), ".cogent-config.json");
36034
36314
  legacyWarnEmitted = false;
36035
36315
  cloudWsClient = null;
36036
36316
  cloudInbox = null;
@@ -36040,6 +36320,7 @@ var init_startup = __esm({
36040
36320
  notifierBoundTo = null;
36041
36321
  reRegistrationInProgress = false;
36042
36322
  presenceRetry = null;
36323
+ ignoredHolders = /* @__PURE__ */ new Set();
36043
36324
  presenceSupersedeBound = false;
36044
36325
  PRESENCE_SUPERSEDED = "presence restore superseded: an explicit cogent_join_session/cogent_create_session ran in this process and owns the channel choice";
36045
36326
  pendingLabelResolve = null;
@@ -36048,12 +36329,12 @@ var init_startup = __esm({
36048
36329
 
36049
36330
  // src/cloud/mail-credential-store.ts
36050
36331
  import crypto9 from "node:crypto";
36051
- import fs21 from "node:fs/promises";
36052
- import path22 from "node:path";
36332
+ import fs22 from "node:fs/promises";
36333
+ import path23 from "node:path";
36053
36334
  import os16 from "node:os";
36054
36335
  function defaultMailCredentialPath(cwd = process.cwd()) {
36055
- const hash = crypto9.createHash("sha256").update(path22.resolve(cwd)).digest("hex").slice(0, 16);
36056
- return path22.join(os16.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
36336
+ const hash = crypto9.createHash("sha256").update(path23.resolve(cwd)).digest("hex").slice(0, 16);
36337
+ return path23.join(os16.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
36057
36338
  }
36058
36339
  function resolveMailCredentialPath(credentialPath) {
36059
36340
  if (credentialPath) return credentialPath;
@@ -36064,16 +36345,16 @@ function resolveMailCredentialPath(credentialPath) {
36064
36345
  async function loadMailCredentials(credentialPath) {
36065
36346
  const filePath = resolveMailCredentialPath(credentialPath);
36066
36347
  try {
36067
- return JSON.parse(await fs21.readFile(filePath, "utf-8"));
36348
+ return JSON.parse(await fs22.readFile(filePath, "utf-8"));
36068
36349
  } catch {
36069
36350
  return null;
36070
36351
  }
36071
36352
  }
36072
36353
  async function saveMailCredentials(creds, credentialPath) {
36073
36354
  const filePath = resolveMailCredentialPath(credentialPath);
36074
- await fs21.mkdir(path22.dirname(filePath), { recursive: true, mode: 448 });
36075
- await fs21.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
36076
- await fs21.chmod(filePath, 384);
36355
+ await fs22.mkdir(path23.dirname(filePath), { recursive: true, mode: 448 });
36356
+ await fs22.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
36357
+ await fs22.chmod(filePath, 384);
36077
36358
  }
36078
36359
  async function persistProvisionedMailbox(mailbox, credentialPath) {
36079
36360
  if (!mailbox?.address || !mailbox.password) return false;
@@ -36094,7 +36375,7 @@ async function persistProvisionedMailbox(mailbox, credentialPath) {
36094
36375
  async function clearMailCredentials(credentialPath) {
36095
36376
  const filePath = resolveMailCredentialPath(credentialPath);
36096
36377
  try {
36097
- await fs21.unlink(filePath);
36378
+ await fs22.unlink(filePath);
36098
36379
  } catch (err) {
36099
36380
  if (err.code !== "ENOENT") throw err;
36100
36381
  }
@@ -36143,10 +36424,10 @@ function registerRegisterPeerTool(server) {
36143
36424
  "cogent_register_peer",
36144
36425
  {
36145
36426
  title: "Register Peer",
36146
- description: "Register a Claude Code session as a named peer on the bridge. Each peer needs a unique peerId, the CC sessionId to resume, the working directory (cwd), and a human-readable label.",
36427
+ description: "Step 3: put this agent online in the channel joined or created in this session. peerId = the peer name you were given (never invent or suffix one); sessionId = this agent session's own resumable id (Claude Code or Codex), not the channel id. Also needs the working directory (cwd) and a human-readable label.",
36147
36428
  inputSchema: {
36148
- peerId: import_zod3.z.string().describe("Unique identifier for this peer, e.g. 'backend' or 'frontend'"),
36149
- sessionId: import_zod3.z.string().describe("Claude Code session ID (used with --resume)"),
36429
+ peerId: import_zod3.z.string().describe("The peer name you were given, e.g. 'backend' or 'frontend'. Never invent or suffix one."),
36430
+ sessionId: import_zod3.z.string().describe("This agent session's own resumable id (Claude Code or Codex) \u2014 NOT the channel id"),
36150
36431
  cwd: import_zod3.z.string().describe("Absolute path to the project working directory"),
36151
36432
  label: import_zod3.z.string().describe("Human-readable label, e.g. 'Cogent_Backend' or 'Cogent_Frontend'"),
36152
36433
  peerSecret: import_zod3.z.string().optional().describe(
@@ -36169,13 +36450,22 @@ function registerRegisterPeerTool(server) {
36169
36450
  async ({ peerId, sessionId, cwd, label, mode, role, peerSecret: argPeerSecret }) => {
36170
36451
  try {
36171
36452
  const config2 = getConfig();
36453
+ if (isReservedPeerName(peerId)) {
36454
+ return errorResult(
36455
+ new BridgeError(
36456
+ "INVALID_INPUT" /* INVALID_INPUT */,
36457
+ `peerId '${PROCESS_MARK}' is reserved by the bridge`,
36458
+ "Register under another peerId"
36459
+ )
36460
+ );
36461
+ }
36172
36462
  const hasExplicitCloudSession = !!config2.COGENT_SESSION_ID || process.env.COGENT_TRUST_PERSISTED_CREDENTIALS === "1";
36173
36463
  if (!hasExplicitCloudSession && hasCloudAttemptInProcess() && !hasJoinedInProcess()) {
36174
36464
  return errorResult(
36175
36465
  new BridgeError(
36176
36466
  "JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
36177
36467
  "A cogent_join_session/cogent_create_session call was attempted this session but did not succeed, so cogent_register_peer will not fall back to local mode or auto-create a new channel (that would silently put you on the WRONG channel while reporting success)",
36178
- "Re-run cogent_join_session with the correct channel name + secret (+ Org_ID for Team channels) and confirm it returns success before calling cogent_register_peer"
36468
+ "Re-run cogent_join_session with the correct channel name + secret (+ Org_ID for Team channels) and confirm it returns success before calling cogent_register_peer; or, if the join answered CHANNEL_NOT_FOUND, cogent_create_session with the same name, secret and Org_ID"
36179
36469
  )
36180
36470
  );
36181
36471
  }
@@ -36273,7 +36563,7 @@ function registerRegisterPeerTool(server) {
36273
36563
  new BridgeError(
36274
36564
  "JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
36275
36565
  "Cloud endpoint + COGENT_SESSION_ID are configured but this bridge has not joined the channel (no session token \u2014 the relay was unreachable or the session label did not resolve at startup). cogent_register_peer will NOT register against local state (that would leave you on no channel while other local agents' data sits on this host).",
36276
- "Call cogent_join_session with the channel name + secret (+ Org_ID for Team channels) and confirm it returns success, then retry cogent_register_peer."
36566
+ "Call cogent_join_session with the channel name + secret (+ Org_ID for Team channels) and confirm it returns success (or, if the join answered CHANNEL_NOT_FOUND, cogent_create_session with the same name, secret and Org_ID), then retry cogent_register_peer."
36277
36567
  )
36278
36568
  );
36279
36569
  }
@@ -36422,9 +36712,25 @@ function registerRegisterPeerTool(server) {
36422
36712
  }
36423
36713
  }
36424
36714
  autoRelay.setLocalPeer(peerId, localSessionId, cwd, mode, label, localSessionId);
36715
+ if (isCloudMode()) {
36716
+ setPresence({ state: "online", restored: false, detail: `registered as '${peerId}' by cogent_register_peer` });
36717
+ }
36718
+ let otherBridges;
36719
+ try {
36720
+ const own = agentSessionId();
36721
+ const others = otherBridgesInFolder(listLiveBridgesInFolder(cwd), { pid: process.pid, sessionId: own }, listProcesses);
36722
+ if (others.length) {
36723
+ otherBridges = otherBridgeNotice(others, peerId, checkWakeOwnership(cwd, peerId), own);
36724
+ if (anotherAgentSessionAmong(others, own)) logger.warn(`Register: ${otherBridges}`);
36725
+ else logger.info(`Register: ${otherBridges}`);
36726
+ }
36727
+ } catch (err) {
36728
+ logger.debug(`Register: could not look for other bridges in this folder: ${err.message}`);
36729
+ }
36425
36730
  const result = {
36426
36731
  success: true,
36427
36732
  action: existing ? "updated" : "registered",
36733
+ ...otherBridges ? { otherBridgeInThisFolder: otherBridges } : {},
36428
36734
  peer,
36429
36735
  sessionResolution: {
36430
36736
  decision: resolution.decision,
@@ -36503,6 +36809,9 @@ var init_register_peer = __esm({
36503
36809
  init_logger();
36504
36810
  init_heartbeat();
36505
36811
  init_auto_relay();
36812
+ init_wake_ownership();
36813
+ init_peer_presence();
36814
+ init_stale_bridge_reaper();
36506
36815
  init_session_resolver();
36507
36816
  init_cc_cli();
36508
36817
  init_durable_identity();
@@ -37172,9 +37481,14 @@ var init_ids = __esm({
37172
37481
  });
37173
37482
 
37174
37483
  // cogent/dist/helpers/validation.js
37484
+ function isValidSessionLabel(value) {
37485
+ return SESSION_LABEL_REGEX.test(value);
37486
+ }
37487
+ var SESSION_LABEL_REGEX;
37175
37488
  var init_validation = __esm({
37176
37489
  "cogent/dist/helpers/validation.js"() {
37177
37490
  "use strict";
37491
+ SESSION_LABEL_REGEX = /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/;
37178
37492
  }
37179
37493
  });
37180
37494
 
@@ -37627,7 +37941,8 @@ function registerHealthCheckTool(server) {
37627
37941
  // PRESENCE — the agent's own view of whether it is IN its channel, so it can
37628
37942
  // answer "am I reachable?" without inferring it from transport internals.
37629
37943
  // "online" registered · "offline" owns a peer but is not registered (nobody can
37630
- // reach it) · "deferred" never joined · "local" no relay.
37944
+ // reach it) · "standby" another live bridge serves this peer, so THIS process is not
37945
+ // registered (servedBy names it) · "deferred" never joined · "local" no relay.
37631
37946
  // services/peer-presence.ts carries the vocabulary and how each state arises.
37632
37947
  presence: (() => {
37633
37948
  const p = getPresence();
@@ -37638,7 +37953,8 @@ function registerHealthCheckTool(server) {
37638
37953
  state: p.state,
37639
37954
  restored: p.restored,
37640
37955
  detail: p.detail,
37641
- ..."peerId" in p ? { peerId: p.peerId } : {}
37956
+ ..."peerId" in p ? { peerId: p.peerId } : {},
37957
+ ..."servedBy" in p ? { servedBy: p.servedBy } : {}
37642
37958
  };
37643
37959
  })()
37644
37960
  };
@@ -37725,18 +38041,43 @@ var init_wake_log2 = __esm({
37725
38041
  }
37726
38042
  });
37727
38043
 
38044
+ // src/tools/channel-text.ts
38045
+ function invalidChannelName(name) {
38046
+ if (isValidSessionLabel(name)) return null;
38047
+ return new BridgeError(
38048
+ "INVALID_INPUT" /* INVALID_INPUT */,
38049
+ `Channel names are 3-32 characters: lowercase letters, digits and hyphens. '${name}' is not valid`,
38050
+ "If it differs only by capital letters, retry with it in lowercase; otherwise ask the user."
38051
+ );
38052
+ }
38053
+ function slackMapCommand(o) {
38054
+ return o.team ? `/cogent map ${o.label} <password> <org-id>` : `/cogent map ${o.sessionId} <password>`;
38055
+ }
38056
+ var init_channel_text = __esm({
38057
+ "src/tools/channel-text.ts"() {
38058
+ "use strict";
38059
+ init_dist();
38060
+ init_errors4();
38061
+ }
38062
+ });
38063
+
37728
38064
  // src/tools/create-session.ts
37729
38065
  import crypto11 from "node:crypto";
37730
38066
  function registerCreateSessionTool(server) {
37731
38067
  server.registerTool(
37732
38068
  "cogent_create_session",
37733
38069
  {
37734
- title: "Create Cloud Session",
37735
- description: "Create a new cloud bridge session on the relay server. Returns session ID and secret for other peers to join. Only available when COGENT_ENDPOINT is configured.",
38070
+ title: "Create Cloud Channel",
38071
+ description: "Step 2: create a Cogent channel and join it. Call this ONLY after cogent_join_session answered CHANNEL_NOT_FOUND, with the SAME channel name, secret and (Team channel) orgId. Never choose a different name. Next call: cogent_register_peer.",
37736
38072
  inputSchema: {
37737
- label: import_zod15.z.string().optional().describe("Human-readable label for the session"),
38073
+ label: import_zod15.z.string().optional().describe(
38074
+ "The channel name (3-32 characters: lowercase letters, digits, hyphens) \u2014 the same name the join was given. Auto-generated if omitted."
38075
+ ),
37738
38076
  secret: import_zod15.z.string().min(8).optional().describe(
37739
- "Shared secret for session authentication (min 8 chars). Auto-generated if omitted."
38077
+ "Shared secret / password for the channel (min 8 chars). Auto-generated if omitted."
38078
+ ),
38079
+ orgId: import_zod15.z.string().min(1).optional().describe(
38080
+ "Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it to create a Team channel; omit for a free channel."
37740
38081
  )
37741
38082
  },
37742
38083
  annotations: {
@@ -37746,28 +38087,57 @@ function registerCreateSessionTool(server) {
37746
38087
  openWorldHint: true
37747
38088
  }
37748
38089
  },
37749
- async ({ label, secret }) => {
38090
+ async ({ label, secret, orgId }) => {
37750
38091
  try {
37751
38092
  markCloudAttemptInProcess();
38093
+ if (label !== void 0 && label.trim() === "") {
38094
+ return errorResult(invalidChannelName(label) ?? new Error("label is empty"));
38095
+ }
38096
+ if (secret !== void 0 && secret.trim() === "") {
38097
+ return errorResult(
38098
+ new BridgeError(
38099
+ "INVALID_INPUT" /* INVALID_INPUT */,
38100
+ "The channel password is empty",
38101
+ "Pass the password you were given, or omit `secret` to have one generated."
38102
+ )
38103
+ );
38104
+ }
38105
+ label = label?.trim() || void 0;
38106
+ secret = secret?.trim() || void 0;
38107
+ orgId = orgId?.trim() || void 0;
37752
38108
  const config2 = getConfig();
37753
- if (!config2.COGENT_ENDPOINT) {
38109
+ const endpoint = orgId ? config2.COGENT_TEAM_ENDPOINT : config2.COGENT_ENDPOINT;
38110
+ if (!endpoint) {
37754
38111
  return errorResult(
37755
38112
  new Error(
37756
- "COGENT_ENDPOINT not configured. Set it to use cloud mode."
38113
+ orgId ? "COGENT_TEAM_ENDPOINT not configured. Set it to create Team (Org_ID) channels." : "COGENT_ENDPOINT not configured. Set it to use cloud mode."
37757
38114
  )
37758
38115
  );
37759
38116
  }
38117
+ if (label !== void 0) {
38118
+ const invalid = invalidChannelName(label);
38119
+ if (invalid) return errorResult(invalid);
38120
+ }
38121
+ const secretWasGenerated = secret === void 0;
37760
38122
  const sessionSecret = secret ?? crypto11.randomBytes(16).toString("hex");
38123
+ const createBody = orgId ? { secret: sessionSecret, label, orgId } : { secret: sessionSecret, label };
37761
38124
  const resp = await fetch(
37762
- `${config2.COGENT_ENDPOINT}/api/sessions`,
38125
+ `${endpoint}/api/sessions`,
37763
38126
  {
37764
38127
  method: "POST",
37765
38128
  headers: { "Content-Type": "application/json" },
37766
- body: JSON.stringify({ secret: sessionSecret, label })
38129
+ body: JSON.stringify(createBody)
37767
38130
  }
37768
38131
  );
37769
38132
  if (!resp.ok) {
37770
38133
  const body = await resp.text().catch(() => "");
38134
+ if (resp.status === 400 && body.includes("already in use")) {
38135
+ return errorResult(
38136
+ new Error(
38137
+ `Channel '${label}' already exists (already in use). Call cogent_join_session with the same name, secret${orgId ? " and Org_ID" : ""}. Do not choose another name.`
38138
+ )
38139
+ );
38140
+ }
37771
38141
  return errorResult(
37772
38142
  new Error(
37773
38143
  `Failed to create session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
@@ -37776,7 +38146,7 @@ function registerCreateSessionTool(server) {
37776
38146
  }
37777
38147
  const data = await resp.json();
37778
38148
  await saveCredentials({
37779
- endpoint: config2.COGENT_ENDPOINT,
38149
+ endpoint,
37780
38150
  sessionId: data.sessionId,
37781
38151
  token: data.token,
37782
38152
  label: data.label,
@@ -37786,7 +38156,7 @@ function registerCreateSessionTool(server) {
37786
38156
  try {
37787
38157
  const startupModule = await Promise.resolve().then(() => (init_startup(), startup_exports));
37788
38158
  if (typeof startupModule.reinitCloudBackend === "function") {
37789
- await startupModule.reinitCloudBackend(config2.COGENT_ENDPOINT, data.sessionId, data.token);
38159
+ await startupModule.reinitCloudBackend(endpoint, data.sessionId, data.token);
37790
38160
  logger.info(
37791
38161
  "Cloud backend reinitialized with new session credentials"
37792
38162
  );
@@ -37794,32 +38164,40 @@ function registerCreateSessionTool(server) {
37794
38164
  } catch (err) {
37795
38165
  logger.debug(`Backend reinit not available: ${err}`);
37796
38166
  }
38167
+ const channelName = data.label ?? data.sessionId;
37797
38168
  return successResult({
37798
38169
  success: true,
38170
+ created: true,
37799
38171
  sessionId: data.sessionId,
37800
38172
  label: data.label,
37801
- secret: sessionSecret,
37802
38173
  token: data.token,
37803
38174
  createdAt: data.createdAt,
37804
- config_snippet: {
37805
- env_vars: `COGENT_ENDPOINT=${config2.COGENT_ENDPOINT}
37806
- COGENT_SESSION_ID=${data.label ?? data.sessionId}
38175
+ slackMapCommand: slackMapCommand({ team: !!orgId, label: channelName, sessionId: data.sessionId }),
38176
+ // A secret the CALLER supplied is never echoed back: the caller already has it, and a
38177
+ // tool result can be quoted into a channel by an auto-reply. Only a secret this tool
38178
+ // generated is returned — nothing else knows it.
38179
+ ...secretWasGenerated ? {
38180
+ secret: sessionSecret,
38181
+ config_snippet: {
38182
+ env_vars: `COGENT_ENDPOINT=${endpoint}
38183
+ COGENT_SESSION_ID=${channelName}
37807
38184
  COGENT_SECRET=${sessionSecret}
37808
38185
  COGENT_PLATFORM=${config2.COGENT_PLATFORM}`,
37809
- mcp_config: {
37810
- "cogent": {
37811
- command: "npx",
37812
- args: ["-y", "@essentialai/cogent-bridge"],
37813
- env: {
37814
- COGENT_ENDPOINT: config2.COGENT_ENDPOINT,
37815
- COGENT_SESSION_ID: data.label ?? data.sessionId,
37816
- COGENT_SECRET: sessionSecret,
37817
- COGENT_PLATFORM: config2.COGENT_PLATFORM
38186
+ mcp_config: {
38187
+ "cogent": {
38188
+ command: "npx",
38189
+ args: ["-y", "@essentialai/cogent-bridge"],
38190
+ env: {
38191
+ COGENT_ENDPOINT: endpoint,
38192
+ COGENT_SESSION_ID: channelName,
38193
+ COGENT_SECRET: sessionSecret,
38194
+ COGENT_PLATFORM: config2.COGENT_PLATFORM
38195
+ }
37818
38196
  }
37819
38197
  }
37820
38198
  }
37821
- },
37822
- note: `Session created with label "${data.label ?? data.sessionId}". Share the secret with peers who need to join. Credentials saved locally. Cloud backend updated.`
38199
+ } : {},
38200
+ note: `${orgId ? "Team channel" : "Channel"} "${channelName}" was created by this call and you are joined to it. Credentials saved locally. Cloud backend updated. Next: cogent_register_peer.`
37823
38201
  });
37824
38202
  } catch (err) {
37825
38203
  logger.error("create-session failed", { error: err });
@@ -37837,6 +38215,7 @@ var init_create_session = __esm({
37837
38215
  init_errors4();
37838
38216
  init_credential_store();
37839
38217
  init_logger();
38218
+ init_channel_text();
37840
38219
  }
37841
38220
  });
37842
38221
 
@@ -37846,14 +38225,14 @@ function registerJoinSessionTool(server) {
37846
38225
  "cogent_join_session",
37847
38226
  {
37848
38227
  title: "Join Cloud Channel",
37849
- description: 'Join an existing cloud bridge channel by its channel name (e.g. "mt-space") and shared secret. The channel name is the human-readable label provided by the user, NOT a UUID. Do NOT pass a Claude Code session ID here \u2014 use the channel/space name the user gave you.',
38228
+ description: 'Step 1: join an existing Cogent channel by its channel name (e.g. "mt-space") and shared secret (plus orgId for a Team channel). The channel name is the human-readable label provided by the user, NOT a UUID. Do NOT pass an agent session ID here \u2014 use the channel/space name the user gave you. Next call: cogent_register_peer. If this answers CHANNEL_NOT_FOUND, the next call is cogent_create_session with the same name, secret and orgId.',
37850
38229
  inputSchema: {
37851
38230
  channel: import_zod16.z.string().describe(
37852
- 'The channel name to join (e.g. "mt-space"). This is the human-readable name the user provided, NOT a UUID. Do NOT use a Claude Code session ID here.'
38231
+ 'The channel name to join (e.g. "mt-space"). This is the human-readable name the user provided, NOT a UUID. Do NOT use an agent session ID here.'
37853
38232
  ),
37854
38233
  secret: import_zod16.z.string().min(1).describe("The shared secret / password for the channel"),
37855
38234
  orgId: import_zod16.z.string().min(1).optional().describe(
37856
- "Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it for team channels; omit for free channels."
38235
+ "Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it for team channels; omit for free channels. If you were given one, never retry without it."
37857
38236
  )
37858
38237
  },
37859
38238
  annotations: {
@@ -37881,10 +38260,12 @@ function registerJoinSessionTool(server) {
37881
38260
  if (UUID_V4_RE2.test(channel)) {
37882
38261
  return errorResult(
37883
38262
  new Error(
37884
- `The "channel" parameter ("${channel}") looks like a UUID. You should pass the human-readable channel name (e.g. "mt-space") that the user provided, NOT a Claude Code session ID or any UUID. Please retry with the correct channel name.`
38263
+ `The "channel" parameter ("${channel}") looks like a UUID. You should pass the human-readable channel name (e.g. "mt-space") that the user provided, NOT an agent session ID or any UUID. Please retry with the correct channel name.`
37885
38264
  )
37886
38265
  );
37887
38266
  }
38267
+ const invalid = invalidChannelName(channel);
38268
+ if (invalid) return errorResult(invalid);
37888
38269
  let resolvedSessionId;
37889
38270
  let resolvedLabel;
37890
38271
  if (orgId) {
@@ -37896,6 +38277,13 @@ function registerJoinSessionTool(server) {
37896
38277
  body: JSON.stringify({ label: channel, orgId })
37897
38278
  }
37898
38279
  );
38280
+ if (resolveResp.status === 404) {
38281
+ return errorResult(new BridgeError(
38282
+ "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
38283
+ `Team channel '${channel}' was not found on ${endpoint} for this Org_ID (HTTP 404)`,
38284
+ `If the name and Org_ID are exactly as given, the channel does not exist yet: call cogent_create_session with label '${channel}', the same secret and the same orgId, then cogent_register_peer. Do not call cogent_join_session again first, and never without orgId.`
38285
+ ));
38286
+ }
37899
38287
  if (!resolveResp.ok) {
37900
38288
  const body = await resolveResp.text().catch(() => "");
37901
38289
  return errorResult(new Error(
@@ -37909,6 +38297,13 @@ function registerJoinSessionTool(server) {
37909
38297
  const resolveResp = await fetch(
37910
38298
  `${endpoint}/api/sessions/resolve/${encodeURIComponent(channel)}`
37911
38299
  );
38300
+ if (resolveResp.status === 404) {
38301
+ return errorResult(new BridgeError(
38302
+ "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
38303
+ `Channel '${channel}' was not found on ${endpoint} (HTTP 404)`,
38304
+ `If you were given an Org_ID you left it out: call cogent_join_session again WITH orgId and do not create anything. Otherwise call cogent_create_session with label '${channel}' and the same secret.`
38305
+ ));
38306
+ }
37912
38307
  if (!resolveResp.ok) {
37913
38308
  const body = await resolveResp.text().catch(() => "");
37914
38309
  return errorResult(new Error(`Failed to resolve channel name "${channel}": HTTP ${resolveResp.status}${body ? ` - ${body}` : ""}`));
@@ -37928,9 +38323,10 @@ function registerJoinSessionTool(server) {
37928
38323
  );
37929
38324
  if (!resp.ok) {
37930
38325
  const body = await resp.text().catch(() => "");
38326
+ const wrong = resp.status === 401 ? `. The password${orgId ? " or Org_ID" : ""} is wrong. Do not retry with guesses - ask the user.` : "";
37931
38327
  return errorResult(
37932
38328
  new Error(
37933
- `Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
38329
+ `Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}${wrong}`
37934
38330
  )
37935
38331
  );
37936
38332
  }
@@ -37979,6 +38375,11 @@ function registerJoinSessionTool(server) {
37979
38375
  token: data.token,
37980
38376
  label: resolvedLabel ?? data.label ?? channel,
37981
38377
  peerCount: data.peerCount,
38378
+ slackMapCommand: slackMapCommand({
38379
+ team: !!orgId,
38380
+ label: resolvedLabel ?? data.label ?? channel,
38381
+ sessionId: data.sessionId
38382
+ }),
37982
38383
  note: "Successfully joined session. Credentials saved locally. Cloud backend updated. You can now use cogent_register_peer.",
37983
38384
  ...updateNudge ? { updateAvailable: updateNudge } : {}
37984
38385
  });
@@ -37999,6 +38400,7 @@ var init_join_session = __esm({
37999
38400
  init_credential_store();
38000
38401
  init_logger();
38001
38402
  init_npm_update_check();
38403
+ init_channel_text();
38002
38404
  UUID_V4_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
38003
38405
  }
38004
38406
  });
@@ -38233,8 +38635,8 @@ var require_cookies = __commonJS({
38233
38635
  if (urlparts.hostname !== cookie.domain && (cookie.domain.charAt(0) !== "." || ("." + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
38234
38636
  return false;
38235
38637
  }
38236
- let path26 = this.getPath(urlparts.pathname);
38237
- if (path26.substr(0, cookie.path.length) !== cookie.path) {
38638
+ let path27 = this.getPath(urlparts.pathname);
38639
+ if (path27.substr(0, cookie.path.length) !== cookie.path) {
38238
38640
  return false;
38239
38641
  }
38240
38642
  if (cookie.secure && urlparts.protocol !== "https:") {
@@ -38294,16 +38696,16 @@ var require_cookies = __commonJS({
38294
38696
  * @returns {String} Normalized path
38295
38697
  */
38296
38698
  getPath(pathname) {
38297
- let path26 = (pathname || "/").split("/");
38298
- path26.pop();
38299
- path26 = path26.join("/").trim();
38300
- if (path26.charAt(0) !== "/") {
38301
- path26 = "/" + path26;
38699
+ let path27 = (pathname || "/").split("/");
38700
+ path27.pop();
38701
+ path27 = path27.join("/").trim();
38702
+ if (path27.charAt(0) !== "/") {
38703
+ path27 = "/" + path27;
38302
38704
  }
38303
- if (path26.substr(-1) !== "/") {
38304
- path26 += "/";
38705
+ if (path27.substr(-1) !== "/") {
38706
+ path27 += "/";
38305
38707
  }
38306
- return path26;
38708
+ return path27;
38307
38709
  }
38308
38710
  };
38309
38711
  module.exports = Cookies;
@@ -38604,7 +39006,7 @@ var require_shared = __commonJS({
38604
39006
  "use strict";
38605
39007
  var urllib = __require("url");
38606
39008
  var util2 = __require("util");
38607
- var fs24 = __require("fs");
39009
+ var fs25 = __require("fs");
38608
39010
  var nmfetch = require_fetch();
38609
39011
  var dns = __require("dns");
38610
39012
  var net = __require("net");
@@ -38990,7 +39392,7 @@ var require_shared = __commonJS({
38990
39392
  }
38991
39393
  return callback(null, parsedDataUri.data);
38992
39394
  } else if (content.path) {
38993
- return resolveStream(fs24.createReadStream(content.path), callback);
39395
+ return resolveStream(fs25.createReadStream(content.path), callback);
38994
39396
  }
38995
39397
  }
38996
39398
  if (typeof data[key].content === "string" && !["utf8", "usascii", "ascii"].includes(encoding)) {
@@ -39114,7 +39516,7 @@ var require_shared = __commonJS({
39114
39516
  var require_mime_types = __commonJS({
39115
39517
  "node_modules/nodemailer/lib/mime-funcs/mime-types.js"(exports, module) {
39116
39518
  "use strict";
39117
- var path26 = __require("path");
39519
+ var path27 = __require("path");
39118
39520
  var defaultMimeType = "application/octet-stream";
39119
39521
  var defaultExtension = "bin";
39120
39522
  var mimeTypes = /* @__PURE__ */ new Map([
@@ -41172,7 +41574,7 @@ var require_mime_types = __commonJS({
41172
41574
  if (!filename) {
41173
41575
  return defaultMimeType;
41174
41576
  }
41175
- let parsed = path26.parse(filename);
41577
+ let parsed = path27.parse(filename);
41176
41578
  let extension = (parsed.ext.substr(1) || parsed.name || "").split("?").shift().trim().toLowerCase();
41177
41579
  let value = defaultMimeType;
41178
41580
  if (extensions.has(extension)) {
@@ -42574,7 +42976,7 @@ var require_mime_node = __commonJS({
42574
42976
  "node_modules/nodemailer/lib/mime-node/index.js"(exports, module) {
42575
42977
  "use strict";
42576
42978
  var crypto12 = __require("crypto");
42577
- var fs24 = __require("fs");
42979
+ var fs25 = __require("fs");
42578
42980
  var punycode = require_punycode();
42579
42981
  var PassThrough = __require("stream").PassThrough;
42580
42982
  var shared = require_shared();
@@ -43289,7 +43691,7 @@ var require_mime_node = __commonJS({
43289
43691
  setImmediate(() => contentStream.emit("error", new Error("File access rejected for " + content.path)));
43290
43692
  return contentStream;
43291
43693
  }
43292
- return fs24.createReadStream(content.path);
43694
+ return fs25.createReadStream(content.path);
43293
43695
  } else if (content && typeof content.href === "string") {
43294
43696
  if (this.disableUrlAccess) {
43295
43697
  contentStream = new PassThrough();
@@ -44310,8 +44712,8 @@ var require_dkim = __commonJS({
44310
44712
  var RelaxedBody = require_relaxed_body();
44311
44713
  var sign = require_sign();
44312
44714
  var PassThrough = __require("stream").PassThrough;
44313
- var fs24 = __require("fs");
44314
- var path26 = __require("path");
44715
+ var fs25 = __require("fs");
44716
+ var path27 = __require("path");
44315
44717
  var crypto12 = __require("crypto");
44316
44718
  var DKIM_ALGO = "sha256";
44317
44719
  var MAX_MESSAGE_SIZE = 128 * 1024;
@@ -44325,7 +44727,7 @@ var require_dkim = __commonJS({
44325
44727
  this.chunks = [];
44326
44728
  this.chunklen = 0;
44327
44729
  this.readPos = 0;
44328
- this.cachePath = this.cacheDir ? path26.join(this.cacheDir, "message." + Date.now() + "-" + crypto12.randomBytes(14).toString("hex")) : false;
44730
+ this.cachePath = this.cacheDir ? path27.join(this.cacheDir, "message." + Date.now() + "-" + crypto12.randomBytes(14).toString("hex")) : false;
44329
44731
  this.cache = false;
44330
44732
  this.headers = false;
44331
44733
  this.bodyHash = false;
@@ -44345,10 +44747,10 @@ var require_dkim = __commonJS({
44345
44747
  if (!this.cache || !this.cachePath) {
44346
44748
  return;
44347
44749
  }
44348
- fs24.unlink(this.cachePath, () => false);
44750
+ fs25.unlink(this.cachePath, () => false);
44349
44751
  }
44350
44752
  createReadCache() {
44351
- this.cache = fs24.createReadStream(this.cachePath);
44753
+ this.cache = fs25.createReadStream(this.cachePath);
44352
44754
  this.cache.once("error", (err) => {
44353
44755
  this.cleanup();
44354
44756
  this.output.emit("error", err);
@@ -44404,7 +44806,7 @@ var require_dkim = __commonJS({
44404
44806
  }
44405
44807
  createWriteCache() {
44406
44808
  this.output.usingCache = true;
44407
- this.cache = fs24.createWriteStream(this.cachePath);
44809
+ this.cache = fs25.createWriteStream(this.cachePath);
44408
44810
  this.cache.once("error", (err) => {
44409
44811
  this.cleanup();
44410
44812
  this.relaxedBody.unpipe(this.cache);
@@ -49293,13 +49695,13 @@ var require_nodemailer = __commonJS({
49293
49695
  });
49294
49696
 
49295
49697
  // src/mail/mail-sender.ts
49296
- import fs22 from "node:fs/promises";
49297
- import path23 from "node:path";
49698
+ import fs23 from "node:fs/promises";
49699
+ import path24 from "node:path";
49298
49700
  async function buildAndSendMail(sender, creds, params) {
49299
49701
  const attachments = [];
49300
49702
  for (const p of params.attachmentPaths ?? []) {
49301
- const content = await fs22.readFile(p);
49302
- attachments.push({ filename: path23.basename(p), content });
49703
+ const content = await fs23.readFile(p);
49704
+ attachments.push({ filename: path24.basename(p), content });
49303
49705
  }
49304
49706
  const { messageId } = await sender.send({
49305
49707
  from: creds.address,
@@ -49688,8 +50090,8 @@ var require_req = __commonJS({
49688
50090
  if (req.originalUrl) {
49689
50091
  _req.url = req.originalUrl;
49690
50092
  } else {
49691
- const path26 = req.path;
49692
- _req.url = typeof path26 === "string" ? path26 : req.url ? req.url.path || req.url : void 0;
50093
+ const path27 = req.path;
50094
+ _req.url = typeof path27 === "string" ? path27 : req.url ? req.url.path || req.url : void 0;
49693
50095
  }
49694
50096
  if (req.query) {
49695
50097
  _req.query = req.query;
@@ -49854,14 +50256,14 @@ var require_redact = __commonJS({
49854
50256
  }
49855
50257
  return obj;
49856
50258
  }
49857
- function parsePath(path26) {
50259
+ function parsePath(path27) {
49858
50260
  const parts = [];
49859
50261
  let current = "";
49860
50262
  let inBrackets = false;
49861
50263
  let inQuotes = false;
49862
50264
  let quoteChar = "";
49863
- for (let i = 0; i < path26.length; i++) {
49864
- const char = path26[i];
50265
+ for (let i = 0; i < path27.length; i++) {
50266
+ const char = path27[i];
49865
50267
  if (!inBrackets && char === ".") {
49866
50268
  if (current) {
49867
50269
  parts.push(current);
@@ -49992,10 +50394,10 @@ var require_redact = __commonJS({
49992
50394
  return current;
49993
50395
  }
49994
50396
  function redactPaths(obj, paths, censor, remove = false) {
49995
- for (const path26 of paths) {
49996
- const parts = parsePath(path26);
50397
+ for (const path27 of paths) {
50398
+ const parts = parsePath(path27);
49997
50399
  if (parts.includes("*")) {
49998
- redactWildcardPath(obj, parts, censor, path26, remove);
50400
+ redactWildcardPath(obj, parts, censor, path27, remove);
49999
50401
  } else {
50000
50402
  if (remove) {
50001
50403
  removeKey(obj, parts);
@@ -50080,8 +50482,8 @@ var require_redact = __commonJS({
50080
50482
  }
50081
50483
  } else {
50082
50484
  if (afterWildcard.includes("*")) {
50083
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
50084
- const fullPath = [...pathArray.slice(0, pathLength), ...path26];
50485
+ const wrappedCensor = typeof censor === "function" ? (value, path27) => {
50486
+ const fullPath = [...pathArray.slice(0, pathLength), ...path27];
50085
50487
  return censor(value, fullPath);
50086
50488
  } : censor;
50087
50489
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -50116,8 +50518,8 @@ var require_redact = __commonJS({
50116
50518
  return null;
50117
50519
  }
50118
50520
  const pathStructure = /* @__PURE__ */ new Map();
50119
- for (const path26 of pathsToClone) {
50120
- const parts = parsePath(path26);
50521
+ for (const path27 of pathsToClone) {
50522
+ const parts = parsePath(path27);
50121
50523
  let current = pathStructure;
50122
50524
  for (let i = 0; i < parts.length; i++) {
50123
50525
  const part = parts[i];
@@ -50169,24 +50571,24 @@ var require_redact = __commonJS({
50169
50571
  }
50170
50572
  return cloneSelectively(obj, pathStructure);
50171
50573
  }
50172
- function validatePath(path26) {
50173
- if (typeof path26 !== "string") {
50574
+ function validatePath(path27) {
50575
+ if (typeof path27 !== "string") {
50174
50576
  throw new Error("Paths must be (non-empty) strings");
50175
50577
  }
50176
- if (path26 === "") {
50578
+ if (path27 === "") {
50177
50579
  throw new Error("Invalid redaction path ()");
50178
50580
  }
50179
- if (path26.includes("..")) {
50180
- throw new Error(`Invalid redaction path (${path26})`);
50581
+ if (path27.includes("..")) {
50582
+ throw new Error(`Invalid redaction path (${path27})`);
50181
50583
  }
50182
- if (path26.includes(",")) {
50183
- throw new Error(`Invalid redaction path (${path26})`);
50584
+ if (path27.includes(",")) {
50585
+ throw new Error(`Invalid redaction path (${path27})`);
50184
50586
  }
50185
50587
  let bracketCount = 0;
50186
50588
  let inQuotes = false;
50187
50589
  let quoteChar = "";
50188
- for (let i = 0; i < path26.length; i++) {
50189
- const char = path26[i];
50590
+ for (let i = 0; i < path27.length; i++) {
50591
+ const char = path27[i];
50190
50592
  if ((char === '"' || char === "'") && bracketCount > 0) {
50191
50593
  if (!inQuotes) {
50192
50594
  inQuotes = true;
@@ -50200,20 +50602,20 @@ var require_redact = __commonJS({
50200
50602
  } else if (char === "]" && !inQuotes) {
50201
50603
  bracketCount--;
50202
50604
  if (bracketCount < 0) {
50203
- throw new Error(`Invalid redaction path (${path26})`);
50605
+ throw new Error(`Invalid redaction path (${path27})`);
50204
50606
  }
50205
50607
  }
50206
50608
  }
50207
50609
  if (bracketCount !== 0) {
50208
- throw new Error(`Invalid redaction path (${path26})`);
50610
+ throw new Error(`Invalid redaction path (${path27})`);
50209
50611
  }
50210
50612
  }
50211
50613
  function validatePaths(paths) {
50212
50614
  if (!Array.isArray(paths)) {
50213
50615
  throw new TypeError("paths must be an array");
50214
50616
  }
50215
- for (const path26 of paths) {
50216
- validatePath(path26);
50617
+ for (const path27 of paths) {
50618
+ validatePath(path27);
50217
50619
  }
50218
50620
  }
50219
50621
  function slowRedact(options = {}) {
@@ -50381,8 +50783,8 @@ var require_redaction = __commonJS({
50381
50783
  if (shape[k] === null) {
50382
50784
  o[k] = (value) => topCensor(value, [k]);
50383
50785
  } else {
50384
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
50385
- return censor(value, [k, ...path26]);
50786
+ const wrappedCensor = typeof censor === "function" ? (value, path27) => {
50787
+ return censor(value, [k, ...path27]);
50386
50788
  } : censor;
50387
50789
  o[k] = Redact({
50388
50790
  paths: shape[k],
@@ -50600,10 +51002,10 @@ var require_atomic_sleep = __commonJS({
50600
51002
  var require_sonic_boom = __commonJS({
50601
51003
  "node_modules/sonic-boom/index.js"(exports, module) {
50602
51004
  "use strict";
50603
- var fs24 = __require("fs");
51005
+ var fs25 = __require("fs");
50604
51006
  var EventEmitter = __require("events");
50605
51007
  var inherits = __require("util").inherits;
50606
- var path26 = __require("path");
51008
+ var path27 = __require("path");
50607
51009
  var sleep4 = require_atomic_sleep();
50608
51010
  var assert2 = __require("assert");
50609
51011
  var BUSY_WRITE_TIMEOUT = 100;
@@ -50657,20 +51059,20 @@ var require_sonic_boom = __commonJS({
50657
51059
  const mode = sonic.mode;
50658
51060
  if (sonic.sync) {
50659
51061
  try {
50660
- if (sonic.mkdir) fs24.mkdirSync(path26.dirname(file), { recursive: true });
50661
- const fd = fs24.openSync(file, flags, mode);
51062
+ if (sonic.mkdir) fs25.mkdirSync(path27.dirname(file), { recursive: true });
51063
+ const fd = fs25.openSync(file, flags, mode);
50662
51064
  fileOpened(null, fd);
50663
51065
  } catch (err) {
50664
51066
  fileOpened(err);
50665
51067
  throw err;
50666
51068
  }
50667
51069
  } else if (sonic.mkdir) {
50668
- fs24.mkdir(path26.dirname(file), { recursive: true }, (err) => {
51070
+ fs25.mkdir(path27.dirname(file), { recursive: true }, (err) => {
50669
51071
  if (err) return fileOpened(err);
50670
- fs24.open(file, flags, mode, fileOpened);
51072
+ fs25.open(file, flags, mode, fileOpened);
50671
51073
  });
50672
51074
  } else {
50673
- fs24.open(file, flags, mode, fileOpened);
51075
+ fs25.open(file, flags, mode, fileOpened);
50674
51076
  }
50675
51077
  }
50676
51078
  function SonicBoom(opts) {
@@ -50711,8 +51113,8 @@ var require_sonic_boom = __commonJS({
50711
51113
  this.flush = flushBuffer;
50712
51114
  this.flushSync = flushBufferSync;
50713
51115
  this._actualWrite = actualWriteBuffer;
50714
- fsWriteSync = () => fs24.writeSync(this.fd, this._writingBuf);
50715
- fsWrite = () => fs24.write(this.fd, this._writingBuf, this.release);
51116
+ fsWriteSync = () => fs25.writeSync(this.fd, this._writingBuf);
51117
+ fsWrite = () => fs25.write(this.fd, this._writingBuf, this.release);
50716
51118
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
50717
51119
  this._writingBuf = "";
50718
51120
  this.write = write;
@@ -50721,15 +51123,15 @@ var require_sonic_boom = __commonJS({
50721
51123
  this._actualWrite = actualWrite;
50722
51124
  fsWriteSync = () => {
50723
51125
  if (Buffer.isBuffer(this._writingBuf)) {
50724
- return fs24.writeSync(this.fd, this._writingBuf);
51126
+ return fs25.writeSync(this.fd, this._writingBuf);
50725
51127
  }
50726
- return fs24.writeSync(this.fd, this._writingBuf, "utf8");
51128
+ return fs25.writeSync(this.fd, this._writingBuf, "utf8");
50727
51129
  };
50728
51130
  fsWrite = () => {
50729
51131
  if (Buffer.isBuffer(this._writingBuf)) {
50730
- return fs24.write(this.fd, this._writingBuf, this.release);
51132
+ return fs25.write(this.fd, this._writingBuf, this.release);
50731
51133
  }
50732
- return fs24.write(this.fd, this._writingBuf, "utf8", this.release);
51134
+ return fs25.write(this.fd, this._writingBuf, "utf8", this.release);
50733
51135
  };
50734
51136
  } else {
50735
51137
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -50786,7 +51188,7 @@ var require_sonic_boom = __commonJS({
50786
51188
  }
50787
51189
  }
50788
51190
  if (this._fsync) {
50789
- fs24.fsyncSync(this.fd);
51191
+ fs25.fsyncSync(this.fd);
50790
51192
  }
50791
51193
  const len = this._len;
50792
51194
  if (this._reopening) {
@@ -50900,7 +51302,7 @@ var require_sonic_boom = __commonJS({
50900
51302
  const onDrain = () => {
50901
51303
  if (!this._fsync) {
50902
51304
  try {
50903
- fs24.fsync(this.fd, (err) => {
51305
+ fs25.fsync(this.fd, (err) => {
50904
51306
  this._flushPending = false;
50905
51307
  cb(err);
50906
51308
  });
@@ -51002,7 +51404,7 @@ var require_sonic_boom = __commonJS({
51002
51404
  const fd = this.fd;
51003
51405
  this.once("ready", () => {
51004
51406
  if (fd !== this.fd) {
51005
- fs24.close(fd, (err) => {
51407
+ fs25.close(fd, (err) => {
51006
51408
  if (err) {
51007
51409
  return this.emit("error", err);
51008
51410
  }
@@ -51051,7 +51453,7 @@ var require_sonic_boom = __commonJS({
51051
51453
  buf = this._bufs[0];
51052
51454
  }
51053
51455
  try {
51054
- const n = Buffer.isBuffer(buf) ? fs24.writeSync(this.fd, buf) : fs24.writeSync(this.fd, buf, "utf8");
51456
+ const n = Buffer.isBuffer(buf) ? fs25.writeSync(this.fd, buf) : fs25.writeSync(this.fd, buf, "utf8");
51055
51457
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
51056
51458
  buf = releasedBufObj.writingBuf;
51057
51459
  this._len = releasedBufObj.len;
@@ -51067,7 +51469,7 @@ var require_sonic_boom = __commonJS({
51067
51469
  }
51068
51470
  }
51069
51471
  try {
51070
- fs24.fsyncSync(this.fd);
51472
+ fs25.fsyncSync(this.fd);
51071
51473
  } catch {
51072
51474
  }
51073
51475
  }
@@ -51088,7 +51490,7 @@ var require_sonic_boom = __commonJS({
51088
51490
  buf = mergeBuf(this._bufs[0], this._lens[0]);
51089
51491
  }
51090
51492
  try {
51091
- const n = fs24.writeSync(this.fd, buf);
51493
+ const n = fs25.writeSync(this.fd, buf);
51092
51494
  buf = buf.subarray(n);
51093
51495
  this._len = Math.max(this._len - n, 0);
51094
51496
  if (buf.length <= 0) {
@@ -51116,13 +51518,13 @@ var require_sonic_boom = __commonJS({
51116
51518
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
51117
51519
  if (this.sync) {
51118
51520
  try {
51119
- const written = Buffer.isBuffer(this._writingBuf) ? fs24.writeSync(this.fd, this._writingBuf) : fs24.writeSync(this.fd, this._writingBuf, "utf8");
51521
+ const written = Buffer.isBuffer(this._writingBuf) ? fs25.writeSync(this.fd, this._writingBuf) : fs25.writeSync(this.fd, this._writingBuf, "utf8");
51120
51522
  release(null, written);
51121
51523
  } catch (err) {
51122
51524
  release(err);
51123
51525
  }
51124
51526
  } else {
51125
- fs24.write(this.fd, this._writingBuf, release);
51527
+ fs25.write(this.fd, this._writingBuf, release);
51126
51528
  }
51127
51529
  }
51128
51530
  function actualWriteBuffer() {
@@ -51131,7 +51533,7 @@ var require_sonic_boom = __commonJS({
51131
51533
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
51132
51534
  if (this.sync) {
51133
51535
  try {
51134
- const written = fs24.writeSync(this.fd, this._writingBuf);
51536
+ const written = fs25.writeSync(this.fd, this._writingBuf);
51135
51537
  release(null, written);
51136
51538
  } catch (err) {
51137
51539
  release(err);
@@ -51140,7 +51542,7 @@ var require_sonic_boom = __commonJS({
51140
51542
  if (kCopyBuffer) {
51141
51543
  this._writingBuf = Buffer.from(this._writingBuf);
51142
51544
  }
51143
- fs24.write(this.fd, this._writingBuf, release);
51545
+ fs25.write(this.fd, this._writingBuf, release);
51144
51546
  }
51145
51547
  }
51146
51548
  function actualClose(sonic) {
@@ -51156,12 +51558,12 @@ var require_sonic_boom = __commonJS({
51156
51558
  sonic._lens = [];
51157
51559
  assert2(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
51158
51560
  try {
51159
- fs24.fsync(sonic.fd, closeWrapped);
51561
+ fs25.fsync(sonic.fd, closeWrapped);
51160
51562
  } catch {
51161
51563
  }
51162
51564
  function closeWrapped() {
51163
51565
  if (sonic.fd !== 1 && sonic.fd !== 2) {
51164
- fs24.close(sonic.fd, done);
51566
+ fs25.close(sonic.fd, done);
51165
51567
  } else {
51166
51568
  done();
51167
51569
  }
@@ -51997,15 +52399,15 @@ var require_transport = __commonJS({
51997
52399
  if (!unquoted) {
51998
52400
  return false;
51999
52401
  }
52000
- let path26 = unquoted;
52001
- if (path26.startsWith("file://")) {
52402
+ let path27 = unquoted;
52403
+ if (path27.startsWith("file://")) {
52002
52404
  try {
52003
- path26 = fileURLToPath(path26);
52405
+ path27 = fileURLToPath(path27);
52004
52406
  } catch {
52005
52407
  return false;
52006
52408
  }
52007
52409
  }
52008
- return isAbsolute(path26) && !existsSync(path26);
52410
+ return isAbsolute(path27) && !existsSync(path27);
52009
52411
  }
52010
52412
  function stripQuotes(value) {
52011
52413
  const first = value[0];
@@ -86072,15 +86474,15 @@ var require_tools2 = __commonJS({
86072
86474
  * @param {String} path - Mailbox path to encode
86073
86475
  * @returns {String} Encoded mailbox path
86074
86476
  */
86075
- encodePath(connection, path26) {
86076
- path26 = (path26 || "").toString();
86077
- if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path26)) {
86477
+ encodePath(connection, path27) {
86478
+ path27 = (path27 || "").toString();
86479
+ if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path27)) {
86078
86480
  try {
86079
- path26 = iconv.encode(path26, "utf-7-imap").toString();
86481
+ path27 = iconv.encode(path27, "utf-7-imap").toString();
86080
86482
  } catch {
86081
86483
  }
86082
86484
  }
86083
- return path26;
86485
+ return path27;
86084
86486
  },
86085
86487
  /**
86086
86488
  * Decodes a mailbox path from modified UTF-7 if the server does not support UTF8=ACCEPT.
@@ -86089,15 +86491,15 @@ var require_tools2 = __commonJS({
86089
86491
  * @param {String} path - Mailbox path to decode
86090
86492
  * @returns {String} Decoded mailbox path
86091
86493
  */
86092
- decodePath(connection, path26) {
86093
- path26 = (path26 || "").toString();
86094
- if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(path26)) {
86494
+ decodePath(connection, path27) {
86495
+ path27 = (path27 || "").toString();
86496
+ if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(path27)) {
86095
86497
  try {
86096
- path26 = iconv.decode(Buffer.from(path26), "utf-7-imap").toString();
86498
+ path27 = iconv.decode(Buffer.from(path27), "utf-7-imap").toString();
86097
86499
  } catch {
86098
86500
  }
86099
86501
  }
86100
- return path26;
86502
+ return path27;
86101
86503
  },
86102
86504
  /**
86103
86505
  * Normalizes a mailbox path by joining array segments with the namespace delimiter,
@@ -86108,17 +86510,17 @@ var require_tools2 = __commonJS({
86108
86510
  * @param {Boolean} [skipNamespace] - If true, skips prepending the namespace prefix
86109
86511
  * @returns {String} Normalized mailbox path
86110
86512
  */
86111
- normalizePath(connection, path26, skipNamespace) {
86112
- if (Array.isArray(path26)) {
86113
- path26 = path26.join(connection.namespace && connection.namespace.delimiter || "");
86513
+ normalizePath(connection, path27, skipNamespace) {
86514
+ if (Array.isArray(path27)) {
86515
+ path27 = path27.join(connection.namespace && connection.namespace.delimiter || "");
86114
86516
  }
86115
- if (path26.toUpperCase() === "INBOX") {
86517
+ if (path27.toUpperCase() === "INBOX") {
86116
86518
  return "INBOX";
86117
86519
  }
86118
- if (!skipNamespace && connection.namespace && connection.namespace.prefix && !path26.startsWith(connection.namespace.prefix)) {
86119
- path26 = connection.namespace.prefix + path26;
86520
+ if (!skipNamespace && connection.namespace && connection.namespace.prefix && !path27.startsWith(connection.namespace.prefix)) {
86521
+ path27 = connection.namespace.prefix + path27;
86120
86522
  }
86121
- return path26;
86523
+ return path27;
86122
86524
  },
86123
86525
  /**
86124
86526
  * Compares two mailbox paths for equality after normalization.
@@ -86449,14 +86851,14 @@ var require_tools2 = __commonJS({
86449
86851
  }
86450
86852
  }
86451
86853
  if (map.emailId || map.uid) {
86452
- let path26 = mailbox.path;
86453
- if (/[\u0080-\uffff]/.test(path26)) {
86854
+ let path27 = mailbox.path;
86855
+ if (/[\u0080-\uffff]/.test(path27)) {
86454
86856
  try {
86455
- path26 = iconv.encode(path26, "utf-7-imap").toString();
86857
+ path27 = iconv.encode(path27, "utf-7-imap").toString();
86456
86858
  } catch {
86457
86859
  }
86458
86860
  }
86459
- map.id = map.emailId || createHash2("md5").update([path26, mailbox.uidValidity?.toString() || "", map.uid.toString()].join(":")).digest("hex");
86861
+ map.id = map.emailId || createHash2("md5").update([path27, mailbox.uidValidity?.toString() || "", map.uid.toString()].join(":")).digest("hex");
86460
86862
  }
86461
86863
  if (map.flags) {
86462
86864
  let flagColor = tools.getFlagColor(map.flags);
@@ -86631,16 +87033,16 @@ var require_tools2 = __commonJS({
86631
87033
  * @returns {Object} Parsed body structure tree with part numbers, types, parameters, and child nodes
86632
87034
  */
86633
87035
  parseBodystructure(entry) {
86634
- let walk = (node, path26) => {
86635
- path26 = path26 || [];
87036
+ let walk = (node, path27) => {
87037
+ path27 = path27 || [];
86636
87038
  let curNode = {}, i = 0, part = 0;
86637
- if (path26.length) {
86638
- curNode.part = path26.join(".");
87039
+ if (path27.length) {
87040
+ curNode.part = path27.join(".");
86639
87041
  }
86640
87042
  if (Array.isArray(node[0])) {
86641
87043
  curNode.childNodes = [];
86642
87044
  while (Array.isArray(node[i])) {
86643
- curNode.childNodes.push(walk(node[i], path26.concat(++part)));
87045
+ curNode.childNodes.push(walk(node[i], path27.concat(++part)));
86644
87046
  i++;
86645
87047
  }
86646
87048
  curNode.type = "multipart/" + ((node[i++] || {}).value || "").toString().toLowerCase();
@@ -86683,7 +87085,7 @@ var require_tools2 = __commonJS({
86683
87085
  // the encapsulated message shares the part number with its wrapper.
86684
87086
  // Distinction is via suffixes: path.MIME = wrapper headers,
86685
87087
  // path.HEADER = encapsulated message headers.
86686
- walk(node[i], path26)
87088
+ walk(node[i], path27)
86687
87089
  ];
86688
87090
  }
86689
87091
  i++;
@@ -88645,14 +89047,14 @@ var require_select = __commonJS({
88645
89047
  // update into a silent no-op for the rest of the session.
88646
89048
  permanentflags: { key: "permanentFlags", parse: (value) => Array.isArray(value) && new Set(value) }
88647
89049
  });
88648
- module.exports = async (connection, path26, options) => {
89050
+ module.exports = async (connection, path27, options) => {
88649
89051
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
88650
89052
  return;
88651
89053
  }
88652
89054
  options = options || {};
88653
- path26 = normalizePath(connection, path26);
88654
- if (!connection.folders.has(path26)) {
88655
- let folders = await connection.run("LIST", "", path26);
89055
+ path27 = normalizePath(connection, path27);
89056
+ if (!connection.folders.has(path27)) {
89057
+ let folders = await connection.run("LIST", "", path27);
88656
89058
  if (!folders) {
88657
89059
  throw new Error("Failed to fetch folders");
88658
89060
  }
@@ -88660,10 +89062,10 @@ var require_select = __commonJS({
88660
89062
  connection.folders.set(folder.path, folder);
88661
89063
  });
88662
89064
  }
88663
- let folderListData = connection.folders.has(path26) ? connection.folders.get(path26) : false;
89065
+ let folderListData = connection.folders.has(path27) ? connection.folders.get(path27) : false;
88664
89066
  let response;
88665
89067
  try {
88666
- let map = { path: path26 };
89068
+ let map = { path: path27 };
88667
89069
  if (folderListData) {
88668
89070
  ["delimiter", "specialUse", "subscribed", "listed"].forEach((key) => {
88669
89071
  if (folderListData[key]) {
@@ -88682,7 +89084,7 @@ var require_select = __commonJS({
88682
89084
  ]);
88683
89085
  map.qresync = true;
88684
89086
  }
88685
- let encodedPath = encodePath(connection, path26);
89087
+ let encodedPath = encodePath(connection, path27);
88686
89088
  let selectCommand = {
88687
89089
  command: !options.readOnly ? "SELECT" : "EXAMINE",
88688
89090
  /* c8 ignore next */
@@ -88742,12 +89144,12 @@ var require_select = __commonJS({
88742
89144
  // since the client's last known state. Only received when QRESYNC was requested.
88743
89145
  // A dummy mailbox object is passed because the mailbox isn't officially open yet.
88744
89146
  VANISHED: async (untagged) => {
88745
- await connection.untaggedVanished(untagged, { path: path26, uidNext: false, uidValidity: false });
89147
+ await connection.untaggedVanished(untagged, { path: path27, uidNext: false, uidValidity: false });
88746
89148
  },
88747
89149
  // Untagged FETCH during SELECT/EXAMINE: only occurs with QRESYNC, delivering
88748
89150
  // updated flags for messages that changed since the client's last modseq.
88749
89151
  FETCH: async (untagged) => {
88750
- await connection.untaggedFetch(untagged, { path: path26, uidNext: false, uidValidity: false });
89152
+ await connection.untaggedFetch(untagged, { path: path27, uidNext: false, uidValidity: false });
88751
89153
  }
88752
89154
  }
88753
89155
  });
@@ -88761,13 +89163,13 @@ var require_select = __commonJS({
88761
89163
  }
88762
89164
  let currentMailbox = connection.mailbox;
88763
89165
  connection.mailbox = false;
88764
- if (currentMailbox && currentMailbox.path !== path26) {
89166
+ if (currentMailbox && currentMailbox.path !== path27) {
88765
89167
  connection.emit("mailboxClose", currentMailbox);
88766
89168
  }
88767
89169
  connection.mailbox = map;
88768
89170
  connection.currentSelectCommand = selectCommand;
88769
89171
  connection.state = connection.states.SELECTED;
88770
- if (!currentMailbox || currentMailbox.path !== path26) {
89172
+ if (!currentMailbox || currentMailbox.path !== path27) {
88771
89173
  connection.emit("mailboxOpen", connection.mailbox);
88772
89174
  }
88773
89175
  response.next();
@@ -88982,17 +89384,17 @@ var require_create = __commonJS({
88982
89384
  "node_modules/imapflow/lib/commands/create.js"(exports, module) {
88983
89385
  "use strict";
88984
89386
  var { encodePath, normalizePath, getStatusCode, enhanceCommandError } = require_tools2();
88985
- module.exports = async (connection, path26) => {
89387
+ module.exports = async (connection, path27) => {
88986
89388
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
88987
89389
  return;
88988
89390
  }
88989
- path26 = normalizePath(connection, path26);
89391
+ path27 = normalizePath(connection, path27);
88990
89392
  let response;
88991
89393
  try {
88992
89394
  let map = {
88993
- path: path26
89395
+ path: path27
88994
89396
  };
88995
- response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89397
+ response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
88996
89398
  let section = response.response.attributes && response.response.attributes[0] && response.response.attributes[0].section && response.response.attributes[0].section.length ? response.response.attributes[0].section : false;
88997
89399
  if (section) {
88998
89400
  let key;
@@ -89018,13 +89420,13 @@ var require_create = __commonJS({
89018
89420
  }
89019
89421
  map.created = true;
89020
89422
  response.next();
89021
- await connection.run("SUBSCRIBE", path26);
89423
+ await connection.run("SUBSCRIBE", path27);
89022
89424
  return map;
89023
89425
  } catch (err) {
89024
89426
  let errorCode = getStatusCode(err.response);
89025
89427
  if (errorCode === "ALREADYEXISTS") {
89026
89428
  return {
89027
- path: path26,
89429
+ path: path27,
89028
89430
  created: false
89029
89431
  };
89030
89432
  }
@@ -89041,20 +89443,20 @@ var require_delete = __commonJS({
89041
89443
  "node_modules/imapflow/lib/commands/delete.js"(exports, module) {
89042
89444
  "use strict";
89043
89445
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89044
- module.exports = async (connection, path26) => {
89446
+ module.exports = async (connection, path27) => {
89045
89447
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89046
89448
  return;
89047
89449
  }
89048
- path26 = normalizePath(connection, path26);
89049
- if (connection.state === connection.states.SELECTED && connection.mailbox.path === path26) {
89450
+ path27 = normalizePath(connection, path27);
89451
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
89050
89452
  await connection.run("CLOSE");
89051
89453
  }
89052
89454
  let response;
89053
89455
  try {
89054
89456
  let map = {
89055
- path: path26
89457
+ path: path27
89056
89458
  };
89057
- response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89459
+ response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89058
89460
  response.next();
89059
89461
  return map;
89060
89462
  } catch (err) {
@@ -89071,23 +89473,23 @@ var require_rename = __commonJS({
89071
89473
  "node_modules/imapflow/lib/commands/rename.js"(exports, module) {
89072
89474
  "use strict";
89073
89475
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89074
- module.exports = async (connection, path26, newPath) => {
89476
+ module.exports = async (connection, path27, newPath) => {
89075
89477
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89076
89478
  return;
89077
89479
  }
89078
- path26 = normalizePath(connection, path26);
89480
+ path27 = normalizePath(connection, path27);
89079
89481
  newPath = normalizePath(connection, newPath);
89080
- if (connection.state === connection.states.SELECTED && connection.mailbox.path === path26) {
89482
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
89081
89483
  await connection.run("CLOSE");
89082
89484
  }
89083
89485
  let response;
89084
89486
  try {
89085
89487
  let map = {
89086
- path: path26,
89488
+ path: path27,
89087
89489
  newPath
89088
89490
  };
89089
89491
  response = await connection.exec("RENAME", [
89090
- { type: "ATOM", value: encodePath(connection, path26) },
89492
+ { type: "ATOM", value: encodePath(connection, path27) },
89091
89493
  { type: "ATOM", value: encodePath(connection, newPath) }
89092
89494
  ]);
89093
89495
  response.next();
@@ -89134,14 +89536,14 @@ var require_subscribe = __commonJS({
89134
89536
  "node_modules/imapflow/lib/commands/subscribe.js"(exports, module) {
89135
89537
  "use strict";
89136
89538
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89137
- module.exports = async (connection, path26) => {
89539
+ module.exports = async (connection, path27) => {
89138
89540
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89139
89541
  return;
89140
89542
  }
89141
- path26 = normalizePath(connection, path26);
89543
+ path27 = normalizePath(connection, path27);
89142
89544
  let response;
89143
89545
  try {
89144
- response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89546
+ response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89145
89547
  response.next();
89146
89548
  return true;
89147
89549
  } catch (err) {
@@ -89158,14 +89560,14 @@ var require_unsubscribe = __commonJS({
89158
89560
  "node_modules/imapflow/lib/commands/unsubscribe.js"(exports, module) {
89159
89561
  "use strict";
89160
89562
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89161
- module.exports = async (connection, path26) => {
89563
+ module.exports = async (connection, path27) => {
89162
89564
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89163
89565
  return;
89164
89566
  }
89165
- path26 = normalizePath(connection, path26);
89567
+ path27 = normalizePath(connection, path27);
89166
89568
  let response;
89167
89569
  try {
89168
- response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89570
+ response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89169
89571
  response.next();
89170
89572
  return true;
89171
89573
  } catch (err) {
@@ -89971,11 +90373,11 @@ var require_status = __commonJS({
89971
90373
  var { encodePath, normalizePath, buildStatusQueryAttributes, isRev2Active } = require_tools2();
89972
90374
  var { parseStatusList } = require_status_fields();
89973
90375
  var MAILBOX_UPDATERS = {
89974
- messages: (value, connection, path26) => {
90376
+ messages: (value, connection, path27) => {
89975
90377
  let prevCount = connection.mailbox.exists;
89976
90378
  if (prevCount !== value) {
89977
90379
  connection.mailbox.exists = value;
89978
- connection.emit("exists", { path: path26, count: value, prevCount });
90380
+ connection.emit("exists", { path: path27, count: value, prevCount });
89979
90381
  }
89980
90382
  },
89981
90383
  uidNext: (value, connection) => {
@@ -89985,28 +90387,28 @@ var require_status = __commonJS({
89985
90387
  connection.mailbox.highestModseq = value;
89986
90388
  }
89987
90389
  };
89988
- module.exports = async (connection, path26, query) => {
89989
- if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path26) {
90390
+ module.exports = async (connection, path27, query) => {
90391
+ if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
89990
90392
  return false;
89991
90393
  }
89992
- path26 = normalizePath(connection, path26);
89993
- let encodedPath = encodePath(connection, path26);
90394
+ path27 = normalizePath(connection, path27);
90395
+ let encodedPath = encodePath(connection, path27);
89994
90396
  let attributes = [{ type: encodedPath.indexOf("&") >= 0 ? "STRING" : "ATOM", value: encodedPath }];
89995
90397
  let queryAttributes = buildStatusQueryAttributes(connection, query);
89996
90398
  let syntheticRecent = query && query.recent && isRev2Active(connection);
89997
90399
  if (!queryAttributes.length) {
89998
- return syntheticRecent ? { path: path26, recent: 0 } : false;
90400
+ return syntheticRecent ? { path: path27, recent: 0 } : false;
89999
90401
  }
90000
90402
  attributes.push(queryAttributes);
90001
90403
  let response;
90002
90404
  try {
90003
- let map = { path: path26 };
90405
+ let map = { path: path27 };
90004
90406
  response = await connection.exec("STATUS", attributes, {
90005
90407
  untagged: {
90006
90408
  // STATUS response: * STATUS <mailbox> (<key> <value> <key> <value> ...)
90007
90409
  // Parsed as alternating key-value pairs (i % 2 pattern).
90008
90410
  STATUS: async (untagged) => {
90009
- let updateCurrent = connection.state === connection.states.SELECTED && path26 === connection.mailbox.path;
90411
+ let updateCurrent = connection.state === connection.states.SELECTED && path27 === connection.mailbox.path;
90010
90412
  let list = untagged.attributes && Array.isArray(untagged.attributes[1]) ? untagged.attributes[1] : false;
90011
90413
  if (!list) {
90012
90414
  return;
@@ -90014,7 +90416,7 @@ var require_status = __commonJS({
90014
90416
  parseStatusList(list, (key, value) => {
90015
90417
  map[key] = value;
90016
90418
  if (updateCurrent && MAILBOX_UPDATERS[key]) {
90017
- MAILBOX_UPDATERS[key](value, connection, path26);
90419
+ MAILBOX_UPDATERS[key](value, connection, path27);
90018
90420
  }
90019
90421
  });
90020
90422
  }
@@ -90027,9 +90429,9 @@ var require_status = __commonJS({
90027
90429
  return map;
90028
90430
  } catch (err) {
90029
90431
  if (err.responseStatus === "NO") {
90030
- let folders = await connection.run("LIST", "", path26, { listOnly: true });
90432
+ let folders = await connection.run("LIST", "", path27, { listOnly: true });
90031
90433
  if (folders && !folders.length) {
90032
- let error2 = new Error(`Mailbox doesn't exist: ${path26}`);
90434
+ let error2 = new Error(`Mailbox doesn't exist: ${path27}`);
90033
90435
  error2.code = "NotFound";
90034
90436
  error2.response = err;
90035
90437
  throw error2;
@@ -90176,15 +90578,15 @@ var require_quota = __commonJS({
90176
90578
  "node_modules/imapflow/lib/commands/quota.js"(exports, module) {
90177
90579
  "use strict";
90178
90580
  var { encodePath, normalizePath, enhanceCommandError, parseUintValue, isUnsafeKey } = require_tools2();
90179
- module.exports = async (connection, path26) => {
90180
- if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path26) {
90581
+ module.exports = async (connection, path27) => {
90582
+ if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
90181
90583
  return;
90182
90584
  }
90183
90585
  if (!connection.capabilities.has("QUOTA")) {
90184
90586
  return false;
90185
90587
  }
90186
- path26 = normalizePath(connection, path26);
90187
- let map = { path: path26 };
90588
+ path27 = normalizePath(connection, path27);
90589
+ let map = { path: path27 };
90188
90590
  let processQuotaResponse = (untagged) => {
90189
90591
  let attributes = untagged.attributes && untagged.attributes[1];
90190
90592
  if (!attributes || !attributes.length) {
@@ -90224,7 +90626,7 @@ var require_quota = __commonJS({
90224
90626
  let quotaFound = false;
90225
90627
  let response;
90226
90628
  try {
90227
- response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection, path26) }], {
90629
+ response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection, path27) }], {
90228
90630
  untagged: {
90229
90631
  // QUOTAROOT response tells us which quota root applies to this mailbox.
90230
90632
  // A mailbox may have zero or one quota root.
@@ -90367,15 +90769,15 @@ var require_idle = __commonJS({
90367
90769
  }
90368
90770
  }
90369
90771
  async function pollOnce2(connection, session) {
90370
- let path26 = connection.mailbox && connection.mailbox.path;
90772
+ let path27 = connection.mailbox && connection.mailbox.path;
90371
90773
  switch (connection.missingIdleCommand) {
90372
90774
  case "SELECT":
90373
90775
  connection.log.debug({ src: "c", msg: `Running SELECT to detect changes in folder`, cid: connection.id });
90374
- await connection.runInternal("SELECT", path26, { readOnly: session.selectCommand.command === "EXAMINE" });
90776
+ await connection.runInternal("SELECT", path27, { readOnly: session.selectCommand.command === "EXAMINE" });
90375
90777
  break;
90376
90778
  case "STATUS": {
90377
90779
  connection.log.debug({ src: "c", msg: `Running STATUS to detect changes in folder`, cid: connection.id });
90378
- let status = await connection.runInternal("STATUS", path26, {
90780
+ let status = await connection.runInternal("STATUS", path27, {
90379
90781
  messages: true,
90380
90782
  uidNext: true,
90381
90783
  uidValidity: true,
@@ -92062,12 +92464,12 @@ var require_imap_flow = __commonJS({
92062
92464
  this.emit("flags", updateEvent);
92063
92465
  }
92064
92466
  }
92065
- async ensureSelectedMailbox(path26) {
92066
- if (!path26) {
92467
+ async ensureSelectedMailbox(path27) {
92468
+ if (!path27) {
92067
92469
  return false;
92068
92470
  }
92069
- if (!this.mailbox || !comparePaths(this, this.mailbox.path, path26)) {
92070
- return await this.mailboxOpen(path26);
92471
+ if (!this.mailbox || !comparePaths(this, this.mailbox.path, path27)) {
92472
+ return await this.mailboxOpen(path27);
92071
92473
  }
92072
92474
  return true;
92073
92475
  }
@@ -92482,9 +92884,9 @@ var require_imap_flow = __commonJS({
92482
92884
  * let quota = await client.getQuota();
92483
92885
  * console.log(quota.storage.used, quota.storage.limit)
92484
92886
  */
92485
- async getQuota(path26) {
92486
- path26 = path26 || "INBOX";
92487
- return await this.run("QUOTA", path26);
92887
+ async getQuota(path27) {
92888
+ path27 = path27 || "INBOX";
92889
+ return await this.run("QUOTA", path27);
92488
92890
  }
92489
92891
  /**
92490
92892
  * @typedef {Object} ListResponse
@@ -92594,8 +92996,8 @@ var require_imap_flow = __commonJS({
92594
92996
  * console.log(info.path);
92595
92997
  * // "INBOX.parent.child" // assumes "INBOX." as namespace prefix and "." as delimiter
92596
92998
  */
92597
- async mailboxCreate(path26) {
92598
- return await this.run("CREATE", path26);
92999
+ async mailboxCreate(path27) {
93000
+ return await this.run("CREATE", path27);
92599
93001
  }
92600
93002
  /**
92601
93003
  * @typedef {Object} MailboxRenameResponse
@@ -92616,8 +93018,8 @@ var require_imap_flow = __commonJS({
92616
93018
  * console.log(info.newPath);
92617
93019
  * // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
92618
93020
  */
92619
- async mailboxRename(path26, newPath) {
92620
- return await this.run("RENAME", path26, newPath);
93021
+ async mailboxRename(path27, newPath) {
93022
+ return await this.run("RENAME", path27, newPath);
92621
93023
  }
92622
93024
  /**
92623
93025
  * @typedef {Object} MailboxDeleteResponse
@@ -92636,8 +93038,8 @@ var require_imap_flow = __commonJS({
92636
93038
  * console.log(info.path);
92637
93039
  * // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
92638
93040
  */
92639
- async mailboxDelete(path26) {
92640
- return await this.run("DELETE", path26);
93041
+ async mailboxDelete(path27) {
93042
+ return await this.run("DELETE", path27);
92641
93043
  }
92642
93044
  /**
92643
93045
  * Subscribes to a mailbox
@@ -92648,8 +93050,8 @@ var require_imap_flow = __commonJS({
92648
93050
  * @example
92649
93051
  * await client.mailboxSubscribe('Important stuff ❗️');
92650
93052
  */
92651
- async mailboxSubscribe(path26) {
92652
- return await this.run("SUBSCRIBE", path26);
93053
+ async mailboxSubscribe(path27) {
93054
+ return await this.run("SUBSCRIBE", path27);
92653
93055
  }
92654
93056
  /**
92655
93057
  * Unsubscribes from a mailbox
@@ -92660,8 +93062,8 @@ var require_imap_flow = __commonJS({
92660
93062
  * @example
92661
93063
  * await client.mailboxUnsubscribe('Important stuff ❗️');
92662
93064
  */
92663
- async mailboxUnsubscribe(path26) {
92664
- return await this.run("UNSUBSCRIBE", path26);
93065
+ async mailboxUnsubscribe(path27) {
93066
+ return await this.run("UNSUBSCRIBE", path27);
92665
93067
  }
92666
93068
  /**
92667
93069
  * Opens a mailbox to access messages. You can perform message operations only against an opened mailbox.
@@ -92679,8 +93081,8 @@ var require_imap_flow = __commonJS({
92679
93081
  * console.log(mailbox.exists);
92680
93082
  * // 125
92681
93083
  */
92682
- async mailboxOpen(path26, options) {
92683
- return await this.run("SELECT", path26, options);
93084
+ async mailboxOpen(path27, options) {
93085
+ return await this.run("SELECT", path27, options);
92684
93086
  }
92685
93087
  /**
92686
93088
  * Closes a previously opened mailbox
@@ -92727,8 +93129,8 @@ var require_imap_flow = __commonJS({
92727
93129
  * console.log(status.unseen);
92728
93130
  * // 123
92729
93131
  */
92730
- async status(path26, query) {
92731
- return await this.run("STATUS", path26, query);
93132
+ async status(path27, query) {
93133
+ return await this.run("STATUS", path27, query);
92732
93134
  }
92733
93135
  /**
92734
93136
  * Starts listening for new or deleted messages from the currently opened mailbox. Only required if {@link ImapFlow#disableAutoIdle} is set to `true`
@@ -92982,8 +93384,8 @@ var require_imap_flow = __commonJS({
92982
93384
  * @example
92983
93385
  * await client.append('INBOX', rawMessageBuffer, ['\\Seen'], new Date(2000, 1, 1));
92984
93386
  */
92985
- async append(path26, content, flags, idate) {
92986
- return await this.run("APPEND", path26, content, flags, idate) || false;
93387
+ async append(path27, content, flags, idate) {
93388
+ return await this.run("APPEND", path27, content, flags, idate) || false;
92987
93389
  }
92988
93390
  /**
92989
93391
  * @typedef {Object} CopyResponseObject
@@ -93827,7 +94229,7 @@ var require_imap_flow = __commonJS({
93827
94229
  await new Promise((resolve2) => setImmediate(resolve2));
93828
94230
  }
93829
94231
  const lock = this.locks.shift();
93830
- const { resolve, reject, path: path26, options, lockId } = lock;
94232
+ const { resolve, reject, path: path27, options, lockId } = lock;
93831
94233
  if (lock.acquireTimer) {
93832
94234
  clearTimeout(lock.acquireTimer);
93833
94235
  lock.acquireTimer = null;
@@ -93843,7 +94245,7 @@ var require_imap_flow = __commonJS({
93843
94245
  this.log.warn({
93844
94246
  msg: "Mailbox lock held for a long time",
93845
94247
  lockId: lock.lockId,
93846
- path: path26,
94248
+ path: path27,
93847
94249
  heldFor: Date.now() - lock.heldAt,
93848
94250
  /* c8 ignore next */
93849
94251
  // the held-lock-warning diagnostic with a description set is a timing-dependent log detail
@@ -93879,52 +94281,52 @@ var require_imap_flow = __commonJS({
93879
94281
  }
93880
94282
  };
93881
94283
  if (!this.usable || !this.socket || this.socket.destroyed) {
93882
- this.log.trace({ msg: "Failed to acquire mailbox lock", path: path26, lockId, idling: this.idling });
94284
+ this.log.trace({ msg: "Failed to acquire mailbox lock", path: path27, lockId, idling: this.idling });
93883
94285
  let error2 = new Error("Connection not available");
93884
94286
  error2.code = "NoConnection";
93885
94287
  reject(error2);
93886
94288
  continue;
93887
94289
  }
93888
- if (this.mailbox && this.mailbox.path === path26 && !!this.mailbox.readOnly === !!options.readOnly) {
94290
+ if (this.mailbox && this.mailbox.path === path27 && !!this.mailbox.readOnly === !!options.readOnly) {
93889
94291
  this.log.trace({
93890
94292
  msg: "Mailbox lock acquired [existing]",
93891
- path: path26,
94293
+ path: path27,
93892
94294
  lockId,
93893
94295
  idling: this.idling,
93894
94296
  ...options.description && { description: options.description }
93895
94297
  });
93896
94298
  this.currentLock = lock;
93897
94299
  armHeldTimer();
93898
- resolve({ path: path26, release });
94300
+ resolve({ path: path27, release });
93899
94301
  break;
93900
94302
  }
93901
94303
  try {
93902
- await this.mailboxOpen(path26, options);
94304
+ await this.mailboxOpen(path27, options);
93903
94305
  this.log.trace({
93904
94306
  msg: "Mailbox lock acquired [selected]",
93905
- path: path26,
94307
+ path: path27,
93906
94308
  lockId,
93907
94309
  idling: this.idling,
93908
94310
  ...options.description && { description: options.description }
93909
94311
  });
93910
94312
  this.currentLock = lock;
93911
94313
  armHeldTimer();
93912
- resolve({ path: path26, release });
94314
+ resolve({ path: path27, release });
93913
94315
  break;
93914
94316
  } catch (err) {
93915
94317
  if (err.responseStatus === "NO") {
93916
94318
  try {
93917
- let folders = await this.run("LIST", "", path26, { listOnly: true });
94319
+ let folders = await this.run("LIST", "", path27, { listOnly: true });
93918
94320
  if (!folders || !folders.length) {
93919
94321
  err.mailboxMissing = true;
93920
94322
  }
93921
94323
  } catch (E) {
93922
- this.log.trace({ msg: "Failed to verify failed mailbox", path: path26, err: E });
94324
+ this.log.trace({ msg: "Failed to verify failed mailbox", path: path27, err: E });
93923
94325
  }
93924
94326
  }
93925
94327
  this.log.trace({
93926
94328
  msg: "Failed to acquire mailbox lock",
93927
- path: path26,
94329
+ path: path27,
93928
94330
  lockId,
93929
94331
  idling: this.idling,
93930
94332
  ...options.description && { description: options.description },
@@ -93963,13 +94365,13 @@ var require_imap_flow = __commonJS({
93963
94365
  * lock.release();
93964
94366
  * }
93965
94367
  */
93966
- getMailboxLock(path26, options) {
94368
+ getMailboxLock(path27, options) {
93967
94369
  options = options || {};
93968
- path26 = normalizePath(this, path26);
94370
+ path27 = normalizePath(this, path27);
93969
94371
  let lockId = ++this.lockCounter;
93970
94372
  this.log.trace({
93971
94373
  msg: "Requesting lock",
93972
- path: path26,
94374
+ path: path27,
93973
94375
  lockId,
93974
94376
  ...options.description && { description: options.description },
93975
94377
  activeLock: this.currentLock ? {
@@ -93978,7 +94380,7 @@ var require_imap_flow = __commonJS({
93978
94380
  } : null
93979
94381
  });
93980
94382
  let lockPromise = new Promise((resolve, reject) => {
93981
- let lockEntry = { resolve, reject, path: path26, options, lockId };
94383
+ let lockEntry = { resolve, reject, path: path27, options, lockId };
93982
94384
  this.locks.push(lockEntry);
93983
94385
  if (Number(options.acquireTimeout) > 0) {
93984
94386
  lockEntry.acquireTimer = setTimeout(() => {
@@ -94067,16 +94469,16 @@ var require_imap_flow = __commonJS({
94067
94469
  });
94068
94470
 
94069
94471
  // src/mail/mail-fetcher.ts
94070
- import fs23 from "node:fs/promises";
94071
- import path24 from "node:path";
94472
+ import fs24 from "node:fs/promises";
94473
+ import path25 from "node:path";
94072
94474
  async function saveAttachments(attachments, downloadDir) {
94073
94475
  if (attachments.length === 0) return [];
94074
- await fs23.mkdir(downloadDir, { recursive: true });
94476
+ await fs24.mkdir(downloadDir, { recursive: true });
94075
94477
  const saved = [];
94076
94478
  for (const a of attachments) {
94077
- const name = path24.basename(a.filename) || "attachment";
94078
- const savedPath = path24.join(downloadDir, name);
94079
- await fs23.writeFile(savedPath, a.content);
94479
+ const name = path25.basename(a.filename) || "attachment";
94480
+ const savedPath = path25.join(downloadDir, name);
94481
+ await fs24.writeFile(savedPath, a.content);
94080
94482
  saved.push({ filename: name, savedPath, size: a.content.length });
94081
94483
  }
94082
94484
  return saved;
@@ -94207,7 +94609,7 @@ var init_mail_fetcher = __esm({
94207
94609
 
94208
94610
  // src/tools/fetch-mail.ts
94209
94611
  import os17 from "node:os";
94210
- import path25 from "node:path";
94612
+ import path26 from "node:path";
94211
94613
  function registerFetchMailTool(server, deps = {}) {
94212
94614
  const makeFetcher = deps.fetcherFactory ?? ((creds) => new ImapflowMailFetcher(creds));
94213
94615
  server.registerTool(
@@ -94269,7 +94671,7 @@ var init_fetch_mail = __esm({
94269
94671
  init_mail_fetcher();
94270
94672
  init_auth_error();
94271
94673
  init_validate();
94272
- DEFAULT_DOWNLOAD_DIR = path25.join(os17.homedir(), ".cogent", "mail-downloads");
94674
+ DEFAULT_DOWNLOAD_DIR = path26.join(os17.homedir(), ".cogent", "mail-downloads");
94273
94675
  }
94274
94676
  });
94275
94677
 
@@ -94360,9 +94762,74 @@ var init_rotate_mail_creds = __esm({
94360
94762
 
94361
94763
  // src/index.ts
94362
94764
  var index_exports = {};
94765
+ function shutdown(reason) {
94766
+ if (shuttingDown) return;
94767
+ shuttingDown = true;
94768
+ try {
94769
+ logger.info(`Shutting down: ${reason}`);
94770
+ autoRelay.stop();
94771
+ withdrawBridge(process.cwd(), PROCESS_MARK);
94772
+ heartbeat.stop();
94773
+ if (cloudWsClient) {
94774
+ cloudWsClient.disconnect();
94775
+ }
94776
+ logger.close();
94777
+ } finally {
94778
+ process.exit(0);
94779
+ }
94780
+ }
94781
+ async function clientGone(reason) {
94782
+ if (draining || shuttingDown) return;
94783
+ draining = true;
94784
+ autoRelay.announceDraining();
94785
+ const busy = () => {
94786
+ const d = autoRelay.getDiagnostics();
94787
+ return { requests: stdoutDead ? [] : [...inFlightRequests.values()], wake: d.processing, queued: d.queueLength };
94788
+ };
94789
+ const b0 = busy();
94790
+ if (!b0.requests.length && !b0.wake && !b0.queued) return shutdown(reason);
94791
+ let capMs = drainCapMs(3e5);
94792
+ try {
94793
+ capMs = drainCapMs(getConfig().COGENT_TIMEOUT_MS);
94794
+ } catch {
94795
+ }
94796
+ logger.info(
94797
+ `Client gone (${reason}) \u2014 draining before exit (cap ${Math.round(capMs / 1e3)}s): ${b0.requests.length} MCP request(s) [${b0.requests.join(", ")}], wake running: ${b0.wake}, queued: ${b0.queued}`
94798
+ );
94799
+ cancelPresenceRetry();
94800
+ heartbeat.stop();
94801
+ cloudWsClient?.disconnect();
94802
+ const t0 = Date.now();
94803
+ let b = b0;
94804
+ while (Date.now() - t0 < capMs) {
94805
+ b = busy();
94806
+ if (!b.requests.length && !b.wake && !b.queued) break;
94807
+ await new Promise((r) => setTimeout(r, 50));
94808
+ }
94809
+ if (!stdoutDead) {
94810
+ await new Promise((r) => {
94811
+ const t = setTimeout(r, 1e3);
94812
+ try {
94813
+ process.stdout.write("", () => {
94814
+ clearTimeout(t);
94815
+ r();
94816
+ });
94817
+ } catch {
94818
+ clearTimeout(t);
94819
+ r();
94820
+ }
94821
+ });
94822
+ }
94823
+ const left = b.requests.length || b.wake || b.queued;
94824
+ const undeliverable = stdoutDead && inFlightRequests.size ? ` (${inFlightRequests.size} MCP response(s) undeliverable: stdout closed)` : "";
94825
+ shutdown(
94826
+ left ? `${reason}; drain cap reached after ${Date.now() - t0}ms \u2014 ABANDONED ${b.requests.length} MCP request(s) [${b.requests.join(", ")}], wake running: ${b.wake}, queued: ${b.queued}${undeliverable}` : `${reason}; drained in ${Date.now() - t0}ms (${b0.requests.length} MCP request(s), wake: ${b0.wake}, queued: ${b0.queued})${undeliverable}`
94827
+ );
94828
+ }
94363
94829
  async function main() {
94830
+ markBridgeProcess(process.cwd(), SERVER_VERSION);
94364
94831
  await runStartup();
94365
- const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
94832
+ const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, { instructions: SERVER_INSTRUCTIONS });
94366
94833
  registerRegisterPeerTool(server);
94367
94834
  registerDeregisterPeerTool(server);
94368
94835
  registerSendMessageTool(server);
@@ -94407,7 +94874,31 @@ async function main() {
94407
94874
  });
94408
94875
  }
94409
94876
  const transport = new StdioServerTransport();
94877
+ transport.onclose = () => void clientGone("MCP transport closed");
94410
94878
  await server.connect(transport);
94879
+ const sdkOnMessage = transport.onmessage;
94880
+ transport.onmessage = (msg) => {
94881
+ if ("method" in msg && "id" in msg) {
94882
+ const tool = msg.method === "tools/call" ? msg.params?.name : void 0;
94883
+ inFlightRequests.set(msg.id, typeof tool === "string" ? `tools/call ${tool}` : msg.method);
94884
+ } else if ("method" in msg && msg.method === "notifications/cancelled") {
94885
+ const id = msg.params?.requestId;
94886
+ if (typeof id === "string" || typeof id === "number") inFlightRequests.delete(id);
94887
+ }
94888
+ sdkOnMessage?.(msg);
94889
+ };
94890
+ const sdkSend = transport.send.bind(transport);
94891
+ transport.send = (msg) => {
94892
+ const settles = !("method" in msg) && "id" in msg ? msg.id : void 0;
94893
+ return sdkSend(msg).finally(() => {
94894
+ if (settles !== void 0) inFlightRequests.delete(settles);
94895
+ });
94896
+ };
94897
+ const stdinIsDevice = startedWithoutClient();
94898
+ if (!process.stdin.isTTY && !stdinIsDevice) {
94899
+ process.stdin.once("end", () => void clientGone("stdin EOF \u2014 the MCP client is gone"));
94900
+ process.stdin.once("close", () => void clientGone("stdin closed \u2014 the MCP client is gone"));
94901
+ }
94411
94902
  process.stderr.write(
94412
94903
  `${SERVER_NAME} v${SERVER_VERSION} running on stdio
94413
94904
  `
@@ -94432,14 +94923,17 @@ async function main() {
94432
94923
  "Server ready. Tools: cogent_register_peer, cogent_deregister_peer, cogent_send_message, cogent_list_peers, cogent_get_history, cogent_health_check, cogent_create_session, cogent_join_session"
94433
94924
  );
94434
94925
  }
94926
+ var shuttingDown, draining, stdoutDead, inFlightRequests;
94435
94927
  var init_index = __esm({
94436
94928
  "src/index.ts"() {
94437
94929
  "use strict";
94438
94930
  init_mcp();
94439
94931
  init_stdio2();
94440
94932
  init_constants();
94933
+ init_instructions();
94441
94934
  init_npm_update_check();
94442
94935
  init_startup();
94936
+ init_config();
94443
94937
  init_logger();
94444
94938
  init_register_peer();
94445
94939
  init_send_message();
@@ -94455,10 +94949,12 @@ var init_index = __esm({
94455
94949
  init_fetch_mail();
94456
94950
  init_rotate_mail_creds();
94457
94951
  init_heartbeat();
94952
+ init_wake_inflight();
94953
+ init_wake_ownership();
94458
94954
  process.on("uncaughtException", (err) => {
94459
94955
  if (err.code === "EPIPE") {
94460
- logger.close();
94461
- process.exit(0);
94956
+ stdoutDead = true;
94957
+ void clientGone("stdout EPIPE \u2014 the MCP client is gone");
94462
94958
  return;
94463
94959
  }
94464
94960
  logger.error(`Uncaught exception: ${err.message}`, { stack: err.stack });
@@ -94467,26 +94963,12 @@ var init_index = __esm({
94467
94963
  const msg = reason instanceof Error ? reason.message : String(reason);
94468
94964
  logger.error(`Unhandled rejection: ${msg}`);
94469
94965
  });
94470
- process.on("SIGTERM", () => {
94471
- logger.info("SIGTERM received, shutting down");
94472
- autoRelay.stop();
94473
- heartbeat.stop();
94474
- if (cloudWsClient) {
94475
- cloudWsClient.disconnect();
94476
- }
94477
- logger.close();
94478
- process.exit(0);
94479
- });
94480
- process.on("SIGINT", () => {
94481
- logger.info("SIGINT received, shutting down");
94482
- autoRelay.stop();
94483
- heartbeat.stop();
94484
- if (cloudWsClient) {
94485
- cloudWsClient.disconnect();
94486
- }
94487
- logger.close();
94488
- process.exit(0);
94489
- });
94966
+ shuttingDown = false;
94967
+ draining = false;
94968
+ stdoutDead = false;
94969
+ process.on("SIGTERM", () => shutdown("SIGTERM received"));
94970
+ process.on("SIGINT", () => shutdown("SIGINT received"));
94971
+ inFlightRequests = /* @__PURE__ */ new Map();
94490
94972
  main().catch((err) => {
94491
94973
  const msg = err instanceof Error ? err.message : String(err);
94492
94974
  logger.error(`Fatal startup error: ${msg}`);