@essentialai/cogent-bridge-bundled 3.23.9 โ†’ 3.24.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 +222 -7
  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.23.9") {
26393
- return "3.23.9";
26392
+ if ("3.24.1") {
26393
+ return "3.24.1";
26394
26394
  }
26395
26395
  try {
26396
26396
  const require2 = createRequire(import.meta.url);
@@ -35122,6 +35122,113 @@ var init_auto_relay = __esm({
35122
35122
  }
35123
35123
  });
35124
35124
 
35125
+ // src/services/peer-presence.ts
35126
+ function autoPresenceEnabled(env = process.env) {
35127
+ const v = env.COGENT_AUTO_PRESENCE;
35128
+ if (v === void 0 || v === "") return true;
35129
+ return !/^(0|false|no|off)$/i.test(v.trim());
35130
+ }
35131
+ async function restorePresence(deps) {
35132
+ try {
35133
+ if (!deps.isCloudConfigured()) {
35134
+ return { state: "local", restored: false, detail: "local mode \u2014 presence does not apply" };
35135
+ }
35136
+ if (deps.alreadyRegisteredInProcess()) {
35137
+ return { state: "online", restored: false, detail: "registered by this process" };
35138
+ }
35139
+ const creds = await deps.loadCredentials();
35140
+ if (!creds || !creds.endpoint || !creds.sessionId || !creds.token) {
35141
+ return {
35142
+ state: "deferred",
35143
+ restored: false,
35144
+ detail: "no stored channel credentials for this working directory \u2014 join a channel first"
35145
+ };
35146
+ }
35147
+ if (!creds.peerId) {
35148
+ return {
35149
+ state: "deferred",
35150
+ restored: false,
35151
+ detail: "channel credentials exist but name no peer \u2014 nothing was registered here"
35152
+ };
35153
+ }
35154
+ const peerId = creds.peerId;
35155
+ if (deps.peerAlreadyServed(peerId)) {
35156
+ return {
35157
+ state: "online",
35158
+ restored: false,
35159
+ detail: `peer '${peerId}' is already served by a live bridge for this working directory`
35160
+ };
35161
+ }
35162
+ if (!autoPresenceEnabled(deps.env ?? process.env)) {
35163
+ return {
35164
+ state: "offline",
35165
+ restored: false,
35166
+ detail: `peer '${peerId}' is not registered and COGENT_AUTO_PRESENCE is off \u2014 this agent is absent from its channel`
35167
+ };
35168
+ }
35169
+ await deps.goOnline({
35170
+ peerId,
35171
+ endpoint: creds.endpoint,
35172
+ sessionId: creds.sessionId,
35173
+ token: creds.token,
35174
+ cwd: deps.cwd(),
35175
+ // ๐Ÿ”ด THE PEER'S DISPLAY LABEL IS NOT PERSISTED ANYWHERE โ€” only the CHANNEL's is,
35176
+ // in credentials.label (create-session.ts writes `label: data.label`; join-session
35177
+ // writes the resolved channel label). Using that would label the agent after the
35178
+ // channel: a restore once put "paymentorchestrator" beside a sibling called "POFE".
35179
+ // peerId is the one identifier we hold that genuinely names this agent. The
35180
+ // operator's chosen label returns on the next cogent_register_peer, which carries it.
35181
+ label: peerId,
35182
+ // ๐Ÿ”ด WITHOUT THIS THE RESTORE CANNOT RECLAIM ITS OWN PEER. A re-join issues a NEW
35183
+ // token, and AUD-003 ownership is proven by the token that CREATED the peer or by
35184
+ // the secret issued with it. Omitting it means an entry owned by an earlier token
35185
+ // answers PEER_NOT_YOURS and the agent stays offline โ€” precisely the state this
35186
+ // module exists to leave. The secret is in the credential file; send it.
35187
+ peerSecret: creds.peerSecret
35188
+ });
35189
+ return {
35190
+ state: "online",
35191
+ restored: true,
35192
+ peerId,
35193
+ // Says what THIS process did. Whether the relay now lists the peer is the relay's
35194
+ // state, and asserting it from here would be a success nobody measured.
35195
+ detail: `re-registered peer '${peerId}' from stored credentials`
35196
+ };
35197
+ } catch (err) {
35198
+ const reason = err instanceof Error ? err.message : String(err);
35199
+ return {
35200
+ state: "offline",
35201
+ restored: false,
35202
+ detail: `presence restore failed: ${reason}`
35203
+ };
35204
+ }
35205
+ }
35206
+ function setPresence(outcome) {
35207
+ lastPresence = outcome;
35208
+ }
35209
+ function getPresence() {
35210
+ return lastPresence;
35211
+ }
35212
+ function logPresence(outcome) {
35213
+ if (outcome.state === "online" && outcome.restored) {
35214
+ logger.info(
35215
+ `Presence: offline -> online \u2014 ${outcome.detail}. This agent is addressable on its channel again, and leftover bridges for this checkout are now reapable.`
35216
+ );
35217
+ } else if (outcome.state === "offline") {
35218
+ logger.warn(`Presence: OFFLINE \u2014 ${outcome.detail}.`);
35219
+ } else {
35220
+ logger.debug(`Presence: ${outcome.state} \u2014 ${outcome.detail}.`);
35221
+ }
35222
+ }
35223
+ var lastPresence;
35224
+ var init_peer_presence = __esm({
35225
+ "src/services/peer-presence.ts"() {
35226
+ "use strict";
35227
+ init_logger();
35228
+ lastPresence = null;
35229
+ }
35230
+ });
35231
+
35125
35232
  // src/services/heartbeat.ts
35126
35233
  var HeartbeatService, heartbeat;
35127
35234
  var init_heartbeat = __esm({
@@ -35353,8 +35460,10 @@ __export(startup_exports, {
35353
35460
  cloudWsClient: () => cloudWsClient,
35354
35461
  hasPendingLabelResolve: () => hasPendingLabelResolve,
35355
35462
  isCloudMode: () => isCloudMode2,
35463
+ presenceRegisterArgs: () => presenceRegisterArgs,
35356
35464
  reinitCloudBackend: () => reinitCloudBackend,
35357
35465
  resolvePendingLabel: () => resolvePendingLabel,
35466
+ restorePeerPresence: () => restorePeerPresence,
35358
35467
  runPreflights: () => runPreflights,
35359
35468
  runStartup: () => runStartup,
35360
35469
  setInboxNotifier: () => setInboxNotifier,
@@ -35485,6 +35594,58 @@ async function triggerReRegistration() {
35485
35594
  reRegistrationInProgress = false;
35486
35595
  }
35487
35596
  }
35597
+ function presenceRegisterArgs(p) {
35598
+ return [
35599
+ p.peerId,
35600
+ p.sessionId,
35601
+ p.cwd,
35602
+ p.label,
35603
+ CLIENT_VERSION,
35604
+ "agent",
35605
+ void 0,
35606
+ // channelSessionId โ€” not tracked on a presence restore
35607
+ void 0,
35608
+ // capabilities โ€” likewise
35609
+ deriveWorkspaceId(p.cwd),
35610
+ p.sessionId,
35611
+ // threadId
35612
+ p.peerSecret
35613
+ // AUD-003 ownership proof โ€” reclaims a peer owned by an earlier token
35614
+ ];
35615
+ }
35616
+ async function restorePeerPresence() {
35617
+ const outcome = await restorePresence({
35618
+ // The endpoint being a relay URL is what makes presence meaningful. We deliberately do
35619
+ // NOT gate on the active backend being the cloud one: at startup it is still the
35620
+ // deferred FileBackend placeholder, and gating on it made this whole path inert
35621
+ // (measured: "skipped: not-cloud-mode" with valid credentials on disk).
35622
+ isCloudConfigured: () => {
35623
+ const ep = getConfig().COGENT_ENDPOINT;
35624
+ return !!ep && isCloudEndpoint(ep);
35625
+ },
35626
+ alreadyRegisteredInProcess: () => autoRelay.getDiagnostics().registered,
35627
+ peerAlreadyServed: (peerId) => {
35628
+ try {
35629
+ return listLiveBridges(process.cwd(), peerId).some((b) => b.pid !== process.pid);
35630
+ } catch {
35631
+ return false;
35632
+ }
35633
+ },
35634
+ loadCredentials: () => loadCredentials(),
35635
+ cwd: () => process.cwd(),
35636
+ goOnline: async ({ peerId, endpoint, sessionId, token, cwd, label, peerSecret }) => {
35637
+ await reinitCloudBackend(endpoint, sessionId, token);
35638
+ const backend = getBackend();
35639
+ await backend.registerPeer(...presenceRegisterArgs({ peerId, sessionId, cwd, label, peerSecret }));
35640
+ autoRelay.setLocalPeer(peerId, sessionId, cwd, "agent", label, sessionId);
35641
+ if (cloudWsClient) cloudWsClient.setPeerId(peerId);
35642
+ heartbeat.restart();
35643
+ }
35644
+ });
35645
+ setPresence(outcome);
35646
+ logPresence(outcome);
35647
+ return outcome;
35648
+ }
35488
35649
  function createCloudWsClient(endpoint, sessionId, token, http, inbox, pollIntervalMs) {
35489
35650
  const client = new CloudWsClient({
35490
35651
  endpoint,
@@ -35736,6 +35897,8 @@ var init_startup = __esm({
35736
35897
  init_cloud();
35737
35898
  init_http_client();
35738
35899
  init_auto_relay();
35900
+ init_peer_presence();
35901
+ init_wake_ownership();
35739
35902
  init_heartbeat();
35740
35903
  init_codex_preflight();
35741
35904
  init_codex_cli();
@@ -35892,10 +36055,24 @@ function registerRegisterPeerTool(server) {
35892
36055
  {
35893
36056
  method: "POST",
35894
36057
  headers: { "Content-Type": "application/json" },
35895
- body: JSON.stringify({
35896
- secret: autoSecret,
35897
- label: `Auto-created by ${label}`
35898
- })
36058
+ // ๐Ÿ”ด NO `label` โ€” let the relay name the channel.
36059
+ //
36060
+ // This used to send `Auto-created by ${label}`, which the relay's own
36061
+ // CreateSessionRequestSchema can NEVER accept: it requires
36062
+ // /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/ (lowercase, digits, hyphens, 3-32 chars).
36063
+ // "Auto-created by ..." has a capital A and spaces, so EVERY auto-create got
36064
+ // HTTP 400 INVALID_INPUT and the zero-config path โ€” register with no channel
36065
+ // configured โ€” could not work at all. Measured against a real relay 2026-09-15:
36066
+ // this body 400s, the same POST without a label returns 201.
36067
+ //
36068
+ // The 400 was visible as far back as 3.5.2 and was read as "don't fall into
36069
+ // auto-create" (see e2e/team-join-live.e2e.test.ts), so the symptom was routed
36070
+ // around and the path itself stayed broken.
36071
+ //
36072
+ // Omitting the label is not a workaround: the relay generates one with
36073
+ // collision-retry scoped to the org (generateSessionLabel + isLabelTaken). A
36074
+ // client-side slug would have to re-implement that and could still collide.
36075
+ body: JSON.stringify({ secret: autoSecret })
35899
36076
  }
35900
36077
  );
35901
36078
  if (!resp.ok) {
@@ -35914,6 +36091,8 @@ function registerRegisterPeerTool(server) {
35914
36091
  sessionId: cloudSessionId,
35915
36092
  token: cloudToken,
35916
36093
  peerId,
36094
+ // The CHANNEL's label (not this peer's) โ€” the name a human needs to join it.
36095
+ label: created.label,
35917
36096
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
35918
36097
  });
35919
36098
  try {
@@ -37113,6 +37292,18 @@ function registerDeregisterPeerTool(server) {
37113
37292
  logger.warn("failed to clear local mail credentials after deprovision", { error: err });
37114
37293
  }
37115
37294
  }
37295
+ if (removed) {
37296
+ try {
37297
+ const creds = await loadCredentials();
37298
+ if (creds?.peerId === peerId) {
37299
+ const { peerId: _dropped, peerSecret: _secret, ...rest } = creds;
37300
+ await saveCredentials({ ...rest, savedAt: (/* @__PURE__ */ new Date()).toISOString() });
37301
+ logger.info("cleared stored peerId after deregister", { peerId });
37302
+ }
37303
+ } catch (err) {
37304
+ logger.warn("failed to clear stored peerId after deregister", { error: err });
37305
+ }
37306
+ }
37116
37307
  return successResult({
37117
37308
  success: removed,
37118
37309
  message: removed ? `Peer '${peerId}' deregistered` : `Peer '${peerId}' was not registered`
@@ -37135,6 +37326,7 @@ var init_deregister_peer = __esm({
37135
37326
  init_logger();
37136
37327
  init_heartbeat();
37137
37328
  init_mail_credential_store();
37329
+ init_credential_store();
37138
37330
  }
37139
37331
  });
37140
37332
 
@@ -37238,7 +37430,24 @@ function registerHealthCheckTool(server) {
37238
37430
  // never has an upstream relay version to report).
37239
37431
  ...cloud ? { wsHealth, relayVersion, deliveryPath, lastWsError: delivery?.lastWsError ?? null } : {}
37240
37432
  },
37241
- autoRelay: autoRelay.getDiagnostics()
37433
+ autoRelay: autoRelay.getDiagnostics(),
37434
+ // PRESENCE โ€” the agent's own view of whether it is IN its channel, so it can
37435
+ // answer "am I reachable?" without inferring it from transport internals.
37436
+ // "online" registered ยท "offline" owns a peer but is not registered (nobody can
37437
+ // reach it) ยท "deferred" never joined ยท "local" no relay.
37438
+ // services/peer-presence.ts carries the vocabulary and how each state arises.
37439
+ presence: (() => {
37440
+ const p = getPresence();
37441
+ if (!p) {
37442
+ return { state: "unknown", detail: "presence has not been evaluated yet" };
37443
+ }
37444
+ return {
37445
+ state: p.state,
37446
+ restored: p.restored,
37447
+ detail: p.detail,
37448
+ ..."peerId" in p ? { peerId: p.peerId } : {}
37449
+ };
37450
+ })()
37242
37451
  };
37243
37452
  return successResult(enriched);
37244
37453
  } catch (err) {
@@ -37258,6 +37467,7 @@ var init_health_check2 = __esm({
37258
37467
  init_errors4();
37259
37468
  init_logger();
37260
37469
  init_auto_relay();
37470
+ init_peer_presence();
37261
37471
  }
37262
37472
  });
37263
37473
 
@@ -94019,6 +94229,11 @@ async function main() {
94019
94229
  `Preflight error (non-fatal): ${err instanceof Error ? err.message : String(err)}`
94020
94230
  );
94021
94231
  });
94232
+ void restorePeerPresence().catch((err) => {
94233
+ logger.warn(
94234
+ `Presence restore error (non-fatal): ${err instanceof Error ? err.message : String(err)}`
94235
+ );
94236
+ });
94022
94237
  startUpdateCheckLoop(SERVER_VERSION);
94023
94238
  logger.info(
94024
94239
  "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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@essentialai/cogent-bridge-bundled",
3
- "version": "3.23.9",
3
+ "version": "3.24.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": {