@essentialai/cogent-bridge-bundled 3.24.2 → 3.25.1

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.
Files changed (2) hide show
  1. package/cogent-bridge.mjs +64 -16
  2. package/package.json +1 -1
package/cogent-bridge.mjs CHANGED
@@ -26389,8 +26389,8 @@ var init_stdio2 = __esm({
26389
26389
  // src/constants.ts
26390
26390
  import { createRequire } from "node:module";
26391
26391
  function resolveVersion() {
26392
- if ("3.24.2") {
26393
- return "3.24.2";
26392
+ if ("3.25.1") {
26393
+ return "3.25.1";
26394
26394
  }
26395
26395
  try {
26396
26396
  const require2 = createRequire(import.meta.url);
@@ -27028,7 +27028,8 @@ async function getHistory(peerId, limit = 150, includeRelayEchoes = false, metad
27028
27028
  timestamp: m.timestamp,
27029
27029
  durationMs: m.durationMs,
27030
27030
  isRelayEcho: m.isRelayEcho === true,
27031
- success: m.success
27031
+ success: m.success,
27032
+ attachmentCount: m.attachments?.length ?? 0
27032
27033
  }));
27033
27034
  return projected;
27034
27035
  }
@@ -27710,7 +27711,7 @@ var init_file_backend = __esm({
27710
27711
  threadId
27711
27712
  );
27712
27713
  }
27713
- async deregisterPeer(peerId) {
27714
+ async deregisterPeer(peerId, _peerSecret) {
27714
27715
  return { removed: await deregisterPeer(peerId), mailboxDeprovisioned: false };
27715
27716
  }
27716
27717
  getPeer(peerId) {
@@ -27871,10 +27872,10 @@ var init_http_backend = __esm({
27871
27872
  * confirmed the Team mailbox was reaped, so the deregister-peer tool can clear the now-dead
27872
27873
  * local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
27873
27874
  */
27874
- async deregisterPeer(peerId) {
27875
+ async deregisterPeer(peerId, peerSecret) {
27875
27876
  const path26 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27876
27877
  try {
27877
- const headers = await this.http.delete(path26, {});
27878
+ const headers = await this.http.delete(path26, peerSecret ? { peerSecret } : {});
27878
27879
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
27879
27880
  return { removed: true, mailboxDeprovisioned };
27880
27881
  } catch (err) {
@@ -27942,6 +27943,9 @@ var init_http_backend = __esm({
27942
27943
  if (record2.attachments && record2.attachments.length > 0) {
27943
27944
  body.attachments = record2.attachments;
27944
27945
  }
27946
+ if (record2.replyExpected === false && await relaySupports(this.http, "terminal-messages")) {
27947
+ body.replyExpected = false;
27948
+ }
27945
27949
  const resp = await this.http.post(path26, body);
27946
27950
  return {
27947
27951
  ...record2,
@@ -28125,6 +28129,38 @@ var init_http_client = __esm({
28125
28129
  clearTimeout(timer);
28126
28130
  }
28127
28131
  }
28132
+ /**
28133
+ * Parse a SUCCESS body, turning an unparseable one into a BridgeError.
28134
+ *
28135
+ * 🔴 WHY THIS EXISTS. `throwMappedError` has always guarded the NON-2xx path, so an nginx 502 or
28136
+ * 413 HTML page arrives as a clean BridgeError. The 2xx path did not: `return resp.json()` let a
28137
+ * truncated or empty success body escape as a raw `SyntaxError` carrying no code, no suggestion,
28138
+ * and nothing in the signature to warn a caller it could happen — callers at
28139
+ * http-backend.ts (list peers / get history / health check) simply propagated it.
28140
+ *
28141
+ * That is the worst corner of the trade-off the vault describes (how much information a failure
28142
+ * carries vs how strictly consumers must handle it —
28143
+ * memory/typescript-master-vault/concepts/Error_Handling.md), in a codebase whose own
28144
+ * BridgeError(code, message, suggestion) is the answer to it.
28145
+ *
28146
+ * A 2xx with an unreadable body is REAL: @hono/node-server can answer with a null body or append
28147
+ * `Error: …` to an already-streaming response (handleResponseError), and any proxy may truncate a
28148
+ * long /poll body. STARTUP_FAILED is deliberately the same code throwMappedError falls back to
28149
+ * for a non-JSON error body, so both directions of "the relay said something we cannot read"
28150
+ * report identically rather than inventing a second vocabulary.
28151
+ */
28152
+ async parseJson(resp, method, url) {
28153
+ try {
28154
+ return await resp.json();
28155
+ } catch (e) {
28156
+ const detail = e instanceof Error ? e.message : String(e);
28157
+ throw new BridgeError(
28158
+ "STARTUP_FAILED" /* STARTUP_FAILED */,
28159
+ `Relay returned HTTP ${resp.status} with an unreadable body for ${method} ${url.pathname}: ${detail}`,
28160
+ "The response was not valid JSON \u2014 usually a proxy error page or a truncated body. Retry; if it persists, check the relay and any proxy in front of it."
28161
+ );
28162
+ }
28163
+ }
28128
28164
  /**
28129
28165
  * Perform an authenticated GET request.
28130
28166
  * Appends query parameters to the URL if provided.
@@ -28140,7 +28176,7 @@ var init_http_client = __esm({
28140
28176
  if (!resp.ok) {
28141
28177
  await this.throwMappedError(resp);
28142
28178
  }
28143
- return resp.json();
28179
+ return this.parseJson(resp, "GET", url);
28144
28180
  }
28145
28181
  /**
28146
28182
  * Perform an authenticated POST request with a JSON body.
@@ -28158,7 +28194,7 @@ var init_http_client = __esm({
28158
28194
  if (resp.status === 204 || resp.headers?.get("content-length") === "0") {
28159
28195
  return void 0;
28160
28196
  }
28161
- return resp.json();
28197
+ return this.parseJson(resp, "POST", url);
28162
28198
  }
28163
28199
  /**
28164
28200
  * Perform an authenticated PATCH request with a JSON body.
@@ -28177,7 +28213,7 @@ var init_http_client = __esm({
28177
28213
  if (resp.status === 204 || resp.headers?.get("content-length") === "0") {
28178
28214
  return void 0;
28179
28215
  }
28180
- return resp.json();
28216
+ return this.parseJson(resp, "PATCH", url);
28181
28217
  }
28182
28218
  /**
28183
28219
  * Perform an authenticated DELETE request.
@@ -36370,7 +36406,10 @@ function registerSendMessageTool(server) {
36370
36406
  inputSchema: {
36371
36407
  fromPeerId: import_zod4.z.string().describe("Peer ID of the sender, e.g. 'backend'"),
36372
36408
  toPeerId: import_zod4.z.string().describe("Peer ID of the recipient, e.g. 'frontend'. Use '*' or 'broadcast' to send to all peers."),
36373
- message: import_zod4.z.string().describe("The message content to send to the target peer")
36409
+ message: import_zod4.z.string().describe("The message content to send to the target peer"),
36410
+ replyExpected: import_zod4.z.boolean().optional().describe(
36411
+ "Set false for a TERMINAL message \u2014 an acknowledgement, confirmation or FYI that conveys information and needs no answer. The recipient's check-on-stop hook then never counts it as owing a reply. Omit (or true) for anything that asks a question or expects a response. Without this, two agents acknowledging each other never terminate: every ACK is itself a directed message demanding an ACK."
36412
+ )
36374
36413
  },
36375
36414
  annotations: {
36376
36415
  readOnlyHint: false,
@@ -36379,7 +36418,7 @@ function registerSendMessageTool(server) {
36379
36418
  openWorldHint: true
36380
36419
  }
36381
36420
  },
36382
- async ({ fromPeerId, toPeerId, message }) => {
36421
+ async ({ fromPeerId, toPeerId, message, replyExpected }) => {
36383
36422
  try {
36384
36423
  if (isCloudDeferred(getConfig().COGENT_ENDPOINT)) {
36385
36424
  return successResult({
@@ -36421,7 +36460,8 @@ function registerSendMessageTool(server) {
36421
36460
  response: null,
36422
36461
  durationMs: Date.now() - startMs2,
36423
36462
  success: true,
36424
- error: null
36463
+ error: null,
36464
+ ...replyExpected === false ? { replyExpected: false } : {}
36425
36465
  });
36426
36466
  return successResult({
36427
36467
  success: true,
@@ -36484,7 +36524,8 @@ function registerSendMessageTool(server) {
36484
36524
  response: null,
36485
36525
  durationMs,
36486
36526
  success: true,
36487
- error: null
36527
+ error: null,
36528
+ ...replyExpected === false ? { replyExpected: false } : {}
36488
36529
  });
36489
36530
  } catch (recordErr) {
36490
36531
  autoRelay.clearExpectation(toPeerId);
@@ -36579,7 +36620,8 @@ function registerSendMessageTool(server) {
36579
36620
  response: success2 ? result.stdout : null,
36580
36621
  durationMs,
36581
36622
  success: success2,
36582
- error: success2 ? null : result.stderr
36623
+ error: success2 ? null : result.stderr,
36624
+ ...replyExpected === false ? { replyExpected: false } : {}
36583
36625
  });
36584
36626
  return successResult({
36585
36627
  success: success2,
@@ -36676,6 +36718,7 @@ var init_message = __esm({
36676
36718
  durationMs: import_zod6.z.number().nullable().describe("Round-trip duration in ms"),
36677
36719
  success: import_zod6.z.boolean().describe("Whether delivery succeeded"),
36678
36720
  pending: import_zod6.z.boolean().optional().describe("Delivered+acked; the reply is still expected"),
36721
+ replyExpected: import_zod6.z.boolean().optional().describe("Sender declares the message terminal \u2014 no reply expected. Absent/true = a reply is expected."),
36679
36722
  error: import_zod6.z.string().nullable().describe("Error message if delivery failed"),
36680
36723
  originPlatform: import_zod6.z.enum(["cc", "codex", "slack", "gchat", "web", "gemini", "whatsapp", "telegram", "discord"]).optional().describe("Platform that originated this message"),
36681
36724
  attachments: import_zod6.z.array(AttachmentSchema).optional().describe("Cogent Mail M2.5 \u2014 file references (byte transport = email)")
@@ -37189,7 +37232,7 @@ function registerGetHistoryTool(server) {
37189
37232
  "Include auto-relay echo records that mirror the recipient's reply. Off by default to keep history readable; turn on for debugging the relay pipeline (260511-o3p, requires server 3.1.6+)."
37190
37233
  ),
37191
37234
  metadataOnly: import_zod12.z.boolean().optional().default(false).describe(
37192
- 'Return records as metadata only \u2014 keys limited to {id, fromPeerId, toPeerId, timestamp, durationMs, isRelayEcho, success}. message and response bodies are omitted entirely. Target: \u226590% payload reduction for cheap "did head move?" polling. Added in 3.2 (HIST-02).'
37235
+ 'Return records as metadata only \u2014 keys limited to {id, fromPeerId, toPeerId, timestamp, durationMs, isRelayEcho, success, attachmentCount}. message and response bodies are omitted entirely. Target: \u226590% payload reduction for cheap "did head move?" polling. Added in 3.2 (HIST-02); attachmentCount added by Cogent Mail M2.5.'
37193
37236
  ),
37194
37237
  dedupInferredEchoes: import_zod12.z.boolean().optional().default(false).describe(
37195
37238
  "Suppress untagged auto-relay echo records via content-and-direction heuristic: drop M[i] when M[i].message === M[i-1].response AND fromPeerId/toPeerId are swapped AND \u0394t < 120s. Catches the ~13% of echoes that bypass the isRelayEcho tag (peer-driven re-broadcasts). Requires server 3.2.1+; older servers ignore the param. Added in 3.2.1 (FIX-INFERRED-ECHO, Phase 18 light)."
@@ -37285,7 +37328,12 @@ function registerDeregisterPeerTool(server) {
37285
37328
  });
37286
37329
  }
37287
37330
  const backend = getBackend();
37288
- const { removed, mailboxDeprovisioned } = await backend.deregisterPeer(peerId);
37331
+ let ownershipProof;
37332
+ try {
37333
+ ownershipProof = (await loadCredentials())?.peerSecret;
37334
+ } catch {
37335
+ }
37336
+ const { removed, mailboxDeprovisioned } = await backend.deregisterPeer(peerId, ownershipProof);
37289
37337
  if (removed) heartbeat.stop();
37290
37338
  if (mailboxDeprovisioned) {
37291
37339
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@essentialai/cogent-bridge-bundled",
3
- "version": "3.24.2",
3
+ "version": "3.25.1",
4
4
  "description": "Zero-dependency, pre-bundled Cogent MCP bridge — a single self-contained file for fast cold `npx` startup (used by the Codex plugin, whose MCP startup window is short). Functionally identical to @essentialai/cogent-bridge; carries no npm dependencies so `npx` skips dependency install.",
5
5
  "type": "module",
6
6
  "bin": {