@essentialai/cogent-plugin 3.25.5 → 3.25.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/bridge/cogent-bridge.mjs +967 -382
- package/commands/register.md +44 -32
- package/package.json +1 -1
- package/skills/bridge-setup/SKILL.md +17 -6
package/bridge/cogent-bridge.mjs
CHANGED
|
@@ -625,6 +625,20 @@ function hasJoinedInProcess() {
|
|
|
625
625
|
function markCloudAttemptInProcess() {
|
|
626
626
|
cloudAttemptInProcessFlag = true;
|
|
627
627
|
joinedInProcessFlag = false;
|
|
628
|
+
cloudAttemptGeneration++;
|
|
629
|
+
for (const fn of cloudAttemptListeners) {
|
|
630
|
+
try {
|
|
631
|
+
fn();
|
|
632
|
+
} catch {
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function getCloudAttemptGeneration() {
|
|
637
|
+
return cloudAttemptGeneration;
|
|
638
|
+
}
|
|
639
|
+
function onCloudAttemptInProcess(fn) {
|
|
640
|
+
cloudAttemptListeners.add(fn);
|
|
641
|
+
return () => cloudAttemptListeners.delete(fn);
|
|
628
642
|
}
|
|
629
643
|
function hasCloudAttemptInProcess() {
|
|
630
644
|
return cloudAttemptInProcessFlag;
|
|
@@ -662,7 +676,7 @@ async function legacyGlobalCredentialsExist() {
|
|
|
662
676
|
return false;
|
|
663
677
|
}
|
|
664
678
|
}
|
|
665
|
-
var LEGACY_GLOBAL_CREDENTIAL_PATH, joinedInProcessFlag, cloudAttemptInProcessFlag;
|
|
679
|
+
var LEGACY_GLOBAL_CREDENTIAL_PATH, joinedInProcessFlag, cloudAttemptInProcessFlag, cloudAttemptGeneration, cloudAttemptListeners;
|
|
666
680
|
var init_credential_store = __esm({
|
|
667
681
|
"src/cloud/credential-store.ts"() {
|
|
668
682
|
"use strict";
|
|
@@ -672,6 +686,8 @@ var init_credential_store = __esm({
|
|
|
672
686
|
);
|
|
673
687
|
joinedInProcessFlag = false;
|
|
674
688
|
cloudAttemptInProcessFlag = false;
|
|
689
|
+
cloudAttemptGeneration = 0;
|
|
690
|
+
cloudAttemptListeners = /* @__PURE__ */ new Set();
|
|
675
691
|
}
|
|
676
692
|
});
|
|
677
693
|
|
|
@@ -1266,8 +1282,8 @@ var init_parseUtil = __esm({
|
|
|
1266
1282
|
init_errors();
|
|
1267
1283
|
init_en();
|
|
1268
1284
|
makeIssue = (params) => {
|
|
1269
|
-
const { data, path:
|
|
1270
|
-
const fullPath = [...
|
|
1285
|
+
const { data, path: path27, errorMaps, issueData } = params;
|
|
1286
|
+
const fullPath = [...path27, ...issueData.path || []];
|
|
1271
1287
|
const fullIssue = {
|
|
1272
1288
|
...issueData,
|
|
1273
1289
|
path: fullPath
|
|
@@ -1547,11 +1563,11 @@ var init_types = __esm({
|
|
|
1547
1563
|
init_parseUtil();
|
|
1548
1564
|
init_util();
|
|
1549
1565
|
ParseInputLazyPath = class {
|
|
1550
|
-
constructor(parent, value,
|
|
1566
|
+
constructor(parent, value, path27, key) {
|
|
1551
1567
|
this._cachedPath = [];
|
|
1552
1568
|
this.parent = parent;
|
|
1553
1569
|
this.data = value;
|
|
1554
|
-
this._path =
|
|
1570
|
+
this._path = path27;
|
|
1555
1571
|
this._key = key;
|
|
1556
1572
|
}
|
|
1557
1573
|
get path() {
|
|
@@ -5003,10 +5019,10 @@ function assignProp(target, prop, value) {
|
|
|
5003
5019
|
configurable: true
|
|
5004
5020
|
});
|
|
5005
5021
|
}
|
|
5006
|
-
function getElementAtPath(obj,
|
|
5007
|
-
if (!
|
|
5022
|
+
function getElementAtPath(obj, path27) {
|
|
5023
|
+
if (!path27)
|
|
5008
5024
|
return obj;
|
|
5009
|
-
return
|
|
5025
|
+
return path27.reduce((acc, key) => acc?.[key], obj);
|
|
5010
5026
|
}
|
|
5011
5027
|
function promiseAllObject(promisesObj) {
|
|
5012
5028
|
const keys = Object.keys(promisesObj);
|
|
@@ -5255,11 +5271,11 @@ function aborted(x, startIndex = 0) {
|
|
|
5255
5271
|
}
|
|
5256
5272
|
return false;
|
|
5257
5273
|
}
|
|
5258
|
-
function prefixIssues(
|
|
5274
|
+
function prefixIssues(path27, issues) {
|
|
5259
5275
|
return issues.map((iss) => {
|
|
5260
5276
|
var _a;
|
|
5261
5277
|
(_a = iss).path ?? (_a.path = []);
|
|
5262
|
-
iss.path.unshift(
|
|
5278
|
+
iss.path.unshift(path27);
|
|
5263
5279
|
return iss;
|
|
5264
5280
|
});
|
|
5265
5281
|
}
|
|
@@ -17065,8 +17081,8 @@ var require_utils = __commonJS({
|
|
|
17065
17081
|
}
|
|
17066
17082
|
return ind;
|
|
17067
17083
|
}
|
|
17068
|
-
function removeDotSegments(
|
|
17069
|
-
let input =
|
|
17084
|
+
function removeDotSegments(path27) {
|
|
17085
|
+
let input = path27;
|
|
17070
17086
|
const output = [];
|
|
17071
17087
|
let nextSlash = -1;
|
|
17072
17088
|
let len = 0;
|
|
@@ -17265,8 +17281,8 @@ var require_schemes = __commonJS({
|
|
|
17265
17281
|
wsComponent.secure = void 0;
|
|
17266
17282
|
}
|
|
17267
17283
|
if (wsComponent.resourceName) {
|
|
17268
|
-
const [
|
|
17269
|
-
wsComponent.path =
|
|
17284
|
+
const [path27, query] = wsComponent.resourceName.split("?");
|
|
17285
|
+
wsComponent.path = path27 && path27 !== "/" ? path27 : void 0;
|
|
17270
17286
|
wsComponent.query = query;
|
|
17271
17287
|
wsComponent.resourceName = void 0;
|
|
17272
17288
|
}
|
|
@@ -20619,12 +20635,12 @@ var require_dist = __commonJS({
|
|
|
20619
20635
|
throw new Error(`Unknown format "${name}"`);
|
|
20620
20636
|
return f;
|
|
20621
20637
|
};
|
|
20622
|
-
function addFormats(ajv, list,
|
|
20638
|
+
function addFormats(ajv, list, fs25, exportName) {
|
|
20623
20639
|
var _a;
|
|
20624
20640
|
var _b;
|
|
20625
20641
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
20626
20642
|
for (const f of list)
|
|
20627
|
-
ajv.addFormat(f,
|
|
20643
|
+
ajv.addFormat(f, fs25[f]);
|
|
20628
20644
|
}
|
|
20629
20645
|
module.exports = exports = formatsPlugin;
|
|
20630
20646
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -21736,8 +21752,8 @@ var require_parseUtil = __commonJS({
|
|
|
21736
21752
|
var errors_js_1 = require_errors2();
|
|
21737
21753
|
var en_js_1 = __importDefault(require_en());
|
|
21738
21754
|
var makeIssue2 = (params) => {
|
|
21739
|
-
const { data, path:
|
|
21740
|
-
const fullPath = [...
|
|
21755
|
+
const { data, path: path27, errorMaps, issueData } = params;
|
|
21756
|
+
const fullPath = [...path27, ...issueData.path || []];
|
|
21741
21757
|
const fullIssue = {
|
|
21742
21758
|
...issueData,
|
|
21743
21759
|
path: fullPath
|
|
@@ -21891,11 +21907,11 @@ var require_types2 = __commonJS({
|
|
|
21891
21907
|
var parseUtil_js_1 = require_parseUtil();
|
|
21892
21908
|
var util_js_1 = require_util2();
|
|
21893
21909
|
var ParseInputLazyPath2 = class {
|
|
21894
|
-
constructor(parent, value,
|
|
21910
|
+
constructor(parent, value, path27, key) {
|
|
21895
21911
|
this._cachedPath = [];
|
|
21896
21912
|
this.parent = parent;
|
|
21897
21913
|
this.data = value;
|
|
21898
|
-
this._path =
|
|
21914
|
+
this._path = path27;
|
|
21899
21915
|
this._key = key;
|
|
21900
21916
|
}
|
|
21901
21917
|
get path() {
|
|
@@ -26396,8 +26412,8 @@ var init_stdio2 = __esm({
|
|
|
26396
26412
|
// src/constants.ts
|
|
26397
26413
|
import { createRequire } from "node:module";
|
|
26398
26414
|
function resolveVersion() {
|
|
26399
|
-
if ("3.25.
|
|
26400
|
-
return "3.25.
|
|
26415
|
+
if ("3.25.7") {
|
|
26416
|
+
return "3.25.7";
|
|
26401
26417
|
}
|
|
26402
26418
|
try {
|
|
26403
26419
|
const require2 = createRequire(import.meta.url);
|
|
@@ -26416,6 +26432,34 @@ var init_constants = __esm({
|
|
|
26416
26432
|
}
|
|
26417
26433
|
});
|
|
26418
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
|
+
|
|
26419
26463
|
// src/logger.ts
|
|
26420
26464
|
import fs5 from "node:fs";
|
|
26421
26465
|
import path5 from "node:path";
|
|
@@ -26787,11 +26831,15 @@ var init_errors4 = __esm({
|
|
|
26787
26831
|
BridgeErrorCode2["DIR_NOT_WRITABLE"] = "DIR_NOT_WRITABLE";
|
|
26788
26832
|
BridgeErrorCode2["NETWORK_TIMEOUT"] = "NETWORK_TIMEOUT";
|
|
26789
26833
|
BridgeErrorCode2["JOIN_NOT_CONFIRMED"] = "JOIN_NOT_CONFIRMED";
|
|
26834
|
+
BridgeErrorCode2["CHANNEL_NOT_FOUND"] = "CHANNEL_NOT_FOUND";
|
|
26835
|
+
BridgeErrorCode2["PEER_NOT_YOURS"] = "PEER_NOT_YOURS";
|
|
26790
26836
|
return BridgeErrorCode2;
|
|
26791
26837
|
})(BridgeErrorCode || {});
|
|
26792
26838
|
BridgeError = class extends Error {
|
|
26793
26839
|
code;
|
|
26794
26840
|
suggestion;
|
|
26841
|
+
/** Relay hint: ms until a refused peerId can be reclaimed (PEER_NOT_YOURS only). */
|
|
26842
|
+
retryAfterMs;
|
|
26795
26843
|
constructor(code, message, suggestion) {
|
|
26796
26844
|
const fullMessage = suggestion ? `${code}: ${message}. ${suggestion}` : `${code}: ${message}`;
|
|
26797
26845
|
super(fullMessage);
|
|
@@ -27838,7 +27886,7 @@ var init_http_backend = __esm({
|
|
|
27838
27886
|
* in cloud mode we ignore it and use this.sessionId (the cloud session).
|
|
27839
27887
|
*/
|
|
27840
27888
|
async registerPeer(peerId, _sessionId, cwd, label, clientVersion, mode, _channelSessionId, capabilities, workspaceId, threadId, peerSecret) {
|
|
27841
|
-
const
|
|
27889
|
+
const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
|
|
27842
27890
|
const body = {
|
|
27843
27891
|
peerId,
|
|
27844
27892
|
cwd,
|
|
@@ -27869,7 +27917,7 @@ var init_http_backend = __esm({
|
|
|
27869
27917
|
if (peerSecret !== void 0 && await relaySupports(this.http, "peer-ownership")) {
|
|
27870
27918
|
body.peerSecret = peerSecret;
|
|
27871
27919
|
}
|
|
27872
|
-
const peer = await this.http.post(
|
|
27920
|
+
const peer = await this.http.post(path27, body);
|
|
27873
27921
|
const issued = peer?.peerSecret;
|
|
27874
27922
|
if (issued) {
|
|
27875
27923
|
try {
|
|
@@ -27889,9 +27937,9 @@ var init_http_backend = __esm({
|
|
|
27889
27937
|
* local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
|
|
27890
27938
|
*/
|
|
27891
27939
|
async deregisterPeer(peerId, peerSecret) {
|
|
27892
|
-
const
|
|
27940
|
+
const path27 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
|
|
27893
27941
|
try {
|
|
27894
|
-
const headers = await this.http.delete(
|
|
27942
|
+
const headers = await this.http.delete(path27, peerSecret ? { peerSecret } : {});
|
|
27895
27943
|
const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
|
|
27896
27944
|
return { removed: true, mailboxDeprovisioned };
|
|
27897
27945
|
} catch (err) {
|
|
@@ -27915,8 +27963,8 @@ var init_http_backend = __esm({
|
|
|
27915
27963
|
* GET /api/sessions/:sessionId/peers
|
|
27916
27964
|
*/
|
|
27917
27965
|
async listPeers() {
|
|
27918
|
-
const
|
|
27919
|
-
const result = await this.http.get(
|
|
27966
|
+
const path27 = PATHS.peers.replace(":sessionId", this.sessionId);
|
|
27967
|
+
const result = await this.http.get(path27);
|
|
27920
27968
|
return result.peers;
|
|
27921
27969
|
}
|
|
27922
27970
|
/**
|
|
@@ -27924,8 +27972,8 @@ var init_http_backend = __esm({
|
|
|
27924
27972
|
* Calls the lightweight heartbeat endpoint on the cloud relay server.
|
|
27925
27973
|
*/
|
|
27926
27974
|
async updateLastSeen(peerId) {
|
|
27927
|
-
const
|
|
27928
|
-
await this.http.post(
|
|
27975
|
+
const path27 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
|
|
27976
|
+
await this.http.post(path27, { peerId });
|
|
27929
27977
|
}
|
|
27930
27978
|
/**
|
|
27931
27979
|
* Record a message in the cloud session.
|
|
@@ -27936,7 +27984,7 @@ var init_http_backend = __esm({
|
|
|
27936
27984
|
* the input record to construct a full MessageRecord.
|
|
27937
27985
|
*/
|
|
27938
27986
|
async recordMessage(record2) {
|
|
27939
|
-
const
|
|
27987
|
+
const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
|
|
27940
27988
|
const body = {
|
|
27941
27989
|
fromPeerId: record2.fromPeerId,
|
|
27942
27990
|
toPeerId: record2.toPeerId,
|
|
@@ -27962,7 +28010,7 @@ var init_http_backend = __esm({
|
|
|
27962
28010
|
if (record2.replyExpected === false && await relaySupports(this.http, "terminal-messages")) {
|
|
27963
28011
|
body.replyExpected = false;
|
|
27964
28012
|
}
|
|
27965
|
-
const resp = await this.http.post(
|
|
28013
|
+
const resp = await this.http.post(path27, body);
|
|
27966
28014
|
return {
|
|
27967
28015
|
...record2,
|
|
27968
28016
|
id: resp.id,
|
|
@@ -27976,7 +28024,7 @@ var init_http_backend = __esm({
|
|
|
27976
28024
|
* Supports optional peerId filter and limit (default 300).
|
|
27977
28025
|
*/
|
|
27978
28026
|
async getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes) {
|
|
27979
|
-
const
|
|
28027
|
+
const path27 = PATHS.messages.replace(":sessionId", this.sessionId);
|
|
27980
28028
|
const query = {};
|
|
27981
28029
|
if (peerId) {
|
|
27982
28030
|
query.peerId = peerId;
|
|
@@ -27991,7 +28039,7 @@ var init_http_backend = __esm({
|
|
|
27991
28039
|
if (dedupInferredEchoes) {
|
|
27992
28040
|
query.dedupInferredEchoes = "true";
|
|
27993
28041
|
}
|
|
27994
|
-
const result = await this.http.get(
|
|
28042
|
+
const result = await this.http.get(path27, query);
|
|
27995
28043
|
return result.messages;
|
|
27996
28044
|
}
|
|
27997
28045
|
/**
|
|
@@ -28002,12 +28050,12 @@ var init_http_backend = __esm({
|
|
|
28002
28050
|
* so that get-history shows the actual response (not null).
|
|
28003
28051
|
*/
|
|
28004
28052
|
async updateMessageResponse(messageId, response, durationMs, pending) {
|
|
28005
|
-
const
|
|
28053
|
+
const path27 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
|
|
28006
28054
|
const body = { response, durationMs };
|
|
28007
28055
|
if (pending === true) {
|
|
28008
28056
|
body.pending = true;
|
|
28009
28057
|
}
|
|
28010
|
-
await this.http.patch(
|
|
28058
|
+
await this.http.patch(path27, body);
|
|
28011
28059
|
}
|
|
28012
28060
|
/**
|
|
28013
28061
|
* Validate a session.
|
|
@@ -28181,8 +28229,8 @@ var init_http_client = __esm({
|
|
|
28181
28229
|
* Perform an authenticated GET request.
|
|
28182
28230
|
* Appends query parameters to the URL if provided.
|
|
28183
28231
|
*/
|
|
28184
|
-
async get(
|
|
28185
|
-
const url = new URL(
|
|
28232
|
+
async get(path27, query) {
|
|
28233
|
+
const url = new URL(path27, this.baseUrl);
|
|
28186
28234
|
if (query) {
|
|
28187
28235
|
for (const [k, v] of Object.entries(query)) {
|
|
28188
28236
|
url.searchParams.set(k, v);
|
|
@@ -28197,8 +28245,8 @@ var init_http_client = __esm({
|
|
|
28197
28245
|
/**
|
|
28198
28246
|
* Perform an authenticated POST request with a JSON body.
|
|
28199
28247
|
*/
|
|
28200
|
-
async post(
|
|
28201
|
-
const url = new URL(
|
|
28248
|
+
async post(path27, body) {
|
|
28249
|
+
const url = new URL(path27, this.baseUrl);
|
|
28202
28250
|
const resp = await this.fetchWithTimeout(url, {
|
|
28203
28251
|
method: "POST",
|
|
28204
28252
|
headers: this.headers(),
|
|
@@ -28216,8 +28264,8 @@ var init_http_client = __esm({
|
|
|
28216
28264
|
* Perform an authenticated PATCH request with a JSON body.
|
|
28217
28265
|
* Used to update existing resources (e.g., message response fields).
|
|
28218
28266
|
*/
|
|
28219
|
-
async patch(
|
|
28220
|
-
const url = new URL(
|
|
28267
|
+
async patch(path27, body) {
|
|
28268
|
+
const url = new URL(path27, this.baseUrl);
|
|
28221
28269
|
const resp = await this.fetchWithTimeout(url, {
|
|
28222
28270
|
method: "PATCH",
|
|
28223
28271
|
headers: this.headers(),
|
|
@@ -28242,8 +28290,8 @@ var init_http_client = __esm({
|
|
|
28242
28290
|
* "Malformed JSON in request body" 400 from cogent-server <=3.1.2 when
|
|
28243
28291
|
* any client (including third-party tools) DELETEd a peer without a body.
|
|
28244
28292
|
*/
|
|
28245
|
-
async delete(
|
|
28246
|
-
const url = new URL(
|
|
28293
|
+
async delete(path27, body) {
|
|
28294
|
+
const url = new URL(path27, this.baseUrl);
|
|
28247
28295
|
const headers = {
|
|
28248
28296
|
"Authorization": `Bearer ${this.token}`
|
|
28249
28297
|
};
|
|
@@ -28278,12 +28326,16 @@ var init_http_client = __esm({
|
|
|
28278
28326
|
} catch {
|
|
28279
28327
|
errorBody = { message: resp.statusText };
|
|
28280
28328
|
}
|
|
28281
|
-
const code = errorBody.code && errorBody.code in BridgeErrorCode ? errorBody.code : "STARTUP_FAILED" /* STARTUP_FAILED */;
|
|
28282
|
-
|
|
28329
|
+
const code = /PEER_NOT_YOURS/.test(errorBody.message ?? "") ? "PEER_NOT_YOURS" /* PEER_NOT_YOURS */ : errorBody.code && errorBody.code in BridgeErrorCode ? errorBody.code : "STARTUP_FAILED" /* STARTUP_FAILED */;
|
|
28330
|
+
const err = new BridgeError(
|
|
28283
28331
|
code,
|
|
28284
28332
|
errorBody.message ?? `HTTP ${resp.status}`,
|
|
28285
28333
|
errorBody.suggestion
|
|
28286
28334
|
);
|
|
28335
|
+
if (typeof errorBody.retryAfterMs === "number" && Number.isFinite(errorBody.retryAfterMs)) {
|
|
28336
|
+
err.retryAfterMs = errorBody.retryAfterMs;
|
|
28337
|
+
}
|
|
28338
|
+
throw err;
|
|
28287
28339
|
}
|
|
28288
28340
|
};
|
|
28289
28341
|
}
|
|
@@ -32540,14 +32592,14 @@ var init_ws_client = __esm({
|
|
|
32540
32592
|
this.restoreCursor();
|
|
32541
32593
|
const poll = async () => {
|
|
32542
32594
|
try {
|
|
32543
|
-
const
|
|
32595
|
+
const path27 = `/api/sessions/${this.opts.sessionId}/poll`;
|
|
32544
32596
|
const query = {
|
|
32545
32597
|
peerId: this.opts.peerId
|
|
32546
32598
|
};
|
|
32547
32599
|
if (this.lastMessageId) {
|
|
32548
32600
|
query.lastMessageId = this.lastMessageId;
|
|
32549
32601
|
}
|
|
32550
|
-
const result = await this.opts.http.get(
|
|
32602
|
+
const result = await this.opts.http.get(path27, query);
|
|
32551
32603
|
if (result.messages && result.messages.length > 0) {
|
|
32552
32604
|
this.opts.onMessages(result.messages);
|
|
32553
32605
|
this.advanceCursor(result.messages[result.messages.length - 1].id);
|
|
@@ -33464,6 +33516,10 @@ import crypto5 from "node:crypto";
|
|
|
33464
33516
|
import fs15 from "node:fs";
|
|
33465
33517
|
import os11 from "node:os";
|
|
33466
33518
|
import path16 from "node:path";
|
|
33519
|
+
function drainCapMs(timeoutMs) {
|
|
33520
|
+
const t = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e5;
|
|
33521
|
+
return Math.min(INFLIGHT_TIMEOUT_FACTOR * t, INFLIGHT_MAX_MS);
|
|
33522
|
+
}
|
|
33467
33523
|
function hashCwd3(cwd) {
|
|
33468
33524
|
return crypto5.createHash("sha256").update(path16.resolve(cwd)).digest("hex").slice(0, 16);
|
|
33469
33525
|
}
|
|
@@ -33790,12 +33846,36 @@ import crypto8 from "node:crypto";
|
|
|
33790
33846
|
import fs18 from "node:fs";
|
|
33791
33847
|
import os14 from "node:os";
|
|
33792
33848
|
import path19 from "node:path";
|
|
33849
|
+
function agentSessionId(env = process.env) {
|
|
33850
|
+
if (env.COGENT_PLATFORM && env.COGENT_PLATFORM !== "cc") return void 0;
|
|
33851
|
+
const id = env.CLAUDE_CODE_SESSION_ID?.trim();
|
|
33852
|
+
return id && id.length <= 128 ? id : void 0;
|
|
33853
|
+
}
|
|
33854
|
+
function startedWithoutClient() {
|
|
33855
|
+
if (withoutClient === void 0) {
|
|
33856
|
+
try {
|
|
33857
|
+
withoutClient = fs18.fstatSync(0).isCharacterDevice();
|
|
33858
|
+
} catch {
|
|
33859
|
+
withoutClient = false;
|
|
33860
|
+
}
|
|
33861
|
+
}
|
|
33862
|
+
return withoutClient;
|
|
33863
|
+
}
|
|
33793
33864
|
function hashCwd6(cwd) {
|
|
33794
33865
|
return crypto8.createHash("sha256").update(path19.resolve(cwd)).digest("hex").slice(0, 16);
|
|
33795
33866
|
}
|
|
33796
33867
|
function bridgeDirFor(cwd, peerId) {
|
|
33797
33868
|
return path19.join(os14.homedir(), ".cogent", "bridges", `${hashCwd6(cwd)}.${safe4(peerId)}`);
|
|
33798
33869
|
}
|
|
33870
|
+
function isReservedPeerName(peerId) {
|
|
33871
|
+
return safe4(peerId).toLowerCase() === safe4(PROCESS_MARK).toLowerCase();
|
|
33872
|
+
}
|
|
33873
|
+
function registryText(value) {
|
|
33874
|
+
return String(value ?? "").replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64) || "unreadable";
|
|
33875
|
+
}
|
|
33876
|
+
function registryOwnerLabel(o) {
|
|
33877
|
+
return `pid ${registryText(o.pid)} (v${registryText(o.version)}, ${JSON.stringify(String(o.endpoint ?? "").slice(0, 200))})`;
|
|
33878
|
+
}
|
|
33799
33879
|
function pidAlive(pid) {
|
|
33800
33880
|
if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) return false;
|
|
33801
33881
|
if (pid === process.pid) return true;
|
|
@@ -33806,7 +33886,7 @@ function pidAlive(pid) {
|
|
|
33806
33886
|
return err?.code === "EPERM";
|
|
33807
33887
|
}
|
|
33808
33888
|
}
|
|
33809
|
-
function announceBridge(cwd, peerId, version2, endpoint) {
|
|
33889
|
+
function announceBridge(cwd, peerId, version2, endpoint, sessionId = agentSessionId()) {
|
|
33810
33890
|
const dir = bridgeDirFor(cwd, peerId);
|
|
33811
33891
|
try {
|
|
33812
33892
|
fs18.mkdirSync(dir, { recursive: true });
|
|
@@ -33816,13 +33896,30 @@ function announceBridge(cwd, peerId, version2, endpoint) {
|
|
|
33816
33896
|
version: version2,
|
|
33817
33897
|
peerId,
|
|
33818
33898
|
endpoint,
|
|
33819
|
-
cwd: path19.resolve(cwd)
|
|
33899
|
+
cwd: path19.resolve(cwd),
|
|
33900
|
+
parentPid: process.ppid,
|
|
33901
|
+
...sessionId ? { sessionId } : {},
|
|
33902
|
+
// 🔴 A headless bridge never had a client to lose (review r7 FIX2-2, SEC2-2): when its launching
|
|
33903
|
+
// shell exited, the changed parent read as "client gone" and any bridge that started took its name.
|
|
33904
|
+
...startedWithoutClient() ? { noClient: true } : {}
|
|
33820
33905
|
};
|
|
33821
33906
|
fs18.writeFileSync(path19.join(dir, `${process.pid}.json`), JSON.stringify(entry));
|
|
33822
33907
|
} catch (err) {
|
|
33823
33908
|
logger.debug(`wake-ownership: could not announce this bridge (${err.message})`);
|
|
33824
33909
|
}
|
|
33825
33910
|
}
|
|
33911
|
+
function markBridgeDraining(cwd, peerId) {
|
|
33912
|
+
const file = path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`);
|
|
33913
|
+
try {
|
|
33914
|
+
const entry = JSON.parse(fs18.readFileSync(file, "utf-8"));
|
|
33915
|
+
fs18.writeFileSync(file, JSON.stringify({ ...entry, draining: true }));
|
|
33916
|
+
} catch {
|
|
33917
|
+
}
|
|
33918
|
+
}
|
|
33919
|
+
function markBridgeProcess(cwd, version2) {
|
|
33920
|
+
listLiveBridges(cwd, PROCESS_MARK);
|
|
33921
|
+
announceBridge(cwd, PROCESS_MARK, version2, "");
|
|
33922
|
+
}
|
|
33826
33923
|
function withdrawBridge(cwd, peerId) {
|
|
33827
33924
|
try {
|
|
33828
33925
|
fs18.unlinkSync(path19.join(bridgeDirFor(cwd, peerId), `${process.pid}.json`));
|
|
@@ -33859,6 +33956,16 @@ function listLiveBridges(cwd, peerId) {
|
|
|
33859
33956
|
live.sort((a, b) => b.startedAt - a.startedAt || b.pid - a.pid);
|
|
33860
33957
|
return live;
|
|
33861
33958
|
}
|
|
33959
|
+
function listLiveBridgesInFolder(cwd) {
|
|
33960
|
+
const prefix = `${hashCwd6(cwd)}.`;
|
|
33961
|
+
let dirs;
|
|
33962
|
+
try {
|
|
33963
|
+
dirs = fs18.readdirSync(path19.join(os14.homedir(), ".cogent", "bridges"));
|
|
33964
|
+
} catch {
|
|
33965
|
+
return [];
|
|
33966
|
+
}
|
|
33967
|
+
return dirs.filter((d) => d.startsWith(prefix)).flatMap((d) => listLiveBridges(cwd, d.slice(prefix.length)));
|
|
33968
|
+
}
|
|
33862
33969
|
function checkWakeOwnership(cwd, peerId) {
|
|
33863
33970
|
let live;
|
|
33864
33971
|
try {
|
|
@@ -33879,13 +33986,14 @@ function checkWakeOwnership(cwd, peerId) {
|
|
|
33879
33986
|
}
|
|
33880
33987
|
return { isOwner: true, liveCount: live.length + 1 };
|
|
33881
33988
|
}
|
|
33882
|
-
var PROCESS_STARTED_AT, safe4;
|
|
33989
|
+
var PROCESS_STARTED_AT, withoutClient, safe4, PROCESS_MARK;
|
|
33883
33990
|
var init_wake_ownership = __esm({
|
|
33884
33991
|
"src/services/wake-ownership.ts"() {
|
|
33885
33992
|
"use strict";
|
|
33886
33993
|
init_logger();
|
|
33887
33994
|
PROCESS_STARTED_AT = Date.now() - Math.floor(process.uptime() * 1e3);
|
|
33888
33995
|
safe4 = (s) => String(s).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
33996
|
+
PROCESS_MARK = ".process";
|
|
33889
33997
|
}
|
|
33890
33998
|
});
|
|
33891
33999
|
|
|
@@ -33904,6 +34012,39 @@ function versionFromArgv(argv) {
|
|
|
33904
34012
|
const m = argv.match(/\/cogent\/(\d+\.\d+\.\d+)\//);
|
|
33905
34013
|
return m ? m[1] : null;
|
|
33906
34014
|
}
|
|
34015
|
+
function versionAtLeast(a, b) {
|
|
34016
|
+
const pa = a.split(/[-+]/)[0].split(".").map(Number);
|
|
34017
|
+
const pb = b.split(/[-+]/)[0].split(".").map(Number);
|
|
34018
|
+
for (let i = 0; i < 3; i++) {
|
|
34019
|
+
const x = pa[i] ?? 0;
|
|
34020
|
+
const y = pb[i] ?? 0;
|
|
34021
|
+
if (x !== y) return x > y;
|
|
34022
|
+
}
|
|
34023
|
+
return true;
|
|
34024
|
+
}
|
|
34025
|
+
function bridgeVersion(argv, readFile = (p) => fs19.readFileSync(p, "utf-8")) {
|
|
34026
|
+
const fromPath = versionFromArgv(argv);
|
|
34027
|
+
if (fromPath) return fromPath;
|
|
34028
|
+
const candidates = [];
|
|
34029
|
+
const pkg = argv.match(/(\S*\/@essentialai\/cogent-bridge(?:-bundled)?)\/dist\/(?:cli|index)\.js(?:\s|$)/);
|
|
34030
|
+
if (pkg) candidates.push(path20.join(pkg[1], "package.json"));
|
|
34031
|
+
const bin = argv.match(/(\S*\/node_modules)\/\.bin\/cogent-bridge(?:\s|$)/);
|
|
34032
|
+
if (bin) {
|
|
34033
|
+
for (const name of ["cogent-bridge", "cogent-bridge-bundled"]) {
|
|
34034
|
+
candidates.push(path20.join(bin[1], "@essentialai", name, "package.json"));
|
|
34035
|
+
}
|
|
34036
|
+
}
|
|
34037
|
+
for (const file of candidates) {
|
|
34038
|
+
try {
|
|
34039
|
+
const pj = JSON.parse(readFile(file));
|
|
34040
|
+
if (typeof pj.name === "string" && pj.name.startsWith("@essentialai/cogent-bridge") && typeof pj.version === "string" && /^\d+\.\d+\.\d+/.test(pj.version)) {
|
|
34041
|
+
return pj.version;
|
|
34042
|
+
}
|
|
34043
|
+
} catch {
|
|
34044
|
+
}
|
|
34045
|
+
}
|
|
34046
|
+
return null;
|
|
34047
|
+
}
|
|
33907
34048
|
function listProcesses() {
|
|
33908
34049
|
let out;
|
|
33909
34050
|
try {
|
|
@@ -33965,25 +34106,13 @@ function ancestorsOf(pid, procs) {
|
|
|
33965
34106
|
}
|
|
33966
34107
|
return seen;
|
|
33967
34108
|
}
|
|
33968
|
-
function announcedPidsFor(cwd) {
|
|
33969
|
-
const pids = /* @__PURE__ */ new Set();
|
|
33970
|
-
try {
|
|
33971
|
-
const base = path20.dirname(bridgeDirFor(cwd, "x"));
|
|
33972
|
-
const prefix = path20.basename(bridgeDirFor(cwd, "x")).split(".")[0];
|
|
33973
|
-
for (const dir of fs19.readdirSync(base)) {
|
|
33974
|
-
if (!dir.startsWith(`${prefix}.`)) continue;
|
|
33975
|
-
const peerId = dir.slice(prefix.length + 1);
|
|
33976
|
-
for (const e of listLiveBridges(cwd, peerId)) pids.add(e.pid);
|
|
33977
|
-
}
|
|
33978
|
-
} catch {
|
|
33979
|
-
}
|
|
33980
|
-
return pids;
|
|
33981
|
-
}
|
|
33982
34109
|
function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
|
|
34110
|
+
const versionOf = opts.versionOf ?? ((argv) => bridgeVersion(argv));
|
|
33983
34111
|
const selfPid = opts.selfPid ?? process.pid;
|
|
33984
|
-
const selfStartedAt = opts.selfStartedAt ??
|
|
34112
|
+
const selfStartedAt = opts.selfStartedAt ?? procs.find((p) => p.pid === selfPid)?.startedAt ?? NaN;
|
|
34113
|
+
if (!Number.isFinite(selfStartedAt)) return [];
|
|
33985
34114
|
const cwdOf = opts.cwdOf ?? processCwd;
|
|
33986
|
-
const announced = opts.announced ??
|
|
34115
|
+
const announced = opts.announced ?? new Set(listLiveBridgesInFolder(cwd).map((e) => e.pid));
|
|
33987
34116
|
const target = canonicalPath(cwd);
|
|
33988
34117
|
const ancestors = ancestorsOf(selfPid, procs);
|
|
33989
34118
|
const out = [];
|
|
@@ -33995,10 +34124,11 @@ function findStaleBridges(cwd, procs = listProcesses(), opts = {}) {
|
|
|
33995
34124
|
if (!Number.isFinite(p.startedAt) || p.startedAt >= selfStartedAt) continue;
|
|
33996
34125
|
const theirCwd = cwdOf(p.pid);
|
|
33997
34126
|
if (!theirCwd || canonicalPath(theirCwd) !== target) continue;
|
|
33998
|
-
const ver =
|
|
34127
|
+
const ver = versionOf(p.argv);
|
|
34128
|
+
if (!ver || versionAtLeast(ver, SELF_SUPERSESSION_VERSION)) continue;
|
|
33999
34129
|
out.push({
|
|
34000
34130
|
proc: p,
|
|
34001
|
-
reason: `pid ${p.pid}
|
|
34131
|
+
reason: `pid ${p.pid} (version ${ver}) is a cogent bridge in this exact checkout, started ${new Date(p.startedAt).toISOString()} \u2014 before this process \u2014 and is not in the bridge registry; version ${ver} predates ${SELF_SUPERSESSION_VERSION} self-supersession and would keep waking this session forever`
|
|
34002
34132
|
});
|
|
34003
34133
|
}
|
|
34004
34134
|
return out;
|
|
@@ -34032,21 +34162,25 @@ function reapStaleBridges(cwd, opts = {}) {
|
|
|
34032
34162
|
}
|
|
34033
34163
|
if (reaped.length) {
|
|
34034
34164
|
logger.warn(
|
|
34035
|
-
`Cogent: reaped ${reaped.length} stale bridge process(es)
|
|
34165
|
+
`Cogent: reaped ${reaped.length} stale bridge process(es) for this checkout, each at a version before ${SELF_SUPERSESSION_VERSION}: they could not stand down on their own.`
|
|
34036
34166
|
);
|
|
34037
34167
|
}
|
|
34038
34168
|
return reaped;
|
|
34039
34169
|
}
|
|
34170
|
+
var SELF_SUPERSESSION_VERSION;
|
|
34040
34171
|
var init_stale_bridge_reaper = __esm({
|
|
34041
34172
|
"src/services/stale-bridge-reaper.ts"() {
|
|
34042
34173
|
"use strict";
|
|
34043
34174
|
init_logger();
|
|
34044
34175
|
init_wake_ownership();
|
|
34176
|
+
SELF_SUPERSESSION_VERSION = "3.23.4";
|
|
34045
34177
|
}
|
|
34046
34178
|
});
|
|
34047
34179
|
|
|
34048
34180
|
// src/services/auto-relay.ts
|
|
34049
34181
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
34182
|
+
import fs20 from "node:fs";
|
|
34183
|
+
import path21 from "node:path";
|
|
34050
34184
|
function buildStatusNotice(status, peerId, traceId) {
|
|
34051
34185
|
const tail = traceId ? ` (trace ${traceId})` : "";
|
|
34052
34186
|
if (status === RELAY_STATUS.QUEUED) {
|
|
@@ -34173,6 +34307,21 @@ function truncate(s) {
|
|
|
34173
34307
|
const flat = s.replace(/\s+/g, " ").trim();
|
|
34174
34308
|
return flat.length > DIAGNOSTIC_MAX ? `${flat.slice(0, DIAGNOSTIC_MAX - 1)}\u2026` : flat;
|
|
34175
34309
|
}
|
|
34310
|
+
function isInsideOwnFolder(dir) {
|
|
34311
|
+
try {
|
|
34312
|
+
const real = fs20.realpathSync.native(dir);
|
|
34313
|
+
return real === process.cwd() || real.startsWith(process.cwd() + path21.sep);
|
|
34314
|
+
} catch {
|
|
34315
|
+
return false;
|
|
34316
|
+
}
|
|
34317
|
+
}
|
|
34318
|
+
function isOwnFolder(dir) {
|
|
34319
|
+
try {
|
|
34320
|
+
return fs20.realpathSync.native(dir) === fs20.realpathSync.native(process.cwd());
|
|
34321
|
+
} catch {
|
|
34322
|
+
return false;
|
|
34323
|
+
}
|
|
34324
|
+
}
|
|
34176
34325
|
var RELAY_STATUS, STATUS_MARKER_RE, DIAGNOSTIC_MAX, EARLY_ACK_TTL_MS, EARLY_ACK_MAX, AutoRelayService, autoRelay;
|
|
34177
34326
|
var init_auto_relay = __esm({
|
|
34178
34327
|
"src/services/auto-relay.ts"() {
|
|
@@ -34213,6 +34362,8 @@ var init_auto_relay = __esm({
|
|
|
34213
34362
|
*/
|
|
34214
34363
|
pinnedSessionId = null;
|
|
34215
34364
|
localCwd = null;
|
|
34365
|
+
/** Every folder this process announced the current peer name under — what a drain or a stop must cover. */
|
|
34366
|
+
announcedCwds = /* @__PURE__ */ new Set();
|
|
34216
34367
|
/**
|
|
34217
34368
|
* Peer participation mode (3.2.0, Phase 17 OBS-03).
|
|
34218
34369
|
* - "agent" (default): full auto-relay — inbound directed messages run
|
|
@@ -34276,6 +34427,7 @@ var init_auto_relay = __esm({
|
|
|
34276
34427
|
* successful registration so we know which session to inject into.
|
|
34277
34428
|
*/
|
|
34278
34429
|
setLocalPeer(peerId, sessionId, cwd, mode, label, pinnedSessionId) {
|
|
34430
|
+
if (this.localPeerId && this.localPeerId !== peerId) this.withdrawAnnouncement();
|
|
34279
34431
|
this.localPeerId = peerId;
|
|
34280
34432
|
this.localSessionId = sessionId;
|
|
34281
34433
|
this.pinnedSessionId = pinnedSessionId ?? sessionId;
|
|
@@ -34285,7 +34437,12 @@ var init_auto_relay = __esm({
|
|
|
34285
34437
|
logger.info(
|
|
34286
34438
|
`Auto-relay configured for peer ${peerId} (session: ${sessionId}, pinned: ${this.pinnedSessionId}, mode: ${this.localMode}, label: ${this.localLabel})`
|
|
34287
34439
|
);
|
|
34288
|
-
|
|
34440
|
+
const dirs = /* @__PURE__ */ new Set([path21.resolve(cwd)]);
|
|
34441
|
+
if (isInsideOwnFolder(path21.resolve(cwd))) dirs.add(process.cwd());
|
|
34442
|
+
for (const dir of dirs) {
|
|
34443
|
+
this.announcedCwds.add(dir);
|
|
34444
|
+
announceBridge(dir, peerId, CLIENT_VERSION, getConfig().COGENT_ENDPOINT ?? "local");
|
|
34445
|
+
}
|
|
34289
34446
|
this.supersededNotified.clear();
|
|
34290
34447
|
if (!this.reapedStaleBridges) {
|
|
34291
34448
|
this.reapedStaleBridges = true;
|
|
@@ -34660,10 +34817,13 @@ var init_auto_relay = __esm({
|
|
|
34660
34817
|
}
|
|
34661
34818
|
}
|
|
34662
34819
|
if (this.localPeerId && this.localCwd) {
|
|
34663
|
-
const
|
|
34664
|
-
|
|
34665
|
-
|
|
34666
|
-
|
|
34820
|
+
const dirs = /* @__PURE__ */ new Set([path21.resolve(this.localCwd), ...isOwnFolder(this.localCwd) ? [process.cwd()] : []]);
|
|
34821
|
+
for (const dir of dirs) {
|
|
34822
|
+
const own = checkWakeOwnership(dir, this.localPeerId);
|
|
34823
|
+
if (!own.isOwner) {
|
|
34824
|
+
await this._reportSuperseded(msg, own.owner);
|
|
34825
|
+
return;
|
|
34826
|
+
}
|
|
34667
34827
|
}
|
|
34668
34828
|
}
|
|
34669
34829
|
if (this.localPeerId && !this.awarenessOnly.has(msg.id)) {
|
|
@@ -34708,7 +34868,7 @@ var init_auto_relay = __esm({
|
|
|
34708
34868
|
* notice generator.
|
|
34709
34869
|
*/
|
|
34710
34870
|
async _reportSuperseded(msg, owner) {
|
|
34711
|
-
const who = owner ?
|
|
34871
|
+
const who = owner ? registryOwnerLabel(owner) : "a newer bridge";
|
|
34712
34872
|
logger.warn(
|
|
34713
34873
|
`Auto-relay: NOT waking for ${msg.fromPeerId} \u2014 this bridge (pid ${process.pid}, v${CLIENT_VERSION}) has been superseded for peer "${this.localPeerId}" in this checkout by ${who}. It is a leftover process; the newer bridge is answering. Standing down.`
|
|
34714
34874
|
);
|
|
@@ -35139,6 +35299,24 @@ var init_auto_relay = __esm({
|
|
|
35139
35299
|
activeDeliveryAckWaiters: Array.from(this.deliveryAckWaiters.keys())
|
|
35140
35300
|
};
|
|
35141
35301
|
}
|
|
35302
|
+
/**
|
|
35303
|
+
* Stop claiming this peer's name for this checkout, WITHOUT stopping work already in flight.
|
|
35304
|
+
* Called the moment the MCP client is gone: a draining bridge serves no agent, and while it
|
|
35305
|
+
* counted as the peer's holder, the restarted agent's new bridge stood by behind it (review r2
|
|
35306
|
+
* NEW-1). The announcement is MARKED, not removed — see markBridgeDraining (R3-2). Idempotent.
|
|
35307
|
+
* 🔴 EVERY announcement, not only the last registered cwd's (review r7 SEC2-1, ABC2-2, FIX2-5):
|
|
35308
|
+
* after a register with another spelling of the folder, the one for the bridge's own folder stayed
|
|
35309
|
+
* unmarked, and the restarted agent waited out the drain or stood by for good.
|
|
35310
|
+
*/
|
|
35311
|
+
announceDraining() {
|
|
35312
|
+
if (!this.localPeerId) return;
|
|
35313
|
+
for (const dir of this.announcedCwds) markBridgeDraining(dir, this.localPeerId);
|
|
35314
|
+
}
|
|
35315
|
+
/** Remove this bridge's ownership announcements (graceful shutdown, a rename). Idempotent. */
|
|
35316
|
+
withdrawAnnouncement() {
|
|
35317
|
+
if (this.localPeerId) for (const dir of this.announcedCwds) withdrawBridge(dir, this.localPeerId);
|
|
35318
|
+
this.announcedCwds.clear();
|
|
35319
|
+
}
|
|
35142
35320
|
/**
|
|
35143
35321
|
* Stop the auto-relay service: clear queue and reset state.
|
|
35144
35322
|
*/
|
|
@@ -35158,7 +35336,7 @@ var init_auto_relay = __esm({
|
|
|
35158
35336
|
}
|
|
35159
35337
|
this.deliveryAckWaiters.clear();
|
|
35160
35338
|
this.recentAcks.clear();
|
|
35161
|
-
|
|
35339
|
+
this.withdrawAnnouncement();
|
|
35162
35340
|
this.queue = [];
|
|
35163
35341
|
this.awarenessOnly.clear();
|
|
35164
35342
|
this.supersededNotified.clear();
|
|
@@ -35178,6 +35356,63 @@ var init_auto_relay = __esm({
|
|
|
35178
35356
|
});
|
|
35179
35357
|
|
|
35180
35358
|
// src/services/peer-presence.ts
|
|
35359
|
+
function holderRelation(holderSession, ownSession) {
|
|
35360
|
+
if (holderSession && ownSession) return holderSession === ownSession ? "same-session" : "other-session";
|
|
35361
|
+
return holderSession || ownSession ? "unknown" : "no-session";
|
|
35362
|
+
}
|
|
35363
|
+
function holderClientGone(holder, procs) {
|
|
35364
|
+
if (holder.noClient === true) return false;
|
|
35365
|
+
const byPid = new Map(procs.map((p) => [p.pid, p]));
|
|
35366
|
+
let cur = byPid.get(holder.pid);
|
|
35367
|
+
if (!cur) return false;
|
|
35368
|
+
if (typeof holder.parentPid === "number") return cur.ppid !== holder.parentPid;
|
|
35369
|
+
for (let hops = 0; hops < 3; hops++) {
|
|
35370
|
+
if (cur.ppid === 1) return true;
|
|
35371
|
+
const parent = byPid.get(cur.ppid);
|
|
35372
|
+
if (!parent) return false;
|
|
35373
|
+
const exe = parent.argv.trim().split(/\s+/)[0] ?? "";
|
|
35374
|
+
if (ORPHAN_PARENT_RE.test(exe.split("/").pop() ?? "")) return true;
|
|
35375
|
+
if (!NPX_WRAPPER_RE.test(parent.argv.trim())) return false;
|
|
35376
|
+
cur = parent;
|
|
35377
|
+
}
|
|
35378
|
+
return false;
|
|
35379
|
+
}
|
|
35380
|
+
function insideCodexWakeTurn(selfPid, procs) {
|
|
35381
|
+
const byPid = new Map(procs.map((p) => [p.pid, p]));
|
|
35382
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35383
|
+
let cur = byPid.get(selfPid)?.ppid;
|
|
35384
|
+
while (cur && cur > 1 && !seen.has(cur)) {
|
|
35385
|
+
seen.add(cur);
|
|
35386
|
+
const p = byPid.get(cur);
|
|
35387
|
+
if (!p) break;
|
|
35388
|
+
if (/(^|[\s/])codex(\.js)?\s+exec\s+resume(\s|$)/.test(p.argv)) return true;
|
|
35389
|
+
cur = p.ppid;
|
|
35390
|
+
}
|
|
35391
|
+
return false;
|
|
35392
|
+
}
|
|
35393
|
+
function otherBridgesInFolder(entries, self, listProcs) {
|
|
35394
|
+
let procs = null;
|
|
35395
|
+
return entries.filter(
|
|
35396
|
+
(e) => e.peerId !== PROCESS_MARK && e.pid !== self.pid && !e.draining && holderRelation(e.sessionId, self.sessionId) !== "same-session" && !holderClientGone(e, procs ??= listProcs())
|
|
35397
|
+
);
|
|
35398
|
+
}
|
|
35399
|
+
function anotherAgentSessionAmong(others, ownSession) {
|
|
35400
|
+
return others.some((o) => holderRelation(o.sessionId, ownSession) === "other-session");
|
|
35401
|
+
}
|
|
35402
|
+
function otherBridgeNotice(others, peerId, verdict, ownSession) {
|
|
35403
|
+
const lines = others.map((o) => {
|
|
35404
|
+
const version2 = registryText(o.version);
|
|
35405
|
+
const who = holderRelation(o.sessionId, ownSession) === "other-session" ? `Another live agent session in this folder (bridge pid ${o.pid}, version ${version2}, agent session ${registryText(o.sessionId)})` : `Another live bridge in this folder (pid ${o.pid}, version ${version2}; its agent session cannot be compared with this one, so it may be this agent's own previous or second bridge)`;
|
|
35406
|
+
if (o.peerId !== peerId) {
|
|
35407
|
+
return `${who} is still registered as '${registryText(o.peerId)}'. It keeps that name while it runs, but the folder's saved identity now points at this bridge ('${peerId}'): after a restart that bridge's agent comes back as '${peerId}' only if this bridge is no longer running then; otherwise it stays out of the channel until it registers again.`;
|
|
35408
|
+
}
|
|
35409
|
+
if (verdict.isOwner) {
|
|
35410
|
+
return `${who} was registered as '${peerId}'. It is now superseded: this bridge holds '${peerId}' and that bridge has stopped answering for it.`;
|
|
35411
|
+
}
|
|
35412
|
+
return `${who} is registered as '${peerId}' too. NOBODY answers for '${peerId}' in this channel now: the bridge that started last (pid ${verdict.owner?.pid ?? "unknown"}) is the one that wakes its agent, but in this channel the relay registration now belongs to this bridge, so the relay refuses that bridge's replies here and this bridge does not wake. It stays that way until that bridge is closed or its agent registers again. If that bridge is registered in another channel, it still answers there.`;
|
|
35413
|
+
});
|
|
35414
|
+
return lines.join(" ") + (anotherAgentSessionAmong(others, ownSession) ? ` Two agents in one folder are not supported yet: each agent needs its own peer name and, for now, its own folder.` : "");
|
|
35415
|
+
}
|
|
35181
35416
|
function autoPresenceEnabled(env = process.env) {
|
|
35182
35417
|
const v = env.COGENT_AUTO_PRESENCE;
|
|
35183
35418
|
if (v === void 0 || v === "") return true;
|
|
@@ -35207,11 +35442,42 @@ async function restorePresence(deps) {
|
|
|
35207
35442
|
};
|
|
35208
35443
|
}
|
|
35209
35444
|
const peerId = creds.peerId;
|
|
35210
|
-
if (deps.
|
|
35445
|
+
if (deps.startedByWakeTurn?.()) {
|
|
35211
35446
|
return {
|
|
35212
|
-
state: "
|
|
35447
|
+
state: "deferred",
|
|
35213
35448
|
restored: false,
|
|
35214
|
-
detail: `peer '${peerId}'
|
|
35449
|
+
detail: `this bridge runs inside a codex wake turn ('codex exec resume'); peer '${peerId}' belongs to the agent's own bridge, which started this turn \u2014 nothing to restore here`
|
|
35450
|
+
};
|
|
35451
|
+
}
|
|
35452
|
+
const served = deps.peerAlreadyServed(peerId);
|
|
35453
|
+
if (served) {
|
|
35454
|
+
const session = deps.agentSessionId?.();
|
|
35455
|
+
const holder = holderRelation(served.sessionId, session);
|
|
35456
|
+
const servedBy = {
|
|
35457
|
+
...served,
|
|
35458
|
+
...served.version === void 0 ? {} : { version: registryText(served.version) },
|
|
35459
|
+
...served.sessionId === void 0 ? {} : { sessionId: registryText(served.sessionId) }
|
|
35460
|
+
};
|
|
35461
|
+
const started = Number.isFinite(servedBy.startedAt) ? new Date(servedBy.startedAt).toISOString() : "unknown";
|
|
35462
|
+
const recheck = holder === "same-session";
|
|
35463
|
+
const every = deps.recheckSeconds ? ` (re-checked every ${deps.recheckSeconds}s)` : "";
|
|
35464
|
+
const take = `To take '${peerId}' for this agent now, run /cogent:register (cogent_join_session, then cogent_register_peer)`;
|
|
35465
|
+
const why = {
|
|
35466
|
+
"same-session": `That bridge serves this same agent session (${session})`,
|
|
35467
|
+
"no-session": `Neither bridge records an agent session (codex, gemini), so it cannot be told whether that bridge is this agent's previous one or another agent's. ${take}`,
|
|
35468
|
+
"other-session": `That bridge serves another agent session (${servedBy.sessionId}; ours: ${session}). Two agents in one folder are not supported yet: a second agent needs its own folder and peer name. ${take}`,
|
|
35469
|
+
unknown: `Its agent session cannot be compared with this one (that bridge: ${servedBy.sessionId ?? "not recorded"}; this bridge: ${session ?? "not known"}): it may be this agent's own other bridge of an older version, or another agent's. ${take}`
|
|
35470
|
+
};
|
|
35471
|
+
return {
|
|
35472
|
+
state: "standby",
|
|
35473
|
+
restored: false,
|
|
35474
|
+
peerId,
|
|
35475
|
+
servedBy,
|
|
35476
|
+
holder,
|
|
35477
|
+
recheck,
|
|
35478
|
+
// A final standby is evaluated once, so it says "when this bridge started": the health
|
|
35479
|
+
// check keeps showing this text after that bridge is gone.
|
|
35480
|
+
detail: `peer '${peerId}' ${recheck ? "is already served" : "was already served when this bridge started"} by a live bridge for this working directory (pid ${servedBy.pid}, version ${servedBy.version ?? "unknown"}, started ${started}); this bridge has NOT registered and ` + (recheck ? `restores '${peerId}' by itself once that bridge is gone${every}. ` : `does NOT take '${peerId}' by itself, also after that bridge is gone. `) + why[holder]
|
|
35215
35481
|
};
|
|
35216
35482
|
}
|
|
35217
35483
|
if (!autoPresenceEnabled(deps.env ?? process.env)) {
|
|
@@ -35271,15 +35537,22 @@ function logPresence(outcome) {
|
|
|
35271
35537
|
);
|
|
35272
35538
|
} else if (outcome.state === "offline") {
|
|
35273
35539
|
logger.warn(`Presence: OFFLINE \u2014 ${outcome.detail}.`);
|
|
35540
|
+
} else if (outcome.state === "standby" && outcome.holder === "other-session") {
|
|
35541
|
+
logger.warn(`Presence: STANDBY \u2014 ${outcome.detail}.`);
|
|
35542
|
+
} else if (outcome.state === "standby" || outcome.state === "deferred") {
|
|
35543
|
+
logger.info(`Presence: ${outcome.state.toUpperCase()} \u2014 ${outcome.detail}.`);
|
|
35274
35544
|
} else {
|
|
35275
35545
|
logger.debug(`Presence: ${outcome.state} \u2014 ${outcome.detail}.`);
|
|
35276
35546
|
}
|
|
35277
35547
|
}
|
|
35278
|
-
var lastPresence;
|
|
35548
|
+
var ORPHAN_PARENT_RE, NPX_WRAPPER_RE, lastPresence;
|
|
35279
35549
|
var init_peer_presence = __esm({
|
|
35280
35550
|
"src/services/peer-presence.ts"() {
|
|
35281
35551
|
"use strict";
|
|
35282
35552
|
init_logger();
|
|
35553
|
+
init_wake_ownership();
|
|
35554
|
+
ORPHAN_PARENT_RE = /^(init|launchd|systemd)$/;
|
|
35555
|
+
NPX_WRAPPER_RE = /^(?:\S*\/)?(?:sh|bash|dash) -c cogent-bridge\b|^npm exec @essentialai\/cogent-bridge/;
|
|
35283
35556
|
lastPresence = null;
|
|
35284
35557
|
}
|
|
35285
35558
|
});
|
|
@@ -35517,6 +35790,7 @@ __export(startup_exports, {
|
|
|
35517
35790
|
hasPendingLabelResolve: () => hasPendingLabelResolve,
|
|
35518
35791
|
isCloudMode: () => isCloudMode2,
|
|
35519
35792
|
presenceRegisterArgs: () => presenceRegisterArgs,
|
|
35793
|
+
presenceRetryPending: () => presenceRetryPending,
|
|
35520
35794
|
reinitCloudBackend: () => reinitCloudBackend,
|
|
35521
35795
|
resolvePendingLabel: () => resolvePendingLabel,
|
|
35522
35796
|
restorePeerPresence: () => restorePeerPresence,
|
|
@@ -35526,8 +35800,8 @@ __export(startup_exports, {
|
|
|
35526
35800
|
triggerReRegistration: () => triggerReRegistration
|
|
35527
35801
|
});
|
|
35528
35802
|
import os15 from "node:os";
|
|
35529
|
-
import
|
|
35530
|
-
import
|
|
35803
|
+
import path22 from "node:path";
|
|
35804
|
+
import fs21 from "node:fs/promises";
|
|
35531
35805
|
import readline2 from "node:readline";
|
|
35532
35806
|
import { execFile as execFile5 } from "node:child_process";
|
|
35533
35807
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -35545,7 +35819,7 @@ function bindInboxNotifier() {
|
|
|
35545
35819
|
}
|
|
35546
35820
|
async function loadPersistedConfig() {
|
|
35547
35821
|
try {
|
|
35548
|
-
const raw = await
|
|
35822
|
+
const raw = await fs21.readFile(PERSIST_PATH, "utf-8");
|
|
35549
35823
|
return JSON.parse(raw);
|
|
35550
35824
|
} catch {
|
|
35551
35825
|
return {};
|
|
@@ -35553,7 +35827,7 @@ async function loadPersistedConfig() {
|
|
|
35553
35827
|
}
|
|
35554
35828
|
async function savePersistedConfig(config2) {
|
|
35555
35829
|
try {
|
|
35556
|
-
await
|
|
35830
|
+
await fs21.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
35557
35831
|
} catch (err) {
|
|
35558
35832
|
const msg = err instanceof Error ? err.message : String(err);
|
|
35559
35833
|
logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
|
|
@@ -35588,11 +35862,11 @@ First run detected. Where should cogent-bridge store its data?
|
|
|
35588
35862
|
});
|
|
35589
35863
|
}
|
|
35590
35864
|
async function validateStateDir(statePath) {
|
|
35591
|
-
await
|
|
35592
|
-
const testFile =
|
|
35865
|
+
await fs21.mkdir(statePath, { recursive: true });
|
|
35866
|
+
const testFile = path22.join(statePath, ".write-test");
|
|
35593
35867
|
try {
|
|
35594
|
-
await
|
|
35595
|
-
await
|
|
35868
|
+
await fs21.writeFile(testFile, "test", "utf-8");
|
|
35869
|
+
await fs21.unlink(testFile);
|
|
35596
35870
|
} catch {
|
|
35597
35871
|
throw new BridgeError(
|
|
35598
35872
|
"STARTUP_FAILED" /* STARTUP_FAILED */,
|
|
@@ -35669,15 +35943,37 @@ function presenceRegisterArgs(p) {
|
|
|
35669
35943
|
// AUD-003 ownership proof — reclaims a peer owned by an earlier token
|
|
35670
35944
|
];
|
|
35671
35945
|
}
|
|
35946
|
+
function presenceRetryPending() {
|
|
35947
|
+
return presenceRetry !== null;
|
|
35948
|
+
}
|
|
35672
35949
|
function cancelPresenceRetry() {
|
|
35673
35950
|
if (presenceRetry) clearTimeout(presenceRetry);
|
|
35674
35951
|
presenceRetry = null;
|
|
35675
35952
|
}
|
|
35676
|
-
function
|
|
35953
|
+
function presenceRetryBaseMs() {
|
|
35677
35954
|
const base = Number(process.env.COGENT_PRESENCE_RETRY_MS);
|
|
35678
|
-
return
|
|
35955
|
+
return Number.isFinite(base) && base > 0 ? base : 3e4;
|
|
35956
|
+
}
|
|
35957
|
+
function presenceRetryDelayMs(attempt) {
|
|
35958
|
+
return Math.min(presenceRetryBaseMs() * 2 ** attempt, 3e5);
|
|
35959
|
+
}
|
|
35960
|
+
function standbyRecheckMs() {
|
|
35961
|
+
return Math.max(250, Math.min(presenceRetryBaseMs(), 15e3));
|
|
35679
35962
|
}
|
|
35680
35963
|
async function restorePeerPresence(attempt = 0) {
|
|
35964
|
+
if (!presenceSupersedeBound) {
|
|
35965
|
+
presenceSupersedeBound = true;
|
|
35966
|
+
onCloudAttemptInProcess(() => cancelPresenceRetry());
|
|
35967
|
+
}
|
|
35968
|
+
const superseded = { state: "deferred", restored: false, detail: PRESENCE_SUPERSEDED };
|
|
35969
|
+
if (hasCloudAttemptInProcess()) {
|
|
35970
|
+
logPresence(superseded);
|
|
35971
|
+
return superseded;
|
|
35972
|
+
}
|
|
35973
|
+
const generation = getCloudAttemptGeneration();
|
|
35974
|
+
const stillCurrent = () => getCloudAttemptGeneration() === generation;
|
|
35975
|
+
let procs = null;
|
|
35976
|
+
const ps = () => procs ??= listProcesses();
|
|
35681
35977
|
const outcome = await restorePresence({
|
|
35682
35978
|
// The endpoint being a relay URL is what makes presence meaningful. We deliberately do
|
|
35683
35979
|
// NOT gate on the active backend being the cloud one: at startup it is still the
|
|
@@ -35690,34 +35986,65 @@ async function restorePeerPresence(attempt = 0) {
|
|
|
35690
35986
|
alreadyRegisteredInProcess: () => autoRelay.getDiagnostics().registered,
|
|
35691
35987
|
peerAlreadyServed: (peerId) => {
|
|
35692
35988
|
try {
|
|
35693
|
-
|
|
35989
|
+
const holders = listLiveBridges(process.cwd(), peerId).filter((b) => b.pid !== process.pid && !b.draining);
|
|
35990
|
+
const other = holders.find((b) => {
|
|
35991
|
+
if (!holderClientGone(b, ps())) return true;
|
|
35992
|
+
if (!ignoredHolders.has(b.pid)) {
|
|
35993
|
+
ignoredHolders.add(b.pid);
|
|
35994
|
+
logger.info(
|
|
35995
|
+
`Presence: ignoring bridge pid ${b.pid} (${registryText(b.version)}) announced for '${peerId}' \u2014 its MCP client is gone (parent then: ${b.parentPid === void 0 ? "not recorded" : registryText(b.parentPid)}), so it serves no agent`
|
|
35996
|
+
);
|
|
35997
|
+
}
|
|
35998
|
+
return false;
|
|
35999
|
+
});
|
|
36000
|
+
return other ? { pid: other.pid, version: other.version, startedAt: other.startedAt, sessionId: other.sessionId } : null;
|
|
35694
36001
|
} catch {
|
|
35695
|
-
return
|
|
36002
|
+
return null;
|
|
35696
36003
|
}
|
|
35697
36004
|
},
|
|
36005
|
+
agentSessionId: () => agentSessionId(),
|
|
36006
|
+
startedByWakeTurn: () => insideCodexWakeTurn(process.pid, ps()),
|
|
35698
36007
|
loadCredentials: () => loadCredentials(),
|
|
35699
36008
|
cwd: () => process.cwd(),
|
|
36009
|
+
recheckSeconds: Math.round(standbyRecheckMs() / 1e3),
|
|
35700
36010
|
goOnline: async ({ peerId, endpoint, sessionId, token, cwd, label, peerSecret }) => {
|
|
36011
|
+
if (!stillCurrent()) throw new Error(PRESENCE_SUPERSEDED);
|
|
35701
36012
|
await reinitCloudBackend(endpoint, sessionId, token);
|
|
35702
36013
|
const backend = getBackend();
|
|
35703
36014
|
await backend.registerPeer(...presenceRegisterArgs({ peerId, sessionId, cwd, label, peerSecret }));
|
|
36015
|
+
const slot = await loadCredentials();
|
|
36016
|
+
if (!stillCurrent() || slot?.sessionId !== sessionId || slot?.endpoint !== endpoint) {
|
|
36017
|
+
throw new Error(PRESENCE_SUPERSEDED);
|
|
36018
|
+
}
|
|
35704
36019
|
autoRelay.setLocalPeer(peerId, sessionId, cwd, "agent", label, sessionId);
|
|
35705
36020
|
if (cloudWsClient) cloudWsClient.setPeerId(peerId);
|
|
35706
36021
|
heartbeat.restart();
|
|
36022
|
+
markJoinedInProcess();
|
|
35707
36023
|
}
|
|
35708
36024
|
});
|
|
36025
|
+
if (!stillCurrent()) {
|
|
36026
|
+
logPresence(superseded);
|
|
36027
|
+
return superseded;
|
|
36028
|
+
}
|
|
36029
|
+
const prev = getPresence();
|
|
35709
36030
|
setPresence(outcome);
|
|
35710
|
-
|
|
35711
|
-
|
|
35712
|
-
|
|
36031
|
+
if (outcome.state === "standby" && prev?.state === "standby" && prev.servedBy.pid === outcome.servedBy.pid) {
|
|
36032
|
+
logger.debug(`Presence: STANDBY (unchanged) \u2014 ${outcome.detail}.`);
|
|
36033
|
+
} else {
|
|
36034
|
+
logPresence(outcome);
|
|
36035
|
+
}
|
|
36036
|
+
const failed = outcome.state === "offline" && outcome.detail.startsWith("presence restore failed");
|
|
36037
|
+
const standby = outcome.state === "standby" && outcome.recheck;
|
|
36038
|
+
if (failed || standby) {
|
|
36039
|
+
const delay = standby ? standbyRecheckMs() : presenceRetryDelayMs(attempt);
|
|
35713
36040
|
cancelPresenceRetry();
|
|
35714
36041
|
presenceRetry = setTimeout(() => {
|
|
35715
36042
|
presenceRetry = null;
|
|
35716
|
-
void restorePeerPresence(attempt + 1).catch(() => {
|
|
36043
|
+
void restorePeerPresence(standby ? 0 : attempt + 1).catch(() => {
|
|
35717
36044
|
});
|
|
35718
36045
|
}, delay);
|
|
35719
36046
|
presenceRetry.unref?.();
|
|
35720
|
-
logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
|
|
36047
|
+
if (failed) logger.warn(`presence: restore failed \u2014 retrying in ${Math.round(delay / 1e3)}s`);
|
|
35721
36048
|
}
|
|
35722
36049
|
return outcome;
|
|
35723
36050
|
}
|
|
@@ -35851,10 +36178,10 @@ async function runStartup() {
|
|
|
35851
36178
|
if (envStatePath) {
|
|
35852
36179
|
statePath = envStatePath;
|
|
35853
36180
|
} else {
|
|
35854
|
-
const defaultPath =
|
|
36181
|
+
const defaultPath = path22.join(os15.homedir(), ".cogent");
|
|
35855
36182
|
statePath = await firstRunPrompt(defaultPath);
|
|
35856
36183
|
}
|
|
35857
|
-
if (!envStatePath && statePath !==
|
|
36184
|
+
if (!envStatePath && statePath !== path22.join(os15.homedir(), ".cogent")) {
|
|
35858
36185
|
process.env.COGENT_STATE_PATH = statePath;
|
|
35859
36186
|
} else if (!envStatePath) {
|
|
35860
36187
|
process.env.COGENT_STATE_PATH = statePath;
|
|
@@ -35918,7 +36245,7 @@ async function runStartup() {
|
|
|
35918
36245
|
}
|
|
35919
36246
|
initLogger(
|
|
35920
36247
|
config2.COGENT_LOG_LEVEL,
|
|
35921
|
-
|
|
36248
|
+
path22.join(config2.COGENT_STATE_PATH, "logs")
|
|
35922
36249
|
);
|
|
35923
36250
|
if (isCloud && effectiveSessionId && effectiveToken) {
|
|
35924
36251
|
cloudInbox = new MessageInbox();
|
|
@@ -35958,7 +36285,7 @@ async function runPreflights() {
|
|
|
35958
36285
|
await preflightClaude(config2.COGENT_CLAUDE_PATH);
|
|
35959
36286
|
}
|
|
35960
36287
|
}
|
|
35961
|
-
var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, pendingLabelResolve;
|
|
36288
|
+
var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, presenceRetry, ignoredHolders, presenceSupersedeBound, PRESENCE_SUPERSEDED, pendingLabelResolve;
|
|
35962
36289
|
var init_startup = __esm({
|
|
35963
36290
|
"src/startup.ts"() {
|
|
35964
36291
|
"use strict";
|
|
@@ -35974,6 +36301,7 @@ var init_startup = __esm({
|
|
|
35974
36301
|
init_auto_relay();
|
|
35975
36302
|
init_peer_presence();
|
|
35976
36303
|
init_wake_ownership();
|
|
36304
|
+
init_stale_bridge_reaper();
|
|
35977
36305
|
init_heartbeat();
|
|
35978
36306
|
init_codex_preflight();
|
|
35979
36307
|
init_codex_cli();
|
|
@@ -35982,7 +36310,7 @@ var init_startup = __esm({
|
|
|
35982
36310
|
init_auto_relay();
|
|
35983
36311
|
UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
35984
36312
|
execFileAsync3 = promisify4(execFile5);
|
|
35985
|
-
PERSIST_PATH =
|
|
36313
|
+
PERSIST_PATH = path22.join(os15.homedir(), ".cogent-config.json");
|
|
35986
36314
|
legacyWarnEmitted = false;
|
|
35987
36315
|
cloudWsClient = null;
|
|
35988
36316
|
cloudInbox = null;
|
|
@@ -35992,18 +36320,21 @@ var init_startup = __esm({
|
|
|
35992
36320
|
notifierBoundTo = null;
|
|
35993
36321
|
reRegistrationInProgress = false;
|
|
35994
36322
|
presenceRetry = null;
|
|
36323
|
+
ignoredHolders = /* @__PURE__ */ new Set();
|
|
36324
|
+
presenceSupersedeBound = false;
|
|
36325
|
+
PRESENCE_SUPERSEDED = "presence restore superseded: an explicit cogent_join_session/cogent_create_session ran in this process and owns the channel choice";
|
|
35995
36326
|
pendingLabelResolve = null;
|
|
35996
36327
|
}
|
|
35997
36328
|
});
|
|
35998
36329
|
|
|
35999
36330
|
// src/cloud/mail-credential-store.ts
|
|
36000
36331
|
import crypto9 from "node:crypto";
|
|
36001
|
-
import
|
|
36002
|
-
import
|
|
36332
|
+
import fs22 from "node:fs/promises";
|
|
36333
|
+
import path23 from "node:path";
|
|
36003
36334
|
import os16 from "node:os";
|
|
36004
36335
|
function defaultMailCredentialPath(cwd = process.cwd()) {
|
|
36005
|
-
const hash = crypto9.createHash("sha256").update(
|
|
36006
|
-
return
|
|
36336
|
+
const hash = crypto9.createHash("sha256").update(path23.resolve(cwd)).digest("hex").slice(0, 16);
|
|
36337
|
+
return path23.join(os16.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
|
|
36007
36338
|
}
|
|
36008
36339
|
function resolveMailCredentialPath(credentialPath) {
|
|
36009
36340
|
if (credentialPath) return credentialPath;
|
|
@@ -36014,16 +36345,16 @@ function resolveMailCredentialPath(credentialPath) {
|
|
|
36014
36345
|
async function loadMailCredentials(credentialPath) {
|
|
36015
36346
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
36016
36347
|
try {
|
|
36017
|
-
return JSON.parse(await
|
|
36348
|
+
return JSON.parse(await fs22.readFile(filePath, "utf-8"));
|
|
36018
36349
|
} catch {
|
|
36019
36350
|
return null;
|
|
36020
36351
|
}
|
|
36021
36352
|
}
|
|
36022
36353
|
async function saveMailCredentials(creds, credentialPath) {
|
|
36023
36354
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
36024
|
-
await
|
|
36025
|
-
await
|
|
36026
|
-
await
|
|
36355
|
+
await fs22.mkdir(path23.dirname(filePath), { recursive: true, mode: 448 });
|
|
36356
|
+
await fs22.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
36357
|
+
await fs22.chmod(filePath, 384);
|
|
36027
36358
|
}
|
|
36028
36359
|
async function persistProvisionedMailbox(mailbox, credentialPath) {
|
|
36029
36360
|
if (!mailbox?.address || !mailbox.password) return false;
|
|
@@ -36044,7 +36375,7 @@ async function persistProvisionedMailbox(mailbox, credentialPath) {
|
|
|
36044
36375
|
async function clearMailCredentials(credentialPath) {
|
|
36045
36376
|
const filePath = resolveMailCredentialPath(credentialPath);
|
|
36046
36377
|
try {
|
|
36047
|
-
await
|
|
36378
|
+
await fs22.unlink(filePath);
|
|
36048
36379
|
} catch (err) {
|
|
36049
36380
|
if (err.code !== "ENOENT") throw err;
|
|
36050
36381
|
}
|
|
@@ -36064,15 +36395,39 @@ function unresolvedSessionReason(r) {
|
|
|
36064
36395
|
if (r.sessionId) return null;
|
|
36065
36396
|
return r.candidateCount === 0 ? "no-candidates" : "ambiguous";
|
|
36066
36397
|
}
|
|
36398
|
+
function peerReclaimWaitMs() {
|
|
36399
|
+
const v = Number(process.env.COGENT_PEER_RECLAIM_WAIT_MS);
|
|
36400
|
+
return Number.isFinite(v) && v >= 0 ? v : 5e4;
|
|
36401
|
+
}
|
|
36402
|
+
async function retrySamePeerId(first, attempt, budgetMs = peerReclaimWaitMs(), sleep4 = (ms) => new Promise((r) => setTimeout(r, ms))) {
|
|
36403
|
+
let err = first;
|
|
36404
|
+
const start = Date.now();
|
|
36405
|
+
let backoff = 1e3;
|
|
36406
|
+
for (; ; ) {
|
|
36407
|
+
const remaining = budgetMs - (Date.now() - start);
|
|
36408
|
+
const retryAfter = err.retryAfterMs;
|
|
36409
|
+
if (retryAfter === void 0 || remaining <= 0 || retryAfter > remaining) throw err;
|
|
36410
|
+
const wait = Math.min(Math.max(retryAfter, backoff), remaining);
|
|
36411
|
+
logger.warn(`register_peer: peerId held by an earlier registration \u2014 retrying the SAME id in ${Math.round(wait / 1e3)}s`);
|
|
36412
|
+
await sleep4(wait);
|
|
36413
|
+
backoff = Math.min(backoff * 2, 15e3);
|
|
36414
|
+
try {
|
|
36415
|
+
return await attempt();
|
|
36416
|
+
} catch (next) {
|
|
36417
|
+
if (!(next instanceof BridgeError && next.code === "PEER_NOT_YOURS" /* PEER_NOT_YOURS */)) throw next;
|
|
36418
|
+
err = next;
|
|
36419
|
+
}
|
|
36420
|
+
}
|
|
36421
|
+
}
|
|
36067
36422
|
function registerRegisterPeerTool(server) {
|
|
36068
36423
|
server.registerTool(
|
|
36069
36424
|
"cogent_register_peer",
|
|
36070
36425
|
{
|
|
36071
36426
|
title: "Register Peer",
|
|
36072
|
-
description: "
|
|
36427
|
+
description: "Step 3: put this agent online in the channel joined or created in this session. peerId = the peer name you were given (never invent or suffix one); sessionId = this agent session's own resumable id (Claude Code or Codex), not the channel id. Also needs the working directory (cwd) and a human-readable label.",
|
|
36073
36428
|
inputSchema: {
|
|
36074
|
-
peerId: import_zod3.z.string().describe("
|
|
36075
|
-
sessionId: import_zod3.z.string().describe("
|
|
36429
|
+
peerId: import_zod3.z.string().describe("The peer name you were given, e.g. 'backend' or 'frontend'. Never invent or suffix one."),
|
|
36430
|
+
sessionId: import_zod3.z.string().describe("This agent session's own resumable id (Claude Code or Codex) \u2014 NOT the channel id"),
|
|
36076
36431
|
cwd: import_zod3.z.string().describe("Absolute path to the project working directory"),
|
|
36077
36432
|
label: import_zod3.z.string().describe("Human-readable label, e.g. 'Cogent_Backend' or 'Cogent_Frontend'"),
|
|
36078
36433
|
peerSecret: import_zod3.z.string().optional().describe(
|
|
@@ -36095,13 +36450,22 @@ function registerRegisterPeerTool(server) {
|
|
|
36095
36450
|
async ({ peerId, sessionId, cwd, label, mode, role, peerSecret: argPeerSecret }) => {
|
|
36096
36451
|
try {
|
|
36097
36452
|
const config2 = getConfig();
|
|
36453
|
+
if (isReservedPeerName(peerId)) {
|
|
36454
|
+
return errorResult(
|
|
36455
|
+
new BridgeError(
|
|
36456
|
+
"INVALID_INPUT" /* INVALID_INPUT */,
|
|
36457
|
+
`peerId '${PROCESS_MARK}' is reserved by the bridge`,
|
|
36458
|
+
"Register under another peerId"
|
|
36459
|
+
)
|
|
36460
|
+
);
|
|
36461
|
+
}
|
|
36098
36462
|
const hasExplicitCloudSession = !!config2.COGENT_SESSION_ID || process.env.COGENT_TRUST_PERSISTED_CREDENTIALS === "1";
|
|
36099
36463
|
if (!hasExplicitCloudSession && hasCloudAttemptInProcess() && !hasJoinedInProcess()) {
|
|
36100
36464
|
return errorResult(
|
|
36101
36465
|
new BridgeError(
|
|
36102
36466
|
"JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
|
|
36103
36467
|
"A cogent_join_session/cogent_create_session call was attempted this session but did not succeed, so cogent_register_peer will not fall back to local mode or auto-create a new channel (that would silently put you on the WRONG channel while reporting success)",
|
|
36104
|
-
"Re-run cogent_join_session with the correct channel name + secret (+ Org_ID for Team channels) and confirm it returns success before calling cogent_register_peer"
|
|
36468
|
+
"Re-run cogent_join_session with the correct channel name + secret (+ Org_ID for Team channels) and confirm it returns success before calling cogent_register_peer; or, if the join answered CHANNEL_NOT_FOUND, cogent_create_session with the same name, secret and Org_ID"
|
|
36105
36469
|
)
|
|
36106
36470
|
);
|
|
36107
36471
|
}
|
|
@@ -36125,6 +36489,17 @@ function registerRegisterPeerTool(server) {
|
|
|
36125
36489
|
}
|
|
36126
36490
|
}
|
|
36127
36491
|
if (!cloudSessionId) {
|
|
36492
|
+
const stored = await loadCredentials();
|
|
36493
|
+
if (stored?.sessionId) {
|
|
36494
|
+
const channel = stored.label ? `'${stored.label}' (${stored.sessionId})` : `'${stored.sessionId}'`;
|
|
36495
|
+
return errorResult(
|
|
36496
|
+
new BridgeError(
|
|
36497
|
+
"JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
|
|
36498
|
+
`This working directory is already on channel ${channel} at ${stored.endpoint}, but this bridge is not online on it, so cogent_register_peer will NOT auto-create a new channel (that would silently move you off your channel while reporting success)`,
|
|
36499
|
+
`Call cogent_join_session for channel ${channel} (name + secret, + Org_ID for Team channels) and confirm it returns success, then retry cogent_register_peer with the SAME peerId. If that join reports the channel no longer exists, or you do not know its secret, ask the user which channel this agent belongs on and join it (cogent_join_session) or create it (cogent_create_session) explicitly, then register with the SAME peerId \u2014 a channel is never auto-created over a stored one`
|
|
36500
|
+
)
|
|
36501
|
+
);
|
|
36502
|
+
}
|
|
36128
36503
|
autoSecret = crypto10.randomBytes(16).toString("hex");
|
|
36129
36504
|
const resp = await fetch(
|
|
36130
36505
|
`${endpoint}/api/sessions`,
|
|
@@ -36188,7 +36563,7 @@ function registerRegisterPeerTool(server) {
|
|
|
36188
36563
|
new BridgeError(
|
|
36189
36564
|
"JOIN_NOT_CONFIRMED" /* JOIN_NOT_CONFIRMED */,
|
|
36190
36565
|
"Cloud endpoint + COGENT_SESSION_ID are configured but this bridge has not joined the channel (no session token \u2014 the relay was unreachable or the session label did not resolve at startup). cogent_register_peer will NOT register against local state (that would leave you on no channel while other local agents' data sits on this host).",
|
|
36191
|
-
"Call cogent_join_session with the channel name + secret (+ Org_ID for Team channels) and confirm it returns success, then retry cogent_register_peer."
|
|
36566
|
+
"Call cogent_join_session with the channel name + secret (+ Org_ID for Team channels) and confirm it returns success (or, if the join answered CHANNEL_NOT_FOUND, cogent_create_session with the same name, secret and Org_ID), then retry cogent_register_peer."
|
|
36192
36567
|
)
|
|
36193
36568
|
);
|
|
36194
36569
|
}
|
|
@@ -36260,6 +36635,24 @@ function registerRegisterPeerTool(server) {
|
|
|
36260
36635
|
logger.debug(`register_peer: ownership recovery failed: ${recoverErr.message}`);
|
|
36261
36636
|
}
|
|
36262
36637
|
}
|
|
36638
|
+
if (!recovered && regErr instanceof BridgeError && regErr.code === "PEER_NOT_YOURS" /* PEER_NOT_YOURS */) {
|
|
36639
|
+
recovered = await retrySamePeerId(
|
|
36640
|
+
regErr,
|
|
36641
|
+
() => backend.registerPeer(
|
|
36642
|
+
peerId,
|
|
36643
|
+
sessionId,
|
|
36644
|
+
cwd,
|
|
36645
|
+
label,
|
|
36646
|
+
CLIENT_VERSION,
|
|
36647
|
+
mode,
|
|
36648
|
+
channelSessionId,
|
|
36649
|
+
capabilities,
|
|
36650
|
+
workspaceId,
|
|
36651
|
+
threadId,
|
|
36652
|
+
storedPeerSecret
|
|
36653
|
+
)
|
|
36654
|
+
);
|
|
36655
|
+
}
|
|
36263
36656
|
if (!recovered) throw regErr;
|
|
36264
36657
|
peer = recovered;
|
|
36265
36658
|
}
|
|
@@ -36319,9 +36712,25 @@ function registerRegisterPeerTool(server) {
|
|
|
36319
36712
|
}
|
|
36320
36713
|
}
|
|
36321
36714
|
autoRelay.setLocalPeer(peerId, localSessionId, cwd, mode, label, localSessionId);
|
|
36715
|
+
if (isCloudMode()) {
|
|
36716
|
+
setPresence({ state: "online", restored: false, detail: `registered as '${peerId}' by cogent_register_peer` });
|
|
36717
|
+
}
|
|
36718
|
+
let otherBridges;
|
|
36719
|
+
try {
|
|
36720
|
+
const own = agentSessionId();
|
|
36721
|
+
const others = otherBridgesInFolder(listLiveBridgesInFolder(cwd), { pid: process.pid, sessionId: own }, listProcesses);
|
|
36722
|
+
if (others.length) {
|
|
36723
|
+
otherBridges = otherBridgeNotice(others, peerId, checkWakeOwnership(cwd, peerId), own);
|
|
36724
|
+
if (anotherAgentSessionAmong(others, own)) logger.warn(`Register: ${otherBridges}`);
|
|
36725
|
+
else logger.info(`Register: ${otherBridges}`);
|
|
36726
|
+
}
|
|
36727
|
+
} catch (err) {
|
|
36728
|
+
logger.debug(`Register: could not look for other bridges in this folder: ${err.message}`);
|
|
36729
|
+
}
|
|
36322
36730
|
const result = {
|
|
36323
36731
|
success: true,
|
|
36324
36732
|
action: existing ? "updated" : "registered",
|
|
36733
|
+
...otherBridges ? { otherBridgeInThisFolder: otherBridges } : {},
|
|
36325
36734
|
peer,
|
|
36326
36735
|
sessionResolution: {
|
|
36327
36736
|
decision: resolution.decision,
|
|
@@ -36400,6 +36809,9 @@ var init_register_peer = __esm({
|
|
|
36400
36809
|
init_logger();
|
|
36401
36810
|
init_heartbeat();
|
|
36402
36811
|
init_auto_relay();
|
|
36812
|
+
init_wake_ownership();
|
|
36813
|
+
init_peer_presence();
|
|
36814
|
+
init_stale_bridge_reaper();
|
|
36403
36815
|
init_session_resolver();
|
|
36404
36816
|
init_cc_cli();
|
|
36405
36817
|
init_durable_identity();
|
|
@@ -37069,9 +37481,14 @@ var init_ids = __esm({
|
|
|
37069
37481
|
});
|
|
37070
37482
|
|
|
37071
37483
|
// cogent/dist/helpers/validation.js
|
|
37484
|
+
function isValidSessionLabel(value) {
|
|
37485
|
+
return SESSION_LABEL_REGEX.test(value);
|
|
37486
|
+
}
|
|
37487
|
+
var SESSION_LABEL_REGEX;
|
|
37072
37488
|
var init_validation = __esm({
|
|
37073
37489
|
"cogent/dist/helpers/validation.js"() {
|
|
37074
37490
|
"use strict";
|
|
37491
|
+
SESSION_LABEL_REGEX = /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/;
|
|
37075
37492
|
}
|
|
37076
37493
|
});
|
|
37077
37494
|
|
|
@@ -37524,7 +37941,8 @@ function registerHealthCheckTool(server) {
|
|
|
37524
37941
|
// PRESENCE — the agent's own view of whether it is IN its channel, so it can
|
|
37525
37942
|
// answer "am I reachable?" without inferring it from transport internals.
|
|
37526
37943
|
// "online" registered · "offline" owns a peer but is not registered (nobody can
|
|
37527
|
-
// reach it) · "
|
|
37944
|
+
// reach it) · "standby" another live bridge serves this peer, so THIS process is not
|
|
37945
|
+
// registered (servedBy names it) · "deferred" never joined · "local" no relay.
|
|
37528
37946
|
// services/peer-presence.ts carries the vocabulary and how each state arises.
|
|
37529
37947
|
presence: (() => {
|
|
37530
37948
|
const p = getPresence();
|
|
@@ -37535,7 +37953,8 @@ function registerHealthCheckTool(server) {
|
|
|
37535
37953
|
state: p.state,
|
|
37536
37954
|
restored: p.restored,
|
|
37537
37955
|
detail: p.detail,
|
|
37538
|
-
..."peerId" in p ? { peerId: p.peerId } : {}
|
|
37956
|
+
..."peerId" in p ? { peerId: p.peerId } : {},
|
|
37957
|
+
..."servedBy" in p ? { servedBy: p.servedBy } : {}
|
|
37539
37958
|
};
|
|
37540
37959
|
})()
|
|
37541
37960
|
};
|
|
@@ -37622,18 +38041,43 @@ var init_wake_log2 = __esm({
|
|
|
37622
38041
|
}
|
|
37623
38042
|
});
|
|
37624
38043
|
|
|
38044
|
+
// src/tools/channel-text.ts
|
|
38045
|
+
function invalidChannelName(name) {
|
|
38046
|
+
if (isValidSessionLabel(name)) return null;
|
|
38047
|
+
return new BridgeError(
|
|
38048
|
+
"INVALID_INPUT" /* INVALID_INPUT */,
|
|
38049
|
+
`Channel names are 3-32 characters: lowercase letters, digits and hyphens. '${name}' is not valid`,
|
|
38050
|
+
"If it differs only by capital letters, retry with it in lowercase; otherwise ask the user."
|
|
38051
|
+
);
|
|
38052
|
+
}
|
|
38053
|
+
function slackMapCommand(o) {
|
|
38054
|
+
return o.team ? `/cogent map ${o.label} <password> <org-id>` : `/cogent map ${o.sessionId} <password>`;
|
|
38055
|
+
}
|
|
38056
|
+
var init_channel_text = __esm({
|
|
38057
|
+
"src/tools/channel-text.ts"() {
|
|
38058
|
+
"use strict";
|
|
38059
|
+
init_dist();
|
|
38060
|
+
init_errors4();
|
|
38061
|
+
}
|
|
38062
|
+
});
|
|
38063
|
+
|
|
37625
38064
|
// src/tools/create-session.ts
|
|
37626
38065
|
import crypto11 from "node:crypto";
|
|
37627
38066
|
function registerCreateSessionTool(server) {
|
|
37628
38067
|
server.registerTool(
|
|
37629
38068
|
"cogent_create_session",
|
|
37630
38069
|
{
|
|
37631
|
-
title: "Create Cloud
|
|
37632
|
-
description: "
|
|
38070
|
+
title: "Create Cloud Channel",
|
|
38071
|
+
description: "Step 2: create a Cogent channel and join it. Call this ONLY after cogent_join_session answered CHANNEL_NOT_FOUND, with the SAME channel name, secret and (Team channel) orgId. Never choose a different name. Next call: cogent_register_peer.",
|
|
37633
38072
|
inputSchema: {
|
|
37634
|
-
label: import_zod15.z.string().optional().describe(
|
|
38073
|
+
label: import_zod15.z.string().optional().describe(
|
|
38074
|
+
"The channel name (3-32 characters: lowercase letters, digits, hyphens) \u2014 the same name the join was given. Auto-generated if omitted."
|
|
38075
|
+
),
|
|
37635
38076
|
secret: import_zod15.z.string().min(8).optional().describe(
|
|
37636
|
-
"Shared secret for
|
|
38077
|
+
"Shared secret / password for the channel (min 8 chars). Auto-generated if omitted."
|
|
38078
|
+
),
|
|
38079
|
+
orgId: import_zod15.z.string().min(1).optional().describe(
|
|
38080
|
+
"Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it to create a Team channel; omit for a free channel."
|
|
37637
38081
|
)
|
|
37638
38082
|
},
|
|
37639
38083
|
annotations: {
|
|
@@ -37643,28 +38087,57 @@ function registerCreateSessionTool(server) {
|
|
|
37643
38087
|
openWorldHint: true
|
|
37644
38088
|
}
|
|
37645
38089
|
},
|
|
37646
|
-
async ({ label, secret }) => {
|
|
38090
|
+
async ({ label, secret, orgId }) => {
|
|
37647
38091
|
try {
|
|
37648
38092
|
markCloudAttemptInProcess();
|
|
38093
|
+
if (label !== void 0 && label.trim() === "") {
|
|
38094
|
+
return errorResult(invalidChannelName(label) ?? new Error("label is empty"));
|
|
38095
|
+
}
|
|
38096
|
+
if (secret !== void 0 && secret.trim() === "") {
|
|
38097
|
+
return errorResult(
|
|
38098
|
+
new BridgeError(
|
|
38099
|
+
"INVALID_INPUT" /* INVALID_INPUT */,
|
|
38100
|
+
"The channel password is empty",
|
|
38101
|
+
"Pass the password you were given, or omit `secret` to have one generated."
|
|
38102
|
+
)
|
|
38103
|
+
);
|
|
38104
|
+
}
|
|
38105
|
+
label = label?.trim() || void 0;
|
|
38106
|
+
secret = secret?.trim() || void 0;
|
|
38107
|
+
orgId = orgId?.trim() || void 0;
|
|
37649
38108
|
const config2 = getConfig();
|
|
37650
|
-
|
|
38109
|
+
const endpoint = orgId ? config2.COGENT_TEAM_ENDPOINT : config2.COGENT_ENDPOINT;
|
|
38110
|
+
if (!endpoint) {
|
|
37651
38111
|
return errorResult(
|
|
37652
38112
|
new Error(
|
|
37653
|
-
"COGENT_ENDPOINT not configured. Set it to use cloud mode."
|
|
38113
|
+
orgId ? "COGENT_TEAM_ENDPOINT not configured. Set it to create Team (Org_ID) channels." : "COGENT_ENDPOINT not configured. Set it to use cloud mode."
|
|
37654
38114
|
)
|
|
37655
38115
|
);
|
|
37656
38116
|
}
|
|
38117
|
+
if (label !== void 0) {
|
|
38118
|
+
const invalid = invalidChannelName(label);
|
|
38119
|
+
if (invalid) return errorResult(invalid);
|
|
38120
|
+
}
|
|
38121
|
+
const secretWasGenerated = secret === void 0;
|
|
37657
38122
|
const sessionSecret = secret ?? crypto11.randomBytes(16).toString("hex");
|
|
38123
|
+
const createBody = orgId ? { secret: sessionSecret, label, orgId } : { secret: sessionSecret, label };
|
|
37658
38124
|
const resp = await fetch(
|
|
37659
|
-
`${
|
|
38125
|
+
`${endpoint}/api/sessions`,
|
|
37660
38126
|
{
|
|
37661
38127
|
method: "POST",
|
|
37662
38128
|
headers: { "Content-Type": "application/json" },
|
|
37663
|
-
body: JSON.stringify(
|
|
38129
|
+
body: JSON.stringify(createBody)
|
|
37664
38130
|
}
|
|
37665
38131
|
);
|
|
37666
38132
|
if (!resp.ok) {
|
|
37667
38133
|
const body = await resp.text().catch(() => "");
|
|
38134
|
+
if (resp.status === 400 && body.includes("already in use")) {
|
|
38135
|
+
return errorResult(
|
|
38136
|
+
new Error(
|
|
38137
|
+
`Channel '${label}' already exists (already in use). Call cogent_join_session with the same name, secret${orgId ? " and Org_ID" : ""}. Do not choose another name.`
|
|
38138
|
+
)
|
|
38139
|
+
);
|
|
38140
|
+
}
|
|
37668
38141
|
return errorResult(
|
|
37669
38142
|
new Error(
|
|
37670
38143
|
`Failed to create session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
|
|
@@ -37673,7 +38146,7 @@ function registerCreateSessionTool(server) {
|
|
|
37673
38146
|
}
|
|
37674
38147
|
const data = await resp.json();
|
|
37675
38148
|
await saveCredentials({
|
|
37676
|
-
endpoint
|
|
38149
|
+
endpoint,
|
|
37677
38150
|
sessionId: data.sessionId,
|
|
37678
38151
|
token: data.token,
|
|
37679
38152
|
label: data.label,
|
|
@@ -37683,7 +38156,7 @@ function registerCreateSessionTool(server) {
|
|
|
37683
38156
|
try {
|
|
37684
38157
|
const startupModule = await Promise.resolve().then(() => (init_startup(), startup_exports));
|
|
37685
38158
|
if (typeof startupModule.reinitCloudBackend === "function") {
|
|
37686
|
-
await startupModule.reinitCloudBackend(
|
|
38159
|
+
await startupModule.reinitCloudBackend(endpoint, data.sessionId, data.token);
|
|
37687
38160
|
logger.info(
|
|
37688
38161
|
"Cloud backend reinitialized with new session credentials"
|
|
37689
38162
|
);
|
|
@@ -37691,32 +38164,40 @@ function registerCreateSessionTool(server) {
|
|
|
37691
38164
|
} catch (err) {
|
|
37692
38165
|
logger.debug(`Backend reinit not available: ${err}`);
|
|
37693
38166
|
}
|
|
38167
|
+
const channelName = data.label ?? data.sessionId;
|
|
37694
38168
|
return successResult({
|
|
37695
38169
|
success: true,
|
|
38170
|
+
created: true,
|
|
37696
38171
|
sessionId: data.sessionId,
|
|
37697
38172
|
label: data.label,
|
|
37698
|
-
secret: sessionSecret,
|
|
37699
38173
|
token: data.token,
|
|
37700
38174
|
createdAt: data.createdAt,
|
|
37701
|
-
|
|
37702
|
-
|
|
37703
|
-
|
|
38175
|
+
slackMapCommand: slackMapCommand({ team: !!orgId, label: channelName, sessionId: data.sessionId }),
|
|
38176
|
+
// A secret the CALLER supplied is never echoed back: the caller already has it, and a
|
|
38177
|
+
// tool result can be quoted into a channel by an auto-reply. Only a secret this tool
|
|
38178
|
+
// generated is returned — nothing else knows it.
|
|
38179
|
+
...secretWasGenerated ? {
|
|
38180
|
+
secret: sessionSecret,
|
|
38181
|
+
config_snippet: {
|
|
38182
|
+
env_vars: `COGENT_ENDPOINT=${endpoint}
|
|
38183
|
+
COGENT_SESSION_ID=${channelName}
|
|
37704
38184
|
COGENT_SECRET=${sessionSecret}
|
|
37705
38185
|
COGENT_PLATFORM=${config2.COGENT_PLATFORM}`,
|
|
37706
|
-
|
|
37707
|
-
|
|
37708
|
-
|
|
37709
|
-
|
|
37710
|
-
|
|
37711
|
-
|
|
37712
|
-
|
|
37713
|
-
|
|
37714
|
-
|
|
38186
|
+
mcp_config: {
|
|
38187
|
+
"cogent": {
|
|
38188
|
+
command: "npx",
|
|
38189
|
+
args: ["-y", "@essentialai/cogent-bridge"],
|
|
38190
|
+
env: {
|
|
38191
|
+
COGENT_ENDPOINT: endpoint,
|
|
38192
|
+
COGENT_SESSION_ID: channelName,
|
|
38193
|
+
COGENT_SECRET: sessionSecret,
|
|
38194
|
+
COGENT_PLATFORM: config2.COGENT_PLATFORM
|
|
38195
|
+
}
|
|
37715
38196
|
}
|
|
37716
38197
|
}
|
|
37717
38198
|
}
|
|
37718
|
-
},
|
|
37719
|
-
note:
|
|
38199
|
+
} : {},
|
|
38200
|
+
note: `${orgId ? "Team channel" : "Channel"} "${channelName}" was created by this call and you are joined to it. Credentials saved locally. Cloud backend updated. Next: cogent_register_peer.`
|
|
37720
38201
|
});
|
|
37721
38202
|
} catch (err) {
|
|
37722
38203
|
logger.error("create-session failed", { error: err });
|
|
@@ -37734,6 +38215,7 @@ var init_create_session = __esm({
|
|
|
37734
38215
|
init_errors4();
|
|
37735
38216
|
init_credential_store();
|
|
37736
38217
|
init_logger();
|
|
38218
|
+
init_channel_text();
|
|
37737
38219
|
}
|
|
37738
38220
|
});
|
|
37739
38221
|
|
|
@@ -37743,14 +38225,14 @@ function registerJoinSessionTool(server) {
|
|
|
37743
38225
|
"cogent_join_session",
|
|
37744
38226
|
{
|
|
37745
38227
|
title: "Join Cloud Channel",
|
|
37746
|
-
description: '
|
|
38228
|
+
description: 'Step 1: join an existing Cogent channel by its channel name (e.g. "mt-space") and shared secret (plus orgId for a Team channel). The channel name is the human-readable label provided by the user, NOT a UUID. Do NOT pass an agent session ID here \u2014 use the channel/space name the user gave you. Next call: cogent_register_peer. If this answers CHANNEL_NOT_FOUND, the next call is cogent_create_session with the same name, secret and orgId.',
|
|
37747
38229
|
inputSchema: {
|
|
37748
38230
|
channel: import_zod16.z.string().describe(
|
|
37749
|
-
'The channel name to join (e.g. "mt-space"). This is the human-readable name the user provided, NOT a UUID. Do NOT use
|
|
38231
|
+
'The channel name to join (e.g. "mt-space"). This is the human-readable name the user provided, NOT a UUID. Do NOT use an agent session ID here.'
|
|
37750
38232
|
),
|
|
37751
38233
|
secret: import_zod16.z.string().min(1).describe("The shared secret / password for the channel"),
|
|
37752
38234
|
orgId: import_zod16.z.string().min(1).optional().describe(
|
|
37753
|
-
"Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it for team channels; omit for free channels."
|
|
38235
|
+
"Org_ID \u2014 the 3rd credential for a Team (business) channel. Provide it for team channels; omit for free channels. If you were given one, never retry without it."
|
|
37754
38236
|
)
|
|
37755
38237
|
},
|
|
37756
38238
|
annotations: {
|
|
@@ -37778,10 +38260,12 @@ function registerJoinSessionTool(server) {
|
|
|
37778
38260
|
if (UUID_V4_RE2.test(channel)) {
|
|
37779
38261
|
return errorResult(
|
|
37780
38262
|
new Error(
|
|
37781
|
-
`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
|
|
38263
|
+
`The "channel" parameter ("${channel}") looks like a UUID. You should pass the human-readable channel name (e.g. "mt-space") that the user provided, NOT an agent session ID or any UUID. Please retry with the correct channel name.`
|
|
37782
38264
|
)
|
|
37783
38265
|
);
|
|
37784
38266
|
}
|
|
38267
|
+
const invalid = invalidChannelName(channel);
|
|
38268
|
+
if (invalid) return errorResult(invalid);
|
|
37785
38269
|
let resolvedSessionId;
|
|
37786
38270
|
let resolvedLabel;
|
|
37787
38271
|
if (orgId) {
|
|
@@ -37793,6 +38277,13 @@ function registerJoinSessionTool(server) {
|
|
|
37793
38277
|
body: JSON.stringify({ label: channel, orgId })
|
|
37794
38278
|
}
|
|
37795
38279
|
);
|
|
38280
|
+
if (resolveResp.status === 404) {
|
|
38281
|
+
return errorResult(new BridgeError(
|
|
38282
|
+
"CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
|
|
38283
|
+
`Team channel '${channel}' was not found on ${endpoint} for this Org_ID (HTTP 404)`,
|
|
38284
|
+
`If the name and Org_ID are exactly as given, the channel does not exist yet: call cogent_create_session with label '${channel}', the same secret and the same orgId, then cogent_register_peer. Do not call cogent_join_session again first, and never without orgId.`
|
|
38285
|
+
));
|
|
38286
|
+
}
|
|
37796
38287
|
if (!resolveResp.ok) {
|
|
37797
38288
|
const body = await resolveResp.text().catch(() => "");
|
|
37798
38289
|
return errorResult(new Error(
|
|
@@ -37806,6 +38297,13 @@ function registerJoinSessionTool(server) {
|
|
|
37806
38297
|
const resolveResp = await fetch(
|
|
37807
38298
|
`${endpoint}/api/sessions/resolve/${encodeURIComponent(channel)}`
|
|
37808
38299
|
);
|
|
38300
|
+
if (resolveResp.status === 404) {
|
|
38301
|
+
return errorResult(new BridgeError(
|
|
38302
|
+
"CHANNEL_NOT_FOUND" /* CHANNEL_NOT_FOUND */,
|
|
38303
|
+
`Channel '${channel}' was not found on ${endpoint} (HTTP 404)`,
|
|
38304
|
+
`If you were given an Org_ID you left it out: call cogent_join_session again WITH orgId and do not create anything. Otherwise call cogent_create_session with label '${channel}' and the same secret.`
|
|
38305
|
+
));
|
|
38306
|
+
}
|
|
37809
38307
|
if (!resolveResp.ok) {
|
|
37810
38308
|
const body = await resolveResp.text().catch(() => "");
|
|
37811
38309
|
return errorResult(new Error(`Failed to resolve channel name "${channel}": HTTP ${resolveResp.status}${body ? ` - ${body}` : ""}`));
|
|
@@ -37825,9 +38323,10 @@ function registerJoinSessionTool(server) {
|
|
|
37825
38323
|
);
|
|
37826
38324
|
if (!resp.ok) {
|
|
37827
38325
|
const body = await resp.text().catch(() => "");
|
|
38326
|
+
const wrong = resp.status === 401 ? `. The password${orgId ? " or Org_ID" : ""} is wrong. Do not retry with guesses - ask the user.` : "";
|
|
37828
38327
|
return errorResult(
|
|
37829
38328
|
new Error(
|
|
37830
|
-
`Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}`
|
|
38329
|
+
`Failed to join session: HTTP ${resp.status}${body ? ` - ${body}` : ""}${wrong}`
|
|
37831
38330
|
)
|
|
37832
38331
|
);
|
|
37833
38332
|
}
|
|
@@ -37876,6 +38375,11 @@ function registerJoinSessionTool(server) {
|
|
|
37876
38375
|
token: data.token,
|
|
37877
38376
|
label: resolvedLabel ?? data.label ?? channel,
|
|
37878
38377
|
peerCount: data.peerCount,
|
|
38378
|
+
slackMapCommand: slackMapCommand({
|
|
38379
|
+
team: !!orgId,
|
|
38380
|
+
label: resolvedLabel ?? data.label ?? channel,
|
|
38381
|
+
sessionId: data.sessionId
|
|
38382
|
+
}),
|
|
37879
38383
|
note: "Successfully joined session. Credentials saved locally. Cloud backend updated. You can now use cogent_register_peer.",
|
|
37880
38384
|
...updateNudge ? { updateAvailable: updateNudge } : {}
|
|
37881
38385
|
});
|
|
@@ -37896,6 +38400,7 @@ var init_join_session = __esm({
|
|
|
37896
38400
|
init_credential_store();
|
|
37897
38401
|
init_logger();
|
|
37898
38402
|
init_npm_update_check();
|
|
38403
|
+
init_channel_text();
|
|
37899
38404
|
UUID_V4_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
37900
38405
|
}
|
|
37901
38406
|
});
|
|
@@ -38130,8 +38635,8 @@ var require_cookies = __commonJS({
|
|
|
38130
38635
|
if (urlparts.hostname !== cookie.domain && (cookie.domain.charAt(0) !== "." || ("." + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
|
|
38131
38636
|
return false;
|
|
38132
38637
|
}
|
|
38133
|
-
let
|
|
38134
|
-
if (
|
|
38638
|
+
let path27 = this.getPath(urlparts.pathname);
|
|
38639
|
+
if (path27.substr(0, cookie.path.length) !== cookie.path) {
|
|
38135
38640
|
return false;
|
|
38136
38641
|
}
|
|
38137
38642
|
if (cookie.secure && urlparts.protocol !== "https:") {
|
|
@@ -38191,16 +38696,16 @@ var require_cookies = __commonJS({
|
|
|
38191
38696
|
* @returns {String} Normalized path
|
|
38192
38697
|
*/
|
|
38193
38698
|
getPath(pathname) {
|
|
38194
|
-
let
|
|
38195
|
-
|
|
38196
|
-
|
|
38197
|
-
if (
|
|
38198
|
-
|
|
38699
|
+
let path27 = (pathname || "/").split("/");
|
|
38700
|
+
path27.pop();
|
|
38701
|
+
path27 = path27.join("/").trim();
|
|
38702
|
+
if (path27.charAt(0) !== "/") {
|
|
38703
|
+
path27 = "/" + path27;
|
|
38199
38704
|
}
|
|
38200
|
-
if (
|
|
38201
|
-
|
|
38705
|
+
if (path27.substr(-1) !== "/") {
|
|
38706
|
+
path27 += "/";
|
|
38202
38707
|
}
|
|
38203
|
-
return
|
|
38708
|
+
return path27;
|
|
38204
38709
|
}
|
|
38205
38710
|
};
|
|
38206
38711
|
module.exports = Cookies;
|
|
@@ -38501,7 +39006,7 @@ var require_shared = __commonJS({
|
|
|
38501
39006
|
"use strict";
|
|
38502
39007
|
var urllib = __require("url");
|
|
38503
39008
|
var util2 = __require("util");
|
|
38504
|
-
var
|
|
39009
|
+
var fs25 = __require("fs");
|
|
38505
39010
|
var nmfetch = require_fetch();
|
|
38506
39011
|
var dns = __require("dns");
|
|
38507
39012
|
var net = __require("net");
|
|
@@ -38887,7 +39392,7 @@ var require_shared = __commonJS({
|
|
|
38887
39392
|
}
|
|
38888
39393
|
return callback(null, parsedDataUri.data);
|
|
38889
39394
|
} else if (content.path) {
|
|
38890
|
-
return resolveStream(
|
|
39395
|
+
return resolveStream(fs25.createReadStream(content.path), callback);
|
|
38891
39396
|
}
|
|
38892
39397
|
}
|
|
38893
39398
|
if (typeof data[key].content === "string" && !["utf8", "usascii", "ascii"].includes(encoding)) {
|
|
@@ -39011,7 +39516,7 @@ var require_shared = __commonJS({
|
|
|
39011
39516
|
var require_mime_types = __commonJS({
|
|
39012
39517
|
"node_modules/nodemailer/lib/mime-funcs/mime-types.js"(exports, module) {
|
|
39013
39518
|
"use strict";
|
|
39014
|
-
var
|
|
39519
|
+
var path27 = __require("path");
|
|
39015
39520
|
var defaultMimeType = "application/octet-stream";
|
|
39016
39521
|
var defaultExtension = "bin";
|
|
39017
39522
|
var mimeTypes = /* @__PURE__ */ new Map([
|
|
@@ -41069,7 +41574,7 @@ var require_mime_types = __commonJS({
|
|
|
41069
41574
|
if (!filename) {
|
|
41070
41575
|
return defaultMimeType;
|
|
41071
41576
|
}
|
|
41072
|
-
let parsed =
|
|
41577
|
+
let parsed = path27.parse(filename);
|
|
41073
41578
|
let extension = (parsed.ext.substr(1) || parsed.name || "").split("?").shift().trim().toLowerCase();
|
|
41074
41579
|
let value = defaultMimeType;
|
|
41075
41580
|
if (extensions.has(extension)) {
|
|
@@ -42471,7 +42976,7 @@ var require_mime_node = __commonJS({
|
|
|
42471
42976
|
"node_modules/nodemailer/lib/mime-node/index.js"(exports, module) {
|
|
42472
42977
|
"use strict";
|
|
42473
42978
|
var crypto12 = __require("crypto");
|
|
42474
|
-
var
|
|
42979
|
+
var fs25 = __require("fs");
|
|
42475
42980
|
var punycode = require_punycode();
|
|
42476
42981
|
var PassThrough = __require("stream").PassThrough;
|
|
42477
42982
|
var shared = require_shared();
|
|
@@ -43186,7 +43691,7 @@ var require_mime_node = __commonJS({
|
|
|
43186
43691
|
setImmediate(() => contentStream.emit("error", new Error("File access rejected for " + content.path)));
|
|
43187
43692
|
return contentStream;
|
|
43188
43693
|
}
|
|
43189
|
-
return
|
|
43694
|
+
return fs25.createReadStream(content.path);
|
|
43190
43695
|
} else if (content && typeof content.href === "string") {
|
|
43191
43696
|
if (this.disableUrlAccess) {
|
|
43192
43697
|
contentStream = new PassThrough();
|
|
@@ -44207,8 +44712,8 @@ var require_dkim = __commonJS({
|
|
|
44207
44712
|
var RelaxedBody = require_relaxed_body();
|
|
44208
44713
|
var sign = require_sign();
|
|
44209
44714
|
var PassThrough = __require("stream").PassThrough;
|
|
44210
|
-
var
|
|
44211
|
-
var
|
|
44715
|
+
var fs25 = __require("fs");
|
|
44716
|
+
var path27 = __require("path");
|
|
44212
44717
|
var crypto12 = __require("crypto");
|
|
44213
44718
|
var DKIM_ALGO = "sha256";
|
|
44214
44719
|
var MAX_MESSAGE_SIZE = 128 * 1024;
|
|
@@ -44222,7 +44727,7 @@ var require_dkim = __commonJS({
|
|
|
44222
44727
|
this.chunks = [];
|
|
44223
44728
|
this.chunklen = 0;
|
|
44224
44729
|
this.readPos = 0;
|
|
44225
|
-
this.cachePath = this.cacheDir ?
|
|
44730
|
+
this.cachePath = this.cacheDir ? path27.join(this.cacheDir, "message." + Date.now() + "-" + crypto12.randomBytes(14).toString("hex")) : false;
|
|
44226
44731
|
this.cache = false;
|
|
44227
44732
|
this.headers = false;
|
|
44228
44733
|
this.bodyHash = false;
|
|
@@ -44242,10 +44747,10 @@ var require_dkim = __commonJS({
|
|
|
44242
44747
|
if (!this.cache || !this.cachePath) {
|
|
44243
44748
|
return;
|
|
44244
44749
|
}
|
|
44245
|
-
|
|
44750
|
+
fs25.unlink(this.cachePath, () => false);
|
|
44246
44751
|
}
|
|
44247
44752
|
createReadCache() {
|
|
44248
|
-
this.cache =
|
|
44753
|
+
this.cache = fs25.createReadStream(this.cachePath);
|
|
44249
44754
|
this.cache.once("error", (err) => {
|
|
44250
44755
|
this.cleanup();
|
|
44251
44756
|
this.output.emit("error", err);
|
|
@@ -44301,7 +44806,7 @@ var require_dkim = __commonJS({
|
|
|
44301
44806
|
}
|
|
44302
44807
|
createWriteCache() {
|
|
44303
44808
|
this.output.usingCache = true;
|
|
44304
|
-
this.cache =
|
|
44809
|
+
this.cache = fs25.createWriteStream(this.cachePath);
|
|
44305
44810
|
this.cache.once("error", (err) => {
|
|
44306
44811
|
this.cleanup();
|
|
44307
44812
|
this.relaxedBody.unpipe(this.cache);
|
|
@@ -49190,13 +49695,13 @@ var require_nodemailer = __commonJS({
|
|
|
49190
49695
|
});
|
|
49191
49696
|
|
|
49192
49697
|
// src/mail/mail-sender.ts
|
|
49193
|
-
import
|
|
49194
|
-
import
|
|
49698
|
+
import fs23 from "node:fs/promises";
|
|
49699
|
+
import path24 from "node:path";
|
|
49195
49700
|
async function buildAndSendMail(sender, creds, params) {
|
|
49196
49701
|
const attachments = [];
|
|
49197
49702
|
for (const p of params.attachmentPaths ?? []) {
|
|
49198
|
-
const content = await
|
|
49199
|
-
attachments.push({ filename:
|
|
49703
|
+
const content = await fs23.readFile(p);
|
|
49704
|
+
attachments.push({ filename: path24.basename(p), content });
|
|
49200
49705
|
}
|
|
49201
49706
|
const { messageId } = await sender.send({
|
|
49202
49707
|
from: creds.address,
|
|
@@ -49585,8 +50090,8 @@ var require_req = __commonJS({
|
|
|
49585
50090
|
if (req.originalUrl) {
|
|
49586
50091
|
_req.url = req.originalUrl;
|
|
49587
50092
|
} else {
|
|
49588
|
-
const
|
|
49589
|
-
_req.url = typeof
|
|
50093
|
+
const path27 = req.path;
|
|
50094
|
+
_req.url = typeof path27 === "string" ? path27 : req.url ? req.url.path || req.url : void 0;
|
|
49590
50095
|
}
|
|
49591
50096
|
if (req.query) {
|
|
49592
50097
|
_req.query = req.query;
|
|
@@ -49751,14 +50256,14 @@ var require_redact = __commonJS({
|
|
|
49751
50256
|
}
|
|
49752
50257
|
return obj;
|
|
49753
50258
|
}
|
|
49754
|
-
function parsePath(
|
|
50259
|
+
function parsePath(path27) {
|
|
49755
50260
|
const parts = [];
|
|
49756
50261
|
let current = "";
|
|
49757
50262
|
let inBrackets = false;
|
|
49758
50263
|
let inQuotes = false;
|
|
49759
50264
|
let quoteChar = "";
|
|
49760
|
-
for (let i = 0; i <
|
|
49761
|
-
const char =
|
|
50265
|
+
for (let i = 0; i < path27.length; i++) {
|
|
50266
|
+
const char = path27[i];
|
|
49762
50267
|
if (!inBrackets && char === ".") {
|
|
49763
50268
|
if (current) {
|
|
49764
50269
|
parts.push(current);
|
|
@@ -49889,10 +50394,10 @@ var require_redact = __commonJS({
|
|
|
49889
50394
|
return current;
|
|
49890
50395
|
}
|
|
49891
50396
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
49892
|
-
for (const
|
|
49893
|
-
const parts = parsePath(
|
|
50397
|
+
for (const path27 of paths) {
|
|
50398
|
+
const parts = parsePath(path27);
|
|
49894
50399
|
if (parts.includes("*")) {
|
|
49895
|
-
redactWildcardPath(obj, parts, censor,
|
|
50400
|
+
redactWildcardPath(obj, parts, censor, path27, remove);
|
|
49896
50401
|
} else {
|
|
49897
50402
|
if (remove) {
|
|
49898
50403
|
removeKey(obj, parts);
|
|
@@ -49977,8 +50482,8 @@ var require_redact = __commonJS({
|
|
|
49977
50482
|
}
|
|
49978
50483
|
} else {
|
|
49979
50484
|
if (afterWildcard.includes("*")) {
|
|
49980
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
49981
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
50485
|
+
const wrappedCensor = typeof censor === "function" ? (value, path27) => {
|
|
50486
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path27];
|
|
49982
50487
|
return censor(value, fullPath);
|
|
49983
50488
|
} : censor;
|
|
49984
50489
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -50013,8 +50518,8 @@ var require_redact = __commonJS({
|
|
|
50013
50518
|
return null;
|
|
50014
50519
|
}
|
|
50015
50520
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
50016
|
-
for (const
|
|
50017
|
-
const parts = parsePath(
|
|
50521
|
+
for (const path27 of pathsToClone) {
|
|
50522
|
+
const parts = parsePath(path27);
|
|
50018
50523
|
let current = pathStructure;
|
|
50019
50524
|
for (let i = 0; i < parts.length; i++) {
|
|
50020
50525
|
const part = parts[i];
|
|
@@ -50066,24 +50571,24 @@ var require_redact = __commonJS({
|
|
|
50066
50571
|
}
|
|
50067
50572
|
return cloneSelectively(obj, pathStructure);
|
|
50068
50573
|
}
|
|
50069
|
-
function validatePath(
|
|
50070
|
-
if (typeof
|
|
50574
|
+
function validatePath(path27) {
|
|
50575
|
+
if (typeof path27 !== "string") {
|
|
50071
50576
|
throw new Error("Paths must be (non-empty) strings");
|
|
50072
50577
|
}
|
|
50073
|
-
if (
|
|
50578
|
+
if (path27 === "") {
|
|
50074
50579
|
throw new Error("Invalid redaction path ()");
|
|
50075
50580
|
}
|
|
50076
|
-
if (
|
|
50077
|
-
throw new Error(`Invalid redaction path (${
|
|
50581
|
+
if (path27.includes("..")) {
|
|
50582
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
50078
50583
|
}
|
|
50079
|
-
if (
|
|
50080
|
-
throw new Error(`Invalid redaction path (${
|
|
50584
|
+
if (path27.includes(",")) {
|
|
50585
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
50081
50586
|
}
|
|
50082
50587
|
let bracketCount = 0;
|
|
50083
50588
|
let inQuotes = false;
|
|
50084
50589
|
let quoteChar = "";
|
|
50085
|
-
for (let i = 0; i <
|
|
50086
|
-
const char =
|
|
50590
|
+
for (let i = 0; i < path27.length; i++) {
|
|
50591
|
+
const char = path27[i];
|
|
50087
50592
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
50088
50593
|
if (!inQuotes) {
|
|
50089
50594
|
inQuotes = true;
|
|
@@ -50097,20 +50602,20 @@ var require_redact = __commonJS({
|
|
|
50097
50602
|
} else if (char === "]" && !inQuotes) {
|
|
50098
50603
|
bracketCount--;
|
|
50099
50604
|
if (bracketCount < 0) {
|
|
50100
|
-
throw new Error(`Invalid redaction path (${
|
|
50605
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
50101
50606
|
}
|
|
50102
50607
|
}
|
|
50103
50608
|
}
|
|
50104
50609
|
if (bracketCount !== 0) {
|
|
50105
|
-
throw new Error(`Invalid redaction path (${
|
|
50610
|
+
throw new Error(`Invalid redaction path (${path27})`);
|
|
50106
50611
|
}
|
|
50107
50612
|
}
|
|
50108
50613
|
function validatePaths(paths) {
|
|
50109
50614
|
if (!Array.isArray(paths)) {
|
|
50110
50615
|
throw new TypeError("paths must be an array");
|
|
50111
50616
|
}
|
|
50112
|
-
for (const
|
|
50113
|
-
validatePath(
|
|
50617
|
+
for (const path27 of paths) {
|
|
50618
|
+
validatePath(path27);
|
|
50114
50619
|
}
|
|
50115
50620
|
}
|
|
50116
50621
|
function slowRedact(options = {}) {
|
|
@@ -50278,8 +50783,8 @@ var require_redaction = __commonJS({
|
|
|
50278
50783
|
if (shape[k] === null) {
|
|
50279
50784
|
o[k] = (value) => topCensor(value, [k]);
|
|
50280
50785
|
} else {
|
|
50281
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
50282
|
-
return censor(value, [k, ...
|
|
50786
|
+
const wrappedCensor = typeof censor === "function" ? (value, path27) => {
|
|
50787
|
+
return censor(value, [k, ...path27]);
|
|
50283
50788
|
} : censor;
|
|
50284
50789
|
o[k] = Redact({
|
|
50285
50790
|
paths: shape[k],
|
|
@@ -50497,10 +51002,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
50497
51002
|
var require_sonic_boom = __commonJS({
|
|
50498
51003
|
"node_modules/sonic-boom/index.js"(exports, module) {
|
|
50499
51004
|
"use strict";
|
|
50500
|
-
var
|
|
51005
|
+
var fs25 = __require("fs");
|
|
50501
51006
|
var EventEmitter = __require("events");
|
|
50502
51007
|
var inherits = __require("util").inherits;
|
|
50503
|
-
var
|
|
51008
|
+
var path27 = __require("path");
|
|
50504
51009
|
var sleep4 = require_atomic_sleep();
|
|
50505
51010
|
var assert2 = __require("assert");
|
|
50506
51011
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -50554,20 +51059,20 @@ var require_sonic_boom = __commonJS({
|
|
|
50554
51059
|
const mode = sonic.mode;
|
|
50555
51060
|
if (sonic.sync) {
|
|
50556
51061
|
try {
|
|
50557
|
-
if (sonic.mkdir)
|
|
50558
|
-
const fd =
|
|
51062
|
+
if (sonic.mkdir) fs25.mkdirSync(path27.dirname(file), { recursive: true });
|
|
51063
|
+
const fd = fs25.openSync(file, flags, mode);
|
|
50559
51064
|
fileOpened(null, fd);
|
|
50560
51065
|
} catch (err) {
|
|
50561
51066
|
fileOpened(err);
|
|
50562
51067
|
throw err;
|
|
50563
51068
|
}
|
|
50564
51069
|
} else if (sonic.mkdir) {
|
|
50565
|
-
|
|
51070
|
+
fs25.mkdir(path27.dirname(file), { recursive: true }, (err) => {
|
|
50566
51071
|
if (err) return fileOpened(err);
|
|
50567
|
-
|
|
51072
|
+
fs25.open(file, flags, mode, fileOpened);
|
|
50568
51073
|
});
|
|
50569
51074
|
} else {
|
|
50570
|
-
|
|
51075
|
+
fs25.open(file, flags, mode, fileOpened);
|
|
50571
51076
|
}
|
|
50572
51077
|
}
|
|
50573
51078
|
function SonicBoom(opts) {
|
|
@@ -50608,8 +51113,8 @@ var require_sonic_boom = __commonJS({
|
|
|
50608
51113
|
this.flush = flushBuffer;
|
|
50609
51114
|
this.flushSync = flushBufferSync;
|
|
50610
51115
|
this._actualWrite = actualWriteBuffer;
|
|
50611
|
-
fsWriteSync = () =>
|
|
50612
|
-
fsWrite = () =>
|
|
51116
|
+
fsWriteSync = () => fs25.writeSync(this.fd, this._writingBuf);
|
|
51117
|
+
fsWrite = () => fs25.write(this.fd, this._writingBuf, this.release);
|
|
50613
51118
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
50614
51119
|
this._writingBuf = "";
|
|
50615
51120
|
this.write = write;
|
|
@@ -50618,15 +51123,15 @@ var require_sonic_boom = __commonJS({
|
|
|
50618
51123
|
this._actualWrite = actualWrite;
|
|
50619
51124
|
fsWriteSync = () => {
|
|
50620
51125
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
50621
|
-
return
|
|
51126
|
+
return fs25.writeSync(this.fd, this._writingBuf);
|
|
50622
51127
|
}
|
|
50623
|
-
return
|
|
51128
|
+
return fs25.writeSync(this.fd, this._writingBuf, "utf8");
|
|
50624
51129
|
};
|
|
50625
51130
|
fsWrite = () => {
|
|
50626
51131
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
50627
|
-
return
|
|
51132
|
+
return fs25.write(this.fd, this._writingBuf, this.release);
|
|
50628
51133
|
}
|
|
50629
|
-
return
|
|
51134
|
+
return fs25.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
50630
51135
|
};
|
|
50631
51136
|
} else {
|
|
50632
51137
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -50683,7 +51188,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50683
51188
|
}
|
|
50684
51189
|
}
|
|
50685
51190
|
if (this._fsync) {
|
|
50686
|
-
|
|
51191
|
+
fs25.fsyncSync(this.fd);
|
|
50687
51192
|
}
|
|
50688
51193
|
const len = this._len;
|
|
50689
51194
|
if (this._reopening) {
|
|
@@ -50797,7 +51302,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50797
51302
|
const onDrain = () => {
|
|
50798
51303
|
if (!this._fsync) {
|
|
50799
51304
|
try {
|
|
50800
|
-
|
|
51305
|
+
fs25.fsync(this.fd, (err) => {
|
|
50801
51306
|
this._flushPending = false;
|
|
50802
51307
|
cb(err);
|
|
50803
51308
|
});
|
|
@@ -50899,7 +51404,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50899
51404
|
const fd = this.fd;
|
|
50900
51405
|
this.once("ready", () => {
|
|
50901
51406
|
if (fd !== this.fd) {
|
|
50902
|
-
|
|
51407
|
+
fs25.close(fd, (err) => {
|
|
50903
51408
|
if (err) {
|
|
50904
51409
|
return this.emit("error", err);
|
|
50905
51410
|
}
|
|
@@ -50948,7 +51453,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50948
51453
|
buf = this._bufs[0];
|
|
50949
51454
|
}
|
|
50950
51455
|
try {
|
|
50951
|
-
const n = Buffer.isBuffer(buf) ?
|
|
51456
|
+
const n = Buffer.isBuffer(buf) ? fs25.writeSync(this.fd, buf) : fs25.writeSync(this.fd, buf, "utf8");
|
|
50952
51457
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
50953
51458
|
buf = releasedBufObj.writingBuf;
|
|
50954
51459
|
this._len = releasedBufObj.len;
|
|
@@ -50964,7 +51469,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50964
51469
|
}
|
|
50965
51470
|
}
|
|
50966
51471
|
try {
|
|
50967
|
-
|
|
51472
|
+
fs25.fsyncSync(this.fd);
|
|
50968
51473
|
} catch {
|
|
50969
51474
|
}
|
|
50970
51475
|
}
|
|
@@ -50985,7 +51490,7 @@ var require_sonic_boom = __commonJS({
|
|
|
50985
51490
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
50986
51491
|
}
|
|
50987
51492
|
try {
|
|
50988
|
-
const n =
|
|
51493
|
+
const n = fs25.writeSync(this.fd, buf);
|
|
50989
51494
|
buf = buf.subarray(n);
|
|
50990
51495
|
this._len = Math.max(this._len - n, 0);
|
|
50991
51496
|
if (buf.length <= 0) {
|
|
@@ -51013,13 +51518,13 @@ var require_sonic_boom = __commonJS({
|
|
|
51013
51518
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
51014
51519
|
if (this.sync) {
|
|
51015
51520
|
try {
|
|
51016
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
51521
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs25.writeSync(this.fd, this._writingBuf) : fs25.writeSync(this.fd, this._writingBuf, "utf8");
|
|
51017
51522
|
release(null, written);
|
|
51018
51523
|
} catch (err) {
|
|
51019
51524
|
release(err);
|
|
51020
51525
|
}
|
|
51021
51526
|
} else {
|
|
51022
|
-
|
|
51527
|
+
fs25.write(this.fd, this._writingBuf, release);
|
|
51023
51528
|
}
|
|
51024
51529
|
}
|
|
51025
51530
|
function actualWriteBuffer() {
|
|
@@ -51028,7 +51533,7 @@ var require_sonic_boom = __commonJS({
|
|
|
51028
51533
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
51029
51534
|
if (this.sync) {
|
|
51030
51535
|
try {
|
|
51031
|
-
const written =
|
|
51536
|
+
const written = fs25.writeSync(this.fd, this._writingBuf);
|
|
51032
51537
|
release(null, written);
|
|
51033
51538
|
} catch (err) {
|
|
51034
51539
|
release(err);
|
|
@@ -51037,7 +51542,7 @@ var require_sonic_boom = __commonJS({
|
|
|
51037
51542
|
if (kCopyBuffer) {
|
|
51038
51543
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
51039
51544
|
}
|
|
51040
|
-
|
|
51545
|
+
fs25.write(this.fd, this._writingBuf, release);
|
|
51041
51546
|
}
|
|
51042
51547
|
}
|
|
51043
51548
|
function actualClose(sonic) {
|
|
@@ -51053,12 +51558,12 @@ var require_sonic_boom = __commonJS({
|
|
|
51053
51558
|
sonic._lens = [];
|
|
51054
51559
|
assert2(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
51055
51560
|
try {
|
|
51056
|
-
|
|
51561
|
+
fs25.fsync(sonic.fd, closeWrapped);
|
|
51057
51562
|
} catch {
|
|
51058
51563
|
}
|
|
51059
51564
|
function closeWrapped() {
|
|
51060
51565
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
51061
|
-
|
|
51566
|
+
fs25.close(sonic.fd, done);
|
|
51062
51567
|
} else {
|
|
51063
51568
|
done();
|
|
51064
51569
|
}
|
|
@@ -51894,15 +52399,15 @@ var require_transport = __commonJS({
|
|
|
51894
52399
|
if (!unquoted) {
|
|
51895
52400
|
return false;
|
|
51896
52401
|
}
|
|
51897
|
-
let
|
|
51898
|
-
if (
|
|
52402
|
+
let path27 = unquoted;
|
|
52403
|
+
if (path27.startsWith("file://")) {
|
|
51899
52404
|
try {
|
|
51900
|
-
|
|
52405
|
+
path27 = fileURLToPath(path27);
|
|
51901
52406
|
} catch {
|
|
51902
52407
|
return false;
|
|
51903
52408
|
}
|
|
51904
52409
|
}
|
|
51905
|
-
return isAbsolute(
|
|
52410
|
+
return isAbsolute(path27) && !existsSync(path27);
|
|
51906
52411
|
}
|
|
51907
52412
|
function stripQuotes(value) {
|
|
51908
52413
|
const first = value[0];
|
|
@@ -85969,15 +86474,15 @@ var require_tools2 = __commonJS({
|
|
|
85969
86474
|
* @param {String} path - Mailbox path to encode
|
|
85970
86475
|
* @returns {String} Encoded mailbox path
|
|
85971
86476
|
*/
|
|
85972
|
-
encodePath(connection,
|
|
85973
|
-
|
|
85974
|
-
if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(
|
|
86477
|
+
encodePath(connection, path27) {
|
|
86478
|
+
path27 = (path27 || "").toString();
|
|
86479
|
+
if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&\x00-\x08\x0b-\x0c\x0e-\x1f\u0080-\uffff]/.test(path27)) {
|
|
85975
86480
|
try {
|
|
85976
|
-
|
|
86481
|
+
path27 = iconv.encode(path27, "utf-7-imap").toString();
|
|
85977
86482
|
} catch {
|
|
85978
86483
|
}
|
|
85979
86484
|
}
|
|
85980
|
-
return
|
|
86485
|
+
return path27;
|
|
85981
86486
|
},
|
|
85982
86487
|
/**
|
|
85983
86488
|
* Decodes a mailbox path from modified UTF-7 if the server does not support UTF8=ACCEPT.
|
|
@@ -85986,15 +86491,15 @@ var require_tools2 = __commonJS({
|
|
|
85986
86491
|
* @param {String} path - Mailbox path to decode
|
|
85987
86492
|
* @returns {String} Decoded mailbox path
|
|
85988
86493
|
*/
|
|
85989
|
-
decodePath(connection,
|
|
85990
|
-
|
|
85991
|
-
if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(
|
|
86494
|
+
decodePath(connection, path27) {
|
|
86495
|
+
path27 = (path27 || "").toString();
|
|
86496
|
+
if (!connection.enabled.has("UTF8=ACCEPT") && !tools.isRev2Active(connection) && /[&]/.test(path27)) {
|
|
85992
86497
|
try {
|
|
85993
|
-
|
|
86498
|
+
path27 = iconv.decode(Buffer.from(path27), "utf-7-imap").toString();
|
|
85994
86499
|
} catch {
|
|
85995
86500
|
}
|
|
85996
86501
|
}
|
|
85997
|
-
return
|
|
86502
|
+
return path27;
|
|
85998
86503
|
},
|
|
85999
86504
|
/**
|
|
86000
86505
|
* Normalizes a mailbox path by joining array segments with the namespace delimiter,
|
|
@@ -86005,17 +86510,17 @@ var require_tools2 = __commonJS({
|
|
|
86005
86510
|
* @param {Boolean} [skipNamespace] - If true, skips prepending the namespace prefix
|
|
86006
86511
|
* @returns {String} Normalized mailbox path
|
|
86007
86512
|
*/
|
|
86008
|
-
normalizePath(connection,
|
|
86009
|
-
if (Array.isArray(
|
|
86010
|
-
|
|
86513
|
+
normalizePath(connection, path27, skipNamespace) {
|
|
86514
|
+
if (Array.isArray(path27)) {
|
|
86515
|
+
path27 = path27.join(connection.namespace && connection.namespace.delimiter || "");
|
|
86011
86516
|
}
|
|
86012
|
-
if (
|
|
86517
|
+
if (path27.toUpperCase() === "INBOX") {
|
|
86013
86518
|
return "INBOX";
|
|
86014
86519
|
}
|
|
86015
|
-
if (!skipNamespace && connection.namespace && connection.namespace.prefix && !
|
|
86016
|
-
|
|
86520
|
+
if (!skipNamespace && connection.namespace && connection.namespace.prefix && !path27.startsWith(connection.namespace.prefix)) {
|
|
86521
|
+
path27 = connection.namespace.prefix + path27;
|
|
86017
86522
|
}
|
|
86018
|
-
return
|
|
86523
|
+
return path27;
|
|
86019
86524
|
},
|
|
86020
86525
|
/**
|
|
86021
86526
|
* Compares two mailbox paths for equality after normalization.
|
|
@@ -86346,14 +86851,14 @@ var require_tools2 = __commonJS({
|
|
|
86346
86851
|
}
|
|
86347
86852
|
}
|
|
86348
86853
|
if (map.emailId || map.uid) {
|
|
86349
|
-
let
|
|
86350
|
-
if (/[\u0080-\uffff]/.test(
|
|
86854
|
+
let path27 = mailbox.path;
|
|
86855
|
+
if (/[\u0080-\uffff]/.test(path27)) {
|
|
86351
86856
|
try {
|
|
86352
|
-
|
|
86857
|
+
path27 = iconv.encode(path27, "utf-7-imap").toString();
|
|
86353
86858
|
} catch {
|
|
86354
86859
|
}
|
|
86355
86860
|
}
|
|
86356
|
-
map.id = map.emailId || createHash2("md5").update([
|
|
86861
|
+
map.id = map.emailId || createHash2("md5").update([path27, mailbox.uidValidity?.toString() || "", map.uid.toString()].join(":")).digest("hex");
|
|
86357
86862
|
}
|
|
86358
86863
|
if (map.flags) {
|
|
86359
86864
|
let flagColor = tools.getFlagColor(map.flags);
|
|
@@ -86528,16 +87033,16 @@ var require_tools2 = __commonJS({
|
|
|
86528
87033
|
* @returns {Object} Parsed body structure tree with part numbers, types, parameters, and child nodes
|
|
86529
87034
|
*/
|
|
86530
87035
|
parseBodystructure(entry) {
|
|
86531
|
-
let walk = (node,
|
|
86532
|
-
|
|
87036
|
+
let walk = (node, path27) => {
|
|
87037
|
+
path27 = path27 || [];
|
|
86533
87038
|
let curNode = {}, i = 0, part = 0;
|
|
86534
|
-
if (
|
|
86535
|
-
curNode.part =
|
|
87039
|
+
if (path27.length) {
|
|
87040
|
+
curNode.part = path27.join(".");
|
|
86536
87041
|
}
|
|
86537
87042
|
if (Array.isArray(node[0])) {
|
|
86538
87043
|
curNode.childNodes = [];
|
|
86539
87044
|
while (Array.isArray(node[i])) {
|
|
86540
|
-
curNode.childNodes.push(walk(node[i],
|
|
87045
|
+
curNode.childNodes.push(walk(node[i], path27.concat(++part)));
|
|
86541
87046
|
i++;
|
|
86542
87047
|
}
|
|
86543
87048
|
curNode.type = "multipart/" + ((node[i++] || {}).value || "").toString().toLowerCase();
|
|
@@ -86580,7 +87085,7 @@ var require_tools2 = __commonJS({
|
|
|
86580
87085
|
// the encapsulated message shares the part number with its wrapper.
|
|
86581
87086
|
// Distinction is via suffixes: path.MIME = wrapper headers,
|
|
86582
87087
|
// path.HEADER = encapsulated message headers.
|
|
86583
|
-
walk(node[i],
|
|
87088
|
+
walk(node[i], path27)
|
|
86584
87089
|
];
|
|
86585
87090
|
}
|
|
86586
87091
|
i++;
|
|
@@ -88542,14 +89047,14 @@ var require_select = __commonJS({
|
|
|
88542
89047
|
// update into a silent no-op for the rest of the session.
|
|
88543
89048
|
permanentflags: { key: "permanentFlags", parse: (value) => Array.isArray(value) && new Set(value) }
|
|
88544
89049
|
});
|
|
88545
|
-
module.exports = async (connection,
|
|
89050
|
+
module.exports = async (connection, path27, options) => {
|
|
88546
89051
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
88547
89052
|
return;
|
|
88548
89053
|
}
|
|
88549
89054
|
options = options || {};
|
|
88550
|
-
|
|
88551
|
-
if (!connection.folders.has(
|
|
88552
|
-
let folders = await connection.run("LIST", "",
|
|
89055
|
+
path27 = normalizePath(connection, path27);
|
|
89056
|
+
if (!connection.folders.has(path27)) {
|
|
89057
|
+
let folders = await connection.run("LIST", "", path27);
|
|
88553
89058
|
if (!folders) {
|
|
88554
89059
|
throw new Error("Failed to fetch folders");
|
|
88555
89060
|
}
|
|
@@ -88557,10 +89062,10 @@ var require_select = __commonJS({
|
|
|
88557
89062
|
connection.folders.set(folder.path, folder);
|
|
88558
89063
|
});
|
|
88559
89064
|
}
|
|
88560
|
-
let folderListData = connection.folders.has(
|
|
89065
|
+
let folderListData = connection.folders.has(path27) ? connection.folders.get(path27) : false;
|
|
88561
89066
|
let response;
|
|
88562
89067
|
try {
|
|
88563
|
-
let map = { path:
|
|
89068
|
+
let map = { path: path27 };
|
|
88564
89069
|
if (folderListData) {
|
|
88565
89070
|
["delimiter", "specialUse", "subscribed", "listed"].forEach((key) => {
|
|
88566
89071
|
if (folderListData[key]) {
|
|
@@ -88579,7 +89084,7 @@ var require_select = __commonJS({
|
|
|
88579
89084
|
]);
|
|
88580
89085
|
map.qresync = true;
|
|
88581
89086
|
}
|
|
88582
|
-
let encodedPath = encodePath(connection,
|
|
89087
|
+
let encodedPath = encodePath(connection, path27);
|
|
88583
89088
|
let selectCommand = {
|
|
88584
89089
|
command: !options.readOnly ? "SELECT" : "EXAMINE",
|
|
88585
89090
|
/* c8 ignore next */
|
|
@@ -88639,12 +89144,12 @@ var require_select = __commonJS({
|
|
|
88639
89144
|
// since the client's last known state. Only received when QRESYNC was requested.
|
|
88640
89145
|
// A dummy mailbox object is passed because the mailbox isn't officially open yet.
|
|
88641
89146
|
VANISHED: async (untagged) => {
|
|
88642
|
-
await connection.untaggedVanished(untagged, { path:
|
|
89147
|
+
await connection.untaggedVanished(untagged, { path: path27, uidNext: false, uidValidity: false });
|
|
88643
89148
|
},
|
|
88644
89149
|
// Untagged FETCH during SELECT/EXAMINE: only occurs with QRESYNC, delivering
|
|
88645
89150
|
// updated flags for messages that changed since the client's last modseq.
|
|
88646
89151
|
FETCH: async (untagged) => {
|
|
88647
|
-
await connection.untaggedFetch(untagged, { path:
|
|
89152
|
+
await connection.untaggedFetch(untagged, { path: path27, uidNext: false, uidValidity: false });
|
|
88648
89153
|
}
|
|
88649
89154
|
}
|
|
88650
89155
|
});
|
|
@@ -88658,13 +89163,13 @@ var require_select = __commonJS({
|
|
|
88658
89163
|
}
|
|
88659
89164
|
let currentMailbox = connection.mailbox;
|
|
88660
89165
|
connection.mailbox = false;
|
|
88661
|
-
if (currentMailbox && currentMailbox.path !==
|
|
89166
|
+
if (currentMailbox && currentMailbox.path !== path27) {
|
|
88662
89167
|
connection.emit("mailboxClose", currentMailbox);
|
|
88663
89168
|
}
|
|
88664
89169
|
connection.mailbox = map;
|
|
88665
89170
|
connection.currentSelectCommand = selectCommand;
|
|
88666
89171
|
connection.state = connection.states.SELECTED;
|
|
88667
|
-
if (!currentMailbox || currentMailbox.path !==
|
|
89172
|
+
if (!currentMailbox || currentMailbox.path !== path27) {
|
|
88668
89173
|
connection.emit("mailboxOpen", connection.mailbox);
|
|
88669
89174
|
}
|
|
88670
89175
|
response.next();
|
|
@@ -88879,17 +89384,17 @@ var require_create = __commonJS({
|
|
|
88879
89384
|
"node_modules/imapflow/lib/commands/create.js"(exports, module) {
|
|
88880
89385
|
"use strict";
|
|
88881
89386
|
var { encodePath, normalizePath, getStatusCode, enhanceCommandError } = require_tools2();
|
|
88882
|
-
module.exports = async (connection,
|
|
89387
|
+
module.exports = async (connection, path27) => {
|
|
88883
89388
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
88884
89389
|
return;
|
|
88885
89390
|
}
|
|
88886
|
-
|
|
89391
|
+
path27 = normalizePath(connection, path27);
|
|
88887
89392
|
let response;
|
|
88888
89393
|
try {
|
|
88889
89394
|
let map = {
|
|
88890
|
-
path:
|
|
89395
|
+
path: path27
|
|
88891
89396
|
};
|
|
88892
|
-
response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection,
|
|
89397
|
+
response = await connection.exec("CREATE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
|
|
88893
89398
|
let section = response.response.attributes && response.response.attributes[0] && response.response.attributes[0].section && response.response.attributes[0].section.length ? response.response.attributes[0].section : false;
|
|
88894
89399
|
if (section) {
|
|
88895
89400
|
let key;
|
|
@@ -88915,13 +89420,13 @@ var require_create = __commonJS({
|
|
|
88915
89420
|
}
|
|
88916
89421
|
map.created = true;
|
|
88917
89422
|
response.next();
|
|
88918
|
-
await connection.run("SUBSCRIBE",
|
|
89423
|
+
await connection.run("SUBSCRIBE", path27);
|
|
88919
89424
|
return map;
|
|
88920
89425
|
} catch (err) {
|
|
88921
89426
|
let errorCode = getStatusCode(err.response);
|
|
88922
89427
|
if (errorCode === "ALREADYEXISTS") {
|
|
88923
89428
|
return {
|
|
88924
|
-
path:
|
|
89429
|
+
path: path27,
|
|
88925
89430
|
created: false
|
|
88926
89431
|
};
|
|
88927
89432
|
}
|
|
@@ -88938,20 +89443,20 @@ var require_delete = __commonJS({
|
|
|
88938
89443
|
"node_modules/imapflow/lib/commands/delete.js"(exports, module) {
|
|
88939
89444
|
"use strict";
|
|
88940
89445
|
var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
|
|
88941
|
-
module.exports = async (connection,
|
|
89446
|
+
module.exports = async (connection, path27) => {
|
|
88942
89447
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
88943
89448
|
return;
|
|
88944
89449
|
}
|
|
88945
|
-
|
|
88946
|
-
if (connection.state === connection.states.SELECTED && connection.mailbox.path ===
|
|
89450
|
+
path27 = normalizePath(connection, path27);
|
|
89451
|
+
if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
|
|
88947
89452
|
await connection.run("CLOSE");
|
|
88948
89453
|
}
|
|
88949
89454
|
let response;
|
|
88950
89455
|
try {
|
|
88951
89456
|
let map = {
|
|
88952
|
-
path:
|
|
89457
|
+
path: path27
|
|
88953
89458
|
};
|
|
88954
|
-
response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection,
|
|
89459
|
+
response = await connection.exec("DELETE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
|
|
88955
89460
|
response.next();
|
|
88956
89461
|
return map;
|
|
88957
89462
|
} catch (err) {
|
|
@@ -88968,23 +89473,23 @@ var require_rename = __commonJS({
|
|
|
88968
89473
|
"node_modules/imapflow/lib/commands/rename.js"(exports, module) {
|
|
88969
89474
|
"use strict";
|
|
88970
89475
|
var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
|
|
88971
|
-
module.exports = async (connection,
|
|
89476
|
+
module.exports = async (connection, path27, newPath) => {
|
|
88972
89477
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
88973
89478
|
return;
|
|
88974
89479
|
}
|
|
88975
|
-
|
|
89480
|
+
path27 = normalizePath(connection, path27);
|
|
88976
89481
|
newPath = normalizePath(connection, newPath);
|
|
88977
|
-
if (connection.state === connection.states.SELECTED && connection.mailbox.path ===
|
|
89482
|
+
if (connection.state === connection.states.SELECTED && connection.mailbox.path === path27) {
|
|
88978
89483
|
await connection.run("CLOSE");
|
|
88979
89484
|
}
|
|
88980
89485
|
let response;
|
|
88981
89486
|
try {
|
|
88982
89487
|
let map = {
|
|
88983
|
-
path:
|
|
89488
|
+
path: path27,
|
|
88984
89489
|
newPath
|
|
88985
89490
|
};
|
|
88986
89491
|
response = await connection.exec("RENAME", [
|
|
88987
|
-
{ type: "ATOM", value: encodePath(connection,
|
|
89492
|
+
{ type: "ATOM", value: encodePath(connection, path27) },
|
|
88988
89493
|
{ type: "ATOM", value: encodePath(connection, newPath) }
|
|
88989
89494
|
]);
|
|
88990
89495
|
response.next();
|
|
@@ -89031,14 +89536,14 @@ var require_subscribe = __commonJS({
|
|
|
89031
89536
|
"node_modules/imapflow/lib/commands/subscribe.js"(exports, module) {
|
|
89032
89537
|
"use strict";
|
|
89033
89538
|
var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
|
|
89034
|
-
module.exports = async (connection,
|
|
89539
|
+
module.exports = async (connection, path27) => {
|
|
89035
89540
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
89036
89541
|
return;
|
|
89037
89542
|
}
|
|
89038
|
-
|
|
89543
|
+
path27 = normalizePath(connection, path27);
|
|
89039
89544
|
let response;
|
|
89040
89545
|
try {
|
|
89041
|
-
response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection,
|
|
89546
|
+
response = await connection.exec("SUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
|
|
89042
89547
|
response.next();
|
|
89043
89548
|
return true;
|
|
89044
89549
|
} catch (err) {
|
|
@@ -89055,14 +89560,14 @@ var require_unsubscribe = __commonJS({
|
|
|
89055
89560
|
"node_modules/imapflow/lib/commands/unsubscribe.js"(exports, module) {
|
|
89056
89561
|
"use strict";
|
|
89057
89562
|
var { encodePath, normalizePath, enhanceCommandError } = require_tools2();
|
|
89058
|
-
module.exports = async (connection,
|
|
89563
|
+
module.exports = async (connection, path27) => {
|
|
89059
89564
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
89060
89565
|
return;
|
|
89061
89566
|
}
|
|
89062
|
-
|
|
89567
|
+
path27 = normalizePath(connection, path27);
|
|
89063
89568
|
let response;
|
|
89064
89569
|
try {
|
|
89065
|
-
response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection,
|
|
89570
|
+
response = await connection.exec("UNSUBSCRIBE", [{ type: "ATOM", value: encodePath(connection, path27) }]);
|
|
89066
89571
|
response.next();
|
|
89067
89572
|
return true;
|
|
89068
89573
|
} catch (err) {
|
|
@@ -89868,11 +90373,11 @@ var require_status = __commonJS({
|
|
|
89868
90373
|
var { encodePath, normalizePath, buildStatusQueryAttributes, isRev2Active } = require_tools2();
|
|
89869
90374
|
var { parseStatusList } = require_status_fields();
|
|
89870
90375
|
var MAILBOX_UPDATERS = {
|
|
89871
|
-
messages: (value, connection,
|
|
90376
|
+
messages: (value, connection, path27) => {
|
|
89872
90377
|
let prevCount = connection.mailbox.exists;
|
|
89873
90378
|
if (prevCount !== value) {
|
|
89874
90379
|
connection.mailbox.exists = value;
|
|
89875
|
-
connection.emit("exists", { path:
|
|
90380
|
+
connection.emit("exists", { path: path27, count: value, prevCount });
|
|
89876
90381
|
}
|
|
89877
90382
|
},
|
|
89878
90383
|
uidNext: (value, connection) => {
|
|
@@ -89882,28 +90387,28 @@ var require_status = __commonJS({
|
|
|
89882
90387
|
connection.mailbox.highestModseq = value;
|
|
89883
90388
|
}
|
|
89884
90389
|
};
|
|
89885
|
-
module.exports = async (connection,
|
|
89886
|
-
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !
|
|
90390
|
+
module.exports = async (connection, path27, query) => {
|
|
90391
|
+
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
|
|
89887
90392
|
return false;
|
|
89888
90393
|
}
|
|
89889
|
-
|
|
89890
|
-
let encodedPath = encodePath(connection,
|
|
90394
|
+
path27 = normalizePath(connection, path27);
|
|
90395
|
+
let encodedPath = encodePath(connection, path27);
|
|
89891
90396
|
let attributes = [{ type: encodedPath.indexOf("&") >= 0 ? "STRING" : "ATOM", value: encodedPath }];
|
|
89892
90397
|
let queryAttributes = buildStatusQueryAttributes(connection, query);
|
|
89893
90398
|
let syntheticRecent = query && query.recent && isRev2Active(connection);
|
|
89894
90399
|
if (!queryAttributes.length) {
|
|
89895
|
-
return syntheticRecent ? { path:
|
|
90400
|
+
return syntheticRecent ? { path: path27, recent: 0 } : false;
|
|
89896
90401
|
}
|
|
89897
90402
|
attributes.push(queryAttributes);
|
|
89898
90403
|
let response;
|
|
89899
90404
|
try {
|
|
89900
|
-
let map = { path:
|
|
90405
|
+
let map = { path: path27 };
|
|
89901
90406
|
response = await connection.exec("STATUS", attributes, {
|
|
89902
90407
|
untagged: {
|
|
89903
90408
|
// STATUS response: * STATUS <mailbox> (<key> <value> <key> <value> ...)
|
|
89904
90409
|
// Parsed as alternating key-value pairs (i % 2 pattern).
|
|
89905
90410
|
STATUS: async (untagged) => {
|
|
89906
|
-
let updateCurrent = connection.state === connection.states.SELECTED &&
|
|
90411
|
+
let updateCurrent = connection.state === connection.states.SELECTED && path27 === connection.mailbox.path;
|
|
89907
90412
|
let list = untagged.attributes && Array.isArray(untagged.attributes[1]) ? untagged.attributes[1] : false;
|
|
89908
90413
|
if (!list) {
|
|
89909
90414
|
return;
|
|
@@ -89911,7 +90416,7 @@ var require_status = __commonJS({
|
|
|
89911
90416
|
parseStatusList(list, (key, value) => {
|
|
89912
90417
|
map[key] = value;
|
|
89913
90418
|
if (updateCurrent && MAILBOX_UPDATERS[key]) {
|
|
89914
|
-
MAILBOX_UPDATERS[key](value, connection,
|
|
90419
|
+
MAILBOX_UPDATERS[key](value, connection, path27);
|
|
89915
90420
|
}
|
|
89916
90421
|
});
|
|
89917
90422
|
}
|
|
@@ -89924,9 +90429,9 @@ var require_status = __commonJS({
|
|
|
89924
90429
|
return map;
|
|
89925
90430
|
} catch (err) {
|
|
89926
90431
|
if (err.responseStatus === "NO") {
|
|
89927
|
-
let folders = await connection.run("LIST", "",
|
|
90432
|
+
let folders = await connection.run("LIST", "", path27, { listOnly: true });
|
|
89928
90433
|
if (folders && !folders.length) {
|
|
89929
|
-
let error2 = new Error(`Mailbox doesn't exist: ${
|
|
90434
|
+
let error2 = new Error(`Mailbox doesn't exist: ${path27}`);
|
|
89930
90435
|
error2.code = "NotFound";
|
|
89931
90436
|
error2.response = err;
|
|
89932
90437
|
throw error2;
|
|
@@ -90073,15 +90578,15 @@ var require_quota = __commonJS({
|
|
|
90073
90578
|
"node_modules/imapflow/lib/commands/quota.js"(exports, module) {
|
|
90074
90579
|
"use strict";
|
|
90075
90580
|
var { encodePath, normalizePath, enhanceCommandError, parseUintValue, isUnsafeKey } = require_tools2();
|
|
90076
|
-
module.exports = async (connection,
|
|
90077
|
-
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !
|
|
90581
|
+
module.exports = async (connection, path27) => {
|
|
90582
|
+
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path27) {
|
|
90078
90583
|
return;
|
|
90079
90584
|
}
|
|
90080
90585
|
if (!connection.capabilities.has("QUOTA")) {
|
|
90081
90586
|
return false;
|
|
90082
90587
|
}
|
|
90083
|
-
|
|
90084
|
-
let map = { path:
|
|
90588
|
+
path27 = normalizePath(connection, path27);
|
|
90589
|
+
let map = { path: path27 };
|
|
90085
90590
|
let processQuotaResponse = (untagged) => {
|
|
90086
90591
|
let attributes = untagged.attributes && untagged.attributes[1];
|
|
90087
90592
|
if (!attributes || !attributes.length) {
|
|
@@ -90121,7 +90626,7 @@ var require_quota = __commonJS({
|
|
|
90121
90626
|
let quotaFound = false;
|
|
90122
90627
|
let response;
|
|
90123
90628
|
try {
|
|
90124
|
-
response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection,
|
|
90629
|
+
response = await connection.exec("GETQUOTAROOT", [{ type: "ATOM", value: encodePath(connection, path27) }], {
|
|
90125
90630
|
untagged: {
|
|
90126
90631
|
// QUOTAROOT response tells us which quota root applies to this mailbox.
|
|
90127
90632
|
// A mailbox may have zero or one quota root.
|
|
@@ -90264,15 +90769,15 @@ var require_idle = __commonJS({
|
|
|
90264
90769
|
}
|
|
90265
90770
|
}
|
|
90266
90771
|
async function pollOnce2(connection, session) {
|
|
90267
|
-
let
|
|
90772
|
+
let path27 = connection.mailbox && connection.mailbox.path;
|
|
90268
90773
|
switch (connection.missingIdleCommand) {
|
|
90269
90774
|
case "SELECT":
|
|
90270
90775
|
connection.log.debug({ src: "c", msg: `Running SELECT to detect changes in folder`, cid: connection.id });
|
|
90271
|
-
await connection.runInternal("SELECT",
|
|
90776
|
+
await connection.runInternal("SELECT", path27, { readOnly: session.selectCommand.command === "EXAMINE" });
|
|
90272
90777
|
break;
|
|
90273
90778
|
case "STATUS": {
|
|
90274
90779
|
connection.log.debug({ src: "c", msg: `Running STATUS to detect changes in folder`, cid: connection.id });
|
|
90275
|
-
let status = await connection.runInternal("STATUS",
|
|
90780
|
+
let status = await connection.runInternal("STATUS", path27, {
|
|
90276
90781
|
messages: true,
|
|
90277
90782
|
uidNext: true,
|
|
90278
90783
|
uidValidity: true,
|
|
@@ -91959,12 +92464,12 @@ var require_imap_flow = __commonJS({
|
|
|
91959
92464
|
this.emit("flags", updateEvent);
|
|
91960
92465
|
}
|
|
91961
92466
|
}
|
|
91962
|
-
async ensureSelectedMailbox(
|
|
91963
|
-
if (!
|
|
92467
|
+
async ensureSelectedMailbox(path27) {
|
|
92468
|
+
if (!path27) {
|
|
91964
92469
|
return false;
|
|
91965
92470
|
}
|
|
91966
|
-
if (!this.mailbox || !comparePaths(this, this.mailbox.path,
|
|
91967
|
-
return await this.mailboxOpen(
|
|
92471
|
+
if (!this.mailbox || !comparePaths(this, this.mailbox.path, path27)) {
|
|
92472
|
+
return await this.mailboxOpen(path27);
|
|
91968
92473
|
}
|
|
91969
92474
|
return true;
|
|
91970
92475
|
}
|
|
@@ -92379,9 +92884,9 @@ var require_imap_flow = __commonJS({
|
|
|
92379
92884
|
* let quota = await client.getQuota();
|
|
92380
92885
|
* console.log(quota.storage.used, quota.storage.limit)
|
|
92381
92886
|
*/
|
|
92382
|
-
async getQuota(
|
|
92383
|
-
|
|
92384
|
-
return await this.run("QUOTA",
|
|
92887
|
+
async getQuota(path27) {
|
|
92888
|
+
path27 = path27 || "INBOX";
|
|
92889
|
+
return await this.run("QUOTA", path27);
|
|
92385
92890
|
}
|
|
92386
92891
|
/**
|
|
92387
92892
|
* @typedef {Object} ListResponse
|
|
@@ -92491,8 +92996,8 @@ var require_imap_flow = __commonJS({
|
|
|
92491
92996
|
* console.log(info.path);
|
|
92492
92997
|
* // "INBOX.parent.child" // assumes "INBOX." as namespace prefix and "." as delimiter
|
|
92493
92998
|
*/
|
|
92494
|
-
async mailboxCreate(
|
|
92495
|
-
return await this.run("CREATE",
|
|
92999
|
+
async mailboxCreate(path27) {
|
|
93000
|
+
return await this.run("CREATE", path27);
|
|
92496
93001
|
}
|
|
92497
93002
|
/**
|
|
92498
93003
|
* @typedef {Object} MailboxRenameResponse
|
|
@@ -92513,8 +93018,8 @@ var require_imap_flow = __commonJS({
|
|
|
92513
93018
|
* console.log(info.newPath);
|
|
92514
93019
|
* // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
|
|
92515
93020
|
*/
|
|
92516
|
-
async mailboxRename(
|
|
92517
|
-
return await this.run("RENAME",
|
|
93021
|
+
async mailboxRename(path27, newPath) {
|
|
93022
|
+
return await this.run("RENAME", path27, newPath);
|
|
92518
93023
|
}
|
|
92519
93024
|
/**
|
|
92520
93025
|
* @typedef {Object} MailboxDeleteResponse
|
|
@@ -92533,8 +93038,8 @@ var require_imap_flow = __commonJS({
|
|
|
92533
93038
|
* console.log(info.path);
|
|
92534
93039
|
* // "INBOX.Important stuff ❗️" // assumes "INBOX." as namespace prefix
|
|
92535
93040
|
*/
|
|
92536
|
-
async mailboxDelete(
|
|
92537
|
-
return await this.run("DELETE",
|
|
93041
|
+
async mailboxDelete(path27) {
|
|
93042
|
+
return await this.run("DELETE", path27);
|
|
92538
93043
|
}
|
|
92539
93044
|
/**
|
|
92540
93045
|
* Subscribes to a mailbox
|
|
@@ -92545,8 +93050,8 @@ var require_imap_flow = __commonJS({
|
|
|
92545
93050
|
* @example
|
|
92546
93051
|
* await client.mailboxSubscribe('Important stuff ❗️');
|
|
92547
93052
|
*/
|
|
92548
|
-
async mailboxSubscribe(
|
|
92549
|
-
return await this.run("SUBSCRIBE",
|
|
93053
|
+
async mailboxSubscribe(path27) {
|
|
93054
|
+
return await this.run("SUBSCRIBE", path27);
|
|
92550
93055
|
}
|
|
92551
93056
|
/**
|
|
92552
93057
|
* Unsubscribes from a mailbox
|
|
@@ -92557,8 +93062,8 @@ var require_imap_flow = __commonJS({
|
|
|
92557
93062
|
* @example
|
|
92558
93063
|
* await client.mailboxUnsubscribe('Important stuff ❗️');
|
|
92559
93064
|
*/
|
|
92560
|
-
async mailboxUnsubscribe(
|
|
92561
|
-
return await this.run("UNSUBSCRIBE",
|
|
93065
|
+
async mailboxUnsubscribe(path27) {
|
|
93066
|
+
return await this.run("UNSUBSCRIBE", path27);
|
|
92562
93067
|
}
|
|
92563
93068
|
/**
|
|
92564
93069
|
* Opens a mailbox to access messages. You can perform message operations only against an opened mailbox.
|
|
@@ -92576,8 +93081,8 @@ var require_imap_flow = __commonJS({
|
|
|
92576
93081
|
* console.log(mailbox.exists);
|
|
92577
93082
|
* // 125
|
|
92578
93083
|
*/
|
|
92579
|
-
async mailboxOpen(
|
|
92580
|
-
return await this.run("SELECT",
|
|
93084
|
+
async mailboxOpen(path27, options) {
|
|
93085
|
+
return await this.run("SELECT", path27, options);
|
|
92581
93086
|
}
|
|
92582
93087
|
/**
|
|
92583
93088
|
* Closes a previously opened mailbox
|
|
@@ -92624,8 +93129,8 @@ var require_imap_flow = __commonJS({
|
|
|
92624
93129
|
* console.log(status.unseen);
|
|
92625
93130
|
* // 123
|
|
92626
93131
|
*/
|
|
92627
|
-
async status(
|
|
92628
|
-
return await this.run("STATUS",
|
|
93132
|
+
async status(path27, query) {
|
|
93133
|
+
return await this.run("STATUS", path27, query);
|
|
92629
93134
|
}
|
|
92630
93135
|
/**
|
|
92631
93136
|
* Starts listening for new or deleted messages from the currently opened mailbox. Only required if {@link ImapFlow#disableAutoIdle} is set to `true`
|
|
@@ -92879,8 +93384,8 @@ var require_imap_flow = __commonJS({
|
|
|
92879
93384
|
* @example
|
|
92880
93385
|
* await client.append('INBOX', rawMessageBuffer, ['\\Seen'], new Date(2000, 1, 1));
|
|
92881
93386
|
*/
|
|
92882
|
-
async append(
|
|
92883
|
-
return await this.run("APPEND",
|
|
93387
|
+
async append(path27, content, flags, idate) {
|
|
93388
|
+
return await this.run("APPEND", path27, content, flags, idate) || false;
|
|
92884
93389
|
}
|
|
92885
93390
|
/**
|
|
92886
93391
|
* @typedef {Object} CopyResponseObject
|
|
@@ -93724,7 +94229,7 @@ var require_imap_flow = __commonJS({
|
|
|
93724
94229
|
await new Promise((resolve2) => setImmediate(resolve2));
|
|
93725
94230
|
}
|
|
93726
94231
|
const lock = this.locks.shift();
|
|
93727
|
-
const { resolve, reject, path:
|
|
94232
|
+
const { resolve, reject, path: path27, options, lockId } = lock;
|
|
93728
94233
|
if (lock.acquireTimer) {
|
|
93729
94234
|
clearTimeout(lock.acquireTimer);
|
|
93730
94235
|
lock.acquireTimer = null;
|
|
@@ -93740,7 +94245,7 @@ var require_imap_flow = __commonJS({
|
|
|
93740
94245
|
this.log.warn({
|
|
93741
94246
|
msg: "Mailbox lock held for a long time",
|
|
93742
94247
|
lockId: lock.lockId,
|
|
93743
|
-
path:
|
|
94248
|
+
path: path27,
|
|
93744
94249
|
heldFor: Date.now() - lock.heldAt,
|
|
93745
94250
|
/* c8 ignore next */
|
|
93746
94251
|
// the held-lock-warning diagnostic with a description set is a timing-dependent log detail
|
|
@@ -93776,52 +94281,52 @@ var require_imap_flow = __commonJS({
|
|
|
93776
94281
|
}
|
|
93777
94282
|
};
|
|
93778
94283
|
if (!this.usable || !this.socket || this.socket.destroyed) {
|
|
93779
|
-
this.log.trace({ msg: "Failed to acquire mailbox lock", path:
|
|
94284
|
+
this.log.trace({ msg: "Failed to acquire mailbox lock", path: path27, lockId, idling: this.idling });
|
|
93780
94285
|
let error2 = new Error("Connection not available");
|
|
93781
94286
|
error2.code = "NoConnection";
|
|
93782
94287
|
reject(error2);
|
|
93783
94288
|
continue;
|
|
93784
94289
|
}
|
|
93785
|
-
if (this.mailbox && this.mailbox.path ===
|
|
94290
|
+
if (this.mailbox && this.mailbox.path === path27 && !!this.mailbox.readOnly === !!options.readOnly) {
|
|
93786
94291
|
this.log.trace({
|
|
93787
94292
|
msg: "Mailbox lock acquired [existing]",
|
|
93788
|
-
path:
|
|
94293
|
+
path: path27,
|
|
93789
94294
|
lockId,
|
|
93790
94295
|
idling: this.idling,
|
|
93791
94296
|
...options.description && { description: options.description }
|
|
93792
94297
|
});
|
|
93793
94298
|
this.currentLock = lock;
|
|
93794
94299
|
armHeldTimer();
|
|
93795
|
-
resolve({ path:
|
|
94300
|
+
resolve({ path: path27, release });
|
|
93796
94301
|
break;
|
|
93797
94302
|
}
|
|
93798
94303
|
try {
|
|
93799
|
-
await this.mailboxOpen(
|
|
94304
|
+
await this.mailboxOpen(path27, options);
|
|
93800
94305
|
this.log.trace({
|
|
93801
94306
|
msg: "Mailbox lock acquired [selected]",
|
|
93802
|
-
path:
|
|
94307
|
+
path: path27,
|
|
93803
94308
|
lockId,
|
|
93804
94309
|
idling: this.idling,
|
|
93805
94310
|
...options.description && { description: options.description }
|
|
93806
94311
|
});
|
|
93807
94312
|
this.currentLock = lock;
|
|
93808
94313
|
armHeldTimer();
|
|
93809
|
-
resolve({ path:
|
|
94314
|
+
resolve({ path: path27, release });
|
|
93810
94315
|
break;
|
|
93811
94316
|
} catch (err) {
|
|
93812
94317
|
if (err.responseStatus === "NO") {
|
|
93813
94318
|
try {
|
|
93814
|
-
let folders = await this.run("LIST", "",
|
|
94319
|
+
let folders = await this.run("LIST", "", path27, { listOnly: true });
|
|
93815
94320
|
if (!folders || !folders.length) {
|
|
93816
94321
|
err.mailboxMissing = true;
|
|
93817
94322
|
}
|
|
93818
94323
|
} catch (E) {
|
|
93819
|
-
this.log.trace({ msg: "Failed to verify failed mailbox", path:
|
|
94324
|
+
this.log.trace({ msg: "Failed to verify failed mailbox", path: path27, err: E });
|
|
93820
94325
|
}
|
|
93821
94326
|
}
|
|
93822
94327
|
this.log.trace({
|
|
93823
94328
|
msg: "Failed to acquire mailbox lock",
|
|
93824
|
-
path:
|
|
94329
|
+
path: path27,
|
|
93825
94330
|
lockId,
|
|
93826
94331
|
idling: this.idling,
|
|
93827
94332
|
...options.description && { description: options.description },
|
|
@@ -93860,13 +94365,13 @@ var require_imap_flow = __commonJS({
|
|
|
93860
94365
|
* lock.release();
|
|
93861
94366
|
* }
|
|
93862
94367
|
*/
|
|
93863
|
-
getMailboxLock(
|
|
94368
|
+
getMailboxLock(path27, options) {
|
|
93864
94369
|
options = options || {};
|
|
93865
|
-
|
|
94370
|
+
path27 = normalizePath(this, path27);
|
|
93866
94371
|
let lockId = ++this.lockCounter;
|
|
93867
94372
|
this.log.trace({
|
|
93868
94373
|
msg: "Requesting lock",
|
|
93869
|
-
path:
|
|
94374
|
+
path: path27,
|
|
93870
94375
|
lockId,
|
|
93871
94376
|
...options.description && { description: options.description },
|
|
93872
94377
|
activeLock: this.currentLock ? {
|
|
@@ -93875,7 +94380,7 @@ var require_imap_flow = __commonJS({
|
|
|
93875
94380
|
} : null
|
|
93876
94381
|
});
|
|
93877
94382
|
let lockPromise = new Promise((resolve, reject) => {
|
|
93878
|
-
let lockEntry = { resolve, reject, path:
|
|
94383
|
+
let lockEntry = { resolve, reject, path: path27, options, lockId };
|
|
93879
94384
|
this.locks.push(lockEntry);
|
|
93880
94385
|
if (Number(options.acquireTimeout) > 0) {
|
|
93881
94386
|
lockEntry.acquireTimer = setTimeout(() => {
|
|
@@ -93964,16 +94469,16 @@ var require_imap_flow = __commonJS({
|
|
|
93964
94469
|
});
|
|
93965
94470
|
|
|
93966
94471
|
// src/mail/mail-fetcher.ts
|
|
93967
|
-
import
|
|
93968
|
-
import
|
|
94472
|
+
import fs24 from "node:fs/promises";
|
|
94473
|
+
import path25 from "node:path";
|
|
93969
94474
|
async function saveAttachments(attachments, downloadDir) {
|
|
93970
94475
|
if (attachments.length === 0) return [];
|
|
93971
|
-
await
|
|
94476
|
+
await fs24.mkdir(downloadDir, { recursive: true });
|
|
93972
94477
|
const saved = [];
|
|
93973
94478
|
for (const a of attachments) {
|
|
93974
|
-
const name =
|
|
93975
|
-
const savedPath =
|
|
93976
|
-
await
|
|
94479
|
+
const name = path25.basename(a.filename) || "attachment";
|
|
94480
|
+
const savedPath = path25.join(downloadDir, name);
|
|
94481
|
+
await fs24.writeFile(savedPath, a.content);
|
|
93977
94482
|
saved.push({ filename: name, savedPath, size: a.content.length });
|
|
93978
94483
|
}
|
|
93979
94484
|
return saved;
|
|
@@ -94104,7 +94609,7 @@ var init_mail_fetcher = __esm({
|
|
|
94104
94609
|
|
|
94105
94610
|
// src/tools/fetch-mail.ts
|
|
94106
94611
|
import os17 from "node:os";
|
|
94107
|
-
import
|
|
94612
|
+
import path26 from "node:path";
|
|
94108
94613
|
function registerFetchMailTool(server, deps = {}) {
|
|
94109
94614
|
const makeFetcher = deps.fetcherFactory ?? ((creds) => new ImapflowMailFetcher(creds));
|
|
94110
94615
|
server.registerTool(
|
|
@@ -94166,7 +94671,7 @@ var init_fetch_mail = __esm({
|
|
|
94166
94671
|
init_mail_fetcher();
|
|
94167
94672
|
init_auth_error();
|
|
94168
94673
|
init_validate();
|
|
94169
|
-
DEFAULT_DOWNLOAD_DIR =
|
|
94674
|
+
DEFAULT_DOWNLOAD_DIR = path26.join(os17.homedir(), ".cogent", "mail-downloads");
|
|
94170
94675
|
}
|
|
94171
94676
|
});
|
|
94172
94677
|
|
|
@@ -94257,9 +94762,74 @@ var init_rotate_mail_creds = __esm({
|
|
|
94257
94762
|
|
|
94258
94763
|
// src/index.ts
|
|
94259
94764
|
var index_exports = {};
|
|
94765
|
+
function shutdown(reason) {
|
|
94766
|
+
if (shuttingDown) return;
|
|
94767
|
+
shuttingDown = true;
|
|
94768
|
+
try {
|
|
94769
|
+
logger.info(`Shutting down: ${reason}`);
|
|
94770
|
+
autoRelay.stop();
|
|
94771
|
+
withdrawBridge(process.cwd(), PROCESS_MARK);
|
|
94772
|
+
heartbeat.stop();
|
|
94773
|
+
if (cloudWsClient) {
|
|
94774
|
+
cloudWsClient.disconnect();
|
|
94775
|
+
}
|
|
94776
|
+
logger.close();
|
|
94777
|
+
} finally {
|
|
94778
|
+
process.exit(0);
|
|
94779
|
+
}
|
|
94780
|
+
}
|
|
94781
|
+
async function clientGone(reason) {
|
|
94782
|
+
if (draining || shuttingDown) return;
|
|
94783
|
+
draining = true;
|
|
94784
|
+
autoRelay.announceDraining();
|
|
94785
|
+
const busy = () => {
|
|
94786
|
+
const d = autoRelay.getDiagnostics();
|
|
94787
|
+
return { requests: stdoutDead ? [] : [...inFlightRequests.values()], wake: d.processing, queued: d.queueLength };
|
|
94788
|
+
};
|
|
94789
|
+
const b0 = busy();
|
|
94790
|
+
if (!b0.requests.length && !b0.wake && !b0.queued) return shutdown(reason);
|
|
94791
|
+
let capMs = drainCapMs(3e5);
|
|
94792
|
+
try {
|
|
94793
|
+
capMs = drainCapMs(getConfig().COGENT_TIMEOUT_MS);
|
|
94794
|
+
} catch {
|
|
94795
|
+
}
|
|
94796
|
+
logger.info(
|
|
94797
|
+
`Client gone (${reason}) \u2014 draining before exit (cap ${Math.round(capMs / 1e3)}s): ${b0.requests.length} MCP request(s) [${b0.requests.join(", ")}], wake running: ${b0.wake}, queued: ${b0.queued}`
|
|
94798
|
+
);
|
|
94799
|
+
cancelPresenceRetry();
|
|
94800
|
+
heartbeat.stop();
|
|
94801
|
+
cloudWsClient?.disconnect();
|
|
94802
|
+
const t0 = Date.now();
|
|
94803
|
+
let b = b0;
|
|
94804
|
+
while (Date.now() - t0 < capMs) {
|
|
94805
|
+
b = busy();
|
|
94806
|
+
if (!b.requests.length && !b.wake && !b.queued) break;
|
|
94807
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
94808
|
+
}
|
|
94809
|
+
if (!stdoutDead) {
|
|
94810
|
+
await new Promise((r) => {
|
|
94811
|
+
const t = setTimeout(r, 1e3);
|
|
94812
|
+
try {
|
|
94813
|
+
process.stdout.write("", () => {
|
|
94814
|
+
clearTimeout(t);
|
|
94815
|
+
r();
|
|
94816
|
+
});
|
|
94817
|
+
} catch {
|
|
94818
|
+
clearTimeout(t);
|
|
94819
|
+
r();
|
|
94820
|
+
}
|
|
94821
|
+
});
|
|
94822
|
+
}
|
|
94823
|
+
const left = b.requests.length || b.wake || b.queued;
|
|
94824
|
+
const undeliverable = stdoutDead && inFlightRequests.size ? ` (${inFlightRequests.size} MCP response(s) undeliverable: stdout closed)` : "";
|
|
94825
|
+
shutdown(
|
|
94826
|
+
left ? `${reason}; drain cap reached after ${Date.now() - t0}ms \u2014 ABANDONED ${b.requests.length} MCP request(s) [${b.requests.join(", ")}], wake running: ${b.wake}, queued: ${b.queued}${undeliverable}` : `${reason}; drained in ${Date.now() - t0}ms (${b0.requests.length} MCP request(s), wake: ${b0.wake}, queued: ${b0.queued})${undeliverable}`
|
|
94827
|
+
);
|
|
94828
|
+
}
|
|
94260
94829
|
async function main() {
|
|
94830
|
+
markBridgeProcess(process.cwd(), SERVER_VERSION);
|
|
94261
94831
|
await runStartup();
|
|
94262
|
-
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
94832
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
94263
94833
|
registerRegisterPeerTool(server);
|
|
94264
94834
|
registerDeregisterPeerTool(server);
|
|
94265
94835
|
registerSendMessageTool(server);
|
|
@@ -94304,7 +94874,31 @@ async function main() {
|
|
|
94304
94874
|
});
|
|
94305
94875
|
}
|
|
94306
94876
|
const transport = new StdioServerTransport();
|
|
94877
|
+
transport.onclose = () => void clientGone("MCP transport closed");
|
|
94307
94878
|
await server.connect(transport);
|
|
94879
|
+
const sdkOnMessage = transport.onmessage;
|
|
94880
|
+
transport.onmessage = (msg) => {
|
|
94881
|
+
if ("method" in msg && "id" in msg) {
|
|
94882
|
+
const tool = msg.method === "tools/call" ? msg.params?.name : void 0;
|
|
94883
|
+
inFlightRequests.set(msg.id, typeof tool === "string" ? `tools/call ${tool}` : msg.method);
|
|
94884
|
+
} else if ("method" in msg && msg.method === "notifications/cancelled") {
|
|
94885
|
+
const id = msg.params?.requestId;
|
|
94886
|
+
if (typeof id === "string" || typeof id === "number") inFlightRequests.delete(id);
|
|
94887
|
+
}
|
|
94888
|
+
sdkOnMessage?.(msg);
|
|
94889
|
+
};
|
|
94890
|
+
const sdkSend = transport.send.bind(transport);
|
|
94891
|
+
transport.send = (msg) => {
|
|
94892
|
+
const settles = !("method" in msg) && "id" in msg ? msg.id : void 0;
|
|
94893
|
+
return sdkSend(msg).finally(() => {
|
|
94894
|
+
if (settles !== void 0) inFlightRequests.delete(settles);
|
|
94895
|
+
});
|
|
94896
|
+
};
|
|
94897
|
+
const stdinIsDevice = startedWithoutClient();
|
|
94898
|
+
if (!process.stdin.isTTY && !stdinIsDevice) {
|
|
94899
|
+
process.stdin.once("end", () => void clientGone("stdin EOF \u2014 the MCP client is gone"));
|
|
94900
|
+
process.stdin.once("close", () => void clientGone("stdin closed \u2014 the MCP client is gone"));
|
|
94901
|
+
}
|
|
94308
94902
|
process.stderr.write(
|
|
94309
94903
|
`${SERVER_NAME} v${SERVER_VERSION} running on stdio
|
|
94310
94904
|
`
|
|
@@ -94329,14 +94923,17 @@ async function main() {
|
|
|
94329
94923
|
"Server ready. Tools: cogent_register_peer, cogent_deregister_peer, cogent_send_message, cogent_list_peers, cogent_get_history, cogent_health_check, cogent_create_session, cogent_join_session"
|
|
94330
94924
|
);
|
|
94331
94925
|
}
|
|
94926
|
+
var shuttingDown, draining, stdoutDead, inFlightRequests;
|
|
94332
94927
|
var init_index = __esm({
|
|
94333
94928
|
"src/index.ts"() {
|
|
94334
94929
|
"use strict";
|
|
94335
94930
|
init_mcp();
|
|
94336
94931
|
init_stdio2();
|
|
94337
94932
|
init_constants();
|
|
94933
|
+
init_instructions();
|
|
94338
94934
|
init_npm_update_check();
|
|
94339
94935
|
init_startup();
|
|
94936
|
+
init_config();
|
|
94340
94937
|
init_logger();
|
|
94341
94938
|
init_register_peer();
|
|
94342
94939
|
init_send_message();
|
|
@@ -94352,10 +94949,12 @@ var init_index = __esm({
|
|
|
94352
94949
|
init_fetch_mail();
|
|
94353
94950
|
init_rotate_mail_creds();
|
|
94354
94951
|
init_heartbeat();
|
|
94952
|
+
init_wake_inflight();
|
|
94953
|
+
init_wake_ownership();
|
|
94355
94954
|
process.on("uncaughtException", (err) => {
|
|
94356
94955
|
if (err.code === "EPIPE") {
|
|
94357
|
-
|
|
94358
|
-
|
|
94956
|
+
stdoutDead = true;
|
|
94957
|
+
void clientGone("stdout EPIPE \u2014 the MCP client is gone");
|
|
94359
94958
|
return;
|
|
94360
94959
|
}
|
|
94361
94960
|
logger.error(`Uncaught exception: ${err.message}`, { stack: err.stack });
|
|
@@ -94364,26 +94963,12 @@ var init_index = __esm({
|
|
|
94364
94963
|
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
94365
94964
|
logger.error(`Unhandled rejection: ${msg}`);
|
|
94366
94965
|
});
|
|
94367
|
-
|
|
94368
|
-
|
|
94369
|
-
|
|
94370
|
-
|
|
94371
|
-
|
|
94372
|
-
|
|
94373
|
-
}
|
|
94374
|
-
logger.close();
|
|
94375
|
-
process.exit(0);
|
|
94376
|
-
});
|
|
94377
|
-
process.on("SIGINT", () => {
|
|
94378
|
-
logger.info("SIGINT received, shutting down");
|
|
94379
|
-
autoRelay.stop();
|
|
94380
|
-
heartbeat.stop();
|
|
94381
|
-
if (cloudWsClient) {
|
|
94382
|
-
cloudWsClient.disconnect();
|
|
94383
|
-
}
|
|
94384
|
-
logger.close();
|
|
94385
|
-
process.exit(0);
|
|
94386
|
-
});
|
|
94966
|
+
shuttingDown = false;
|
|
94967
|
+
draining = false;
|
|
94968
|
+
stdoutDead = false;
|
|
94969
|
+
process.on("SIGTERM", () => shutdown("SIGTERM received"));
|
|
94970
|
+
process.on("SIGINT", () => shutdown("SIGINT received"));
|
|
94971
|
+
inFlightRequests = /* @__PURE__ */ new Map();
|
|
94387
94972
|
main().catch((err) => {
|
|
94388
94973
|
const msg = err instanceof Error ? err.message : String(err);
|
|
94389
94974
|
logger.error(`Fatal startup error: ${msg}`);
|