@essentialai/cogent-plugin 3.25.6 → 3.25.8

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.8") {
26416
+ return "3.25.8";
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,7 +26831,9 @@ 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";
26836
+ BridgeErrorCode2["PEER_HELD_IN_FOLDER"] = "PEER_HELD_IN_FOLDER";
26807
26837
  return BridgeErrorCode2;
26808
26838
  })(BridgeErrorCode || {});
26809
26839
  BridgeError = class extends Error {
@@ -27857,7 +27887,7 @@ var init_http_backend = __esm({
27857
27887
  * in cloud mode we ignore it and use this.sessionId (the cloud session).
27858
27888
  */
27859
27889
  async registerPeer(peerId, _sessionId, cwd, label, clientVersion, mode, _channelSessionId, capabilities, workspaceId, threadId, peerSecret) {
27860
- const path26 = PATHS.peers.replace(":sessionId", this.sessionId);
27890
+ const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
27861
27891
  const body = {
27862
27892
  peerId,
27863
27893
  cwd,
@@ -27888,7 +27918,7 @@ var init_http_backend = __esm({
27888
27918
  if (peerSecret !== void 0 && await relaySupports(this.http, "peer-ownership")) {
27889
27919
  body.peerSecret = peerSecret;
27890
27920
  }
27891
- const peer = await this.http.post(path26, body);
27921
+ const peer = await this.http.post(path27, body);
27892
27922
  const issued = peer?.peerSecret;
27893
27923
  if (issued) {
27894
27924
  try {
@@ -27908,9 +27938,9 @@ var init_http_backend = __esm({
27908
27938
  * local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
27909
27939
  */
27910
27940
  async deregisterPeer(peerId, peerSecret) {
27911
- const path26 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27941
+ const path27 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27912
27942
  try {
27913
- const headers = await this.http.delete(path26, peerSecret ? { peerSecret } : {});
27943
+ const headers = await this.http.delete(path27, peerSecret ? { peerSecret } : {});
27914
27944
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
27915
27945
  return { removed: true, mailboxDeprovisioned };
27916
27946
  } catch (err) {
@@ -27934,8 +27964,8 @@ var init_http_backend = __esm({
27934
27964
  * GET /api/sessions/:sessionId/peers
27935
27965
  */
27936
27966
  async listPeers() {
27937
- const path26 = PATHS.peers.replace(":sessionId", this.sessionId);
27938
- const result = await this.http.get(path26);
27967
+ const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
27968
+ const result = await this.http.get(path27);
27939
27969
  return result.peers;
27940
27970
  }
27941
27971
  /**
@@ -27943,8 +27973,8 @@ var init_http_backend = __esm({
27943
27973
  * Calls the lightweight heartbeat endpoint on the cloud relay server.
27944
27974
  */
27945
27975
  async updateLastSeen(peerId) {
27946
- const path26 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27947
- await this.http.post(path26, { peerId });
27976
+ const path27 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27977
+ await this.http.post(path27, { peerId });
27948
27978
  }
27949
27979
  /**
27950
27980
  * Record a message in the cloud session.
@@ -27955,7 +27985,7 @@ var init_http_backend = __esm({
27955
27985
  * the input record to construct a full MessageRecord.
27956
27986
  */
27957
27987
  async recordMessage(record2) {
27958
- const path26 = PATHS.messages.replace(":sessionId", this.sessionId);
27988
+ const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
27959
27989
  const body = {
27960
27990
  fromPeerId: record2.fromPeerId,
27961
27991
  toPeerId: record2.toPeerId,
@@ -27981,7 +28011,7 @@ var init_http_backend = __esm({
27981
28011
  if (record2.replyExpected === false && await relaySupports(this.http, "terminal-messages")) {
27982
28012
  body.replyExpected = false;
27983
28013
  }
27984
- const resp = await this.http.post(path26, body);
28014
+ const resp = await this.http.post(path27, body);
27985
28015
  return {
27986
28016
  ...record2,
27987
28017
  id: resp.id,
@@ -27995,7 +28025,7 @@ var init_http_backend = __esm({
27995
28025
  * Supports optional peerId filter and limit (default 300).
27996
28026
  */
27997
28027
  async getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes) {
27998
- const path26 = PATHS.messages.replace(":sessionId", this.sessionId);
28028
+ const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
27999
28029
  const query = {};
28000
28030
  if (peerId) {
28001
28031
  query.peerId = peerId;
@@ -28010,7 +28040,7 @@ var init_http_backend = __esm({
28010
28040
  if (dedupInferredEchoes) {
28011
28041
  query.dedupInferredEchoes = "true";
28012
28042
  }
28013
- const result = await this.http.get(path26, query);
28043
+ const result = await this.http.get(path27, query);
28014
28044
  return result.messages;
28015
28045
  }
28016
28046
  /**
@@ -28021,12 +28051,12 @@ var init_http_backend = __esm({
28021
28051
  * so that get-history shows the actual response (not null).
28022
28052
  */
28023
28053
  async updateMessageResponse(messageId, response, durationMs, pending) {
28024
- const path26 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
28054
+ const path27 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
28025
28055
  const body = { response, durationMs };
28026
28056
  if (pending === true) {
28027
28057
  body.pending = true;
28028
28058
  }
28029
- await this.http.patch(path26, body);
28059
+ await this.http.patch(path27, body);
28030
28060
  }
28031
28061
  /**
28032
28062
  * Validate a session.
@@ -28200,8 +28230,8 @@ var init_http_client = __esm({
28200
28230
  * Perform an authenticated GET request.
28201
28231
  * Appends query parameters to the URL if provided.
28202
28232
  */
28203
- async get(path26, query) {
28204
- const url = new URL(path26, this.baseUrl);
28233
+ async get(path27, query) {
28234
+ const url = new URL(path27, this.baseUrl);
28205
28235
  if (query) {
28206
28236
  for (const [k, v] of Object.entries(query)) {
28207
28237
  url.searchParams.set(k, v);
@@ -28216,8 +28246,8 @@ var init_http_client = __esm({
28216
28246
  /**
28217
28247
  * Perform an authenticated POST request with a JSON body.
28218
28248
  */
28219
- async post(path26, body) {
28220
- const url = new URL(path26, this.baseUrl);
28249
+ async post(path27, body) {
28250
+ const url = new URL(path27, this.baseUrl);
28221
28251
  const resp = await this.fetchWithTimeout(url, {
28222
28252
  method: "POST",
28223
28253
  headers: this.headers(),
@@ -28235,8 +28265,8 @@ var init_http_client = __esm({
28235
28265
  * Perform an authenticated PATCH request with a JSON body.
28236
28266
  * Used to update existing resources (e.g., message response fields).
28237
28267
  */
28238
- async patch(path26, body) {
28239
- const url = new URL(path26, this.baseUrl);
28268
+ async patch(path27, body) {
28269
+ const url = new URL(path27, this.baseUrl);
28240
28270
  const resp = await this.fetchWithTimeout(url, {
28241
28271
  method: "PATCH",
28242
28272
  headers: this.headers(),
@@ -28261,8 +28291,8 @@ var init_http_client = __esm({
28261
28291
  * "Malformed JSON in request body" 400 from cogent-server <=3.1.2 when
28262
28292
  * any client (including third-party tools) DELETEd a peer without a body.
28263
28293
  */
28264
- async delete(path26, body) {
28265
- const url = new URL(path26, this.baseUrl);
28294
+ async delete(path27, body) {
28295
+ const url = new URL(path27, this.baseUrl);
28266
28296
  const headers = {
28267
28297
  "Authorization": `Bearer ${this.token}`
28268
28298
  };
@@ -32563,14 +32593,14 @@ var init_ws_client = __esm({
32563
32593
  this.restoreCursor();
32564
32594
  const poll = async () => {
32565
32595
  try {
32566
- const path26 = `/api/sessions/${this.opts.sessionId}/poll`;
32596
+ const path27 = `/api/sessions/${this.opts.sessionId}/poll`;
32567
32597
  const query = {
32568
32598
  peerId: this.opts.peerId
32569
32599
  };
32570
32600
  if (this.lastMessageId) {
32571
32601
  query.lastMessageId = this.lastMessageId;
32572
32602
  }
32573
- const result = await this.opts.http.get(path26, query);
32603
+ const result = await this.opts.http.get(path27, query);
32574
32604
  if (result.messages && result.messages.length > 0) {
32575
32605
  this.opts.onMessages(result.messages);
32576
32606
  this.advanceCursor(result.messages[result.messages.length - 1].id);
@@ -33487,6 +33517,10 @@ import crypto5 from "node:crypto";
33487
33517
  import fs15 from "node:fs";
33488
33518
  import os11 from "node:os";
33489
33519
  import path16 from "node:path";
33520
+ function drainCapMs(timeoutMs) {
33521
+ const t = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e5;
33522
+ return Math.min(INFLIGHT_TIMEOUT_FACTOR * t, INFLIGHT_MAX_MS);
33523
+ }
33490
33524
  function hashCwd3(cwd) {
33491
33525
  return crypto5.createHash("sha256").update(path16.resolve(cwd)).digest("hex").slice(0, 16);
33492
33526
  }
@@ -33813,12 +33847,36 @@ import crypto8 from "node:crypto";
33813
33847
  import fs18 from "node:fs";
33814
33848
  import os14 from "node:os";
33815
33849
  import path19 from "node:path";
33850
+ function agentSessionId(env = process.env) {
33851
+ if (env.COGENT_PLATFORM && env.COGENT_PLATFORM !== "cc") return void 0;
33852
+ const id = env.CLAUDE_CODE_SESSION_ID?.trim();
33853
+ return id && id.length <= 128 ? id : void 0;
33854
+ }
33855
+ function startedWithoutClient() {
33856
+ if (withoutClient === void 0) {
33857
+ try {
33858
+ withoutClient = fs18.fstatSync(0).isCharacterDevice();
33859
+ } catch {
33860
+ withoutClient = false;
33861
+ }
33862
+ }
33863
+ return withoutClient;
33864
+ }
33816
33865
  function hashCwd6(cwd) {
33817
33866
  return crypto8.createHash("sha256").update(path19.resolve(cwd)).digest("hex").slice(0, 16);
33818
33867
  }
33819
33868
  function bridgeDirFor(cwd, peerId) {
33820
33869
  return path19.join(os14.homedir(), ".cogent", "bridges", `${hashCwd6(cwd)}.${safe4(peerId)}`);
33821
33870
  }
33871
+ function isReservedPeerName(peerId) {
33872
+ return safe4(peerId).toLowerCase() === safe4(PROCESS_MARK).toLowerCase();
33873
+ }
33874
+ function registryText(value) {
33875
+ return String(value ?? "").replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64) || "unreadable";
33876
+ }
33877
+ function registryOwnerLabel(o) {
33878
+ return `pid ${registryText(o.pid)} (v${registryText(o.version)}, ${JSON.stringify(String(o.endpoint ?? "").slice(0, 200))})`;
33879
+ }
33822
33880
  function pidAlive(pid) {
33823
33881
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return false;
33824
33882
  if (pid === process.pid) return true;
@@ -33829,7 +33887,7 @@ function pidAlive(pid) {
33829
33887
  return err?.code === "EPERM";
33830
33888
  }
33831
33889
  }
33832
- function announceBridge(cwd, peerId, version2, endpoint) {
33890
+ function announceBridge(cwd, peerId, version2, endpoint, sessionId = agentSessionId()) {
33833
33891
  const dir = bridgeDirFor(cwd, peerId);
33834
33892
  try {
33835
33893
  fs18.mkdirSync(dir, { recursive: true });
@@ -33839,13 +33897,30 @@ function announceBridge(cwd, peerId, version2, endpoint) {
33839
33897
  version: version2,
33840
33898
  peerId,
33841
33899
  endpoint,
33842
- cwd: path19.resolve(cwd)
33900
+ cwd: path19.resolve(cwd),
33901
+ parentPid: process.ppid,
33902
+ ...sessionId ? { sessionId } : {},
33903
+ // 🔴 A headless bridge never had a client to lose (review r7 FIX2-2, SEC2-2): when its launching
33904
+ // shell exited, the changed parent read as "client gone" and any bridge that started took its name.
33905
+ ...startedWithoutClient() ? { noClient: true } : {}
33843
33906
  };
33844
33907
  fs18.writeFileSync(path19.join(dir, `${process.pid}.json`), JSON.stringify(entry));
33845
33908
  } catch (err) {
33846
33909
  logger.debug(`wake-ownership: could not announce this bridge (${err.message})`);
33847
33910
  }
33848
33911
  }
33912
+ function markBridgeDraining(cwd, peerId) {
33913
+ const file = path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`);
33914
+ try {
33915
+ const entry = JSON.parse(fs18.readFileSync(file, "utf-8"));
33916
+ fs18.writeFileSync(file, JSON.stringify({ ...entry, draining: true }));
33917
+ } catch {
33918
+ }
33919
+ }
33920
+ function markBridgeProcess(cwd, version2) {
33921
+ listLiveBridges(cwd, PROCESS_MARK);
33922
+ announceBridge(cwd, PROCESS_MARK, version2, "");
33923
+ }
33849
33924
  function withdrawBridge(cwd, peerId) {
33850
33925
  try {
33851
33926
  fs18.unlinkSync(path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`));
@@ -33882,6 +33957,16 @@ function listLiveBridges(cwd, peerId) {
33882
33957
  live.sort((a, b) => b.startedAt - a.startedAt || b.pid - a.pid);
33883
33958
  return live;
33884
33959
  }
33960
+ function listLiveBridgesInFolder(cwd) {
33961
+ const prefix = `${hashCwd6(cwd)}.`;
33962
+ let dirs;
33963
+ try {
33964
+ dirs = fs18.readdirSync(path19.join(os14.homedir(), ".cogent", "bridges"));
33965
+ } catch {
33966
+ return [];
33967
+ }
33968
+ return dirs.filter((d) => d.startsWith(prefix)).flatMap((d) => listLiveBridges(cwd, d.slice(prefix.length)));
33969
+ }
33885
33970
  function checkWakeOwnership(cwd, peerId) {
33886
33971
  let live;
33887
33972
  try {
@@ -33902,13 +33987,14 @@ function checkWakeOwnership(cwd, peerId) {
33902
33987
  }
33903
33988
  return { isOwner: true, liveCount: live.length + 1 };
33904
33989
  }
33905
- var PROCESS_STARTED_AT, safe4;
33990
+ var PROCESS_STARTED_AT, withoutClient, safe4, PROCESS_MARK;
33906
33991
  var init_wake_ownership = __esm({
33907
33992
  "src/services/wake-ownership.ts"() {
33908
33993
  "use strict";
33909
33994
  init_logger();
33910
33995
  PROCESS_STARTED_AT = Date.now() - Math.floor(process.uptime() * 1e3);
33911
33996
  safe4 = (s) => String(s).replace(/[^A-Za-z0-9._-]/g, "_");
33997
+ PROCESS_MARK = ".process";
33912
33998
  }
33913
33999
  });
33914
34000
 
@@ -33927,6 +34013,39 @@ function versionFromArgv(argv) {
33927
34013
  const m = argv.match(/\/cogent\/(\d+\.\d+\.\d+)\//);
33928
34014
  return m ? m[1] : null;
33929
34015
  }
34016
+ function versionAtLeast(a, b) {
34017
+ const pa = a.split(/[-+]/)[0].split(".").map(Number);
34018
+ const pb = b.split(/[-+]/)[0].split(".").map(Number);
34019
+ for (let i = 0; i < 3; i++) {
34020
+ const x = pa[i] ?? 0;
34021
+ const y = pb[i] ?? 0;
34022
+ if (x !== y) return x > y;
34023
+ }
34024
+ return true;
34025
+ }
34026
+ function bridgeVersion(argv, readFile = (p) => fs19.readFileSync(p, "utf-8")) {
34027
+ const fromPath = versionFromArgv(argv);
34028
+ if (fromPath) return fromPath;
34029
+ const candidates = [];
34030
+ const pkg = argv.match(/(\S*\/@essentialai\/cogent-bridge(?:-bundled)?)\/dist\/(?:cli|index)\.js(?:\s|$)/);
34031
+ if (pkg) candidates.push(path20.join(pkg[1], "package.json"));
34032
+ const bin = argv.match(/(\S*\/node_modules)\/\.bin\/cogent-bridge(?:\s|$)/);
34033
+ if (bin) {
34034
+ for (const name of ["cogent-bridge", "cogent-bridge-bundled"]) {
34035
+ candidates.push(path20.join(bin[1], "@essentialai", name, "package.json"));
34036
+ }
34037
+ }
34038
+ for (const file of candidates) {
34039
+ try {
34040
+ const pj = JSON.parse(readFile(file));
34041
+ if (typeof pj.name === "string" && pj.name.startsWith("@essentialai/cogent-bridge") && typeof pj.version === "string" && /^\d+\.\d+\.\d+/.test(pj.version)) {
34042
+ return pj.version;
34043
+ }
34044
+ } catch {
34045
+ }
34046
+ }
34047
+ return null;
34048
+ }
33930
34049
  function listProcesses() {
33931
34050
  let out;
33932
34051
  try {
@@ -33988,25 +34107,13 @@ function ancestorsOf(pid, procs) {
33988
34107
  }
33989
34108
  return seen;
33990
34109
  }
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
34110
  function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
34111
+ const versionOf = opts.versionOf ?? ((argv) => bridgeVersion(argv));
34006
34112
  const selfPid = opts.selfPid ?? process.pid;
34007
- const selfStartedAt = opts.selfStartedAt ?? Date.now() - Math.floor(process.uptime() * 1e3);
34113
+ const selfStartedAt = opts.selfStartedAt ?? procs.find((p) => p.pid === selfPid)?.startedAt ?? NaN;
34114
+ if (!Number.isFinite(selfStartedAt)) return [];
34008
34115
  const cwdOf = opts.cwdOf ?? processCwd;
34009
- const announced = opts.announced ?? announcedPidsFor(cwd);
34116
+ const announced = opts.announced ?? new Set(listLiveBridgesInFolder(cwd).map((e) => e.pid));
34010
34117
  const target = canonicalPath(cwd);
34011
34118
  const ancestors = ancestorsOf(selfPid, procs);
34012
34119
  const out = [];
@@ -34018,10 +34125,11 @@ function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
34018
34125
  if (!Number.isFinite(p.startedAt) || p.startedAt >= selfStartedAt) continue;
34019
34126
  const theirCwd = cwdOf(p.pid);
34020
34127
  if (!theirCwd || canonicalPath(theirCwd) !== target) continue;
34021
- const ver = versionFromArgv(p.argv);
34128
+ const ver = versionOf(p.argv);
34129
+ if (!ver || versionAtLeast(ver, SELF_SUPERSESSION_VERSION)) continue;
34022
34130
  out.push({
34023
34131
  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`
34132
+ 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
34133
  });
34026
34134
  }
34027
34135
  return out;
@@ -34055,21 +34163,25 @@ function reapStaleBridges(cwd, opts = {}) {
34055
34163
  }
34056
34164
  if (reaped.length) {
34057
34165
  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.`
34166
+ `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
34167
  );
34060
34168
  }
34061
34169
  return reaped;
34062
34170
  }
34171
+ var SELF_SUPERSESSION_VERSION;
34063
34172
  var init_stale_bridge_reaper = __esm({
34064
34173
  "src/services/stale-bridge-reaper.ts"() {
34065
34174
  "use strict";
34066
34175
  init_logger();
34067
34176
  init_wake_ownership();
34177
+ SELF_SUPERSESSION_VERSION = "3.23.4";
34068
34178
  }
34069
34179
  });
34070
34180
 
34071
34181
  // src/services/auto-relay.ts
34072
34182
  import { randomUUID as randomUUID2 } from "node:crypto";
34183
+ import fs20 from "node:fs";
34184
+ import path21 from "node:path";
34073
34185
  function buildStatusNotice(status, peerId, traceId) {
34074
34186
  const tail = traceId ? ` (trace ${traceId})` : "";
34075
34187
  if (status === RELAY_STATUS.QUEUED) {
@@ -34196,6 +34308,21 @@ function truncate(s) {
34196
34308
  const flat = s.replace(/\s+/g, " ").trim();
34197
34309
  return flat.length > DIAGNOSTIC_MAX ? `${flat.slice(0, DIAGNOSTIC_MAX - 1)}\u2026` : flat;
34198
34310
  }
34311
+ function isInsideOwnFolder(dir) {
34312
+ try {
34313
+ const real = fs20.realpathSync.native(dir);
34314
+ return real === process.cwd() || real.startsWith(process.cwd() + path21.sep);
34315
+ } catch {
34316
+ return false;
34317
+ }
34318
+ }
34319
+ function isOwnFolder(dir) {
34320
+ try {
34321
+ return fs20.realpathSync.native(dir) === fs20.realpathSync.native(process.cwd());
34322
+ } catch {
34323
+ return false;
34324
+ }
34325
+ }
34199
34326
  var RELAY_STATUS, STATUS_MARKER_RE, DIAGNOSTIC_MAX, EARLY_ACK_TTL_MS, EARLY_ACK_MAX, AutoRelayService, autoRelay;
34200
34327
  var init_auto_relay = __esm({
34201
34328
  "src/services/auto-relay.ts"() {
@@ -34236,6 +34363,8 @@ var init_auto_relay = __esm({
34236
34363
  */
34237
34364
  pinnedSessionId = null;
34238
34365
  localCwd = null;
34366
+ /** Every folder this process announced the current peer name under — what a drain or a stop must cover. */
34367
+ announcedCwds = /* @__PURE__ */ new Set();
34239
34368
  /**
34240
34369
  * Peer participation mode (3.2.0, Phase 17 OBS-03).
34241
34370
  * - "agent" (default): full auto-relay — inbound directed messages run
@@ -34299,6 +34428,7 @@ var init_auto_relay = __esm({
34299
34428
  * successful registration so we know which session to inject into.
34300
34429
  */
34301
34430
  setLocalPeer(peerId, sessionId, cwd, mode, label, pinnedSessionId) {
34431
+ if (this.localPeerId && this.localPeerId !== peerId) this.withdrawAnnouncement();
34302
34432
  this.localPeerId = peerId;
34303
34433
  this.localSessionId = sessionId;
34304
34434
  this.pinnedSessionId = pinnedSessionId ?? sessionId;
@@ -34308,7 +34438,12 @@ var init_auto_relay = __esm({
34308
34438
  logger.info(
34309
34439
  `Auto-relay configured for peer ${peerId} (session: ${sessionId}, pinned: ${this.pinnedSessionId}, mode: ${this.localMode}, label: ${this.localLabel})`
34310
34440
  );
34311
- announceBridge(cwd, peerId, CLIENT_VERSION, getConfig().COGENT_ENDPOINT ?? "local");
34441
+ const dirs = /* @__PURE__ */ new Set([path21.resolve(cwd)]);
34442
+ if (isInsideOwnFolder(path21.resolve(cwd))) dirs.add(process.cwd());
34443
+ for (const dir of dirs) {
34444
+ this.announcedCwds.add(dir);
34445
+ announceBridge(dir, peerId, CLIENT_VERSION, getConfig().COGENT_ENDPOINT ?? "local");
34446
+ }
34312
34447
  this.supersededNotified.clear();
34313
34448
  if (!this.reapedStaleBridges) {
34314
34449
  this.reapedStaleBridges = true;
@@ -34683,10 +34818,13 @@ var init_auto_relay = __esm({
34683
34818
  }
34684
34819
  }
34685
34820
  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;
34821
+ const dirs = /* @__PURE__ */ new Set([path21.resolve(this.localCwd), ...isOwnFolder(this.localCwd) ? [process.cwd()] : []]);
34822
+ for (const dir of dirs) {
34823
+ const own = checkWakeOwnership(dir, this.localPeerId);
34824
+ if (!own.isOwner) {
34825
+ await this._reportSuperseded(msg, own.owner);
34826
+ return;
34827
+ }
34690
34828
  }
34691
34829
  }
34692
34830
  if (this.localPeerId && !this.awarenessOnly.has(msg.id)) {
@@ -34731,7 +34869,7 @@ var init_auto_relay = __esm({
34731
34869
  * notice generator.
34732
34870
  */
34733
34871
  async _reportSuperseded(msg, owner) {
34734
- const who = owner ? `pid ${owner.pid} (v${owner.version}, ${owner.endpoint})` : "a newer bridge";
34872
+ const who = owner ? registryOwnerLabel(owner) : "a newer bridge";
34735
34873
  logger.warn(
34736
34874
  `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
34875
  );
@@ -35162,6 +35300,24 @@ var init_auto_relay = __esm({
35162
35300
  activeDeliveryAckWaiters: Array.from(this.deliveryAckWaiters.keys())
35163
35301
  };
35164
35302
  }
35303
+ /**
35304
+ * Stop claiming this peer's name for this checkout, WITHOUT stopping work already in flight.
35305
+ * Called the moment the MCP client is gone: a draining bridge serves no agent, and while it
35306
+ * counted as the peer's holder, the restarted agent's new bridge stood by behind it (review r2
35307
+ * NEW-1). The announcement is MARKED, not removed — see markBridgeDraining (R3-2). Idempotent.
35308
+ * 🔴 EVERY announcement, not only the last registered cwd's (review r7 SEC2-1, ABC2-2, FIX2-5):
35309
+ * after a register with another spelling of the folder, the one for the bridge's own folder stayed
35310
+ * unmarked, and the restarted agent waited out the drain or stood by for good.
35311
+ */
35312
+ announceDraining() {
35313
+ if (!this.localPeerId) return;
35314
+ for (const dir of this.announcedCwds) markBridgeDraining(dir, this.localPeerId);
35315
+ }
35316
+ /** Remove this bridge's ownership announcements (graceful shutdown, a rename). Idempotent. */
35317
+ withdrawAnnouncement() {
35318
+ if (this.localPeerId) for (const dir of this.announcedCwds) withdrawBridge(dir, this.localPeerId);
35319
+ this.announcedCwds.clear();
35320
+ }
35165
35321
  /**
35166
35322
  * Stop the auto-relay service: clear queue and reset state.
35167
35323
  */
@@ -35181,7 +35337,7 @@ var init_auto_relay = __esm({
35181
35337
  }
35182
35338
  this.deliveryAckWaiters.clear();
35183
35339
  this.recentAcks.clear();
35184
- if (this.localCwd && this.localPeerId) withdrawBridge(this.localCwd, this.localPeerId);
35340
+ this.withdrawAnnouncement();
35185
35341
  this.queue = [];
35186
35342
  this.awarenessOnly.clear();
35187
35343
  this.supersededNotified.clear();
@@ -35201,6 +35357,76 @@ var init_auto_relay = __esm({
35201
35357
  });
35202
35358
 
35203
35359
  // src/services/peer-presence.ts
35360
+ function holderRelation(holderSession, ownSession) {
35361
+ if (holderSession && ownSession) return holderSession === ownSession ? "same-session" : "other-session";
35362
+ return holderSession || ownSession ? "unknown" : "no-session";
35363
+ }
35364
+ function holderClientGone(holder, procs) {
35365
+ if (holder.noClient === true) return false;
35366
+ const byPid = new Map(procs.map((p) => [p.pid, p]));
35367
+ let cur = byPid.get(holder.pid);
35368
+ if (!cur) return false;
35369
+ if (typeof holder.parentPid === "number") return cur.ppid !== holder.parentPid;
35370
+ for (let hops = 0; hops < 3; hops++) {
35371
+ if (cur.ppid === 1) return true;
35372
+ const parent = byPid.get(cur.ppid);
35373
+ if (!parent) return false;
35374
+ const exe = parent.argv.trim().split(/\s+/)[0] ?? "";
35375
+ if (ORPHAN_PARENT_RE.test(exe.split("/").pop() ?? "")) return true;
35376
+ if (!NPX_WRAPPER_RE.test(parent.argv.trim())) return false;
35377
+ cur = parent;
35378
+ }
35379
+ return false;
35380
+ }
35381
+ function insideCodexWakeTurn(selfPid, procs) {
35382
+ const byPid = new Map(procs.map((p) => [p.pid, p]));
35383
+ const seen = /* @__PURE__ */ new Set();
35384
+ let cur = byPid.get(selfPid)?.ppid;
35385
+ while (cur && cur > 1 && !seen.has(cur)) {
35386
+ seen.add(cur);
35387
+ const p = byPid.get(cur);
35388
+ if (!p) break;
35389
+ if (/(^|[\s/])codex(\.js)?\s+exec\s+resume(\s|$)/.test(p.argv)) return true;
35390
+ cur = p.ppid;
35391
+ }
35392
+ return false;
35393
+ }
35394
+ function otherBridgesInFolder(entries, self, listProcs) {
35395
+ let procs = null;
35396
+ return entries.filter(
35397
+ (e) => e.peerId !== PROCESS_MARK && e.pid !== self.pid && !e.draining && holderRelation(e.sessionId, self.sessionId) !== "same-session" && !holderClientGone(e, procs ??= listProcs())
35398
+ );
35399
+ }
35400
+ function heldInFolder(others, peerId, ownSession) {
35401
+ return others.find((o) => o.peerId === peerId && !mayBeOwnPreSessionBridge(o, ownSession));
35402
+ }
35403
+ function mayBeOwnPreSessionBridge(holder, ownSession) {
35404
+ if (holder.sessionId || !ownSession) return false;
35405
+ const v = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(holder.version ?? ""));
35406
+ if (!v) return false;
35407
+ const [maj, min, pat] = [Number(v[1]), Number(v[2]), Number(v[3])];
35408
+ return maj < 3 || maj === 3 && (min < 25 || min === 25 && pat < 7);
35409
+ }
35410
+ function heldNameAdvice(peerId) {
35411
+ return `If this agent was just restarted, its previous connection closes within ${HOLDER_LINGER_SECONDS} seconds: wait ${HOLDER_LINGER_SECONDS}+ seconds, then run /cogent:register again with the SAME peer name '${peerId}'. If '${peerId}' is still held after that, another live connection is using it \u2014 another agent, or an old window of this one still open. Do not take the name and do not rename: ask the user`;
35412
+ }
35413
+ function anotherAgentSessionAmong(others, ownSession) {
35414
+ return others.some((o) => holderRelation(o.sessionId, ownSession) === "other-session");
35415
+ }
35416
+ function otherBridgeNotice(others, peerId, verdict, ownSession) {
35417
+ const lines = others.map((o) => {
35418
+ const version2 = registryText(o.version);
35419
+ 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)`;
35420
+ if (o.peerId !== peerId) {
35421
+ 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.`;
35422
+ }
35423
+ if (verdict.isOwner) {
35424
+ return `${who} was registered as '${peerId}'. It is now superseded: this bridge holds '${peerId}' and that bridge has stopped answering for it.`;
35425
+ }
35426
+ 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.`;
35427
+ });
35428
+ 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.` : "");
35429
+ }
35204
35430
  function autoPresenceEnabled(env = process.env) {
35205
35431
  const v = env.COGENT_AUTO_PRESENCE;
35206
35432
  if (v === void 0 || v === "") return true;
@@ -35230,11 +35456,42 @@ async function restorePresence(deps) {
35230
35456
  };
35231
35457
  }
35232
35458
  const peerId = creds.peerId;
35233
- if (deps.peerAlreadyServed(peerId)) {
35459
+ if (deps.startedByWakeTurn?.()) {
35460
+ return {
35461
+ state: "deferred",
35462
+ restored: false,
35463
+ 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`
35464
+ };
35465
+ }
35466
+ const served = deps.peerAlreadyServed(peerId);
35467
+ if (served) {
35468
+ const session = deps.agentSessionId?.();
35469
+ const holder = holderRelation(served.sessionId, session);
35470
+ const servedBy = {
35471
+ ...served,
35472
+ ...served.version === void 0 ? {} : { version: registryText(served.version) },
35473
+ ...served.sessionId === void 0 ? {} : { sessionId: registryText(served.sessionId) }
35474
+ };
35475
+ const started = Number.isFinite(servedBy.startedAt) ? new Date(servedBy.startedAt).toISOString() : "unknown";
35476
+ const recheck = holder === "same-session";
35477
+ const every = deps.recheckSeconds ? ` (re-checked every ${deps.recheckSeconds}s)` : "";
35478
+ const take = heldNameAdvice(peerId);
35479
+ const why = {
35480
+ "same-session": `That bridge serves this same agent session (${session})`,
35481
+ "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}`,
35482
+ "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}`,
35483
+ 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}`
35484
+ };
35234
35485
  return {
35235
- state: "online",
35486
+ state: "standby",
35236
35487
  restored: false,
35237
- detail: `peer '${peerId}' is already served by a live bridge for this working directory`
35488
+ peerId,
35489
+ servedBy,
35490
+ holder,
35491
+ recheck,
35492
+ // A final standby is evaluated once, so it says "when this bridge started": the health
35493
+ // check keeps showing this text after that bridge is gone.
35494
+ 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
35495
  };
35239
35496
  }
35240
35497
  if (!autoPresenceEnabled(deps.env ?? process.env)) {
@@ -35294,15 +35551,23 @@ function logPresence(outcome) {
35294
35551
  );
35295
35552
  } else if (outcome.state === "offline") {
35296
35553
  logger.warn(`Presence: OFFLINE \u2014 ${outcome.detail}.`);
35554
+ } else if (outcome.state === "standby" && outcome.holder === "other-session") {
35555
+ logger.warn(`Presence: STANDBY \u2014 ${outcome.detail}.`);
35556
+ } else if (outcome.state === "standby" || outcome.state === "deferred") {
35557
+ logger.info(`Presence: ${outcome.state.toUpperCase()} \u2014 ${outcome.detail}.`);
35297
35558
  } else {
35298
35559
  logger.debug(`Presence: ${outcome.state} \u2014 ${outcome.detail}.`);
35299
35560
  }
35300
35561
  }
35301
- var lastPresence;
35562
+ var ORPHAN_PARENT_RE, NPX_WRAPPER_RE, HOLDER_LINGER_SECONDS, lastPresence;
35302
35563
  var init_peer_presence = __esm({
35303
35564
  "src/services/peer-presence.ts"() {
35304
35565
  "use strict";
35305
35566
  init_logger();
35567
+ init_wake_ownership();
35568
+ ORPHAN_PARENT_RE = /^(init|launchd|systemd)$/;
35569
+ NPX_WRAPPER_RE = /^(?:\S*\/)?(?:sh|bash|dash) -c cogent-bridge\b|^npm exec @essentialai\/cogent-bridge/;
35570
+ HOLDER_LINGER_SECONDS = 60;
35306
35571
  lastPresence = null;
35307
35572
  }
35308
35573
  });
@@ -35550,8 +35815,8 @@ __export(startup_exports, {
35550
35815
  triggerReRegistration: () => triggerReRegistration
35551
35816
  });
35552
35817
  import os15 from "node:os";
35553
- import path21 from "node:path";
35554
- import fs20 from "node:fs/promises";
35818
+ import path22 from "node:path";
35819
+ import fs21 from "node:fs/promises";
35555
35820
  import readline2 from "node:readline";
35556
35821
  import { execFile as execFile5 } from "node:child_process";
35557
35822
  import { promisify as promisify4 } from "node:util";
@@ -35569,7 +35834,7 @@ function bindInboxNotifier() {
35569
35834
  }
35570
35835
  async function loadPersistedConfig() {
35571
35836
  try {
35572
- const raw = await fs20.readFile(PERSIST_PATH, "utf-8");
35837
+ const raw = await fs21.readFile(PERSIST_PATH, "utf-8");
35573
35838
  return JSON.parse(raw);
35574
35839
  } catch {
35575
35840
  return {};
@@ -35577,7 +35842,7 @@ async function loadPersistedConfig() {
35577
35842
  }
35578
35843
  async function savePersistedConfig(config2) {
35579
35844
  try {
35580
- await fs20.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
35845
+ await fs21.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
35581
35846
  } catch (err) {
35582
35847
  const msg = err instanceof Error ? err.message : String(err);
35583
35848
  logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
@@ -35612,11 +35877,11 @@ First run detected. Where should cogent-bridge store its data?
35612
35877
  });
35613
35878
  }
35614
35879
  async function validateStateDir(statePath) {
35615
- await fs20.mkdir(statePath, { recursive: true });
35616
- const testFile = path21.join(statePath, ".write-test");
35880
+ await fs21.mkdir(statePath, { recursive: true });
35881
+ const testFile = path22.join(statePath, ".write-test");
35617
35882
  try {
35618
- await fs20.writeFile(testFile, "test", "utf-8");
35619
- await fs20.unlink(testFile);
35883
+ await fs21.writeFile(testFile, "test", "utf-8");
35884
+ await fs21.unlink(testFile);
35620
35885
  } catch {
35621
35886
  throw new BridgeError(
35622
35887
  "STARTUP_FAILED" /* STARTUP_FAILED */,
@@ -35700,9 +35965,15 @@ function cancelPresenceRetry() {
35700
35965
  if (presenceRetry) clearTimeout(presenceRetry);
35701
35966
  presenceRetry = null;
35702
35967
  }
35703
- function presenceRetryDelayMs(attempt) {
35968
+ function presenceRetryBaseMs() {
35704
35969
  const base = Number(process.env.COGENT_PRESENCE_RETRY_MS);
35705
- return Math.min((Number.isFinite(base) && base > 0 ? base : 3e4) * 2 ** attempt, 3e5);
35970
+ return Number.isFinite(base) && base > 0 ? base : 3e4;
35971
+ }
35972
+ function presenceRetryDelayMs(attempt) {
35973
+ return Math.min(presenceRetryBaseMs() * 2 ** attempt, 3e5);
35974
+ }
35975
+ function standbyRecheckMs() {
35976
+ return Math.max(250, Math.min(presenceRetryBaseMs(), 15e3));
35706
35977
  }
35707
35978
  async function restorePeerPresence(attempt = 0) {
35708
35979
  if (!presenceSupersedeBound) {
@@ -35716,6 +35987,8 @@ async function restorePeerPresence(attempt = 0) {
35716
35987
  }
35717
35988
  const generation = getCloudAttemptGeneration();
35718
35989
  const stillCurrent = () => getCloudAttemptGeneration() === generation;
35990
+ let procs = null;
35991
+ const ps = () => procs ??= listProcesses();
35719
35992
  const outcome = await restorePresence({
35720
35993
  // The endpoint being a relay URL is what makes presence meaningful. We deliberately do
35721
35994
  // NOT gate on the active backend being the cloud one: at startup it is still the
@@ -35728,13 +36001,27 @@ async function restorePeerPresence(attempt = 0) {
35728
36001
  alreadyRegisteredInProcess: () => autoRelay.getDiagnostics().registered,
35729
36002
  peerAlreadyServed: (peerId) => {
35730
36003
  try {
35731
- return listLiveBridges(process.cwd(), peerId).some((b) => b.pid !== process.pid);
36004
+ const holders = listLiveBridges(process.cwd(), peerId).filter((b) => b.pid !== process.pid && !b.draining);
36005
+ const other = holders.find((b) => {
36006
+ if (!holderClientGone(b, ps())) return true;
36007
+ if (!ignoredHolders.has(b.pid)) {
36008
+ ignoredHolders.add(b.pid);
36009
+ logger.info(
36010
+ `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`
36011
+ );
36012
+ }
36013
+ return false;
36014
+ });
36015
+ return other ? { pid: other.pid, version: other.version, startedAt: other.startedAt, sessionId: other.sessionId } : null;
35732
36016
  } catch {
35733
- return false;
36017
+ return null;
35734
36018
  }
35735
36019
  },
36020
+ agentSessionId: () => agentSessionId(),
36021
+ startedByWakeTurn: () => insideCodexWakeTurn(process.pid, ps()),
35736
36022
  loadCredentials: () => loadCredentials(),
35737
36023
  cwd: () => process.cwd(),
36024
+ recheckSeconds: Math.round(standbyRecheckMs() / 1e3),
35738
36025
  goOnline: async ({ peerId, endpoint, sessionId, token, cwd, label, peerSecret }) => {
35739
36026
  if (!stillCurrent()) throw new Error(PRESENCE_SUPERSEDED);
35740
36027
  await reinitCloudBackend(endpoint, sessionId, token);
@@ -35754,18 +36041,25 @@ async function restorePeerPresence(attempt = 0) {
35754
36041
  logPresence(superseded);
35755
36042
  return superseded;
35756
36043
  }
36044
+ const prev = getPresence();
35757
36045
  setPresence(outcome);
35758
- logPresence(outcome);
35759
- if (outcome.state === "offline" && outcome.detail.startsWith("presence restore failed")) {
35760
- const delay = presenceRetryDelayMs(attempt);
36046
+ if (outcome.state === "standby" && prev?.state === "standby" && prev.servedBy.pid === outcome.servedBy.pid) {
36047
+ logger.debug(`Presence: STANDBY (unchanged) \u2014 ${outcome.detail}.`);
36048
+ } else {
36049
+ logPresence(outcome);
36050
+ }
36051
+ const failed = outcome.state === "offline" && outcome.detail.startsWith("presence restore failed");
36052
+ const standby = outcome.state === "standby" && outcome.recheck;
36053
+ if (failed || standby) {
36054
+ const delay = standby ? standbyRecheckMs() : presenceRetryDelayMs(attempt);
35761
36055
  cancelPresenceRetry();
35762
36056
  presenceRetry = setTimeout(() => {
35763
36057
  presenceRetry = null;
35764
- void restorePeerPresence(attempt + 1).catch(() => {
36058
+ void restorePeerPresence(standby ? 0 : attempt + 1).catch(() => {
35765
36059
  });
35766
36060
  }, delay);
35767
36061
  presenceRetry.unref?.();
35768
- logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
36062
+ if (failed) logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
35769
36063
  }
35770
36064
  return outcome;
35771
36065
  }
@@ -35899,10 +36193,10 @@ async function runStartup() {
35899
36193
  if (envStatePath) {
35900
36194
  statePath = envStatePath;
35901
36195
  } else {
35902
- const defaultPath = path21.join(os15.homedir(), ".cogent");
36196
+ const defaultPath = path22.join(os15.homedir(), ".cogent");
35903
36197
  statePath = await firstRunPrompt(defaultPath);
35904
36198
  }
35905
- if (!envStatePath && statePath !== path21.join(os15.homedir(), ".cogent")) {
36199
+ if (!envStatePath && statePath !== path22.join(os15.homedir(), ".cogent")) {
35906
36200
  process.env.COGENT_STATE_PATH = statePath;
35907
36201
  } else if (!envStatePath) {
35908
36202
  process.env.COGENT_STATE_PATH = statePath;
@@ -35966,7 +36260,7 @@ async function runStartup() {
35966
36260
  }
35967
36261
  initLogger(
35968
36262
  config2.COGENT_LOG_LEVEL,
35969
- path21.join(config2.COGENT_STATE_PATH, "logs")
36263
+ path22.join(config2.COGENT_STATE_PATH, "logs")
35970
36264
  );
35971
36265
  if (isCloud && effectiveSessionId && effectiveToken) {
35972
36266
  cloudInbox = new MessageInbox();
@@ -36006,7 +36300,7 @@ async function runPreflights() {
36006
36300
  await preflightClaude(config2.COGENT_CLAUDE_PATH);
36007
36301
  }
36008
36302
  }
36009
- var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve;
36303
+ var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, ignoredHolders, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve;
36010
36304
  var init_startup = __esm({
36011
36305
  "src/startup.ts"() {
36012
36306
  "use strict";
@@ -36022,6 +36316,7 @@ var init_startup = __esm({
36022
36316
  init_auto_relay();
36023
36317
  init_peer_presence();
36024
36318
  init_wake_ownership();
36319
+ init_stale_bridge_reaper();
36025
36320
  init_heartbeat();
36026
36321
  init_codex_preflight();
36027
36322
  init_codex_cli();
@@ -36030,7 +36325,7 @@ var init_startup = __esm({
36030
36325
  init_auto_relay();
36031
36326
  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
36327
  execFileAsync3 = promisify4(execFile5);
36033
- PERSIST_PATH = path21.join(os15.homedir(), ".cogent-config.json");
36328
+ PERSIST_PATH = path22.join(os15.homedir(), ".cogent-config.json");
36034
36329
  legacyWarnEmitted = false;
36035
36330
  cloudWsClient = null;
36036
36331
  cloudInbox = null;
@@ -36040,6 +36335,7 @@ var init_startup = __esm({
36040
36335
  notifierBoundTo = null;
36041
36336
  reRegistrationInProgress = false;
36042
36337
  presenceRetry = null;
36338
+ ignoredHolders = /* @__PURE__ */ new Set();
36043
36339
  presenceSupersedeBound = false;
36044
36340
  PRESENCE_SUPERSEDED = "presence restore superseded: an explicit cogent_join_session/cogent_create_session ran in this process and owns the channel choice";
36045
36341
  pendingLabelResolve = null;
@@ -36048,12 +36344,12 @@ var init_startup = __esm({
36048
36344
 
36049
36345
  // src/cloud/mail-credential-store.ts
36050
36346
  import crypto9 from "node:crypto";
36051
- import fs21 from "node:fs/promises";
36052
- import path22 from "node:path";
36347
+ import fs22 from "node:fs/promises";
36348
+ import path23 from "node:path";
36053
36349
  import os16 from "node:os";
36054
36350
  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`);
36351
+ const hash = crypto9.createHash("sha256").update(path23.resolve(cwd)).digest("hex").slice(0, 16);
36352
+ return path23.join(os16.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
36057
36353
  }
36058
36354
  function resolveMailCredentialPath(credentialPath) {
36059
36355
  if (credentialPath) return credentialPath;
@@ -36064,16 +36360,16 @@ function resolveMailCredentialPath(credentialPath) {
36064
36360
  async function loadMailCredentials(credentialPath) {
36065
36361
  const filePath = resolveMailCredentialPath(credentialPath);
36066
36362
  try {
36067
- return JSON.parse(await fs21.readFile(filePath, "utf-8"));
36363
+ return JSON.parse(await fs22.readFile(filePath, "utf-8"));
36068
36364
  } catch {
36069
36365
  return null;
36070
36366
  }
36071
36367
  }
36072
36368
  async function saveMailCredentials(creds, credentialPath) {
36073
36369
  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);
36370
+ await fs22.mkdir(path23.dirname(filePath), { recursive: true, mode: 448 });
36371
+ await fs22.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
36372
+ await fs22.chmod(filePath, 384);
36077
36373
  }
36078
36374
  async function persistProvisionedMailbox(mailbox, credentialPath) {
36079
36375
  if (!mailbox?.address || !mailbox.password) return false;
@@ -36094,7 +36390,7 @@ async function persistProvisionedMailbox(mailbox, credentialPath) {
36094
36390
  async function clearMailCredentials(credentialPath) {
36095
36391
  const filePath = resolveMailCredentialPath(credentialPath);
36096
36392
  try {
36097
- await fs21.unlink(filePath);
36393
+ await fs22.unlink(filePath);
36098
36394
  } catch (err) {
36099
36395
  if (err.code !== "ENOENT") throw err;
36100
36396
  }
@@ -36143,10 +36439,10 @@ function registerRegisterPeerTool(server) {
36143
36439
  "cogent_register_peer",
36144
36440
  {
36145
36441
  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.",
36442
+ 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
36443
  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)"),
36444
+ peerId: import_zod3.z.string().describe("The peer name you were given, e.g. 'backend' or 'frontend'. Never invent or suffix one."),
36445
+ sessionId: import_zod3.z.string().describe("This agent session's own resumable id (Claude Code or Codex) \u2014 NOT the channel id"),
36150
36446
  cwd: import_zod3.z.string().describe("Absolute path to the project working directory"),
36151
36447
  label: import_zod3.z.string().describe("Human-readable label, e.g. 'Cogent_Backend' or 'Cogent_Frontend'"),
36152
36448
  peerSecret: import_zod3.z.string().optional().describe(
@@ -36169,16 +36465,43 @@ function registerRegisterPeerTool(server) {
36169
36465
  async ({ peerId, sessionId, cwd, label, mode, role, peerSecret: argPeerSecret }) => {
36170
36466
  try {
36171
36467
  const config2 = getConfig();
36468
+ if (isReservedPeerName(peerId)) {
36469
+ return errorResult(
36470
+ new BridgeError(
36471
+ "INVALID_INPUT" /* INVALID_INPUT */,
36472
+ `peerId '${PROCESS_MARK}' is reserved by the bridge`,
36473
+ "Register under another peerId"
36474
+ )
36475
+ );
36476
+ }
36172
36477
  const hasExplicitCloudSession = !!config2.COGENT_SESSION_ID || process.env.COGENT_TRUST_PERSISTED_CREDENTIALS === "1";
36173
36478
  if (!hasExplicitCloudSession && hasCloudAttemptInProcess() && !hasJoinedInProcess()) {
36174
36479
  return errorResult(
36175
36480
  new BridgeError(
36176
36481
  "JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
36177
36482
  "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"
36483
+ "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
36484
  )
36180
36485
  );
36181
36486
  }
36487
+ if (config2.COGENT_ENDPOINT) try {
36488
+ const own = agentSessionId();
36489
+ const seen = /* @__PURE__ */ new Set();
36490
+ const entries = [...listLiveBridgesInFolder(cwd), ...listLiveBridgesInFolder(process.cwd())].filter((e) => !seen.has(`${e.pid}:${e.peerId}`) && seen.add(`${e.pid}:${e.peerId}`));
36491
+ const holder = heldInFolder(otherBridgesInFolder(entries, { pid: process.pid, sessionId: own }, listProcesses), peerId, own);
36492
+ if (holder) {
36493
+ logger.info(`Register: refused '${peerId}' \u2014 held in this folder by bridge pid ${holder.pid}`);
36494
+ return errorResult(
36495
+ new BridgeError(
36496
+ "PEER_HELD_IN_FOLDER" /* PEER_HELD_IN_FOLDER */,
36497
+ `'${peerId}' is held by another live connection in this folder (bridge pid ${holder.pid}, version ${registryText(holder.version)}); this bridge has NOT registered`,
36498
+ heldNameAdvice(peerId)
36499
+ )
36500
+ );
36501
+ }
36502
+ } catch (err) {
36503
+ logger.debug(`Register: could not check this folder for a holder of '${peerId}': ${err.message}`);
36504
+ }
36182
36505
  const hasCloudEndpointConfig = config2.COGENT_ENDPOINT && isCloudEndpoint(config2.COGENT_ENDPOINT);
36183
36506
  let sessionCreated = false;
36184
36507
  let cloudSessionId;
@@ -36273,7 +36596,7 @@ function registerRegisterPeerTool(server) {
36273
36596
  new BridgeError(
36274
36597
  "JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
36275
36598
  "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."
36599
+ "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
36600
  )
36278
36601
  );
36279
36602
  }
@@ -36422,9 +36745,25 @@ function registerRegisterPeerTool(server) {
36422
36745
  }
36423
36746
  }
36424
36747
  autoRelay.setLocalPeer(peerId, localSessionId, cwd, mode, label, localSessionId);
36748
+ if (isCloudMode()) {
36749
+ setPresence({ state: "online", restored: false, detail: `registered as '${peerId}' by cogent_register_peer` });
36750
+ }
36751
+ let otherBridges;
36752
+ try {
36753
+ const own = agentSessionId();
36754
+ const others = otherBridgesInFolder(listLiveBridgesInFolder(cwd), { pid: process.pid, sessionId: own }, listProcesses);
36755
+ if (others.length) {
36756
+ otherBridges = otherBridgeNotice(others, peerId, checkWakeOwnership(cwd, peerId), own);
36757
+ if (anotherAgentSessionAmong(others, own)) logger.warn(`Register: ${otherBridges}`);
36758
+ else logger.info(`Register: ${otherBridges}`);
36759
+ }
36760
+ } catch (err) {
36761
+ logger.debug(`Register: could not look for other bridges in this folder: ${err.message}`);
36762
+ }
36425
36763
  const result = {
36426
36764
  success: true,
36427
36765
  action: existing ? "updated" : "registered",
36766
+ ...otherBridges ? { otherBridgeInThisFolder: otherBridges } : {},
36428
36767
  peer,
36429
36768
  sessionResolution: {
36430
36769
  decision: resolution.decision,
@@ -36503,6 +36842,9 @@ var init_register_peer = __esm({
36503
36842
  init_logger();
36504
36843
  init_heartbeat();
36505
36844
  init_auto_relay();
36845
+ init_wake_ownership();
36846
+ init_peer_presence();
36847
+ init_stale_bridge_reaper();
36506
36848
  init_session_resolver();
36507
36849
  init_cc_cli();
36508
36850
  init_durable_identity();
@@ -37172,9 +37514,14 @@ var init_ids = __esm({
37172
37514
  });
37173
37515
 
37174
37516
  // cogent/dist/helpers/validation.js
37517
+ function isValidSessionLabel(value) {
37518
+ return SESSION_LABEL_REGEX.test(value);
37519
+ }
37520
+ var SESSION_LABEL_REGEX;
37175
37521
  var init_validation = __esm({
37176
37522
  "cogent/dist/helpers/validation.js"() {
37177
37523
  "use strict";
37524
+ SESSION_LABEL_REGEX = /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/;
37178
37525
  }
37179
37526
  });
37180
37527
 
@@ -37627,7 +37974,8 @@ function registerHealthCheckTool(server) {
37627
37974
  // PRESENCE — the agent's own view of whether it is IN its channel, so it can
37628
37975
  // answer "am I reachable?" without inferring it from transport internals.
37629
37976
  // "online" registered · "offline" owns a peer but is not registered (nobody can
37630
- // reach it) · "deferred" never joined · "local" no relay.
37977
+ // reach it) · "standby" another live bridge serves this peer, so THIS process is not
37978
+ // registered (servedBy names it) · "deferred" never joined · "local" no relay.
37631
37979
  // services/peer-presence.ts carries the vocabulary and how each state arises.
37632
37980
  presence: (() => {
37633
37981
  const p = getPresence();
@@ -37638,7 +37986,8 @@ function registerHealthCheckTool(server) {
37638
37986
  state: p.state,
37639
37987
  restored: p.restored,
37640
37988
  detail: p.detail,
37641
- ..."peerId" in p ? { peerId: p.peerId } : {}
37989
+ ..."peerId" in p ? { peerId: p.peerId } : {},
37990
+ ..."servedBy" in p ? { servedBy: p.servedBy } : {}
37642
37991
  };
37643
37992
  })()
37644
37993
  };
@@ -37725,18 +38074,43 @@ var init_wake_log2 = __esm({
37725
38074
  }
37726
38075
  });
37727
38076
 
38077
+ // src/tools/channel-text.ts
38078
+ function invalidChannelName(name) {
38079
+ if (isValidSessionLabel(name)) return null;
38080
+ return new BridgeError(
38081
+ "INVALID_INPUT" /* INVALID_INPUT */,
38082
+ `Channel names are 3-32 characters: lowercase letters, digits and hyphens. '${name}' is not valid`,
38083
+ "If it differs only by capital letters, retry with it in lowercase; otherwise ask the user."
38084
+ );
38085
+ }
38086
+ function slackMapCommand(o) {
38087
+ return o.team ? `/cogent map ${o.label} <password> <org-id>` : `/cogent map ${o.sessionId} <password>`;
38088
+ }
38089
+ var init_channel_text = __esm({
38090
+ "src/tools/channel-text.ts"() {
38091
+ "use strict";
38092
+ init_dist();
38093
+ init_errors4();
38094
+ }
38095
+ });
38096
+
37728
38097
  // src/tools/create-session.ts
37729
38098
  import crypto11 from "node:crypto";
37730
38099
  function registerCreateSessionTool(server) {
37731
38100
  server.registerTool(
37732
38101
  "cogent_create_session",
37733
38102
  {
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.",
38103
+ title: "Create Cloud Channel",
38104
+ 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
38105
  inputSchema: {
37737
- label: import_zod15.z.string().optional().describe("Human-readable label for the session"),
38106
+ label: import_zod15.z.string().optional().describe(
38107
+ "The channel name (3-32 characters: lowercase letters, digits, hyphens) \u2014 the same name the join was given. Auto-generated if omitted."
38108
+ ),
37738
38109
  secret: import_zod15.z.string().min(8).optional().describe(
37739
- "Shared secret for session authentication (min 8 chars). Auto-generated if omitted."
38110
+ "Shared secret / password for the channel (min 8 chars). Auto-generated if omitted."
38111
+ ),
38112
+ orgId: import_zod15.z.string().min(1).optional().describe(
38113
+ "Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it to create a Team channel; omit for a free channel."
37740
38114
  )
37741
38115
  },
37742
38116
  annotations: {
@@ -37746,28 +38120,57 @@ function registerCreateSessionTool(server) {
37746
38120
  openWorldHint: true
37747
38121
  }
37748
38122
  },
37749
- async ({ label, secret }) => {
38123
+ async ({ label, secret, orgId }) => {
37750
38124
  try {
37751
38125
  markCloudAttemptInProcess();
38126
+ if (label !== void 0 && label.trim() === "") {
38127
+ return errorResult(invalidChannelName(label) ?? new Error("label is empty"));
38128
+ }
38129
+ if (secret !== void 0 && secret.trim() === "") {
38130
+ return errorResult(
38131
+ new BridgeError(
38132
+ "INVALID_INPUT" /* INVALID_INPUT */,
38133
+ "The channel password is empty",
38134
+ "Pass the password you were given, or omit `secret` to have one generated."
38135
+ )
38136
+ );
38137
+ }
38138
+ label = label?.trim() || void 0;
38139
+ secret = secret?.trim() || void 0;
38140
+ orgId = orgId?.trim() || void 0;
37752
38141
  const config2 = getConfig();
37753
- if (!config2.COGENT_ENDPOINT) {
38142
+ const endpoint = orgId ? config2.COGENT_TEAM_ENDPOINT : config2.COGENT_ENDPOINT;
38143
+ if (!endpoint) {
37754
38144
  return errorResult(
37755
38145
  new Error(
37756
- "COGENT_ENDPOINT not configured. Set it to use cloud mode."
38146
+ 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
38147
  )
37758
38148
  );
37759
38149
  }
38150
+ if (label !== void 0) {
38151
+ const invalid = invalidChannelName(label);
38152
+ if (invalid) return errorResult(invalid);
38153
+ }
38154
+ const secretWasGenerated = secret === void 0;
37760
38155
  const sessionSecret = secret ?? crypto11.randomBytes(16).toString("hex");
38156
+ const createBody = orgId ? { secret: sessionSecret, label, orgId } : { secret: sessionSecret, label };
37761
38157
  const resp = await fetch(
37762
- `${config2.COGENT_ENDPOINT}/api/sessions`,
38158
+ `${endpoint}/api/sessions`,
37763
38159
  {
37764
38160
  method: "POST",
37765
38161
  headers: { "Content-Type": "application/json" },
37766
- body: JSON.stringify({ secret: sessionSecret, label })
38162
+ body: JSON.stringify(createBody)
37767
38163
  }
37768
38164
  );
37769
38165
  if (!resp.ok) {
37770
38166
  const body = await resp.text().catch(() => "");
38167
+ if (resp.status === 400 && body.includes("already in use")) {
38168
+ return errorResult(
38169
+ new Error(
38170
+ `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.`
38171
+ )
38172
+ );
38173
+ }
37771
38174
  return errorResult(
37772
38175
  new Error(
37773
38176
  `Failed to create session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
@@ -37776,7 +38179,7 @@ function registerCreateSessionTool(server) {
37776
38179
  }
37777
38180
  const data = await resp.json();
37778
38181
  await saveCredentials({
37779
- endpoint: config2.COGENT_ENDPOINT,
38182
+ endpoint,
37780
38183
  sessionId: data.sessionId,
37781
38184
  token: data.token,
37782
38185
  label: data.label,
@@ -37786,7 +38189,7 @@ function registerCreateSessionTool(server) {
37786
38189
  try {
37787
38190
  const startupModule = await Promise.resolve().then(() => (init_startup(), startup_exports));
37788
38191
  if (typeof startupModule.reinitCloudBackend === "function") {
37789
- await startupModule.reinitCloudBackend(config2.COGENT_ENDPOINT, data.sessionId, data.token);
38192
+ await startupModule.reinitCloudBackend(endpoint, data.sessionId, data.token);
37790
38193
  logger.info(
37791
38194
  "Cloud backend reinitialized with new session credentials"
37792
38195
  );
@@ -37794,32 +38197,40 @@ function registerCreateSessionTool(server) {
37794
38197
  } catch (err) {
37795
38198
  logger.debug(`Backend reinit not available: ${err}`);
37796
38199
  }
38200
+ const channelName = data.label ?? data.sessionId;
37797
38201
  return successResult({
37798
38202
  success: true,
38203
+ created: true,
37799
38204
  sessionId: data.sessionId,
37800
38205
  label: data.label,
37801
- secret: sessionSecret,
37802
38206
  token: data.token,
37803
38207
  createdAt: data.createdAt,
37804
- config_snippet: {
37805
- env_vars: `COGENT_ENDPOINT=${config2.COGENT_ENDPOINT}
37806
- COGENT_SESSION_ID=${data.label ?? data.sessionId}
38208
+ slackMapCommand: slackMapCommand({ team: !!orgId, label: channelName, sessionId: data.sessionId }),
38209
+ // A secret the CALLER supplied is never echoed back: the caller already has it, and a
38210
+ // tool result can be quoted into a channel by an auto-reply. Only a secret this tool
38211
+ // generated is returned — nothing else knows it.
38212
+ ...secretWasGenerated ? {
38213
+ secret: sessionSecret,
38214
+ config_snippet: {
38215
+ env_vars: `COGENT_ENDPOINT=${endpoint}
38216
+ COGENT_SESSION_ID=${channelName}
37807
38217
  COGENT_SECRET=${sessionSecret}
37808
38218
  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
38219
+ mcp_config: {
38220
+ "cogent": {
38221
+ command: "npx",
38222
+ args: ["-y", "@essentialai/cogent-bridge"],
38223
+ env: {
38224
+ COGENT_ENDPOINT: endpoint,
38225
+ COGENT_SESSION_ID: channelName,
38226
+ COGENT_SECRET: sessionSecret,
38227
+ COGENT_PLATFORM: config2.COGENT_PLATFORM
38228
+ }
37818
38229
  }
37819
38230
  }
37820
38231
  }
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.`
38232
+ } : {},
38233
+ 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
38234
  });
37824
38235
  } catch (err) {
37825
38236
  logger.error("create-session failed", { error: err });
@@ -37837,6 +38248,7 @@ var init_create_session = __esm({
37837
38248
  init_errors4();
37838
38249
  init_credential_store();
37839
38250
  init_logger();
38251
+ init_channel_text();
37840
38252
  }
37841
38253
  });
37842
38254
 
@@ -37846,14 +38258,14 @@ function registerJoinSessionTool(server) {
37846
38258
  "cogent_join_session",
37847
38259
  {
37848
38260
  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.',
38261
+ 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
38262
  inputSchema: {
37851
38263
  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.'
38264
+ '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
38265
  ),
37854
38266
  secret: import_zod16.z.string().min(1).describe("The shared secret / password for the channel"),
37855
38267
  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."
38268
+ "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
38269
  )
37858
38270
  },
37859
38271
  annotations: {
@@ -37881,10 +38293,12 @@ function registerJoinSessionTool(server) {
37881
38293
  if (UUID_V4_RE2.test(channel)) {
37882
38294
  return errorResult(
37883
38295
  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.`
38296
+ `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
38297
  )
37886
38298
  );
37887
38299
  }
38300
+ const invalid = invalidChannelName(channel);
38301
+ if (invalid) return errorResult(invalid);
37888
38302
  let resolvedSessionId;
37889
38303
  let resolvedLabel;
37890
38304
  if (orgId) {
@@ -37896,6 +38310,13 @@ function registerJoinSessionTool(server) {
37896
38310
  body: JSON.stringify({ label: channel, orgId })
37897
38311
  }
37898
38312
  );
38313
+ if (resolveResp.status === 404) {
38314
+ return errorResult(new BridgeError(
38315
+ "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
38316
+ `Team channel '${channel}' was not found on ${endpoint} for this Org_ID (HTTP 404)`,
38317
+ `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.`
38318
+ ));
38319
+ }
37899
38320
  if (!resolveResp.ok) {
37900
38321
  const body = await resolveResp.text().catch(() => "");
37901
38322
  return errorResult(new Error(
@@ -37909,6 +38330,13 @@ function registerJoinSessionTool(server) {
37909
38330
  const resolveResp = await fetch(
37910
38331
  `${endpoint}/api/sessions/resolve/${encodeURIComponent(channel)}`
37911
38332
  );
38333
+ if (resolveResp.status === 404) {
38334
+ return errorResult(new BridgeError(
38335
+ "CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
38336
+ `Channel '${channel}' was not found on ${endpoint} (HTTP 404)`,
38337
+ `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.`
38338
+ ));
38339
+ }
37912
38340
  if (!resolveResp.ok) {
37913
38341
  const body = await resolveResp.text().catch(() => "");
37914
38342
  return errorResult(new Error(`Failed to resolve channel name "${channel}": HTTP ${resolveResp.status}${body ? ` - ${body}` : ""}`));
@@ -37928,9 +38356,10 @@ function registerJoinSessionTool(server) {
37928
38356
  );
37929
38357
  if (!resp.ok) {
37930
38358
  const body = await resp.text().catch(() => "");
38359
+ const wrong = resp.status === 401 ? `. The password${orgId ? " or Org_ID" : ""} is wrong. Do not retry with guesses - ask the user.` : "";
37931
38360
  return errorResult(
37932
38361
  new Error(
37933
- `Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
38362
+ `Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}${wrong}`
37934
38363
  )
37935
38364
  );
37936
38365
  }
@@ -37979,6 +38408,11 @@ function registerJoinSessionTool(server) {
37979
38408
  token: data.token,
37980
38409
  label: resolvedLabel ?? data.label ?? channel,
37981
38410
  peerCount: data.peerCount,
38411
+ slackMapCommand: slackMapCommand({
38412
+ team: !!orgId,
38413
+ label: resolvedLabel ?? data.label ?? channel,
38414
+ sessionId: data.sessionId
38415
+ }),
37982
38416
  note: "Successfully joined session. Credentials saved locally. Cloud backend updated. You can now use cogent_register_peer.",
37983
38417
  ...updateNudge ? { updateAvailable: updateNudge } : {}
37984
38418
  });
@@ -37999,6 +38433,7 @@ var init_join_session = __esm({
37999
38433
  init_credential_store();
38000
38434
  init_logger();
38001
38435
  init_npm_update_check();
38436
+ init_channel_text();
38002
38437
  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
38438
  }
38004
38439
  });
@@ -38233,8 +38668,8 @@ var require_cookies = __commonJS({
38233
38668
  if (urlparts.hostname !== cookie.domain && (cookie.domain.charAt(0) !== "." || ("." + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
38234
38669
  return false;
38235
38670
  }
38236
- let path26 = this.getPath(urlparts.pathname);
38237
- if (path26.substr(0, cookie.path.length) !== cookie.path) {
38671
+ let path27 = this.getPath(urlparts.pathname);
38672
+ if (path27.substr(0, cookie.path.length) !== cookie.path) {
38238
38673
  return false;
38239
38674
  }
38240
38675
  if (cookie.secure && urlparts.protocol !== "https:") {
@@ -38294,16 +38729,16 @@ var require_cookies = __commonJS({
38294
38729
  * @returns {String} Normalized path
38295
38730
  */
38296
38731
  getPath(pathname) {
38297
- let path26 = (pathname || "/").split("/");
38298
- path26.pop();
38299
- path26 = path26.join("/").trim();
38300
- if (path26.charAt(0) !== "/") {
38301
- path26 = "/" + path26;
38732
+ let path27 = (pathname || "/").split("/");
38733
+ path27.pop();
38734
+ path27 = path27.join("/").trim();
38735
+ if (path27.charAt(0) !== "/") {
38736
+ path27 = "/" + path27;
38302
38737
  }
38303
- if (path26.substr(-1) !== "/") {
38304
- path26 += "/";
38738
+ if (path27.substr(-1) !== "/") {
38739
+ path27 += "/";
38305
38740
  }
38306
- return path26;
38741
+ return path27;
38307
38742
  }
38308
38743
  };
38309
38744
  module.exports = Cookies;
@@ -38604,7 +39039,7 @@ var require_shared = __commonJS({
38604
39039
  "use strict";
38605
39040
  var urllib = __require("url");
38606
39041
  var util2 = __require("util");
38607
- var fs24 = __require("fs");
39042
+ var fs25 = __require("fs");
38608
39043
  var nmfetch = require_fetch();
38609
39044
  var dns = __require("dns");
38610
39045
  var net = __require("net");
@@ -38990,7 +39425,7 @@ var require_shared = __commonJS({
38990
39425
  }
38991
39426
  return callback(null, parsedDataUri.data);
38992
39427
  } else if (content.path) {
38993
- return resolveStream(fs24.createReadStream(content.path), callback);
39428
+ return resolveStream(fs25.createReadStream(content.path), callback);
38994
39429
  }
38995
39430
  }
38996
39431
  if (typeof data[key].content === "string" && !["utf8", "usascii", "ascii"].includes(encoding)) {
@@ -39114,7 +39549,7 @@ var require_shared = __commonJS({
39114
39549
  var require_mime_types = __commonJS({
39115
39550
  "node_modules/nodemailer/lib/mime-funcs/mime-types.js"(exports, module) {
39116
39551
  "use strict";
39117
- var path26 = __require("path");
39552
+ var path27 = __require("path");
39118
39553
  var defaultMimeType = "application/octet-stream";
39119
39554
  var defaultExtension = "bin";
39120
39555
  var mimeTypes = /* @__PURE__ */ new Map([
@@ -41172,7 +41607,7 @@ var require_mime_types = __commonJS({
41172
41607
  if (!filename) {
41173
41608
  return defaultMimeType;
41174
41609
  }
41175
- let parsed = path26.parse(filename);
41610
+ let parsed = path27.parse(filename);
41176
41611
  let extension = (parsed.ext.substr(1) || parsed.name || "").split("?").shift().trim().toLowerCase();
41177
41612
  let value = defaultMimeType;
41178
41613
  if (extensions.has(extension)) {
@@ -42574,7 +43009,7 @@ var require_mime_node = __commonJS({
42574
43009
  "node_modules/nodemailer/lib/mime-node/index.js"(exports, module) {
42575
43010
  "use strict";
42576
43011
  var crypto12 = __require("crypto");
42577
- var fs24 = __require("fs");
43012
+ var fs25 = __require("fs");
42578
43013
  var punycode = require_punycode();
42579
43014
  var PassThrough = __require("stream").PassThrough;
42580
43015
  var shared = require_shared();
@@ -43289,7 +43724,7 @@ var require_mime_node = __commonJS({
43289
43724
  setImmediate(() => contentStream.emit("error", new Error("File access rejected for " + content.path)));
43290
43725
  return contentStream;
43291
43726
  }
43292
- return fs24.createReadStream(content.path);
43727
+ return fs25.createReadStream(content.path);
43293
43728
  } else if (content && typeof content.href === "string") {
43294
43729
  if (this.disableUrlAccess) {
43295
43730
  contentStream = new PassThrough();
@@ -44310,8 +44745,8 @@ var require_dkim = __commonJS({
44310
44745
  var RelaxedBody = require_relaxed_body();
44311
44746
  var sign = require_sign();
44312
44747
  var PassThrough = __require("stream").PassThrough;
44313
- var fs24 = __require("fs");
44314
- var path26 = __require("path");
44748
+ var fs25 = __require("fs");
44749
+ var path27 = __require("path");
44315
44750
  var crypto12 = __require("crypto");
44316
44751
  var DKIM_ALGO = "sha256";
44317
44752
  var MAX_MESSAGE_SIZE = 128 * 1024;
@@ -44325,7 +44760,7 @@ var require_dkim = __commonJS({
44325
44760
  this.chunks = [];
44326
44761
  this.chunklen = 0;
44327
44762
  this.readPos = 0;
44328
- this.cachePath = this.cacheDir ? path26.join(this.cacheDir, "message." + Date.now() + "-" + crypto12.randomBytes(14).toString("hex")) : false;
44763
+ this.cachePath = this.cacheDir ? path27.join(this.cacheDir, "message." + Date.now() + "-" + crypto12.randomBytes(14).toString("hex")) : false;
44329
44764
  this.cache = false;
44330
44765
  this.headers = false;
44331
44766
  this.bodyHash = false;
@@ -44345,10 +44780,10 @@ var require_dkim = __commonJS({
44345
44780
  if (!this.cache || !this.cachePath) {
44346
44781
  return;
44347
44782
  }
44348
- fs24.unlink(this.cachePath, () => false);
44783
+ fs25.unlink(this.cachePath, () => false);
44349
44784
  }
44350
44785
  createReadCache() {
44351
- this.cache = fs24.createReadStream(this.cachePath);
44786
+ this.cache = fs25.createReadStream(this.cachePath);
44352
44787
  this.cache.once("error", (err) => {
44353
44788
  this.cleanup();
44354
44789
  this.output.emit("error", err);
@@ -44404,7 +44839,7 @@ var require_dkim = __commonJS({
44404
44839
  }
44405
44840
  createWriteCache() {
44406
44841
  this.output.usingCache = true;
44407
- this.cache = fs24.createWriteStream(this.cachePath);
44842
+ this.cache = fs25.createWriteStream(this.cachePath);
44408
44843
  this.cache.once("error", (err) => {
44409
44844
  this.cleanup();
44410
44845
  this.relaxedBody.unpipe(this.cache);
@@ -49293,13 +49728,13 @@ var require_nodemailer = __commonJS({
49293
49728
  });
49294
49729
 
49295
49730
  // src/mail/mail-sender.ts
49296
- import fs22 from "node:fs/promises";
49297
- import path23 from "node:path";
49731
+ import fs23 from "node:fs/promises";
49732
+ import path24 from "node:path";
49298
49733
  async function buildAndSendMail(sender, creds, params) {
49299
49734
  const attachments = [];
49300
49735
  for (const p of params.attachmentPaths ?? []) {
49301
- const content = await fs22.readFile(p);
49302
- attachments.push({ filename: path23.basename(p), content });
49736
+ const content = await fs23.readFile(p);
49737
+ attachments.push({ filename: path24.basename(p), content });
49303
49738
  }
49304
49739
  const { messageId } = await sender.send({
49305
49740
  from: creds.address,
@@ -49688,8 +50123,8 @@ var require_req = __commonJS({
49688
50123
  if (req.originalUrl) {
49689
50124
  _req.url = req.originalUrl;
49690
50125
  } else {
49691
- const path26 = req.path;
49692
- _req.url = typeof path26 === "string" ? path26 : req.url ? req.url.path || req.url : void 0;
50126
+ const path27 = req.path;
50127
+ _req.url = typeof path27 === "string" ? path27 : req.url ? req.url.path || req.url : void 0;
49693
50128
  }
49694
50129
  if (req.query) {
49695
50130
  _req.query = req.query;
@@ -49854,14 +50289,14 @@ var require_redact = __commonJS({
49854
50289
  }
49855
50290
  return obj;
49856
50291
  }
49857
- function parsePath(path26) {
50292
+ function parsePath(path27) {
49858
50293
  const parts = [];
49859
50294
  let current = "";
49860
50295
  let inBrackets = false;
49861
50296
  let inQuotes = false;
49862
50297
  let quoteChar = "";
49863
- for (let i = 0; i < path26.length; i++) {
49864
- const char = path26[i];
50298
+ for (let i = 0; i < path27.length; i++) {
50299
+ const char = path27[i];
49865
50300
  if (!inBrackets && char === ".") {
49866
50301
  if (current) {
49867
50302
  parts.push(current);
@@ -49992,10 +50427,10 @@ var require_redact = __commonJS({
49992
50427
  return current;
49993
50428
  }
49994
50429
  function redactPaths(obj, paths, censor, remove = false) {
49995
- for (const path26 of paths) {
49996
- const parts = parsePath(path26);
50430
+ for (const path27 of paths) {
50431
+ const parts = parsePath(path27);
49997
50432
  if (parts.includes("*")) {
49998
- redactWildcardPath(obj, parts, censor, path26, remove);
50433
+ redactWildcardPath(obj, parts, censor, path27, remove);
49999
50434
  } else {
50000
50435
  if (remove) {
50001
50436
  removeKey(obj, parts);
@@ -50080,8 +50515,8 @@ var require_redact = __commonJS({
50080
50515
  }
50081
50516
  } else {
50082
50517
  if (afterWildcard.includes("*")) {
50083
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
50084
- const fullPath = [...pathArray.slice(0, pathLength), ...path26];
50518
+ const wrappedCensor = typeof censor === "function" ? (value, path27) => {
50519
+ const fullPath = [...pathArray.slice(0, pathLength), ...path27];
50085
50520
  return censor(value, fullPath);
50086
50521
  } : censor;
50087
50522
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -50116,8 +50551,8 @@ var require_redact = __commonJS({
50116
50551
  return null;
50117
50552
  }
50118
50553
  const pathStructure = /* @__PURE__ */ new Map();
50119
- for (const path26 of pathsToClone) {
50120
- const parts = parsePath(path26);
50554
+ for (const path27 of pathsToClone) {
50555
+ const parts = parsePath(path27);
50121
50556
  let current = pathStructure;
50122
50557
  for (let i = 0; i < parts.length; i++) {
50123
50558
  const part = parts[i];
@@ -50169,24 +50604,24 @@ var require_redact = __commonJS({
50169
50604
  }
50170
50605
  return cloneSelectively(obj, pathStructure);
50171
50606
  }
50172
- function validatePath(path26) {
50173
- if (typeof path26 !== "string") {
50607
+ function validatePath(path27) {
50608
+ if (typeof path27 !== "string") {
50174
50609
  throw new Error("Paths must be (non-empty) strings");
50175
50610
  }
50176
- if (path26 === "") {
50611
+ if (path27 === "") {
50177
50612
  throw new Error("Invalid redaction path ()");
50178
50613
  }
50179
- if (path26.includes("..")) {
50180
- throw new Error(`Invalid redaction path (${path26})`);
50614
+ if (path27.includes("..")) {
50615
+ throw new Error(`Invalid redaction path (${path27})`);
50181
50616
  }
50182
- if (path26.includes(",")) {
50183
- throw new Error(`Invalid redaction path (${path26})`);
50617
+ if (path27.includes(",")) {
50618
+ throw new Error(`Invalid redaction path (${path27})`);
50184
50619
  }
50185
50620
  let bracketCount = 0;
50186
50621
  let inQuotes = false;
50187
50622
  let quoteChar = "";
50188
- for (let i = 0; i < path26.length; i++) {
50189
- const char = path26[i];
50623
+ for (let i = 0; i < path27.length; i++) {
50624
+ const char = path27[i];
50190
50625
  if ((char === '"' || char === "'") && bracketCount > 0) {
50191
50626
  if (!inQuotes) {
50192
50627
  inQuotes = true;
@@ -50200,20 +50635,20 @@ var require_redact = __commonJS({
50200
50635
  } else if (char === "]" && !inQuotes) {
50201
50636
  bracketCount--;
50202
50637
  if (bracketCount < 0) {
50203
- throw new Error(`Invalid redaction path (${path26})`);
50638
+ throw new Error(`Invalid redaction path (${path27})`);
50204
50639
  }
50205
50640
  }
50206
50641
  }
50207
50642
  if (bracketCount !== 0) {
50208
- throw new Error(`Invalid redaction path (${path26})`);
50643
+ throw new Error(`Invalid redaction path (${path27})`);
50209
50644
  }
50210
50645
  }
50211
50646
  function validatePaths(paths) {
50212
50647
  if (!Array.isArray(paths)) {
50213
50648
  throw new TypeError("paths must be an array");
50214
50649
  }
50215
- for (const path26 of paths) {
50216
- validatePath(path26);
50650
+ for (const path27 of paths) {
50651
+ validatePath(path27);
50217
50652
  }
50218
50653
  }
50219
50654
  function slowRedact(options = {}) {
@@ -50381,8 +50816,8 @@ var require_redaction = __commonJS({
50381
50816
  if (shape[k] === null) {
50382
50817
  o[k] = (value) => topCensor(value, [k]);
50383
50818
  } else {
50384
- const wrappedCensor = typeof censor === "function" ? (value, path26) => {
50385
- return censor(value, [k, ...path26]);
50819
+ const wrappedCensor = typeof censor === "function" ? (value, path27) => {
50820
+ return censor(value, [k, ...path27]);
50386
50821
  } : censor;
50387
50822
  o[k] = Redact({
50388
50823
  paths: shape[k],
@@ -50600,10 +51035,10 @@ var require_atomic_sleep = __commonJS({
50600
51035
  var require_sonic_boom = __commonJS({
50601
51036
  "node_modules/sonic-boom/index.js"(exports, module) {
50602
51037
  "use strict";
50603
- var fs24 = __require("fs");
51038
+ var fs25 = __require("fs");
50604
51039
  var EventEmitter = __require("events");
50605
51040
  var inherits = __require("util").inherits;
50606
- var path26 = __require("path");
51041
+ var path27 = __require("path");
50607
51042
  var sleep4 = require_atomic_sleep();
50608
51043
  var assert2 = __require("assert");
50609
51044
  var BUSY_WRITE_TIMEOUT = 100;
@@ -50657,20 +51092,20 @@ var require_sonic_boom = __commonJS({
50657
51092
  const mode = sonic.mode;
50658
51093
  if (sonic.sync) {
50659
51094
  try {
50660
- if (sonic.mkdir) fs24.mkdirSync(path26.dirname(file), { recursive: true });
50661
- const fd = fs24.openSync(file, flags, mode);
51095
+ if (sonic.mkdir) fs25.mkdirSync(path27.dirname(file), { recursive: true });
51096
+ const fd = fs25.openSync(file, flags, mode);
50662
51097
  fileOpened(null, fd);
50663
51098
  } catch (err) {
50664
51099
  fileOpened(err);
50665
51100
  throw err;
50666
51101
  }
50667
51102
  } else if (sonic.mkdir) {
50668
- fs24.mkdir(path26.dirname(file), { recursive: true }, (err) => {
51103
+ fs25.mkdir(path27.dirname(file), { recursive: true }, (err) => {
50669
51104
  if (err) return fileOpened(err);
50670
- fs24.open(file, flags, mode, fileOpened);
51105
+ fs25.open(file, flags, mode, fileOpened);
50671
51106
  });
50672
51107
  } else {
50673
- fs24.open(file, flags, mode, fileOpened);
51108
+ fs25.open(file, flags, mode, fileOpened);
50674
51109
  }
50675
51110
  }
50676
51111
  function SonicBoom(opts) {
@@ -50711,8 +51146,8 @@ var require_sonic_boom = __commonJS({
50711
51146
  this.flush = flushBuffer;
50712
51147
  this.flushSync = flushBufferSync;
50713
51148
  this._actualWrite = actualWriteBuffer;
50714
- fsWriteSync = () => fs24.writeSync(this.fd, this._writingBuf);
50715
- fsWrite = () => fs24.write(this.fd, this._writingBuf, this.release);
51149
+ fsWriteSync = () => fs25.writeSync(this.fd, this._writingBuf);
51150
+ fsWrite = () => fs25.write(this.fd, this._writingBuf, this.release);
50716
51151
  } else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
50717
51152
  this._writingBuf = "";
50718
51153
  this.write = write;
@@ -50721,15 +51156,15 @@ var require_sonic_boom = __commonJS({
50721
51156
  this._actualWrite = actualWrite;
50722
51157
  fsWriteSync = () => {
50723
51158
  if (Buffer.isBuffer(this._writingBuf)) {
50724
- return fs24.writeSync(this.fd, this._writingBuf);
51159
+ return fs25.writeSync(this.fd, this._writingBuf);
50725
51160
  }
50726
- return fs24.writeSync(this.fd, this._writingBuf, "utf8");
51161
+ return fs25.writeSync(this.fd, this._writingBuf, "utf8");
50727
51162
  };
50728
51163
  fsWrite = () => {
50729
51164
  if (Buffer.isBuffer(this._writingBuf)) {
50730
- return fs24.write(this.fd, this._writingBuf, this.release);
51165
+ return fs25.write(this.fd, this._writingBuf, this.release);
50731
51166
  }
50732
- return fs24.write(this.fd, this._writingBuf, "utf8", this.release);
51167
+ return fs25.write(this.fd, this._writingBuf, "utf8", this.release);
50733
51168
  };
50734
51169
  } else {
50735
51170
  throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
@@ -50786,7 +51221,7 @@ var require_sonic_boom = __commonJS({
50786
51221
  }
50787
51222
  }
50788
51223
  if (this._fsync) {
50789
- fs24.fsyncSync(this.fd);
51224
+ fs25.fsyncSync(this.fd);
50790
51225
  }
50791
51226
  const len = this._len;
50792
51227
  if (this._reopening) {
@@ -50900,7 +51335,7 @@ var require_sonic_boom = __commonJS({
50900
51335
  const onDrain = () => {
50901
51336
  if (!this._fsync) {
50902
51337
  try {
50903
- fs24.fsync(this.fd, (err) => {
51338
+ fs25.fsync(this.fd, (err) => {
50904
51339
  this._flushPending = false;
50905
51340
  cb(err);
50906
51341
  });
@@ -51002,7 +51437,7 @@ var require_sonic_boom = __commonJS({
51002
51437
  const fd = this.fd;
51003
51438
  this.once("ready", () => {
51004
51439
  if (fd !== this.fd) {
51005
- fs24.close(fd, (err) => {
51440
+ fs25.close(fd, (err) => {
51006
51441
  if (err) {
51007
51442
  return this.emit("error", err);
51008
51443
  }
@@ -51051,7 +51486,7 @@ var require_sonic_boom = __commonJS({
51051
51486
  buf = this._bufs[0];
51052
51487
  }
51053
51488
  try {
51054
- const n = Buffer.isBuffer(buf) ? fs24.writeSync(this.fd, buf) : fs24.writeSync(this.fd, buf, "utf8");
51489
+ const n = Buffer.isBuffer(buf) ? fs25.writeSync(this.fd, buf) : fs25.writeSync(this.fd, buf, "utf8");
51055
51490
  const releasedBufObj = releaseWritingBuf(buf, this._len, n);
51056
51491
  buf = releasedBufObj.writingBuf;
51057
51492
  this._len = releasedBufObj.len;
@@ -51067,7 +51502,7 @@ var require_sonic_boom = __commonJS({
51067
51502
  }
51068
51503
  }
51069
51504
  try {
51070
- fs24.fsyncSync(this.fd);
51505
+ fs25.fsyncSync(this.fd);
51071
51506
  } catch {
51072
51507
  }
51073
51508
  }
@@ -51088,7 +51523,7 @@ var require_sonic_boom = __commonJS({
51088
51523
  buf = mergeBuf(this._bufs[0], this._lens[0]);
51089
51524
  }
51090
51525
  try {
51091
- const n = fs24.writeSync(this.fd, buf);
51526
+ const n = fs25.writeSync(this.fd, buf);
51092
51527
  buf = buf.subarray(n);
51093
51528
  this._len = Math.max(this._len - n, 0);
51094
51529
  if (buf.length <= 0) {
@@ -51116,13 +51551,13 @@ var require_sonic_boom = __commonJS({
51116
51551
  this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
51117
51552
  if (this.sync) {
51118
51553
  try {
51119
- const written = Buffer.isBuffer(this._writingBuf) ? fs24.writeSync(this.fd, this._writingBuf) : fs24.writeSync(this.fd, this._writingBuf, "utf8");
51554
+ const written = Buffer.isBuffer(this._writingBuf) ? fs25.writeSync(this.fd, this._writingBuf) : fs25.writeSync(this.fd, this._writingBuf, "utf8");
51120
51555
  release(null, written);
51121
51556
  } catch (err) {
51122
51557
  release(err);
51123
51558
  }
51124
51559
  } else {
51125
- fs24.write(this.fd, this._writingBuf, release);
51560
+ fs25.write(this.fd, this._writingBuf, release);
51126
51561
  }
51127
51562
  }
51128
51563
  function actualWriteBuffer() {
@@ -51131,7 +51566,7 @@ var require_sonic_boom = __commonJS({
51131
51566
  this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
51132
51567
  if (this.sync) {
51133
51568
  try {
51134
- const written = fs24.writeSync(this.fd, this._writingBuf);
51569
+ const written = fs25.writeSync(this.fd, this._writingBuf);
51135
51570
  release(null, written);
51136
51571
  } catch (err) {
51137
51572
  release(err);
@@ -51140,7 +51575,7 @@ var require_sonic_boom = __commonJS({
51140
51575
  if (kCopyBuffer) {
51141
51576
  this._writingBuf = Buffer.from(this._writingBuf);
51142
51577
  }
51143
- fs24.write(this.fd, this._writingBuf, release);
51578
+ fs25.write(this.fd, this._writingBuf, release);
51144
51579
  }
51145
51580
  }
51146
51581
  function actualClose(sonic) {
@@ -51156,12 +51591,12 @@ var require_sonic_boom = __commonJS({
51156
51591
  sonic._lens = [];
51157
51592
  assert2(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
51158
51593
  try {
51159
- fs24.fsync(sonic.fd, closeWrapped);
51594
+ fs25.fsync(sonic.fd, closeWrapped);
51160
51595
  } catch {
51161
51596
  }
51162
51597
  function closeWrapped() {
51163
51598
  if (sonic.fd !== 1 && sonic.fd !== 2) {
51164
- fs24.close(sonic.fd, done);
51599
+ fs25.close(sonic.fd, done);
51165
51600
  } else {
51166
51601
  done();
51167
51602
  }
@@ -51997,15 +52432,15 @@ var require_transport = __commonJS({
51997
52432
  if (!unquoted) {
51998
52433
  return false;
51999
52434
  }
52000
- let path26 = unquoted;
52001
- if (path26.startsWith("file://")) {
52435
+ let path27 = unquoted;
52436
+ if (path27.startsWith("file://")) {
52002
52437
  try {
52003
- path26 = fileURLToPath(path26);
52438
+ path27 = fileURLToPath(path27);
52004
52439
  } catch {
52005
52440
  return false;
52006
52441
  }
52007
52442
  }
52008
- return isAbsolute(path26) && !existsSync(path26);
52443
+ return isAbsolute(path27) && !existsSync(path27);
52009
52444
  }
52010
52445
  function stripQuotes(value) {
52011
52446
  const first = value[0];
@@ -86072,15 +86507,15 @@ var require_tools2 = __commonJS({
86072
86507
  * @param {String} path - Mailbox path to encode
86073
86508
  * @returns {String} Encoded mailbox path
86074
86509
  */
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)) {
86510
+ encodePath(connection, path27) {
86511
+ path27 = (path27 || "").toString();
86512
+ if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path27)) {
86078
86513
  try {
86079
- path26 = iconv.encode(path26, "utf-7-imap").toString();
86514
+ path27 = iconv.encode(path27, "utf-7-imap").toString();
86080
86515
  } catch {
86081
86516
  }
86082
86517
  }
86083
- return path26;
86518
+ return path27;
86084
86519
  },
86085
86520
  /**
86086
86521
  * Decodes a mailbox path from modified UTF-7 if the server does not support UTF8=ACCEPT.
@@ -86089,15 +86524,15 @@ var require_tools2 = __commonJS({
86089
86524
  * @param {String} path - Mailbox path to decode
86090
86525
  * @returns {String} Decoded mailbox path
86091
86526
  */
86092
- decodePath(connection, path26) {
86093
- path26 = (path26 || "").toString();
86094
- if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(path26)) {
86527
+ decodePath(connection, path27) {
86528
+ path27 = (path27 || "").toString();
86529
+ if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(path27)) {
86095
86530
  try {
86096
- path26 = iconv.decode(Buffer.from(path26), "utf-7-imap").toString();
86531
+ path27 = iconv.decode(Buffer.from(path27), "utf-7-imap").toString();
86097
86532
  } catch {
86098
86533
  }
86099
86534
  }
86100
- return path26;
86535
+ return path27;
86101
86536
  },
86102
86537
  /**
86103
86538
  * Normalizes a mailbox path by joining array segments with the namespace delimiter,
@@ -86108,17 +86543,17 @@ var require_tools2 = __commonJS({
86108
86543
  * @param {Boolean} [skipNamespace] - If true, skips prepending the namespace prefix
86109
86544
  * @returns {String} Normalized mailbox path
86110
86545
  */
86111
- normalizePath(connection, path26, skipNamespace) {
86112
- if (Array.isArray(path26)) {
86113
- path26 = path26.join(connection.namespace && connection.namespace.delimiter || "");
86546
+ normalizePath(connection, path27, skipNamespace) {
86547
+ if (Array.isArray(path27)) {
86548
+ path27 = path27.join(connection.namespace && connection.namespace.delimiter || "");
86114
86549
  }
86115
- if (path26.toUpperCase() === "INBOX") {
86550
+ if (path27.toUpperCase() === "INBOX") {
86116
86551
  return "INBOX";
86117
86552
  }
86118
- if (!skipNamespace && connection.namespace && connection.namespace.prefix && !path26.startsWith(connection.namespace.prefix)) {
86119
- path26 = connection.namespace.prefix + path26;
86553
+ if (!skipNamespace && connection.namespace && connection.namespace.prefix && !path27.startsWith(connection.namespace.prefix)) {
86554
+ path27 = connection.namespace.prefix + path27;
86120
86555
  }
86121
- return path26;
86556
+ return path27;
86122
86557
  },
86123
86558
  /**
86124
86559
  * Compares two mailbox paths for equality after normalization.
@@ -86449,14 +86884,14 @@ var require_tools2 = __commonJS({
86449
86884
  }
86450
86885
  }
86451
86886
  if (map.emailId || map.uid) {
86452
- let path26 = mailbox.path;
86453
- if (/[\u0080-\uffff]/.test(path26)) {
86887
+ let path27 = mailbox.path;
86888
+ if (/[\u0080-\uffff]/.test(path27)) {
86454
86889
  try {
86455
- path26 = iconv.encode(path26, "utf-7-imap").toString();
86890
+ path27 = iconv.encode(path27, "utf-7-imap").toString();
86456
86891
  } catch {
86457
86892
  }
86458
86893
  }
86459
- map.id = map.emailId || createHash2("md5").update([path26, mailbox.uidValidity?.toString() || "", map.uid.toString()].join(":")).digest("hex");
86894
+ map.id = map.emailId || createHash2("md5").update([path27, mailbox.uidValidity?.toString() || "", map.uid.toString()].join(":")).digest("hex");
86460
86895
  }
86461
86896
  if (map.flags) {
86462
86897
  let flagColor = tools.getFlagColor(map.flags);
@@ -86631,16 +87066,16 @@ var require_tools2 = __commonJS({
86631
87066
  * @returns {Object} Parsed body structure tree with part numbers, types, parameters, and child nodes
86632
87067
  */
86633
87068
  parseBodystructure(entry) {
86634
- let walk = (node, path26) => {
86635
- path26 = path26 || [];
87069
+ let walk = (node, path27) => {
87070
+ path27 = path27 || [];
86636
87071
  let curNode = {}, i = 0, part = 0;
86637
- if (path26.length) {
86638
- curNode.part = path26.join(".");
87072
+ if (path27.length) {
87073
+ curNode.part = path27.join(".");
86639
87074
  }
86640
87075
  if (Array.isArray(node[0])) {
86641
87076
  curNode.childNodes = [];
86642
87077
  while (Array.isArray(node[i])) {
86643
- curNode.childNodes.push(walk(node[i], path26.concat(++part)));
87078
+ curNode.childNodes.push(walk(node[i], path27.concat(++part)));
86644
87079
  i++;
86645
87080
  }
86646
87081
  curNode.type = "multipart/" + ((node[i++] || {}).value || "").toString().toLowerCase();
@@ -86683,7 +87118,7 @@ var require_tools2 = __commonJS({
86683
87118
  // the encapsulated message shares the part number with its wrapper.
86684
87119
  // Distinction is via suffixes: path.MIME = wrapper headers,
86685
87120
  // path.HEADER = encapsulated message headers.
86686
- walk(node[i], path26)
87121
+ walk(node[i], path27)
86687
87122
  ];
86688
87123
  }
86689
87124
  i++;
@@ -88645,14 +89080,14 @@ var require_select = __commonJS({
88645
89080
  // update into a silent no-op for the rest of the session.
88646
89081
  permanentflags: { key: "permanentFlags", parse: (value) => Array.isArray(value) && new Set(value) }
88647
89082
  });
88648
- module.exports = async (connection, path26, options) => {
89083
+ module.exports = async (connection, path27, options) => {
88649
89084
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
88650
89085
  return;
88651
89086
  }
88652
89087
  options = options || {};
88653
- path26 = normalizePath(connection, path26);
88654
- if (!connection.folders.has(path26)) {
88655
- let folders = await connection.run("LIST", "", path26);
89088
+ path27 = normalizePath(connection, path27);
89089
+ if (!connection.folders.has(path27)) {
89090
+ let folders = await connection.run("LIST", "", path27);
88656
89091
  if (!folders) {
88657
89092
  throw new Error("Failed to fetch folders");
88658
89093
  }
@@ -88660,10 +89095,10 @@ var require_select = __commonJS({
88660
89095
  connection.folders.set(folder.path, folder);
88661
89096
  });
88662
89097
  }
88663
- let folderListData = connection.folders.has(path26) ? connection.folders.get(path26) : false;
89098
+ let folderListData = connection.folders.has(path27) ? connection.folders.get(path27) : false;
88664
89099
  let response;
88665
89100
  try {
88666
- let map = { path: path26 };
89101
+ let map = { path: path27 };
88667
89102
  if (folderListData) {
88668
89103
  ["delimiter", "specialUse", "subscribed", "listed"].forEach((key) => {
88669
89104
  if (folderListData[key]) {
@@ -88682,7 +89117,7 @@ var require_select = __commonJS({
88682
89117
  ]);
88683
89118
  map.qresync = true;
88684
89119
  }
88685
- let encodedPath = encodePath(connection, path26);
89120
+ let encodedPath = encodePath(connection, path27);
88686
89121
  let selectCommand = {
88687
89122
  command: !options.readOnly ? "SELECT" : "EXAMINE",
88688
89123
  /* c8 ignore next */
@@ -88742,12 +89177,12 @@ var require_select = __commonJS({
88742
89177
  // since the client's last known state. Only received when QRESYNC was requested.
88743
89178
  // A dummy mailbox object is passed because the mailbox isn't officially open yet.
88744
89179
  VANISHED: async (untagged) => {
88745
- await connection.untaggedVanished(untagged, { path: path26, uidNext: false, uidValidity: false });
89180
+ await connection.untaggedVanished(untagged, { path: path27, uidNext: false, uidValidity: false });
88746
89181
  },
88747
89182
  // Untagged FETCH during SELECT/EXAMINE: only occurs with QRESYNC, delivering
88748
89183
  // updated flags for messages that changed since the client's last modseq.
88749
89184
  FETCH: async (untagged) => {
88750
- await connection.untaggedFetch(untagged, { path: path26, uidNext: false, uidValidity: false });
89185
+ await connection.untaggedFetch(untagged, { path: path27, uidNext: false, uidValidity: false });
88751
89186
  }
88752
89187
  }
88753
89188
  });
@@ -88761,13 +89196,13 @@ var require_select = __commonJS({
88761
89196
  }
88762
89197
  let currentMailbox = connection.mailbox;
88763
89198
  connection.mailbox = false;
88764
- if (currentMailbox && currentMailbox.path !== path26) {
89199
+ if (currentMailbox && currentMailbox.path !== path27) {
88765
89200
  connection.emit("mailboxClose", currentMailbox);
88766
89201
  }
88767
89202
  connection.mailbox = map;
88768
89203
  connection.currentSelectCommand = selectCommand;
88769
89204
  connection.state = connection.states.SELECTED;
88770
- if (!currentMailbox || currentMailbox.path !== path26) {
89205
+ if (!currentMailbox || currentMailbox.path !== path27) {
88771
89206
  connection.emit("mailboxOpen", connection.mailbox);
88772
89207
  }
88773
89208
  response.next();
@@ -88982,17 +89417,17 @@ var require_create = __commonJS({
88982
89417
  "node_modules/imapflow/lib/commands/create.js"(exports, module) {
88983
89418
  "use strict";
88984
89419
  var { encodePath, normalizePath, getStatusCode, enhanceCommandError } = require_tools2();
88985
- module.exports = async (connection, path26) => {
89420
+ module.exports = async (connection, path27) => {
88986
89421
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
88987
89422
  return;
88988
89423
  }
88989
- path26 = normalizePath(connection, path26);
89424
+ path27 = normalizePath(connection, path27);
88990
89425
  let response;
88991
89426
  try {
88992
89427
  let map = {
88993
- path: path26
89428
+ path: path27
88994
89429
  };
88995
- response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89430
+ response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
88996
89431
  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
89432
  if (section) {
88998
89433
  let key;
@@ -89018,13 +89453,13 @@ var require_create = __commonJS({
89018
89453
  }
89019
89454
  map.created = true;
89020
89455
  response.next();
89021
- await connection.run("SUBSCRIBE", path26);
89456
+ await connection.run("SUBSCRIBE", path27);
89022
89457
  return map;
89023
89458
  } catch (err) {
89024
89459
  let errorCode = getStatusCode(err.response);
89025
89460
  if (errorCode === "ALREADYEXISTS") {
89026
89461
  return {
89027
- path: path26,
89462
+ path: path27,
89028
89463
  created: false
89029
89464
  };
89030
89465
  }
@@ -89041,20 +89476,20 @@ var require_delete = __commonJS({
89041
89476
  "node_modules/imapflow/lib/commands/delete.js"(exports, module) {
89042
89477
  "use strict";
89043
89478
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89044
- module.exports = async (connection, path26) => {
89479
+ module.exports = async (connection, path27) => {
89045
89480
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89046
89481
  return;
89047
89482
  }
89048
- path26 = normalizePath(connection, path26);
89049
- if (connection.state === connection.states.SELECTED && connection.mailbox.path === path26) {
89483
+ path27 = normalizePath(connection, path27);
89484
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
89050
89485
  await connection.run("CLOSE");
89051
89486
  }
89052
89487
  let response;
89053
89488
  try {
89054
89489
  let map = {
89055
- path: path26
89490
+ path: path27
89056
89491
  };
89057
- response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89492
+ response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89058
89493
  response.next();
89059
89494
  return map;
89060
89495
  } catch (err) {
@@ -89071,23 +89506,23 @@ var require_rename = __commonJS({
89071
89506
  "node_modules/imapflow/lib/commands/rename.js"(exports, module) {
89072
89507
  "use strict";
89073
89508
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89074
- module.exports = async (connection, path26, newPath) => {
89509
+ module.exports = async (connection, path27, newPath) => {
89075
89510
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89076
89511
  return;
89077
89512
  }
89078
- path26 = normalizePath(connection, path26);
89513
+ path27 = normalizePath(connection, path27);
89079
89514
  newPath = normalizePath(connection, newPath);
89080
- if (connection.state === connection.states.SELECTED && connection.mailbox.path === path26) {
89515
+ if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
89081
89516
  await connection.run("CLOSE");
89082
89517
  }
89083
89518
  let response;
89084
89519
  try {
89085
89520
  let map = {
89086
- path: path26,
89521
+ path: path27,
89087
89522
  newPath
89088
89523
  };
89089
89524
  response = await connection.exec("RENAME", [
89090
- { type: "ATOM", value: encodePath(connection, path26) },
89525
+ { type: "ATOM", value: encodePath(connection, path27) },
89091
89526
  { type: "ATOM", value: encodePath(connection, newPath) }
89092
89527
  ]);
89093
89528
  response.next();
@@ -89134,14 +89569,14 @@ var require_subscribe = __commonJS({
89134
89569
  "node_modules/imapflow/lib/commands/subscribe.js"(exports, module) {
89135
89570
  "use strict";
89136
89571
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89137
- module.exports = async (connection, path26) => {
89572
+ module.exports = async (connection, path27) => {
89138
89573
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89139
89574
  return;
89140
89575
  }
89141
- path26 = normalizePath(connection, path26);
89576
+ path27 = normalizePath(connection, path27);
89142
89577
  let response;
89143
89578
  try {
89144
- response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89579
+ response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89145
89580
  response.next();
89146
89581
  return true;
89147
89582
  } catch (err) {
@@ -89158,14 +89593,14 @@ var require_unsubscribe = __commonJS({
89158
89593
  "node_modules/imapflow/lib/commands/unsubscribe.js"(exports, module) {
89159
89594
  "use strict";
89160
89595
  var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
89161
- module.exports = async (connection, path26) => {
89596
+ module.exports = async (connection, path27) => {
89162
89597
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
89163
89598
  return;
89164
89599
  }
89165
- path26 = normalizePath(connection, path26);
89600
+ path27 = normalizePath(connection, path27);
89166
89601
  let response;
89167
89602
  try {
89168
- response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path26) }]);
89603
+ response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
89169
89604
  response.next();
89170
89605
  return true;
89171
89606
  } catch (err) {
@@ -89971,11 +90406,11 @@ var require_status = __commonJS({
89971
90406
  var { encodePath, normalizePath, buildStatusQueryAttributes, isRev2Active } = require_tools2();
89972
90407
  var { parseStatusList } = require_status_fields();
89973
90408
  var MAILBOX_UPDATERS = {
89974
- messages: (value, connection, path26) => {
90409
+ messages: (value, connection, path27) => {
89975
90410
  let prevCount = connection.mailbox.exists;
89976
90411
  if (prevCount !== value) {
89977
90412
  connection.mailbox.exists = value;
89978
- connection.emit("exists", { path: path26, count: value, prevCount });
90413
+ connection.emit("exists", { path: path27, count: value, prevCount });
89979
90414
  }
89980
90415
  },
89981
90416
  uidNext: (value, connection) => {
@@ -89985,28 +90420,28 @@ var require_status = __commonJS({
89985
90420
  connection.mailbox.highestModseq = value;
89986
90421
  }
89987
90422
  };
89988
- module.exports = async (connection, path26, query) => {
89989
- if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path26) {
90423
+ module.exports = async (connection, path27, query) => {
90424
+ if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
89990
90425
  return false;
89991
90426
  }
89992
- path26 = normalizePath(connection, path26);
89993
- let encodedPath = encodePath(connection, path26);
90427
+ path27 = normalizePath(connection, path27);
90428
+ let encodedPath = encodePath(connection, path27);
89994
90429
  let attributes = [{ type: encodedPath.indexOf("&") >= 0 ? "STRING" : "ATOM", value: encodedPath }];
89995
90430
  let queryAttributes = buildStatusQueryAttributes(connection, query);
89996
90431
  let syntheticRecent = query && query.recent && isRev2Active(connection);
89997
90432
  if (!queryAttributes.length) {
89998
- return syntheticRecent ? { path: path26, recent: 0 } : false;
90433
+ return syntheticRecent ? { path: path27, recent: 0 } : false;
89999
90434
  }
90000
90435
  attributes.push(queryAttributes);
90001
90436
  let response;
90002
90437
  try {
90003
- let map = { path: path26 };
90438
+ let map = { path: path27 };
90004
90439
  response = await connection.exec("STATUS", attributes, {
90005
90440
  untagged: {
90006
90441
  // STATUS response: * STATUS <mailbox> (<key> <value> <key> <value> ...)
90007
90442
  // Parsed as alternating key-value pairs (i % 2 pattern).
90008
90443
  STATUS: async (untagged) => {
90009
- let updateCurrent = connection.state === connection.states.SELECTED && path26 === connection.mailbox.path;
90444
+ let updateCurrent = connection.state === connection.states.SELECTED && path27 === connection.mailbox.path;
90010
90445
  let list = untagged.attributes && Array.isArray(untagged.attributes[1]) ? untagged.attributes[1] : false;
90011
90446
  if (!list) {
90012
90447
  return;
@@ -90014,7 +90449,7 @@ var require_status = __commonJS({
90014
90449
  parseStatusList(list, (key, value) => {
90015
90450
  map[key] = value;
90016
90451
  if (updateCurrent && MAILBOX_UPDATERS[key]) {
90017
- MAILBOX_UPDATERS[key](value, connection, path26);
90452
+ MAILBOX_UPDATERS[key](value, connection, path27);
90018
90453
  }
90019
90454
  });
90020
90455
  }
@@ -90027,9 +90462,9 @@ var require_status = __commonJS({
90027
90462
  return map;
90028
90463
  } catch (err) {
90029
90464
  if (err.responseStatus === "NO") {
90030
- let folders = await connection.run("LIST", "", path26, { listOnly: true });
90465
+ let folders = await connection.run("LIST", "", path27, { listOnly: true });
90031
90466
  if (folders && !folders.length) {
90032
- let error2 = new Error(`Mailbox doesn't exist: ${path26}`);
90467
+ let error2 = new Error(`Mailbox doesn't exist: ${path27}`);
90033
90468
  error2.code = "NotFound";
90034
90469
  error2.response = err;
90035
90470
  throw error2;
@@ -90176,15 +90611,15 @@ var require_quota = __commonJS({
90176
90611
  "node_modules/imapflow/lib/commands/quota.js"(exports, module) {
90177
90612
  "use strict";
90178
90613
  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) {
90614
+ module.exports = async (connection, path27) => {
90615
+ if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
90181
90616
  return;
90182
90617
  }
90183
90618
  if (!connection.capabilities.has("QUOTA")) {
90184
90619
  return false;
90185
90620
  }
90186
- path26 = normalizePath(connection, path26);
90187
- let map = { path: path26 };
90621
+ path27 = normalizePath(connection, path27);
90622
+ let map = { path: path27 };
90188
90623
  let processQuotaResponse = (untagged) => {
90189
90624
  let attributes = untagged.attributes && untagged.attributes[1];
90190
90625
  if (!attributes || !attributes.length) {
@@ -90224,7 +90659,7 @@ var require_quota = __commonJS({
90224
90659
  let quotaFound = false;
90225
90660
  let response;
90226
90661
  try {
90227
- response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection, path26) }], {
90662
+ response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection, path27) }], {
90228
90663
  untagged: {
90229
90664
  // QUOTAROOT response tells us which quota root applies to this mailbox.
90230
90665
  // A mailbox may have zero or one quota root.
@@ -90367,15 +90802,15 @@ var require_idle = __commonJS({
90367
90802
  }
90368
90803
  }
90369
90804
  async function pollOnce2(connection, session) {
90370
- let path26 = connection.mailbox && connection.mailbox.path;
90805
+ let path27 = connection.mailbox && connection.mailbox.path;
90371
90806
  switch (connection.missingIdleCommand) {
90372
90807
  case "SELECT":
90373
90808
  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" });
90809
+ await connection.runInternal("SELECT", path27, { readOnly: session.selectCommand.command === "EXAMINE" });
90375
90810
  break;
90376
90811
  case "STATUS": {
90377
90812
  connection.log.debug({ src: "c", msg: `Running STATUS to detect changes in folder`, cid: connection.id });
90378
- let status = await connection.runInternal("STATUS", path26, {
90813
+ let status = await connection.runInternal("STATUS", path27, {
90379
90814
  messages: true,
90380
90815
  uidNext: true,
90381
90816
  uidValidity: true,
@@ -92062,12 +92497,12 @@ var require_imap_flow = __commonJS({
92062
92497
  this.emit("flags", updateEvent);
92063
92498
  }
92064
92499
  }
92065
- async ensureSelectedMailbox(path26) {
92066
- if (!path26) {
92500
+ async ensureSelectedMailbox(path27) {
92501
+ if (!path27) {
92067
92502
  return false;
92068
92503
  }
92069
- if (!this.mailbox || !comparePaths(this, this.mailbox.path, path26)) {
92070
- return await this.mailboxOpen(path26);
92504
+ if (!this.mailbox || !comparePaths(this, this.mailbox.path, path27)) {
92505
+ return await this.mailboxOpen(path27);
92071
92506
  }
92072
92507
  return true;
92073
92508
  }
@@ -92482,9 +92917,9 @@ var require_imap_flow = __commonJS({
92482
92917
  * let quota = await client.getQuota();
92483
92918
  * console.log(quota.storage.used, quota.storage.limit)
92484
92919
  */
92485
- async getQuota(path26) {
92486
- path26 = path26 || "INBOX";
92487
- return await this.run("QUOTA", path26);
92920
+ async getQuota(path27) {
92921
+ path27 = path27 || "INBOX";
92922
+ return await this.run("QUOTA", path27);
92488
92923
  }
92489
92924
  /**
92490
92925
  * @typedef {Object} ListResponse
@@ -92594,8 +93029,8 @@ var require_imap_flow = __commonJS({
92594
93029
  * console.log(info.path);
92595
93030
  * // "INBOX.parent.child" // assumes "INBOX." as namespace prefix and "." as delimiter
92596
93031
  */
92597
- async mailboxCreate(path26) {
92598
- return await this.run("CREATE", path26);
93032
+ async mailboxCreate(path27) {
93033
+ return await this.run("CREATE", path27);
92599
93034
  }
92600
93035
  /**
92601
93036
  * @typedef {Object} MailboxRenameResponse
@@ -92616,8 +93051,8 @@ var require_imap_flow = __commonJS({
92616
93051
  * console.log(info.newPath);
92617
93052
  * // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
92618
93053
  */
92619
- async mailboxRename(path26, newPath) {
92620
- return await this.run("RENAME", path26, newPath);
93054
+ async mailboxRename(path27, newPath) {
93055
+ return await this.run("RENAME", path27, newPath);
92621
93056
  }
92622
93057
  /**
92623
93058
  * @typedef {Object} MailboxDeleteResponse
@@ -92636,8 +93071,8 @@ var require_imap_flow = __commonJS({
92636
93071
  * console.log(info.path);
92637
93072
  * // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
92638
93073
  */
92639
- async mailboxDelete(path26) {
92640
- return await this.run("DELETE", path26);
93074
+ async mailboxDelete(path27) {
93075
+ return await this.run("DELETE", path27);
92641
93076
  }
92642
93077
  /**
92643
93078
  * Subscribes to a mailbox
@@ -92648,8 +93083,8 @@ var require_imap_flow = __commonJS({
92648
93083
  * @example
92649
93084
  * await client.mailboxSubscribe('Important stuff ❗️');
92650
93085
  */
92651
- async mailboxSubscribe(path26) {
92652
- return await this.run("SUBSCRIBE", path26);
93086
+ async mailboxSubscribe(path27) {
93087
+ return await this.run("SUBSCRIBE", path27);
92653
93088
  }
92654
93089
  /**
92655
93090
  * Unsubscribes from a mailbox
@@ -92660,8 +93095,8 @@ var require_imap_flow = __commonJS({
92660
93095
  * @example
92661
93096
  * await client.mailboxUnsubscribe('Important stuff ❗️');
92662
93097
  */
92663
- async mailboxUnsubscribe(path26) {
92664
- return await this.run("UNSUBSCRIBE", path26);
93098
+ async mailboxUnsubscribe(path27) {
93099
+ return await this.run("UNSUBSCRIBE", path27);
92665
93100
  }
92666
93101
  /**
92667
93102
  * Opens a mailbox to access messages. You can perform message operations only against an opened mailbox.
@@ -92679,8 +93114,8 @@ var require_imap_flow = __commonJS({
92679
93114
  * console.log(mailbox.exists);
92680
93115
  * // 125
92681
93116
  */
92682
- async mailboxOpen(path26, options) {
92683
- return await this.run("SELECT", path26, options);
93117
+ async mailboxOpen(path27, options) {
93118
+ return await this.run("SELECT", path27, options);
92684
93119
  }
92685
93120
  /**
92686
93121
  * Closes a previously opened mailbox
@@ -92727,8 +93162,8 @@ var require_imap_flow = __commonJS({
92727
93162
  * console.log(status.unseen);
92728
93163
  * // 123
92729
93164
  */
92730
- async status(path26, query) {
92731
- return await this.run("STATUS", path26, query);
93165
+ async status(path27, query) {
93166
+ return await this.run("STATUS", path27, query);
92732
93167
  }
92733
93168
  /**
92734
93169
  * Starts listening for new or deleted messages from the currently opened mailbox. Only required if {@link ImapFlow#disableAutoIdle} is set to `true`
@@ -92982,8 +93417,8 @@ var require_imap_flow = __commonJS({
92982
93417
  * @example
92983
93418
  * await client.append('INBOX', rawMessageBuffer, ['\\Seen'], new Date(2000, 1, 1));
92984
93419
  */
92985
- async append(path26, content, flags, idate) {
92986
- return await this.run("APPEND", path26, content, flags, idate) || false;
93420
+ async append(path27, content, flags, idate) {
93421
+ return await this.run("APPEND", path27, content, flags, idate) || false;
92987
93422
  }
92988
93423
  /**
92989
93424
  * @typedef {Object} CopyResponseObject
@@ -93827,7 +94262,7 @@ var require_imap_flow = __commonJS({
93827
94262
  await new Promise((resolve2) => setImmediate(resolve2));
93828
94263
  }
93829
94264
  const lock = this.locks.shift();
93830
- const { resolve, reject, path: path26, options, lockId } = lock;
94265
+ const { resolve, reject, path: path27, options, lockId } = lock;
93831
94266
  if (lock.acquireTimer) {
93832
94267
  clearTimeout(lock.acquireTimer);
93833
94268
  lock.acquireTimer = null;
@@ -93843,7 +94278,7 @@ var require_imap_flow = __commonJS({
93843
94278
  this.log.warn({
93844
94279
  msg: "Mailbox lock held for a long time",
93845
94280
  lockId: lock.lockId,
93846
- path: path26,
94281
+ path: path27,
93847
94282
  heldFor: Date.now() - lock.heldAt,
93848
94283
  /* c8 ignore next */
93849
94284
  // the held-lock-warning diagnostic with a description set is a timing-dependent log detail
@@ -93879,52 +94314,52 @@ var require_imap_flow = __commonJS({
93879
94314
  }
93880
94315
  };
93881
94316
  if (!this.usable || !this.socket || this.socket.destroyed) {
93882
- this.log.trace({ msg: "Failed to acquire mailbox lock", path: path26, lockId, idling: this.idling });
94317
+ this.log.trace({ msg: "Failed to acquire mailbox lock", path: path27, lockId, idling: this.idling });
93883
94318
  let error2 = new Error("Connection not available");
93884
94319
  error2.code = "NoConnection";
93885
94320
  reject(error2);
93886
94321
  continue;
93887
94322
  }
93888
- if (this.mailbox && this.mailbox.path === path26 && !!this.mailbox.readOnly === !!options.readOnly) {
94323
+ if (this.mailbox && this.mailbox.path === path27 && !!this.mailbox.readOnly === !!options.readOnly) {
93889
94324
  this.log.trace({
93890
94325
  msg: "Mailbox lock acquired [existing]",
93891
- path: path26,
94326
+ path: path27,
93892
94327
  lockId,
93893
94328
  idling: this.idling,
93894
94329
  ...options.description && { description: options.description }
93895
94330
  });
93896
94331
  this.currentLock = lock;
93897
94332
  armHeldTimer();
93898
- resolve({ path: path26, release });
94333
+ resolve({ path: path27, release });
93899
94334
  break;
93900
94335
  }
93901
94336
  try {
93902
- await this.mailboxOpen(path26, options);
94337
+ await this.mailboxOpen(path27, options);
93903
94338
  this.log.trace({
93904
94339
  msg: "Mailbox lock acquired [selected]",
93905
- path: path26,
94340
+ path: path27,
93906
94341
  lockId,
93907
94342
  idling: this.idling,
93908
94343
  ...options.description && { description: options.description }
93909
94344
  });
93910
94345
  this.currentLock = lock;
93911
94346
  armHeldTimer();
93912
- resolve({ path: path26, release });
94347
+ resolve({ path: path27, release });
93913
94348
  break;
93914
94349
  } catch (err) {
93915
94350
  if (err.responseStatus === "NO") {
93916
94351
  try {
93917
- let folders = await this.run("LIST", "", path26, { listOnly: true });
94352
+ let folders = await this.run("LIST", "", path27, { listOnly: true });
93918
94353
  if (!folders || !folders.length) {
93919
94354
  err.mailboxMissing = true;
93920
94355
  }
93921
94356
  } catch (E) {
93922
- this.log.trace({ msg: "Failed to verify failed mailbox", path: path26, err: E });
94357
+ this.log.trace({ msg: "Failed to verify failed mailbox", path: path27, err: E });
93923
94358
  }
93924
94359
  }
93925
94360
  this.log.trace({
93926
94361
  msg: "Failed to acquire mailbox lock",
93927
- path: path26,
94362
+ path: path27,
93928
94363
  lockId,
93929
94364
  idling: this.idling,
93930
94365
  ...options.description && { description: options.description },
@@ -93963,13 +94398,13 @@ var require_imap_flow = __commonJS({
93963
94398
  * lock.release();
93964
94399
  * }
93965
94400
  */
93966
- getMailboxLock(path26, options) {
94401
+ getMailboxLock(path27, options) {
93967
94402
  options = options || {};
93968
- path26 = normalizePath(this, path26);
94403
+ path27 = normalizePath(this, path27);
93969
94404
  let lockId = ++this.lockCounter;
93970
94405
  this.log.trace({
93971
94406
  msg: "Requesting lock",
93972
- path: path26,
94407
+ path: path27,
93973
94408
  lockId,
93974
94409
  ...options.description && { description: options.description },
93975
94410
  activeLock: this.currentLock ? {
@@ -93978,7 +94413,7 @@ var require_imap_flow = __commonJS({
93978
94413
  } : null
93979
94414
  });
93980
94415
  let lockPromise = new Promise((resolve, reject) => {
93981
- let lockEntry = { resolve, reject, path: path26, options, lockId };
94416
+ let lockEntry = { resolve, reject, path: path27, options, lockId };
93982
94417
  this.locks.push(lockEntry);
93983
94418
  if (Number(options.acquireTimeout) > 0) {
93984
94419
  lockEntry.acquireTimer = setTimeout(() => {
@@ -94067,16 +94502,16 @@ var require_imap_flow = __commonJS({
94067
94502
  });
94068
94503
 
94069
94504
  // src/mail/mail-fetcher.ts
94070
- import fs23 from "node:fs/promises";
94071
- import path24 from "node:path";
94505
+ import fs24 from "node:fs/promises";
94506
+ import path25 from "node:path";
94072
94507
  async function saveAttachments(attachments, downloadDir) {
94073
94508
  if (attachments.length === 0) return [];
94074
- await fs23.mkdir(downloadDir, { recursive: true });
94509
+ await fs24.mkdir(downloadDir, { recursive: true });
94075
94510
  const saved = [];
94076
94511
  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);
94512
+ const name = path25.basename(a.filename) || "attachment";
94513
+ const savedPath = path25.join(downloadDir, name);
94514
+ await fs24.writeFile(savedPath, a.content);
94080
94515
  saved.push({ filename: name, savedPath, size: a.content.length });
94081
94516
  }
94082
94517
  return saved;
@@ -94207,7 +94642,7 @@ var init_mail_fetcher = __esm({
94207
94642
 
94208
94643
  // src/tools/fetch-mail.ts
94209
94644
  import os17 from "node:os";
94210
- import path25 from "node:path";
94645
+ import path26 from "node:path";
94211
94646
  function registerFetchMailTool(server, deps = {}) {
94212
94647
  const makeFetcher = deps.fetcherFactory ?? ((creds) => new ImapflowMailFetcher(creds));
94213
94648
  server.registerTool(
@@ -94269,7 +94704,7 @@ var init_fetch_mail = __esm({
94269
94704
  init_mail_fetcher();
94270
94705
  init_auth_error();
94271
94706
  init_validate();
94272
- DEFAULT_DOWNLOAD_DIR = path25.join(os17.homedir(), ".cogent", "mail-downloads");
94707
+ DEFAULT_DOWNLOAD_DIR = path26.join(os17.homedir(), ".cogent", "mail-downloads");
94273
94708
  }
94274
94709
  });
94275
94710
 
@@ -94360,9 +94795,74 @@ var init_rotate_mail_creds = __esm({
94360
94795
 
94361
94796
  // src/index.ts
94362
94797
  var index_exports = {};
94798
+ function shutdown(reason) {
94799
+ if (shuttingDown) return;
94800
+ shuttingDown = true;
94801
+ try {
94802
+ logger.info(`Shutting down: ${reason}`);
94803
+ autoRelay.stop();
94804
+ withdrawBridge(process.cwd(), PROCESS_MARK);
94805
+ heartbeat.stop();
94806
+ if (cloudWsClient) {
94807
+ cloudWsClient.disconnect();
94808
+ }
94809
+ logger.close();
94810
+ } finally {
94811
+ process.exit(0);
94812
+ }
94813
+ }
94814
+ async function clientGone(reason) {
94815
+ if (draining || shuttingDown) return;
94816
+ draining = true;
94817
+ autoRelay.announceDraining();
94818
+ const busy = () => {
94819
+ const d = autoRelay.getDiagnostics();
94820
+ return { requests: stdoutDead ? [] : [...inFlightRequests.values()], wake: d.processing, queued: d.queueLength };
94821
+ };
94822
+ const b0 = busy();
94823
+ if (!b0.requests.length && !b0.wake && !b0.queued) return shutdown(reason);
94824
+ let capMs = drainCapMs(3e5);
94825
+ try {
94826
+ capMs = drainCapMs(getConfig().COGENT_TIMEOUT_MS);
94827
+ } catch {
94828
+ }
94829
+ logger.info(
94830
+ `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}`
94831
+ );
94832
+ cancelPresenceRetry();
94833
+ heartbeat.stop();
94834
+ cloudWsClient?.disconnect();
94835
+ const t0 = Date.now();
94836
+ let b = b0;
94837
+ while (Date.now() - t0 < capMs) {
94838
+ b = busy();
94839
+ if (!b.requests.length && !b.wake && !b.queued) break;
94840
+ await new Promise((r) => setTimeout(r, 50));
94841
+ }
94842
+ if (!stdoutDead) {
94843
+ await new Promise((r) => {
94844
+ const t = setTimeout(r, 1e3);
94845
+ try {
94846
+ process.stdout.write("", () => {
94847
+ clearTimeout(t);
94848
+ r();
94849
+ });
94850
+ } catch {
94851
+ clearTimeout(t);
94852
+ r();
94853
+ }
94854
+ });
94855
+ }
94856
+ const left = b.requests.length || b.wake || b.queued;
94857
+ const undeliverable = stdoutDead && inFlightRequests.size ? ` (${inFlightRequests.size} MCP response(s) undeliverable: stdout closed)` : "";
94858
+ shutdown(
94859
+ 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}`
94860
+ );
94861
+ }
94363
94862
  async function main() {
94863
+ markBridgeProcess(process.cwd(), SERVER_VERSION);
94364
94864
  await runStartup();
94365
- const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
94865
+ const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, { instructions: SERVER_INSTRUCTIONS });
94366
94866
  registerRegisterPeerTool(server);
94367
94867
  registerDeregisterPeerTool(server);
94368
94868
  registerSendMessageTool(server);
@@ -94407,7 +94907,31 @@ async function main() {
94407
94907
  });
94408
94908
  }
94409
94909
  const transport = new StdioServerTransport();
94910
+ transport.onclose = () => void clientGone("MCP transport closed");
94410
94911
  await server.connect(transport);
94912
+ const sdkOnMessage = transport.onmessage;
94913
+ transport.onmessage = (msg) => {
94914
+ if ("method" in msg && "id" in msg) {
94915
+ const tool = msg.method === "tools/call" ? msg.params?.name : void 0;
94916
+ inFlightRequests.set(msg.id, typeof tool === "string" ? `tools/call ${tool}` : msg.method);
94917
+ } else if ("method" in msg && msg.method === "notifications/cancelled") {
94918
+ const id = msg.params?.requestId;
94919
+ if (typeof id === "string" || typeof id === "number") inFlightRequests.delete(id);
94920
+ }
94921
+ sdkOnMessage?.(msg);
94922
+ };
94923
+ const sdkSend = transport.send.bind(transport);
94924
+ transport.send = (msg) => {
94925
+ const settles = !("method" in msg) && "id" in msg ? msg.id : void 0;
94926
+ return sdkSend(msg).finally(() => {
94927
+ if (settles !== void 0) inFlightRequests.delete(settles);
94928
+ });
94929
+ };
94930
+ const stdinIsDevice = startedWithoutClient();
94931
+ if (!process.stdin.isTTY && !stdinIsDevice) {
94932
+ process.stdin.once("end", () => void clientGone("stdin EOF \u2014 the MCP client is gone"));
94933
+ process.stdin.once("close", () => void clientGone("stdin closed \u2014 the MCP client is gone"));
94934
+ }
94411
94935
  process.stderr.write(
94412
94936
  `${SERVER_NAME} v${SERVER_VERSION} running on stdio
94413
94937
  `
@@ -94432,14 +94956,17 @@ async function main() {
94432
94956
  "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
94957
  );
94434
94958
  }
94959
+ var shuttingDown, draining, stdoutDead, inFlightRequests;
94435
94960
  var init_index = __esm({
94436
94961
  "src/index.ts"() {
94437
94962
  "use strict";
94438
94963
  init_mcp();
94439
94964
  init_stdio2();
94440
94965
  init_constants();
94966
+ init_instructions();
94441
94967
  init_npm_update_check();
94442
94968
  init_startup();
94969
+ init_config();
94443
94970
  init_logger();
94444
94971
  init_register_peer();
94445
94972
  init_send_message();
@@ -94455,10 +94982,12 @@ var init_index = __esm({
94455
94982
  init_fetch_mail();
94456
94983
  init_rotate_mail_creds();
94457
94984
  init_heartbeat();
94985
+ init_wake_inflight();
94986
+ init_wake_ownership();
94458
94987
  process.on("uncaughtException", (err) => {
94459
94988
  if (err.code === "EPIPE") {
94460
- logger.close();
94461
- process.exit(0);
94989
+ stdoutDead = true;
94990
+ void clientGone("stdout EPIPE \u2014 the MCP client is gone");
94462
94991
  return;
94463
94992
  }
94464
94993
  logger.error(`Uncaught exception: ${err.message}`, { stack: err.stack });
@@ -94467,26 +94996,12 @@ var init_index = __esm({
94467
94996
  const msg = reason instanceof Error ? reason.message : String(reason);
94468
94997
  logger.error(`Unhandled rejection: ${msg}`);
94469
94998
  });
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
- });
94999
+ shuttingDown = false;
95000
+ draining = false;
95001
+ stdoutDead = false;
95002
+ process.on("SIGTERM", () => shutdown("SIGTERM received"));
95003
+ process.on("SIGINT", () => shutdown("SIGINT received"));
95004
+ inFlightRequests = /* @__PURE__ */ new Map();
94490
95005
  main().catch((err) => {
94491
95006
  const msg = err instanceof Error ? err.message : String(err);
94492
95007
  logger.error(`Fatal startup error: ${msg}`);