@essentialai/cogent-bridge-bundled 3.20.7 → 3.21.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 +415 -183
  2. package/package.json +1 -1
package/cogent-bridge.mjs CHANGED
@@ -1259,8 +1259,8 @@ var init_parseUtil = __esm({
1259
1259
  init_errors();
1260
1260
  init_en();
1261
1261
  makeIssue = (params) => {
1262
- const { data, path: path19, errorMaps, issueData } = params;
1263
- const fullPath = [...path19, ...issueData.path || []];
1262
+ const { data, path: path20, errorMaps, issueData } = params;
1263
+ const fullPath = [...path20, ...issueData.path || []];
1264
1264
  const fullIssue = {
1265
1265
  ...issueData,
1266
1266
  path: fullPath
@@ -1540,11 +1540,11 @@ var init_types = __esm({
1540
1540
  init_parseUtil();
1541
1541
  init_util();
1542
1542
  ParseInputLazyPath = class {
1543
- constructor(parent, value, path19, key) {
1543
+ constructor(parent, value, path20, key) {
1544
1544
  this._cachedPath = [];
1545
1545
  this.parent = parent;
1546
1546
  this.data = value;
1547
- this._path = path19;
1547
+ this._path = path20;
1548
1548
  this._key = key;
1549
1549
  }
1550
1550
  get path() {
@@ -4996,10 +4996,10 @@ function assignProp(target, prop, value) {
4996
4996
  configurable: true
4997
4997
  });
4998
4998
  }
4999
- function getElementAtPath(obj, path19) {
5000
- if (!path19)
4999
+ function getElementAtPath(obj, path20) {
5000
+ if (!path20)
5001
5001
  return obj;
5002
- return path19.reduce((acc, key) => acc?.[key], obj);
5002
+ return path20.reduce((acc, key) => acc?.[key], obj);
5003
5003
  }
5004
5004
  function promiseAllObject(promisesObj) {
5005
5005
  const keys = Object.keys(promisesObj);
@@ -5248,11 +5248,11 @@ function aborted(x, startIndex = 0) {
5248
5248
  }
5249
5249
  return false;
5250
5250
  }
5251
- function prefixIssues(path19, issues) {
5251
+ function prefixIssues(path20, issues) {
5252
5252
  return issues.map((iss) => {
5253
5253
  var _a;
5254
5254
  (_a = iss).path ?? (_a.path = []);
5255
- iss.path.unshift(path19);
5255
+ iss.path.unshift(path20);
5256
5256
  return iss;
5257
5257
  });
5258
5258
  }
@@ -17058,8 +17058,8 @@ var require_utils = __commonJS({
17058
17058
  }
17059
17059
  return ind;
17060
17060
  }
17061
- function removeDotSegments(path19) {
17062
- let input = path19;
17061
+ function removeDotSegments(path20) {
17062
+ let input = path20;
17063
17063
  const output = [];
17064
17064
  let nextSlash = -1;
17065
17065
  let len = 0;
@@ -17258,8 +17258,8 @@ var require_schemes = __commonJS({
17258
17258
  wsComponent.secure = void 0;
17259
17259
  }
17260
17260
  if (wsComponent.resourceName) {
17261
- const [path19, query] = wsComponent.resourceName.split("?");
17262
- wsComponent.path = path19 && path19 !== "/" ? path19 : void 0;
17261
+ const [path20, query] = wsComponent.resourceName.split("?");
17262
+ wsComponent.path = path20 && path20 !== "/" ? path20 : void 0;
17263
17263
  wsComponent.query = query;
17264
17264
  wsComponent.resourceName = void 0;
17265
17265
  }
@@ -20612,12 +20612,12 @@ var require_dist = __commonJS({
20612
20612
  throw new Error(`Unknown format "${name}"`);
20613
20613
  return f;
20614
20614
  };
20615
- function addFormats(ajv, list, fs17, exportName) {
20615
+ function addFormats(ajv, list, fs18, exportName) {
20616
20616
  var _a;
20617
20617
  var _b;
20618
20618
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
20619
20619
  for (const f of list)
20620
- ajv.addFormat(f, fs17[f]);
20620
+ ajv.addFormat(f, fs18[f]);
20621
20621
  }
20622
20622
  module.exports = exports = formatsPlugin;
20623
20623
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -21729,8 +21729,8 @@ var require_parseUtil = __commonJS({
21729
21729
  var errors_js_1 = require_errors2();
21730
21730
  var en_js_1 = __importDefault(require_en());
21731
21731
  var makeIssue2 = (params) => {
21732
- const { data, path: path19, errorMaps, issueData } = params;
21733
- const fullPath = [...path19, ...issueData.path || []];
21732
+ const { data, path: path20, errorMaps, issueData } = params;
21733
+ const fullPath = [...path20, ...issueData.path || []];
21734
21734
  const fullIssue = {
21735
21735
  ...issueData,
21736
21736
  path: fullPath
@@ -21884,11 +21884,11 @@ var require_types2 = __commonJS({
21884
21884
  var parseUtil_js_1 = require_parseUtil();
21885
21885
  var util_js_1 = require_util2();
21886
21886
  var ParseInputLazyPath2 = class {
21887
- constructor(parent, value, path19, key) {
21887
+ constructor(parent, value, path20, key) {
21888
21888
  this._cachedPath = [];
21889
21889
  this.parent = parent;
21890
21890
  this.data = value;
21891
- this._path = path19;
21891
+ this._path = path20;
21892
21892
  this._key = key;
21893
21893
  }
21894
21894
  get path() {
@@ -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.20.7") {
26393
- return "3.20.7";
26392
+ if ("3.21.1") {
26393
+ return "3.21.1";
26394
26394
  }
26395
26395
  try {
26396
26396
  const require2 = createRequire(import.meta.url);
@@ -27031,10 +27031,6 @@ var init_peer_registry = __esm({
27031
27031
  // src/services/agent-config.ts
27032
27032
  import os4 from "node:os";
27033
27033
  import path8 from "node:path";
27034
- function claudeConfigDir() {
27035
- const override = process.env.CLAUDE_CONFIG_DIR?.trim();
27036
- return override ? override : path8.join(os4.homedir(), ".claude");
27037
- }
27038
27034
  function codexHomeDir() {
27039
27035
  const override = process.env.CODEX_HOME?.trim();
27040
27036
  return override ? override : path8.join(os4.homedir(), ".codex");
@@ -27053,26 +27049,149 @@ var init_agent_config = __esm({
27053
27049
  }
27054
27050
  });
27055
27051
 
27056
- // src/services/cc-cli.ts
27057
- import { spawn } from "node:child_process";
27052
+ // src/services/agent-sessions.ts
27053
+ import crypto3 from "node:crypto";
27058
27054
  import fs7 from "node:fs/promises";
27055
+ import os5 from "node:os";
27059
27056
  import path9 from "node:path";
27060
- async function listCandidates(cwd) {
27057
+ function hashCwd(cwd) {
27058
+ return crypto3.createHash("sha256").update(path9.resolve(cwd)).digest("hex").slice(0, 16);
27059
+ }
27060
+ function agentSessionsDir() {
27061
+ return path9.join(os5.homedir(), ".cogent", "agent-sessions");
27062
+ }
27063
+ function agentSessionPath(cwd, platform) {
27064
+ return path9.join(agentSessionsDir(), `${hashCwd(cwd)}.${platform}.json`);
27065
+ }
27066
+ async function readAgentSession(cwd, platform) {
27061
27067
  try {
27062
- const escapedCwd = cwd.replace(/[^a-zA-Z0-9-]/g, "-");
27063
- const projectDir = path9.join(claudeConfigDir(), "projects", escapedCwd);
27064
- const entries = await fs7.readdir(projectDir);
27065
- const jsonlFiles = entries.filter((f) => f.endsWith(".jsonl"));
27066
- return await Promise.all(
27067
- jsonlFiles.map(async (f) => ({
27068
- sessionId: f.replace(".jsonl", ""),
27069
- mtimeMs: (await fs7.stat(path9.join(projectDir, f))).mtimeMs
27070
- }))
27068
+ const raw = await fs7.readFile(agentSessionPath(cwd, platform), "utf-8");
27069
+ const rec = JSON.parse(raw);
27070
+ if (!rec?.sessionId || !rec?.transcriptPath) return null;
27071
+ return rec;
27072
+ } catch {
27073
+ return null;
27074
+ }
27075
+ }
27076
+ async function learnedRoots(platform) {
27077
+ try {
27078
+ const dir = agentSessionsDir();
27079
+ const files = (await fs7.readdir(dir)).filter(
27080
+ (f) => f.endsWith(`.${platform}.json`)
27081
+ );
27082
+ const recs = await Promise.all(
27083
+ files.map(async (f) => {
27084
+ try {
27085
+ return JSON.parse(
27086
+ await fs7.readFile(path9.join(dir, f), "utf-8")
27087
+ );
27088
+ } catch {
27089
+ return null;
27090
+ }
27091
+ })
27071
27092
  );
27093
+ return [
27094
+ ...new Set(
27095
+ recs.filter((r) => Boolean(r?.root)).sort((a, b) => a.updatedAt < b.updatedAt ? 1 : -1).map((r) => r.root)
27096
+ )
27097
+ ];
27072
27098
  } catch {
27073
27099
  return [];
27074
27100
  }
27075
27101
  }
27102
+ var init_agent_sessions = __esm({
27103
+ "src/services/agent-sessions.ts"() {
27104
+ "use strict";
27105
+ }
27106
+ });
27107
+
27108
+ // src/services/cc-cli.ts
27109
+ import { spawn } from "node:child_process";
27110
+ import fs8 from "node:fs/promises";
27111
+ import os6 from "node:os";
27112
+ import path10 from "node:path";
27113
+ async function projectDirsFor(cwd) {
27114
+ const [roots, forms] = await Promise.all([
27115
+ claudeConfigRoots(),
27116
+ cwdForms(cwd)
27117
+ ]);
27118
+ const dirs = roots.flatMap(
27119
+ (root) => forms.map(
27120
+ (f) => path10.join(root, "projects", f.replace(/[^a-zA-Z0-9-]/g, "-"))
27121
+ )
27122
+ );
27123
+ return [...new Set(dirs)];
27124
+ }
27125
+ async function cwdForms(cwd) {
27126
+ const resolved = path10.resolve(cwd);
27127
+ const forms = /* @__PURE__ */ new Set([resolved]);
27128
+ try {
27129
+ forms.add(await fs8.realpath(resolved));
27130
+ } catch {
27131
+ }
27132
+ return [...forms];
27133
+ }
27134
+ async function claudeConfigRoots() {
27135
+ const roots = [];
27136
+ const env = process.env.CLAUDE_CONFIG_DIR?.trim();
27137
+ if (env) roots.push(env);
27138
+ roots.push(...await learnedRoots("cc"));
27139
+ roots.push(path10.join(os6.homedir(), ".claude"));
27140
+ roots.push(path10.join(os6.homedir(), ".config", "claude"));
27141
+ return [...new Set(roots.map((r) => path10.resolve(r)))];
27142
+ }
27143
+ async function recordedCandidate(cwd) {
27144
+ const rec = await readAgentSession(cwd, "cc");
27145
+ if (!rec) return null;
27146
+ try {
27147
+ const st = await fs8.stat(rec.transcriptPath);
27148
+ return { sessionId: rec.sessionId, mtimeMs: st.mtimeMs };
27149
+ } catch {
27150
+ return null;
27151
+ }
27152
+ }
27153
+ async function transcriptBaseSummary() {
27154
+ const roots = await claudeConfigRoots();
27155
+ const parts = await Promise.all(
27156
+ roots.map(async (root) => {
27157
+ const base = path10.join(root, "projects");
27158
+ try {
27159
+ return `${base} [${(await fs8.readdir(base)).length} project dirs]`;
27160
+ } catch {
27161
+ return `${base} [absent]`;
27162
+ }
27163
+ })
27164
+ );
27165
+ return parts.join(", ");
27166
+ }
27167
+ async function listCandidates(cwd) {
27168
+ const dirs = await projectDirsFor(cwd);
27169
+ const perDir = await Promise.all(
27170
+ dirs.map(async (projectDir) => {
27171
+ try {
27172
+ const entries = await fs8.readdir(projectDir);
27173
+ return await Promise.all(
27174
+ entries.filter((f) => f.endsWith(".jsonl")).map(async (f) => ({
27175
+ sessionId: f.replace(".jsonl", ""),
27176
+ mtimeMs: (await fs8.stat(path10.join(projectDir, f))).mtimeMs
27177
+ }))
27178
+ );
27179
+ } catch {
27180
+ return [];
27181
+ }
27182
+ })
27183
+ );
27184
+ const byId = /* @__PURE__ */ new Map();
27185
+ for (const c2 of perDir.flat()) {
27186
+ const prev = byId.get(c2.sessionId);
27187
+ if (!prev || c2.mtimeMs > prev.mtimeMs) byId.set(c2.sessionId, c2);
27188
+ }
27189
+ const recorded = await recordedCandidate(cwd);
27190
+ if (recorded && !byId.has(recorded.sessionId)) {
27191
+ byId.set(recorded.sessionId, recorded);
27192
+ }
27193
+ return [...byId.values()];
27194
+ }
27076
27195
  async function detectCurrentSession(cwd) {
27077
27196
  const candidates = await listCandidates(cwd);
27078
27197
  if (candidates.length === 0) return null;
@@ -27080,19 +27199,20 @@ async function detectCurrentSession(cwd) {
27080
27199
  return candidates[0].sessionId;
27081
27200
  }
27082
27201
  async function validateSession(sessionId, cwd) {
27083
- const projectHash = cwd.replace(/[^a-zA-Z0-9-]/g, "-");
27084
- const sessionPath = path9.join(
27085
- claudeConfigDir(),
27086
- "projects",
27087
- projectHash,
27088
- `${sessionId}.jsonl`
27202
+ const recorded = await recordedCandidate(cwd);
27203
+ if (recorded?.sessionId === sessionId) return true;
27204
+ const dirs = await projectDirsFor(cwd);
27205
+ const hits = await Promise.all(
27206
+ dirs.map(async (dir) => {
27207
+ try {
27208
+ await fs8.access(path10.join(dir, `${sessionId}.jsonl`));
27209
+ return true;
27210
+ } catch {
27211
+ return false;
27212
+ }
27213
+ })
27089
27214
  );
27090
- try {
27091
- await fs7.access(sessionPath);
27092
- return true;
27093
- } catch {
27094
- return false;
27095
- }
27215
+ return hits.some(Boolean);
27096
27216
  }
27097
27217
  function execClaude(sessionId, message, cwd, timeoutMs) {
27098
27218
  return new Promise((resolve) => {
@@ -27246,15 +27366,16 @@ var init_cc_cli = __esm({
27246
27366
  "use strict";
27247
27367
  init_config();
27248
27368
  init_agent_config();
27369
+ init_agent_sessions();
27249
27370
  }
27250
27371
  });
27251
27372
 
27252
27373
  // src/services/codex-preflight.ts
27253
27374
  import { execFile as execFile2 } from "node:child_process";
27254
27375
  import { promisify as promisify2 } from "node:util";
27255
- import fs8 from "node:fs/promises";
27376
+ import fs9 from "node:fs/promises";
27256
27377
  import { join } from "node:path";
27257
- import os5 from "node:os";
27378
+ import os7 from "node:os";
27258
27379
  function analyzeCodexHelp(helpText) {
27259
27380
  const checked = EXPECTED_CODEX_RESUME_FLAGS.map((f) => f.flag);
27260
27381
  const missing = EXPECTED_CODEX_RESUME_FLAGS.filter(
@@ -27310,7 +27431,7 @@ function classifyUnshareError(err) {
27310
27431
  }
27311
27432
  async function readProc(p) {
27312
27433
  try {
27313
- return (await fs8.readFile(p, "utf8")).trim();
27434
+ return (await fs9.readFile(p, "utf8")).trim();
27314
27435
  } catch {
27315
27436
  return null;
27316
27437
  }
@@ -27363,14 +27484,14 @@ function detectCodexCogentServerCollision(configTomlText) {
27363
27484
  return /^[ \t]*\[mcp_servers\.cogent(\.[^\]]+)?\]/m.test(configTomlText);
27364
27485
  }
27365
27486
  function codexConfigPath(codexHomeDir2) {
27366
- const home = codexHomeDir2 || process.env.CODEX_HOME || join(os5.homedir(), ".codex");
27487
+ const home = codexHomeDir2 || process.env.CODEX_HOME || join(os7.homedir(), ".codex");
27367
27488
  return join(home, "config.toml");
27368
27489
  }
27369
27490
  async function preflightCodexServerCollision(codexHomeDir2) {
27370
27491
  const cfgPath = codexConfigPath(codexHomeDir2);
27371
27492
  let text;
27372
27493
  try {
27373
- text = await fs8.readFile(cfgPath, "utf8");
27494
+ text = await fs9.readFile(cfgPath, "utf8");
27374
27495
  } catch {
27375
27496
  return false;
27376
27497
  }
@@ -27399,22 +27520,22 @@ var init_codex_preflight = __esm({
27399
27520
  });
27400
27521
 
27401
27522
  // src/services/health-check.ts
27402
- import fs9 from "node:fs/promises";
27403
- import path10 from "node:path";
27523
+ import fs10 from "node:fs/promises";
27524
+ import path11 from "node:path";
27404
27525
  import { execFile as execFile3 } from "node:child_process";
27405
27526
  function getStatePath2() {
27406
- return path10.join(getConfig().COGENT_STATE_PATH, "cogent-state.json");
27527
+ return path11.join(getConfig().COGENT_STATE_PATH, "cogent-state.json");
27407
27528
  }
27408
27529
  async function checkStateFile() {
27409
27530
  const statePath = getStatePath2();
27410
- const dir = path10.dirname(statePath);
27531
+ const dir = path11.dirname(statePath);
27411
27532
  try {
27412
- await fs9.access(dir, fs9.constants.R_OK | fs9.constants.W_OK);
27533
+ await fs10.access(dir, fs10.constants.R_OK | fs10.constants.W_OK);
27413
27534
  } catch {
27414
27535
  return { ok: false, message: `State directory not accessible: ${dir}` };
27415
27536
  }
27416
27537
  try {
27417
- const raw = await fs9.readFile(statePath, "utf-8");
27538
+ const raw = await fs10.readFile(statePath, "utf-8");
27418
27539
  JSON.parse(raw);
27419
27540
  return { ok: true, message: "State file readable and valid JSON" };
27420
27541
  } catch (err) {
@@ -27430,9 +27551,9 @@ async function checkStateFile() {
27430
27551
  async function checkLockMechanism() {
27431
27552
  const healthLockPath = getStatePath2() + ".health-lock";
27432
27553
  try {
27433
- await fs9.writeFile(healthLockPath, String(process.pid), { flag: "wx" });
27554
+ await fs10.writeFile(healthLockPath, String(process.pid), { flag: "wx" });
27434
27555
  try {
27435
- await fs9.unlink(healthLockPath);
27556
+ await fs10.unlink(healthLockPath);
27436
27557
  } catch {
27437
27558
  }
27438
27559
  return { ok: true, message: "Lock acquire/release cycle succeeded" };
@@ -27485,7 +27606,7 @@ async function checkHealth() {
27485
27606
  return {
27486
27607
  healthy,
27487
27608
  mcpServerVersion: SERVER_VERSION,
27488
- statePath: path10.join(config2.COGENT_STATE_PATH, "cogent-state.json"),
27609
+ statePath: path11.join(config2.COGENT_STATE_PATH, "cogent-state.json"),
27489
27610
  claudePath: config2.COGENT_CLAUDE_PATH,
27490
27611
  checks,
27491
27612
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -27624,7 +27745,7 @@ var init_http_backend = __esm({
27624
27745
  * in cloud mode we ignore it and use this.sessionId (the cloud session).
27625
27746
  */
27626
27747
  async registerPeer(peerId, _sessionId, cwd, label, clientVersion, mode, _channelSessionId, capabilities, workspaceId, threadId) {
27627
- const path19 = PATHS.peers.replace(":sessionId", this.sessionId);
27748
+ const path20 = PATHS.peers.replace(":sessionId", this.sessionId);
27628
27749
  const body = {
27629
27750
  peerId,
27630
27751
  cwd,
@@ -27652,7 +27773,7 @@ var init_http_backend = __esm({
27652
27773
  body.role = roleCap.slice("role:".length);
27653
27774
  }
27654
27775
  }
27655
- return this.http.post(path19, body);
27776
+ return this.http.post(path20, body);
27656
27777
  }
27657
27778
  /**
27658
27779
  * Deregister a peer from the cloud session.
@@ -27664,9 +27785,9 @@ var init_http_backend = __esm({
27664
27785
  * local mail creds. A 404 (peer not found) resolves to `{ removed: false, ... }`, not a throw.
27665
27786
  */
27666
27787
  async deregisterPeer(peerId) {
27667
- const path19 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27788
+ const path20 = PATHS.peer.replace(":sessionId", this.sessionId).replace(":peerId", peerId);
27668
27789
  try {
27669
- const headers = await this.http.delete(path19, {});
27790
+ const headers = await this.http.delete(path20, {});
27670
27791
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
27671
27792
  return { removed: true, mailboxDeprovisioned };
27672
27793
  } catch {
@@ -27687,8 +27808,8 @@ var init_http_backend = __esm({
27687
27808
  * GET /api/sessions/:sessionId/peers
27688
27809
  */
27689
27810
  async listPeers() {
27690
- const path19 = PATHS.peers.replace(":sessionId", this.sessionId);
27691
- const result = await this.http.get(path19);
27811
+ const path20 = PATHS.peers.replace(":sessionId", this.sessionId);
27812
+ const result = await this.http.get(path20);
27692
27813
  return result.peers;
27693
27814
  }
27694
27815
  /**
@@ -27696,8 +27817,8 @@ var init_http_backend = __esm({
27696
27817
  * Calls the lightweight heartbeat endpoint on the cloud relay server.
27697
27818
  */
27698
27819
  async updateLastSeen(peerId) {
27699
- const path19 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27700
- await this.http.post(path19, { peerId });
27820
+ const path20 = PATHS.heartbeat.replace(":sessionId", this.sessionId);
27821
+ await this.http.post(path20, { peerId });
27701
27822
  }
27702
27823
  /**
27703
27824
  * Record a message in the cloud session.
@@ -27708,7 +27829,7 @@ var init_http_backend = __esm({
27708
27829
  * the input record to construct a full MessageRecord.
27709
27830
  */
27710
27831
  async recordMessage(record2) {
27711
- const path19 = PATHS.messages.replace(":sessionId", this.sessionId);
27832
+ const path20 = PATHS.messages.replace(":sessionId", this.sessionId);
27712
27833
  const body = {
27713
27834
  fromPeerId: record2.fromPeerId,
27714
27835
  toPeerId: record2.toPeerId,
@@ -27720,7 +27841,7 @@ var init_http_backend = __esm({
27720
27841
  if (record2.attachments && record2.attachments.length > 0) {
27721
27842
  body.attachments = record2.attachments;
27722
27843
  }
27723
- const resp = await this.http.post(path19, body);
27844
+ const resp = await this.http.post(path20, body);
27724
27845
  return {
27725
27846
  ...record2,
27726
27847
  id: resp.id,
@@ -27734,7 +27855,7 @@ var init_http_backend = __esm({
27734
27855
  * Supports optional peerId filter and limit (default 300).
27735
27856
  */
27736
27857
  async getHistory(peerId, limit, includeRelayEchoes, metadataOnly, dedupInferredEchoes) {
27737
- const path19 = PATHS.messages.replace(":sessionId", this.sessionId);
27858
+ const path20 = PATHS.messages.replace(":sessionId", this.sessionId);
27738
27859
  const query = {};
27739
27860
  if (peerId) {
27740
27861
  query.peerId = peerId;
@@ -27749,7 +27870,7 @@ var init_http_backend = __esm({
27749
27870
  if (dedupInferredEchoes) {
27750
27871
  query.dedupInferredEchoes = "true";
27751
27872
  }
27752
- const result = await this.http.get(path19, query);
27873
+ const result = await this.http.get(path20, query);
27753
27874
  return result.messages;
27754
27875
  }
27755
27876
  /**
@@ -27760,12 +27881,12 @@ var init_http_backend = __esm({
27760
27881
  * so that get-history shows the actual response (not null).
27761
27882
  */
27762
27883
  async updateMessageResponse(messageId, response, durationMs, pending) {
27763
- const path19 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
27884
+ const path20 = PATHS.message.replace(":sessionId", this.sessionId).replace(":messageId", messageId);
27764
27885
  const body = { response, durationMs };
27765
27886
  if (pending === true) {
27766
27887
  body.pending = true;
27767
27888
  }
27768
- await this.http.patch(path19, body);
27889
+ await this.http.patch(path20, body);
27769
27890
  }
27770
27891
  /**
27771
27892
  * Validate a session.
@@ -27907,8 +28028,8 @@ var init_http_client = __esm({
27907
28028
  * Perform an authenticated GET request.
27908
28029
  * Appends query parameters to the URL if provided.
27909
28030
  */
27910
- async get(path19, query) {
27911
- const url = new URL(path19, this.baseUrl);
28031
+ async get(path20, query) {
28032
+ const url = new URL(path20, this.baseUrl);
27912
28033
  if (query) {
27913
28034
  for (const [k, v] of Object.entries(query)) {
27914
28035
  url.searchParams.set(k, v);
@@ -27923,8 +28044,8 @@ var init_http_client = __esm({
27923
28044
  /**
27924
28045
  * Perform an authenticated POST request with a JSON body.
27925
28046
  */
27926
- async post(path19, body) {
27927
- const url = new URL(path19, this.baseUrl);
28047
+ async post(path20, body) {
28048
+ const url = new URL(path20, this.baseUrl);
27928
28049
  const resp = await this.fetchWithTimeout(url, {
27929
28050
  method: "POST",
27930
28051
  headers: this.headers(),
@@ -27942,8 +28063,8 @@ var init_http_client = __esm({
27942
28063
  * Perform an authenticated PATCH request with a JSON body.
27943
28064
  * Used to update existing resources (e.g., message response fields).
27944
28065
  */
27945
- async patch(path19, body) {
27946
- const url = new URL(path19, this.baseUrl);
28066
+ async patch(path20, body) {
28067
+ const url = new URL(path20, this.baseUrl);
27947
28068
  const resp = await this.fetchWithTimeout(url, {
27948
28069
  method: "PATCH",
27949
28070
  headers: this.headers(),
@@ -27968,8 +28089,8 @@ var init_http_client = __esm({
27968
28089
  * "Malformed JSON in request body" 400 from cogent-server <=3.1.2 when
27969
28090
  * any client (including third-party tools) DELETEd a peer without a body.
27970
28091
  */
27971
- async delete(path19, body) {
27972
- const url = new URL(path19, this.baseUrl);
28092
+ async delete(path20, body) {
28093
+ const url = new URL(path20, this.baseUrl);
27973
28094
  const headers = {
27974
28095
  "Authorization": `Bearer ${this.token}`
27975
28096
  };
@@ -32152,14 +32273,14 @@ var init_ws_client = __esm({
32152
32273
  if (this.pollTimer) return;
32153
32274
  const poll = async () => {
32154
32275
  try {
32155
- const path19 = `/api/sessions/${this.opts.sessionId}/poll`;
32276
+ const path20 = `/api/sessions/${this.opts.sessionId}/poll`;
32156
32277
  const query = {
32157
32278
  peerId: this.opts.peerId
32158
32279
  };
32159
32280
  if (this.lastMessageId) {
32160
32281
  query.lastMessageId = this.lastMessageId;
32161
32282
  }
32162
- const result = await this.opts.http.get(path19, query);
32283
+ const result = await this.opts.http.get(path20, query);
32163
32284
  if (result.messages && result.messages.length > 0) {
32164
32285
  this.opts.onMessages(result.messages);
32165
32286
  this.lastMessageId = result.messages[result.messages.length - 1].id;
@@ -32216,9 +32337,9 @@ var init_cloud = __esm({
32216
32337
 
32217
32338
  // src/services/codex-cli.ts
32218
32339
  import { spawn as spawn2 } from "node:child_process";
32219
- import fs10 from "node:fs/promises";
32220
- import os6 from "node:os";
32221
- import path11 from "node:path";
32340
+ import fs11 from "node:fs/promises";
32341
+ import os8 from "node:os";
32342
+ import path12 from "node:path";
32222
32343
  import { randomUUID } from "node:crypto";
32223
32344
  import { createReadStream } from "node:fs";
32224
32345
  import { createInterface as createInterface2 } from "node:readline";
@@ -32246,7 +32367,7 @@ function execCodex(sessionId, message, cwd, timeoutMs) {
32246
32367
  const config2 = getConfig();
32247
32368
  const effectiveTimeout = timeoutMs ?? config2.COGENT_TIMEOUT_MS;
32248
32369
  const truncated = config2.COGENT_CHAR_LIMIT > 0 && message.length > config2.COGENT_CHAR_LIMIT ? message.slice(0, config2.COGENT_CHAR_LIMIT) + "\n...[truncated]" : message;
32249
- const lastMsgFile = path11.join(os6.tmpdir(), `cogent-codex-${randomUUID()}.txt`);
32370
+ const lastMsgFile = path12.join(os8.tmpdir(), `cogent-codex-${randomUUID()}.txt`);
32250
32371
  const args = [
32251
32372
  "exec",
32252
32373
  "resume",
@@ -32274,7 +32395,7 @@ function execCodex(sessionId, message, cwd, timeoutMs) {
32274
32395
  resolve(result);
32275
32396
  }
32276
32397
  };
32277
- const cleanupFile = () => fs10.rm(lastMsgFile, { force: true }).catch(() => {
32398
+ const cleanupFile = () => fs11.rm(lastMsgFile, { force: true }).catch(() => {
32278
32399
  });
32279
32400
  const timer = setTimeout(async () => {
32280
32401
  killed = true;
@@ -32325,7 +32446,7 @@ function execCodex(sessionId, message, cwd, timeoutMs) {
32325
32446
  }
32326
32447
  let fileMessage = "";
32327
32448
  try {
32328
- fileMessage = await fs10.readFile(lastMsgFile, "utf8");
32449
+ fileMessage = await fs11.readFile(lastMsgFile, "utf8");
32329
32450
  } catch {
32330
32451
  fileMessage = "";
32331
32452
  }
@@ -32346,12 +32467,12 @@ async function listRolloutFiles(root) {
32346
32467
  async function walk(dir) {
32347
32468
  let entries;
32348
32469
  try {
32349
- entries = await fs10.readdir(dir, { withFileTypes: true });
32470
+ entries = await fs11.readdir(dir, { withFileTypes: true });
32350
32471
  } catch {
32351
32472
  return;
32352
32473
  }
32353
32474
  for (const e of entries) {
32354
- const full = path11.join(dir, e.name);
32475
+ const full = path12.join(dir, e.name);
32355
32476
  if (e.isDirectory()) await walk(full);
32356
32477
  else if (e.isFile() && e.name.endsWith(".jsonl")) out.push(full);
32357
32478
  }
@@ -32383,19 +32504,19 @@ async function readSessionMeta(file) {
32383
32504
  }
32384
32505
  }
32385
32506
  function codexSessionsRoot() {
32386
- return path11.join(codexHomeDir(), "sessions");
32507
+ return path12.join(codexHomeDir(), "sessions");
32387
32508
  }
32388
32509
  async function cwdCanonicals(cwd) {
32389
- const resolved = path11.resolve(cwd);
32510
+ const resolved = path12.resolve(cwd);
32390
32511
  const forms = /* @__PURE__ */ new Set([resolved]);
32391
32512
  try {
32392
- forms.add(await fs10.realpath(resolved));
32513
+ forms.add(await fs11.realpath(resolved));
32393
32514
  } catch {
32394
32515
  }
32395
32516
  return forms;
32396
32517
  }
32397
32518
  function metaCwdMatches(metaCwd, forms) {
32398
- return forms.has(path11.resolve(metaCwd));
32519
+ return forms.has(path12.resolve(metaCwd));
32399
32520
  }
32400
32521
  async function detectCurrentCodexSession(cwd) {
32401
32522
  try {
@@ -32403,7 +32524,7 @@ async function detectCurrentCodexSession(cwd) {
32403
32524
  const files = await listRolloutFiles(codexSessionsRoot());
32404
32525
  const withStats = await Promise.all(
32405
32526
  files.map(async (f) => {
32406
- const stat = await fs10.stat(f);
32527
+ const stat = await fs11.stat(f);
32407
32528
  return { file: f, mtimeMs: stat.mtimeMs };
32408
32529
  })
32409
32530
  );
@@ -32422,7 +32543,7 @@ async function listCodexCandidates(cwd) {
32422
32543
  const forms = await cwdCanonicals(cwd);
32423
32544
  const files = await listRolloutFiles(codexSessionsRoot());
32424
32545
  const withStats = await Promise.all(
32425
- files.map(async (f) => ({ file: f, mtimeMs: (await fs10.stat(f)).mtimeMs }))
32546
+ files.map(async (f) => ({ file: f, mtimeMs: (await fs11.stat(f)).mtimeMs }))
32426
32547
  );
32427
32548
  const bySession = /* @__PURE__ */ new Map();
32428
32549
  for (const { file, mtimeMs } of withStats) {
@@ -32462,11 +32583,11 @@ var init_codex_cli = __esm({
32462
32583
  });
32463
32584
 
32464
32585
  // src/services/codex-app-server.ts
32465
- import path12 from "node:path";
32466
- import fs11 from "node:fs/promises";
32586
+ import path13 from "node:path";
32587
+ import fs12 from "node:fs/promises";
32467
32588
  import { spawn as spawn3, spawnSync } from "node:child_process";
32468
32589
  function appServerSocketPath(codexHome = codexHomeDir()) {
32469
- return path12.join(codexHome, "app-server-control", "app-server-control.sock");
32590
+ return path13.join(codexHome, "app-server-control", "app-server-control.sock");
32470
32591
  }
32471
32592
  function rpcUrl(sock) {
32472
32593
  return `ws+unix://${sock}:/rpc`;
@@ -32707,7 +32828,7 @@ var init_codex_app_server = __esm({
32707
32828
  });
32708
32829
  defaultSocketExists = async (p) => {
32709
32830
  try {
32710
- await fs11.stat(p);
32831
+ await fs12.stat(p);
32711
32832
  return true;
32712
32833
  } catch {
32713
32834
  return false;
@@ -32834,6 +32955,23 @@ function listCandidatesFor(platform, cwd) {
32834
32955
  return listCandidates(cwd);
32835
32956
  }
32836
32957
  }
32958
+ async function reportedSessionFor(platform, cwd) {
32959
+ if (platform !== "cc") return null;
32960
+ try {
32961
+ return (await recordedCandidate(cwd))?.sessionId ?? null;
32962
+ } catch {
32963
+ return null;
32964
+ }
32965
+ }
32966
+ function probePathsFor(platform, cwd) {
32967
+ switch (platform) {
32968
+ case "codex":
32969
+ return Promise.resolve([codexSessionsRoot()]);
32970
+ case "cc":
32971
+ default:
32972
+ return projectDirsFor(cwd);
32973
+ }
32974
+ }
32837
32975
  function validateSessionFor(platform, sessionId, cwd) {
32838
32976
  switch (platform) {
32839
32977
  case "codex":
@@ -32905,12 +33043,31 @@ function decideResolution(candidates, pinnedSessionId, pinnedExists, marginMs) {
32905
33043
  };
32906
33044
  }
32907
33045
  async function resolveSession(platform, cwd, pinnedSessionId, marginMs) {
32908
- const [candidates, pinnedExists] = await Promise.all([
33046
+ const [candidates, pinnedExists, reported] = await Promise.all([
32909
33047
  listCandidatesFor(platform, cwd),
32910
- pinnedSessionId ? validateSessionFor(platform, pinnedSessionId, cwd) : Promise.resolve(false)
33048
+ pinnedSessionId ? validateSessionFor(platform, pinnedSessionId, cwd) : Promise.resolve(false),
33049
+ // Layer 1 is an ENHANCEMENT over discovery, never a dependency of it: if the
33050
+ // learned-record lookup is unavailable or throws, resolution must still run
33051
+ // exactly as it did before this layer existed.
33052
+ Promise.resolve().then(() => reportedSessionFor(platform, cwd)).catch(() => null)
32911
33053
  ]);
32912
33054
  const margin = marginMs ?? getConfig().COGENT_RESOLVER_AMBIGUOUS_MARGIN_MS;
32913
- return decideResolution(candidates, pinnedSessionId, pinnedExists, margin);
33055
+ const effectivePin = pinnedExists ? pinnedSessionId : reported ?? pinnedSessionId;
33056
+ const effectiveExists = pinnedExists || reported !== null && reported === effectivePin;
33057
+ const res = decideResolution(candidates, effectivePin, effectiveExists, margin);
33058
+ if (res.candidateCount === 0) {
33059
+ try {
33060
+ const probedPaths = await probePathsFor(platform, cwd);
33061
+ if (probedPaths.length) {
33062
+ res.probedPaths = probedPaths;
33063
+ if (res.fallbackReason) {
33064
+ res.fallbackReason = `${res.fallbackReason} (cwd=${cwd}; scanned ${probedPaths.join(", ")})`;
33065
+ }
33066
+ }
33067
+ } catch {
33068
+ }
33069
+ }
33070
+ return res;
32914
33071
  }
32915
33072
  var init_session_resolver = __esm({
32916
33073
  "src/services/session-resolver.ts"() {
@@ -32921,15 +33078,15 @@ var init_session_resolver = __esm({
32921
33078
  });
32922
33079
 
32923
33080
  // src/services/wake-inflight.ts
32924
- import crypto3 from "node:crypto";
32925
- import fs12 from "node:fs";
32926
- import os7 from "node:os";
32927
- import path13 from "node:path";
32928
- function hashCwd(cwd) {
32929
- return crypto3.createHash("sha256").update(path13.resolve(cwd)).digest("hex").slice(0, 16);
33081
+ import crypto4 from "node:crypto";
33082
+ import fs13 from "node:fs";
33083
+ import os9 from "node:os";
33084
+ import path14 from "node:path";
33085
+ function hashCwd2(cwd) {
33086
+ return crypto4.createHash("sha256").update(path14.resolve(cwd)).digest("hex").slice(0, 16);
32930
33087
  }
32931
33088
  function wakeInflightPath(peerId, cwd = process.cwd()) {
32932
- return path13.join(os7.homedir(), ".cogent", "wake-inflight", `${hashCwd(cwd)}.${safe(peerId)}.json`);
33089
+ return path14.join(os9.homedir(), ".cogent", "wake-inflight", `${hashCwd2(cwd)}.${safe(peerId)}.json`);
32933
33090
  }
32934
33091
  function ttlMs() {
32935
33092
  let timeout = 3e5;
@@ -32942,17 +33099,17 @@ function ttlMs() {
32942
33099
  }
32943
33100
  function readFileSafe(p) {
32944
33101
  try {
32945
- const parsed = JSON.parse(fs12.readFileSync(p, "utf-8"));
33102
+ const parsed = JSON.parse(fs13.readFileSync(p, "utf-8"));
32946
33103
  return parsed && typeof parsed === "object" && parsed.messages ? parsed : { messages: {} };
32947
33104
  } catch {
32948
33105
  return { messages: {} };
32949
33106
  }
32950
33107
  }
32951
33108
  function writeAtomic(p, data) {
32952
- fs12.mkdirSync(path13.dirname(p), { recursive: true });
33109
+ fs13.mkdirSync(path14.dirname(p), { recursive: true });
32953
33110
  const tmp = `${p}.${process.pid}.tmp`;
32954
- fs12.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", "utf-8");
32955
- fs12.renameSync(tmp, p);
33111
+ fs13.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", "utf-8");
33112
+ fs13.renameSync(tmp, p);
32956
33113
  }
32957
33114
  function prune(f, now) {
32958
33115
  for (const [id, rec] of Object.entries(f.messages)) {
@@ -34096,20 +34253,36 @@ __export(startup_exports, {
34096
34253
  cloudHttpClient: () => cloudHttpClient,
34097
34254
  cloudInbox: () => cloudInbox,
34098
34255
  cloudWsClient: () => cloudWsClient,
34256
+ hasPendingLabelResolve: () => hasPendingLabelResolve,
34257
+ isCloudMode: () => isCloudMode2,
34099
34258
  reinitCloudBackend: () => reinitCloudBackend,
34259
+ resolvePendingLabel: () => resolvePendingLabel,
34100
34260
  runPreflights: () => runPreflights,
34101
34261
  runStartup: () => runStartup,
34262
+ setInboxNotifier: () => setInboxNotifier,
34102
34263
  triggerReRegistration: () => triggerReRegistration
34103
34264
  });
34104
- import os8 from "node:os";
34105
- import path14 from "node:path";
34106
- import fs13 from "node:fs/promises";
34265
+ import os10 from "node:os";
34266
+ import path15 from "node:path";
34267
+ import fs14 from "node:fs/promises";
34107
34268
  import readline2 from "node:readline";
34108
34269
  import { execFile as execFile5 } from "node:child_process";
34109
34270
  import { promisify as promisify4 } from "node:util";
34271
+ function isCloudMode2() {
34272
+ return cloudModeActive;
34273
+ }
34274
+ function setInboxNotifier(fn) {
34275
+ inboxNotifier = fn;
34276
+ bindInboxNotifier();
34277
+ }
34278
+ function bindInboxNotifier() {
34279
+ if (!inboxNotifier || !cloudInbox || notifierBoundTo === cloudInbox) return;
34280
+ cloudInbox.onNewMessage(inboxNotifier);
34281
+ notifierBoundTo = cloudInbox;
34282
+ }
34110
34283
  async function loadPersistedConfig() {
34111
34284
  try {
34112
- const raw = await fs13.readFile(PERSIST_PATH, "utf-8");
34285
+ const raw = await fs14.readFile(PERSIST_PATH, "utf-8");
34113
34286
  return JSON.parse(raw);
34114
34287
  } catch {
34115
34288
  return {};
@@ -34117,7 +34290,7 @@ async function loadPersistedConfig() {
34117
34290
  }
34118
34291
  async function savePersistedConfig(config2) {
34119
34292
  try {
34120
- await fs13.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
34293
+ await fs14.writeFile(PERSIST_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
34121
34294
  } catch (err) {
34122
34295
  const msg = err instanceof Error ? err.message : String(err);
34123
34296
  logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
@@ -34152,11 +34325,11 @@ First run detected. Where should cogent-bridge store its data?
34152
34325
  });
34153
34326
  }
34154
34327
  async function validateStateDir(statePath) {
34155
- await fs13.mkdir(statePath, { recursive: true });
34156
- const testFile = path14.join(statePath, ".write-test");
34328
+ await fs14.mkdir(statePath, { recursive: true });
34329
+ const testFile = path15.join(statePath, ".write-test");
34157
34330
  try {
34158
- await fs13.writeFile(testFile, "test", "utf-8");
34159
- await fs13.unlink(testFile);
34331
+ await fs14.writeFile(testFile, "test", "utf-8");
34332
+ await fs14.unlink(testFile);
34160
34333
  } catch {
34161
34334
  throw new BridgeError(
34162
34335
  "STARTUP_FAILED" /* STARTUP_FAILED */,
@@ -34270,6 +34443,46 @@ function createCloudWsClient(endpoint, sessionId, token, http, inbox, pollInterv
34270
34443
  });
34271
34444
  return client;
34272
34445
  }
34446
+ function hasPendingLabelResolve() {
34447
+ return pendingLabelResolve !== null;
34448
+ }
34449
+ async function resolvePendingLabel() {
34450
+ const pending = pendingLabelResolve;
34451
+ pendingLabelResolve = null;
34452
+ if (!pending) return;
34453
+ let resolvedId;
34454
+ try {
34455
+ const resp = await fetch(
34456
+ `${pending.endpoint}/api/sessions/resolve/${encodeURIComponent(pending.label)}`,
34457
+ { signal: AbortSignal.timeout(2500) }
34458
+ );
34459
+ if (!resp.ok) {
34460
+ logger.warn(
34461
+ `Failed to resolve session label "${pending.label}": HTTP ${resp.status}. Staying in deferred mode \u2014 use cogent_join_session.`
34462
+ );
34463
+ return;
34464
+ }
34465
+ resolvedId = (await resp.json()).sessionId;
34466
+ } catch (err) {
34467
+ logger.warn(
34468
+ `Failed to resolve session label "${pending.label}": ${err}. Staying in deferred mode \u2014 use cogent_join_session.`
34469
+ );
34470
+ return;
34471
+ }
34472
+ logger.info(`Resolved session label "${pending.label}" to UUID ${resolvedId}`);
34473
+ try {
34474
+ const persisted = await loadCredentials();
34475
+ if (persisted && persisted.sessionId === resolvedId && persisted.endpoint === pending.endpoint) {
34476
+ await reinitCloudBackend(pending.endpoint, resolvedId, persisted.token);
34477
+ } else {
34478
+ logger.info(
34479
+ `No persisted token for session ${resolvedId}; staying deferred until cogent_join_session provides one.`
34480
+ );
34481
+ }
34482
+ } catch (err) {
34483
+ logger.warn(`Post-connect label upgrade failed (non-fatal): ${err}`);
34484
+ }
34485
+ }
34273
34486
  async function reinitCloudBackend(endpoint, sessionId, token) {
34274
34487
  const config2 = getConfig();
34275
34488
  cloudHttpClient = new HttpClient(endpoint, token);
@@ -34285,6 +34498,7 @@ async function reinitCloudBackend(endpoint, sessionId, token) {
34285
34498
  if (!cloudInbox) {
34286
34499
  cloudInbox = new MessageInbox();
34287
34500
  }
34501
+ bindInboxNotifier();
34288
34502
  cloudWsClient = createCloudWsClient(
34289
34503
  endpoint,
34290
34504
  sessionId,
@@ -34302,10 +34516,10 @@ async function runStartup() {
34302
34516
  if (envStatePath) {
34303
34517
  statePath = envStatePath;
34304
34518
  } else {
34305
- const defaultPath = path14.join(os8.homedir(), ".cogent");
34519
+ const defaultPath = path15.join(os10.homedir(), ".cogent");
34306
34520
  statePath = await firstRunPrompt(defaultPath);
34307
34521
  }
34308
- if (!envStatePath && statePath !== path14.join(os8.homedir(), ".cogent")) {
34522
+ if (!envStatePath && statePath !== path15.join(os10.homedir(), ".cogent")) {
34309
34523
  process.env.COGENT_STATE_PATH = statePath;
34310
34524
  } else if (!envStatePath) {
34311
34525
  process.env.COGENT_STATE_PATH = statePath;
@@ -34316,6 +34530,7 @@ async function runStartup() {
34316
34530
  let effectiveToken;
34317
34531
  const effectiveEndpoint = config2.COGENT_ENDPOINT;
34318
34532
  const isCloud = effectiveEndpoint && isCloudEndpoint(effectiveEndpoint);
34533
+ cloudModeActive = Boolean(isCloud);
34319
34534
  if (isCloud && effectiveSessionId && !UUID_V4_RE.test(effectiveSessionId)) {
34320
34535
  const persisted = await loadCredentials();
34321
34536
  if (persisted && persisted.label === effectiveSessionId && persisted.endpoint === effectiveEndpoint) {
@@ -34323,23 +34538,8 @@ async function runStartup() {
34323
34538
  effectiveSessionId = persisted.sessionId;
34324
34539
  effectiveToken = persisted.token;
34325
34540
  } else {
34326
- try {
34327
- const resolveResp = await fetch(
34328
- `${effectiveEndpoint}/api/sessions/resolve/${encodeURIComponent(effectiveSessionId)}`,
34329
- { signal: AbortSignal.timeout(2500) }
34330
- );
34331
- if (resolveResp.ok) {
34332
- const resolved = await resolveResp.json();
34333
- logger.info(`Resolved session label "${effectiveSessionId}" to UUID ${resolved.sessionId}`);
34334
- effectiveSessionId = resolved.sessionId;
34335
- } else {
34336
- logger.warn(`Failed to resolve session label "${effectiveSessionId}": HTTP ${resolveResp.status}. Entering deferred mode.`);
34337
- effectiveSessionId = void 0;
34338
- }
34339
- } catch (err) {
34340
- logger.warn(`Failed to resolve session label: ${err}. Entering deferred mode.`);
34341
- effectiveSessionId = void 0;
34342
- }
34541
+ pendingLabelResolve = { label: effectiveSessionId, endpoint: effectiveEndpoint };
34542
+ effectiveSessionId = void 0;
34343
34543
  }
34344
34544
  }
34345
34545
  if (isCloud) {
@@ -34383,10 +34583,11 @@ async function runStartup() {
34383
34583
  }
34384
34584
  initLogger(
34385
34585
  config2.COGENT_LOG_LEVEL,
34386
- path14.join(config2.COGENT_STATE_PATH, "logs")
34586
+ path15.join(config2.COGENT_STATE_PATH, "logs")
34387
34587
  );
34388
34588
  if (isCloud && effectiveSessionId && effectiveToken) {
34389
34589
  cloudInbox = new MessageInbox();
34590
+ bindInboxNotifier();
34390
34591
  cloudHttpClient = new HttpClient(effectiveEndpoint, effectiveToken);
34391
34592
  cloudWsClient = createCloudWsClient(
34392
34593
  effectiveEndpoint,
@@ -34422,7 +34623,7 @@ async function runPreflights() {
34422
34623
  await preflightClaude(config2.COGENT_CLAUDE_PATH);
34423
34624
  }
34424
34625
  }
34425
- var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, reRegistrationInProgress;
34626
+ var UUID_V4_RE, execFileAsync3, PERSIST_PATH, legacyWarnEmitted, cloudWsClient, cloudInbox, cloudHttpClient, cloudModeActive, inboxNotifier, notifierBoundTo, reRegistrationInProgress, pendingLabelResolve;
34426
34627
  var init_startup = __esm({
34427
34628
  "src/startup.ts"() {
34428
34629
  "use strict";
@@ -34444,23 +34645,27 @@ var init_startup = __esm({
34444
34645
  init_auto_relay();
34445
34646
  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;
34446
34647
  execFileAsync3 = promisify4(execFile5);
34447
- PERSIST_PATH = path14.join(os8.homedir(), ".cogent-config.json");
34648
+ PERSIST_PATH = path15.join(os10.homedir(), ".cogent-config.json");
34448
34649
  legacyWarnEmitted = false;
34449
34650
  cloudWsClient = null;
34450
34651
  cloudInbox = null;
34451
34652
  cloudHttpClient = null;
34653
+ cloudModeActive = false;
34654
+ inboxNotifier = null;
34655
+ notifierBoundTo = null;
34452
34656
  reRegistrationInProgress = false;
34657
+ pendingLabelResolve = null;
34453
34658
  }
34454
34659
  });
34455
34660
 
34456
34661
  // src/cloud/mail-credential-store.ts
34457
- import crypto4 from "node:crypto";
34458
- import fs14 from "node:fs/promises";
34459
- import path15 from "node:path";
34460
- import os9 from "node:os";
34662
+ import crypto5 from "node:crypto";
34663
+ import fs15 from "node:fs/promises";
34664
+ import path16 from "node:path";
34665
+ import os11 from "node:os";
34461
34666
  function defaultMailCredentialPath(cwd = process.cwd()) {
34462
- const hash = crypto4.createHash("sha256").update(path15.resolve(cwd)).digest("hex").slice(0, 16);
34463
- return path15.join(os9.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
34667
+ const hash = crypto5.createHash("sha256").update(path16.resolve(cwd)).digest("hex").slice(0, 16);
34668
+ return path16.join(os11.homedir(), ".cogent", "mail-credentials", `${hash}.json`);
34464
34669
  }
34465
34670
  function resolveMailCredentialPath(credentialPath) {
34466
34671
  if (credentialPath) return credentialPath;
@@ -34471,16 +34676,16 @@ function resolveMailCredentialPath(credentialPath) {
34471
34676
  async function loadMailCredentials(credentialPath) {
34472
34677
  const filePath = resolveMailCredentialPath(credentialPath);
34473
34678
  try {
34474
- return JSON.parse(await fs14.readFile(filePath, "utf-8"));
34679
+ return JSON.parse(await fs15.readFile(filePath, "utf-8"));
34475
34680
  } catch {
34476
34681
  return null;
34477
34682
  }
34478
34683
  }
34479
34684
  async function saveMailCredentials(creds, credentialPath) {
34480
34685
  const filePath = resolveMailCredentialPath(credentialPath);
34481
- await fs14.mkdir(path15.dirname(filePath), { recursive: true, mode: 448 });
34482
- await fs14.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
34483
- await fs14.chmod(filePath, 384);
34686
+ await fs15.mkdir(path16.dirname(filePath), { recursive: true, mode: 448 });
34687
+ await fs15.writeFile(filePath, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
34688
+ await fs15.chmod(filePath, 384);
34484
34689
  }
34485
34690
  async function persistProvisionedMailbox(mailbox, credentialPath) {
34486
34691
  if (!mailbox?.address || !mailbox.password) return false;
@@ -34501,7 +34706,7 @@ async function persistProvisionedMailbox(mailbox, credentialPath) {
34501
34706
  async function clearMailCredentials(credentialPath) {
34502
34707
  const filePath = resolveMailCredentialPath(credentialPath);
34503
34708
  try {
34504
- await fs14.unlink(filePath);
34709
+ await fs15.unlink(filePath);
34505
34710
  } catch (err) {
34506
34711
  if (err.code !== "ENOENT") throw err;
34507
34712
  }
@@ -34515,7 +34720,7 @@ var init_mail_credential_store = __esm({
34515
34720
  });
34516
34721
 
34517
34722
  // src/tools/register-peer.ts
34518
- import crypto5 from "node:crypto";
34723
+ import crypto6 from "node:crypto";
34519
34724
  function registerRegisterPeerTool(server) {
34520
34725
  server.registerTool(
34521
34726
  "cogent_register_peer",
@@ -34574,7 +34779,7 @@ function registerRegisterPeerTool(server) {
34574
34779
  }
34575
34780
  }
34576
34781
  if (!cloudSessionId) {
34577
- autoSecret = crypto5.randomBytes(16).toString("hex");
34782
+ autoSecret = crypto6.randomBytes(16).toString("hex");
34578
34783
  const resp = await fetch(
34579
34784
  `${endpoint}/api/sessions`,
34580
34785
  {
@@ -34680,6 +34885,19 @@ function registerRegisterPeerTool(server) {
34680
34885
  logger.info(
34681
34886
  `Register: session resolved ${resolution.decision}/${resolution.confidence} (${resolution.candidateCount} candidate[s]) -> ${localSessionId}`
34682
34887
  );
34888
+ const noLocalSession = resolution.candidateCount === 0;
34889
+ if (noLocalSession) {
34890
+ try {
34891
+ const base = getConfig().COGENT_PLATFORM === "cc" ? await transcriptBaseSummary() : "(codex: scans CODEX_HOME/sessions)";
34892
+ logger.warn(
34893
+ `Register: NO local ${getConfig().COGENT_PLATFORM} session found for cwd \u2014 auto-wake WILL be refused. cwd=${cwd}; scanned ${(resolution.probedPaths ?? []).join(", ") || "(unknown)"}; base ${base}. If the base is missing or empty, this agent's config dir is elsewhere \u2014 set CLAUDE_CONFIG_DIR / CODEX_HOME so the BRIDGE process sees it too. If the base has project dirs but none match, the registered cwd is not where this agent runs.`
34894
+ );
34895
+ } catch (err) {
34896
+ logger.warn(
34897
+ `Register: NO local session found for cwd=${cwd} (auto-wake WILL be refused); could not describe the transcript base: ${err.message}`
34898
+ );
34899
+ }
34900
+ }
34683
34901
  autoRelay.setLocalPeer(peerId, localSessionId, cwd, mode, label, localSessionId);
34684
34902
  const result = {
34685
34903
  success: true,
@@ -34688,7 +34906,12 @@ function registerRegisterPeerTool(server) {
34688
34906
  sessionResolution: {
34689
34907
  decision: resolution.decision,
34690
34908
  confidence: resolution.confidence,
34691
- candidateCount: resolution.candidateCount
34909
+ candidateCount: resolution.candidateCount,
34910
+ // Only on the broken path — keeps the happy-path result terse.
34911
+ ...noLocalSession ? {
34912
+ warning: "No local session transcript found for this cwd \u2014 auto-wake will be REFUSED. Verify the cwd is where this agent actually runs and that CLAUDE_CONFIG_DIR / CODEX_HOME are visible to the bridge process.",
34913
+ scannedPaths: resolution.probedPaths ?? []
34914
+ } : {}
34692
34915
  }
34693
34916
  };
34694
34917
  const relayAdvisory = peer?.advisory;
@@ -34758,6 +34981,7 @@ var init_register_peer = __esm({
34758
34981
  init_heartbeat();
34759
34982
  init_auto_relay();
34760
34983
  init_session_resolver();
34984
+ init_cc_cli();
34761
34985
  init_durable_identity();
34762
34986
  init_constants();
34763
34987
  init_npm_update_check();
@@ -35832,7 +36056,7 @@ var init_health_check2 = __esm({
35832
36056
  });
35833
36057
 
35834
36058
  // src/tools/create-session.ts
35835
- import crypto6 from "node:crypto";
36059
+ import crypto7 from "node:crypto";
35836
36060
  function registerCreateSessionTool(server) {
35837
36061
  server.registerTool(
35838
36062
  "cogent_create_session",
@@ -35863,7 +36087,7 @@ function registerCreateSessionTool(server) {
35863
36087
  )
35864
36088
  );
35865
36089
  }
35866
- const sessionSecret = secret ?? crypto6.randomBytes(16).toString("hex");
36090
+ const sessionSecret = secret ?? crypto7.randomBytes(16).toString("hex");
35867
36091
  const resp = await fetch(
35868
36092
  `${config2.COGENT_ENDPOINT}/api/sessions`,
35869
36093
  {
@@ -36187,13 +36411,13 @@ var init_setup_mail = __esm({
36187
36411
  });
36188
36412
 
36189
36413
  // src/mail/mail-sender.ts
36190
- import fs15 from "node:fs/promises";
36191
- import path16 from "node:path";
36414
+ import fs16 from "node:fs/promises";
36415
+ import path17 from "node:path";
36192
36416
  async function buildAndSendMail(sender, creds, params) {
36193
36417
  const attachments = [];
36194
36418
  for (const p of params.attachmentPaths ?? []) {
36195
- const content = await fs15.readFile(p);
36196
- attachments.push({ filename: path16.basename(p), content });
36419
+ const content = await fs16.readFile(p);
36420
+ attachments.push({ filename: path17.basename(p), content });
36197
36421
  }
36198
36422
  const { messageId } = await sender.send({
36199
36423
  from: creds.address,
@@ -36321,16 +36545,16 @@ var init_send_mail = __esm({
36321
36545
  });
36322
36546
 
36323
36547
  // src/mail/mail-fetcher.ts
36324
- import fs16 from "node:fs/promises";
36325
- import path17 from "node:path";
36548
+ import fs17 from "node:fs/promises";
36549
+ import path18 from "node:path";
36326
36550
  async function saveAttachments(attachments, downloadDir) {
36327
36551
  if (attachments.length === 0) return [];
36328
- await fs16.mkdir(downloadDir, { recursive: true });
36552
+ await fs17.mkdir(downloadDir, { recursive: true });
36329
36553
  const saved = [];
36330
36554
  for (const a of attachments) {
36331
- const name = path17.basename(a.filename) || "attachment";
36332
- const savedPath = path17.join(downloadDir, name);
36333
- await fs16.writeFile(savedPath, a.content);
36555
+ const name = path18.basename(a.filename) || "attachment";
36556
+ const savedPath = path18.join(downloadDir, name);
36557
+ await fs17.writeFile(savedPath, a.content);
36334
36558
  saved.push({ filename: name, savedPath, size: a.content.length });
36335
36559
  }
36336
36560
  return saved;
@@ -36461,8 +36685,8 @@ var init_mail_fetcher = __esm({
36461
36685
  });
36462
36686
 
36463
36687
  // src/tools/fetch-mail.ts
36464
- import os10 from "node:os";
36465
- import path18 from "node:path";
36688
+ import os12 from "node:os";
36689
+ import path19 from "node:path";
36466
36690
  function registerFetchMailTool(server, deps = {}) {
36467
36691
  const makeFetcher = deps.fetcherFactory ?? ((creds) => new ImapflowMailFetcher(creds));
36468
36692
  server.registerTool(
@@ -36524,7 +36748,7 @@ var init_fetch_mail = __esm({
36524
36748
  init_mail_fetcher();
36525
36749
  init_auth_error();
36526
36750
  init_validate();
36527
- DEFAULT_DOWNLOAD_DIR = path18.join(os10.homedir(), ".cogent", "mail-downloads");
36751
+ DEFAULT_DOWNLOAD_DIR = path19.join(os12.homedir(), ".cogent", "mail-downloads");
36528
36752
  }
36529
36753
  });
36530
36754
 
@@ -36630,7 +36854,7 @@ async function main() {
36630
36854
  registerSendMailTool(server);
36631
36855
  registerFetchMailTool(server);
36632
36856
  registerRotateMailCredsTool(server);
36633
- if (cloudInbox) {
36857
+ if (isCloudMode2()) {
36634
36858
  server.registerResource(
36635
36859
  "cogent_inbox",
36636
36860
  "cogent://inbox",
@@ -36638,18 +36862,21 @@ async function main() {
36638
36862
  description: "Incoming messages received via cloud bridge WebSocket. Read this resource to see new messages from other peers.",
36639
36863
  mimeType: "application/json"
36640
36864
  },
36865
+ // Read the inbox LAZILY: in deferred mode it does not exist yet and is
36866
+ // created later by reinitCloudBackend(). An empty inbox is the honest
36867
+ // answer for "connected to cloud, no session joined yet".
36641
36868
  async (uri) => ({
36642
36869
  contents: [{
36643
36870
  uri: uri.href,
36644
36871
  mimeType: "application/json",
36645
36872
  text: JSON.stringify({
36646
- messages: cloudInbox.getUnread(),
36647
- lastMessageId: cloudInbox.getLastMessageId()
36873
+ messages: cloudInbox ? cloudInbox.getUnread() : [],
36874
+ lastMessageId: cloudInbox ? cloudInbox.getLastMessageId() : null
36648
36875
  })
36649
36876
  }]
36650
36877
  })
36651
36878
  );
36652
- cloudInbox.onNewMessage(() => {
36879
+ setInboxNotifier(() => {
36653
36880
  try {
36654
36881
  server.server.sendResourceUpdated({ uri: "cogent://inbox" });
36655
36882
  } catch (err) {
@@ -36663,6 +36890,11 @@ async function main() {
36663
36890
  `${SERVER_NAME} v${SERVER_VERSION} running on stdio
36664
36891
  `
36665
36892
  );
36893
+ void resolvePendingLabel().catch((err) => {
36894
+ logger.warn(
36895
+ `Label resolve error (non-fatal): ${err instanceof Error ? err.message : String(err)}`
36896
+ );
36897
+ });
36666
36898
  void runPreflights().catch((err) => {
36667
36899
  logger.warn(
36668
36900
  `Preflight error (non-fatal): ${err instanceof Error ? err.message : String(err)}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@essentialai/cogent-bridge-bundled",
3
- "version": "3.20.7",
3
+ "version": "3.21.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": {