@essentialai/cogent-bridge-bundled 3.24.1 → 3.25.0

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 +65 -15
  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.1") {
26393
- return "3.24.1";
26392
+ if ("3.25.0") {
26393
+ return "3.25.0";
26394
26394
  }
26395
26395
  try {
26396
26396
  const require2 = createRequire(import.meta.url);
@@ -27646,7 +27646,10 @@ async function checkCodexSandbox() {
27646
27646
  const probe = await probeSandboxStatus(config2);
27647
27647
  if (probe.status === "blocked") {
27648
27648
  if (config2.COGENT_CODEX_SANDBOX_FALLBACK) {
27649
- return { ok: true, message: `Sandbox blocked (${probe.detail}) \u2014 auto-bypass fallback is ON, so codex runs unsandboxed` };
27649
+ return {
27650
+ ok: true,
27651
+ message: `Sandbox blocked (${probe.detail}) \u2014 auto-bypass is ON, so codex sessions COGENT WAKES run unsandboxed. This does NOT change an already-running interactive codex session: that keeps the sandbox/approval profile it was launched with, and on this host its bwrap-backed modes will still fail. Relaunch it with --dangerously-bypass-approvals-and-sandbox, or enable unprivileged userns, to fix that.`
27652
+ };
27650
27653
  }
27651
27654
  return { ok: false, message: `Sandbox blocked: ${probe.detail}. Codex can't edit/test \u2014 set COGENT_CODEX_SANDBOX_FALLBACK=1, COGENT_CODEX_SANDBOX=bypass, or enable unprivileged userns` };
27652
27655
  }
@@ -27707,7 +27710,7 @@ var init_file_backend = __esm({
27707
27710
  threadId
27708
27711
  );
27709
27712
  }
27710
- async deregisterPeer(peerId) {
27713
+ async deregisterPeer(peerId, _peerSecret) {
27711
27714
  return { removed: await deregisterPeer(peerId), mailboxDeprovisioned: false };
27712
27715
  }
27713
27716
  getPeer(peerId) {
@@ -27868,10 +27871,10 @@ var init_http_backend = __esm({
27868
27871
  * confirmed the Team mailbox was reaped, so the deregister-peer tool can clear the now-dead
27869
27872
  * local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
27870
27873
  */
27871
- async deregisterPeer(peerId) {
27874
+ async deregisterPeer(peerId, peerSecret) {
27872
27875
  const path26 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27873
27876
  try {
27874
- const headers = await this.http.delete(path26, {});
27877
+ const headers = await this.http.delete(path26, peerSecret ? { peerSecret } : {});
27875
27878
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
27876
27879
  return { removed: true, mailboxDeprovisioned };
27877
27880
  } catch (err) {
@@ -27939,6 +27942,9 @@ var init_http_backend = __esm({
27939
27942
  if (record2.attachments && record2.attachments.length > 0) {
27940
27943
  body.attachments = record2.attachments;
27941
27944
  }
27945
+ if (record2.replyExpected === false && await relaySupports(this.http, "terminal-messages")) {
27946
+ body.replyExpected = false;
27947
+ }
27942
27948
  const resp = await this.http.post(path26, body);
27943
27949
  return {
27944
27950
  ...record2,
@@ -28122,6 +28128,38 @@ var init_http_client = __esm({
28122
28128
  clearTimeout(timer);
28123
28129
  }
28124
28130
  }
28131
+ /**
28132
+ * Parse a SUCCESS body, turning an unparseable one into a BridgeError.
28133
+ *
28134
+ * 🔴 WHY THIS EXISTS. `throwMappedError` has always guarded the NON-2xx path, so an nginx 502 or
28135
+ * 413 HTML page arrives as a clean BridgeError. The 2xx path did not: `return resp.json()` let a
28136
+ * truncated or empty success body escape as a raw `SyntaxError` carrying no code, no suggestion,
28137
+ * and nothing in the signature to warn a caller it could happen — callers at
28138
+ * http-backend.ts (list peers / get history / health check) simply propagated it.
28139
+ *
28140
+ * That is the worst corner of the trade-off the vault describes (how much information a failure
28141
+ * carries vs how strictly consumers must handle it —
28142
+ * memory/typescript-master-vault/concepts/Error_Handling.md), in a codebase whose own
28143
+ * BridgeError(code, message, suggestion) is the answer to it.
28144
+ *
28145
+ * A 2xx with an unreadable body is REAL: @hono/node-server can answer with a null body or append
28146
+ * `Error: …` to an already-streaming response (handleResponseError), and any proxy may truncate a
28147
+ * long /poll body. STARTUP_FAILED is deliberately the same code throwMappedError falls back to
28148
+ * for a non-JSON error body, so both directions of "the relay said something we cannot read"
28149
+ * report identically rather than inventing a second vocabulary.
28150
+ */
28151
+ async parseJson(resp, method, url) {
28152
+ try {
28153
+ return await resp.json();
28154
+ } catch (e) {
28155
+ const detail = e instanceof Error ? e.message : String(e);
28156
+ throw new BridgeError(
28157
+ "STARTUP_FAILED" /* STARTUP_FAILED */,
28158
+ `Relay returned HTTP ${resp.status} with an unreadable body for ${method} ${url.pathname}: ${detail}`,
28159
+ "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."
28160
+ );
28161
+ }
28162
+ }
28125
28163
  /**
28126
28164
  * Perform an authenticated GET request.
28127
28165
  * Appends query parameters to the URL if provided.
@@ -28137,7 +28175,7 @@ var init_http_client = __esm({
28137
28175
  if (!resp.ok) {
28138
28176
  await this.throwMappedError(resp);
28139
28177
  }
28140
- return resp.json();
28178
+ return this.parseJson(resp, "GET", url);
28141
28179
  }
28142
28180
  /**
28143
28181
  * Perform an authenticated POST request with a JSON body.
@@ -28155,7 +28193,7 @@ var init_http_client = __esm({
28155
28193
  if (resp.status === 204 || resp.headers?.get("content-length") === "0") {
28156
28194
  return void 0;
28157
28195
  }
28158
- return resp.json();
28196
+ return this.parseJson(resp, "POST", url);
28159
28197
  }
28160
28198
  /**
28161
28199
  * Perform an authenticated PATCH request with a JSON body.
@@ -28174,7 +28212,7 @@ var init_http_client = __esm({
28174
28212
  if (resp.status === 204 || resp.headers?.get("content-length") === "0") {
28175
28213
  return void 0;
28176
28214
  }
28177
- return resp.json();
28215
+ return this.parseJson(resp, "PATCH", url);
28178
28216
  }
28179
28217
  /**
28180
28218
  * Perform an authenticated DELETE request.
@@ -36367,7 +36405,10 @@ function registerSendMessageTool(server) {
36367
36405
  inputSchema: {
36368
36406
  fromPeerId: import_zod4.z.string().describe("Peer ID of the sender, e.g. 'backend'"),
36369
36407
  toPeerId: import_zod4.z.string().describe("Peer ID of the recipient, e.g. 'frontend'. Use '*' or 'broadcast' to send to all peers."),
36370
- message: import_zod4.z.string().describe("The message content to send to the target peer")
36408
+ message: import_zod4.z.string().describe("The message content to send to the target peer"),
36409
+ replyExpected: import_zod4.z.boolean().optional().describe(
36410
+ "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."
36411
+ )
36371
36412
  },
36372
36413
  annotations: {
36373
36414
  readOnlyHint: false,
@@ -36376,7 +36417,7 @@ function registerSendMessageTool(server) {
36376
36417
  openWorldHint: true
36377
36418
  }
36378
36419
  },
36379
- async ({ fromPeerId, toPeerId, message }) => {
36420
+ async ({ fromPeerId, toPeerId, message, replyExpected }) => {
36380
36421
  try {
36381
36422
  if (isCloudDeferred(getConfig().COGENT_ENDPOINT)) {
36382
36423
  return successResult({
@@ -36418,7 +36459,8 @@ function registerSendMessageTool(server) {
36418
36459
  response: null,
36419
36460
  durationMs: Date.now() - startMs2,
36420
36461
  success: true,
36421
- error: null
36462
+ error: null,
36463
+ ...replyExpected === false ? { replyExpected: false } : {}
36422
36464
  });
36423
36465
  return successResult({
36424
36466
  success: true,
@@ -36481,7 +36523,8 @@ function registerSendMessageTool(server) {
36481
36523
  response: null,
36482
36524
  durationMs,
36483
36525
  success: true,
36484
- error: null
36526
+ error: null,
36527
+ ...replyExpected === false ? { replyExpected: false } : {}
36485
36528
  });
36486
36529
  } catch (recordErr) {
36487
36530
  autoRelay.clearExpectation(toPeerId);
@@ -36576,7 +36619,8 @@ function registerSendMessageTool(server) {
36576
36619
  response: success2 ? result.stdout : null,
36577
36620
  durationMs,
36578
36621
  success: success2,
36579
- error: success2 ? null : result.stderr
36622
+ error: success2 ? null : result.stderr,
36623
+ ...replyExpected === false ? { replyExpected: false } : {}
36580
36624
  });
36581
36625
  return successResult({
36582
36626
  success: success2,
@@ -36673,6 +36717,7 @@ var init_message = __esm({
36673
36717
  durationMs: import_zod6.z.number().nullable().describe("Round-trip duration in ms"),
36674
36718
  success: import_zod6.z.boolean().describe("Whether delivery succeeded"),
36675
36719
  pending: import_zod6.z.boolean().optional().describe("Delivered+acked; the reply is still expected"),
36720
+ replyExpected: import_zod6.z.boolean().optional().describe("Sender declares the message terminal \u2014 no reply expected. Absent/true = a reply is expected."),
36676
36721
  error: import_zod6.z.string().nullable().describe("Error message if delivery failed"),
36677
36722
  originPlatform: import_zod6.z.enum(["cc", "codex", "slack", "gchat", "web", "gemini", "whatsapp", "telegram", "discord"]).optional().describe("Platform that originated this message"),
36678
36723
  attachments: import_zod6.z.array(AttachmentSchema).optional().describe("Cogent Mail M2.5 \u2014 file references (byte transport = email)")
@@ -37282,7 +37327,12 @@ function registerDeregisterPeerTool(server) {
37282
37327
  });
37283
37328
  }
37284
37329
  const backend = getBackend();
37285
- const { removed, mailboxDeprovisioned } = await backend.deregisterPeer(peerId);
37330
+ let ownershipProof;
37331
+ try {
37332
+ ownershipProof = (await loadCredentials())?.peerSecret;
37333
+ } catch {
37334
+ }
37335
+ const { removed, mailboxDeprovisioned } = await backend.deregisterPeer(peerId, ownershipProof);
37286
37336
  if (removed) heartbeat.stop();
37287
37337
  if (mailboxDeprovisioned) {
37288
37338
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@essentialai/cogent-bridge-bundled",
3
- "version": "3.24.1",
3
+ "version": "3.25.0",
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": {