crosscheck-mcp 0.2.26 → 0.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/embed.js CHANGED
@@ -8,15 +8,15 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
 
9
9
  // src/entrypoints/embed.ts
10
10
  import { existsSync as existsSync11 } from "fs";
11
- import path11 from "path";
11
+ import path12 from "path";
12
12
  import { fileURLToPath as fileURLToPath2 } from "url";
13
13
 
14
14
  // src/core/pricing.ts
15
15
  import { readFileSync } from "fs";
16
- function loadPricing(path12) {
16
+ function loadPricing(path13) {
17
17
  let raw;
18
18
  try {
19
- raw = readFileSync(path12, "utf8");
19
+ raw = readFileSync(path13, "utf8");
20
20
  } catch {
21
21
  return {};
22
22
  }
@@ -33,20 +33,30 @@ function modelPricing(pricing, provider, model) {
33
33
  const block = pricing[provider];
34
34
  if (!block || typeof block !== "object" || Array.isArray(block)) return null;
35
35
  const table = block;
36
+ if (model.startsWith("_")) return null;
36
37
  let entry = table[model];
37
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
38
- const best = Object.keys(table).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
39
- entry = best !== void 0 ? table[best] : void 0;
38
+ let match = "exact";
39
+ if (!isRates(entry)) {
40
+ const best = Object.keys(table).filter((k) => !k.startsWith("_")).filter((k) => model.startsWith(k) && DATE_STAMP.test(model.slice(k.length))).sort((a, b) => b.length - a.length)[0];
41
+ if (best !== void 0) {
42
+ entry = table[best];
43
+ match = "stamp";
44
+ }
40
45
  }
41
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
46
+ if (!isRates(entry)) return null;
42
47
  const e = entry;
43
48
  return {
44
49
  prompt_per_1k: numberOrZero(e["prompt_per_1k"]),
45
50
  completion_per_1k: numberOrZero(e["completion_per_1k"]),
46
51
  cached_per_1k: numberOrZero(e["cached_per_1k"]),
47
- ...e["estimated"] === true ? { estimated: true } : {}
52
+ ...e["estimated"] === true ? { estimated: true } : {},
53
+ match
48
54
  };
49
55
  }
56
+ var DATE_STAMP = /^-\d{8}$/;
57
+ function isRates(v) {
58
+ return Boolean(v) && typeof v === "object" && !Array.isArray(v);
59
+ }
50
60
  function numberOrZero(v) {
51
61
  if (typeof v === "number" && Number.isFinite(v)) return v;
52
62
  if (typeof v === "string") {
@@ -126,8 +136,20 @@ var PROVIDER_CAPS = {
126
136
  gemini: {
127
137
  family: "gemini",
128
138
  system_role: "separate",
129
- supports_temperature: true,
130
- reasoning_prefixes: ["gemini-3.1-pro", "gemini-3.5-flash", "gemini-2.5-pro"]
139
+ // No sampling, on any Gemini model. Ignored since 3.6 Flash and rejected
140
+ // by upcoming models (Google, 2026-10). "model" means "omit for reasoning
141
+ // models", and every Gemini model is reasoning-class (below) — so this
142
+ // resolves to never, through the same rule the other providers use. The
143
+ // adapter also never sends it; this keeps the record honest for anything
144
+ // else that reads it.
145
+ supports_temperature: "model",
146
+ // EVERY Gemini model is reasoning-class. The old list named three
147
+ // families and missed gemini-3.8-flash — the DEFAULT — so the default
148
+ // model got the small non-reasoning budgets (768 tokens for an audit)
149
+ // while spending up to ~480 tokens of each call thinking. Google's docs
150
+ // say thinking cannot be switched off on current models, so a list of
151
+ // which ones think is a list that can only ever be incomplete.
152
+ reasoning_prefixes: ["gemini-"]
131
153
  },
132
154
  // Qwen's "Max" tier (qwen-v3.8, qwen-v3.7) is a standard instruct/chat
133
155
  // model, not a visible-reasoning model like QwQ — normal temperature and
@@ -250,6 +272,73 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
250
272
  );
251
273
  }
252
274
 
275
+ // src/providers/network-errors.ts
276
+ function codeOf(e) {
277
+ if (!e || typeof e !== "object") return null;
278
+ const c = e.code;
279
+ return typeof c === "string" && c.length > 0 ? c : null;
280
+ }
281
+ function rootCause(e, depth = 0) {
282
+ if (depth > 5 || !e || typeof e !== "object") return e;
283
+ const o = e;
284
+ if (Array.isArray(o.errors) && o.errors.length > 0) {
285
+ const coded = o.errors.find((x) => codeOf(x) !== null);
286
+ return rootCause(coded ?? o.errors[0], depth + 1);
287
+ }
288
+ if (o.cause !== void 0 && o.cause !== null) return rootCause(o.cause, depth + 1);
289
+ return e;
290
+ }
291
+ var BY_CODE = {
292
+ ENOTFOUND: { cause: "dns", detail: "the provider's hostname did not resolve \u2014 DNS, or a typo'd base URL", transient: false, kind: "network" },
293
+ EAI_AGAIN: { cause: "dns", detail: "DNS lookup failed temporarily \u2014 resolver or network is flapping", transient: true, kind: "network" },
294
+ ECONNREFUSED: { cause: "refused", detail: "the connection was refused \u2014 nothing is listening, or a proxy blocked it", transient: false, kind: "network" },
295
+ ECONNRESET: { cause: "reset", detail: "the peer closed the connection mid-request \u2014 flaky path, or an upstream error behind a proxy", transient: true, kind: "network" },
296
+ EPIPE: { cause: "reset", detail: "the connection closed while we were still writing", transient: true, kind: "network" },
297
+ ETIMEDOUT: { cause: "connect_timeout", detail: "the connection timed out before it was established", transient: true, kind: "timeout" },
298
+ EHOSTUNREACH: { cause: "unreachable", detail: "no route to the provider \u2014 VPN, or offline", transient: true, kind: "network" },
299
+ ENETUNREACH: { cause: "unreachable", detail: "the network is unreachable \u2014 offline, or a routing change", transient: true, kind: "network" },
300
+ ENETDOWN: { cause: "unreachable", detail: "the local network is down", transient: true, kind: "network" },
301
+ EPROTO: { cause: "tls", detail: "the TLS handshake failed \u2014 an intercepting proxy, or a protocol mismatch", transient: false, kind: "network" },
302
+ ERR_TLS_CERT_ALTNAME_INVALID: { cause: "tls", detail: "the certificate did not match the hostname \u2014 traffic is being intercepted", transient: false, kind: "network" },
303
+ CERT_HAS_EXPIRED: { cause: "tls", detail: "the server certificate has expired, or this machine's clock is wrong", transient: false, kind: "network" },
304
+ UNABLE_TO_VERIFY_LEAF_SIGNATURE: { cause: "tls", detail: "the certificate chain could not be verified \u2014 a corporate proxy's root is probably not trusted here", transient: false, kind: "network" },
305
+ UND_ERR_CONNECT_TIMEOUT: { cause: "connect_timeout", detail: "could not open a connection within the timeout \u2014 firewall, or the host is down", transient: true, kind: "timeout" },
306
+ UND_ERR_HEADERS_TIMEOUT: { cause: "read_timeout", detail: "connected, but the provider sent no response headers in time \u2014 it is overloaded or thinking too long", transient: true, kind: "timeout" },
307
+ UND_ERR_BODY_TIMEOUT: { cause: "read_timeout", detail: "the response body stalled mid-stream", transient: true, kind: "timeout" },
308
+ UND_ERR_SOCKET: { cause: "reset", detail: "the socket closed unexpectedly", transient: true, kind: "network" },
309
+ UND_ERR_ABORTED: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" },
310
+ ABORT_ERR: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" }
311
+ };
312
+ function diagnoseNetworkError(e) {
313
+ const root = rootCause(e);
314
+ const code = codeOf(root) ?? codeOf(e);
315
+ if (code && BY_CODE[code]) return { ...BY_CODE[code], code };
316
+ const name = root && typeof root === "object" ? root.name : void 0;
317
+ if (name === "AbortError" || name === "TimeoutError") {
318
+ return {
319
+ cause: name === "TimeoutError" ? "read_timeout" : "aborted",
320
+ code: code ?? String(name),
321
+ detail: name === "TimeoutError" ? "the request exceeded its timeout" : "the request was cancelled",
322
+ transient: name === "TimeoutError",
323
+ kind: name === "TimeoutError" ? "timeout" : "network"
324
+ };
325
+ }
326
+ return {
327
+ cause: "unknown",
328
+ code,
329
+ detail: code ? `the connection failed with ${code}` : "the connection failed and the underlying error carried no code",
330
+ transient: true,
331
+ kind: "network"
332
+ };
333
+ }
334
+ function looksLikeNetworkFailure(d) {
335
+ return d.code !== null || d.cause !== "unknown";
336
+ }
337
+ function networkErrorMessage(provider, d) {
338
+ const code = d.code ? ` [${d.code}]` : "";
339
+ return `${provider}: ${d.detail}${code}`;
340
+ }
341
+
253
342
  // src/providers/retry.ts
254
343
  var override = null;
255
344
  function resolveRetryConfig() {
@@ -572,7 +661,11 @@ async function sendAnthropic(args) {
572
661
  try {
573
662
  respLike = await doFetch(url, init);
574
663
  } catch (e) {
575
- throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
664
+ const d = diagnoseNetworkError(e);
665
+ if (!looksLikeNetworkFailure(d)) throw e;
666
+ throw new ProviderError(d.kind, networkErrorMessage("anthropic", d), {
667
+ transient: d.transient
668
+ });
576
669
  }
577
670
  const status = respLike.status;
578
671
  if (status >= 200 && status < 300) {
@@ -645,6 +738,11 @@ function jsonSchemaToGeminiSchema(schema) {
645
738
  }
646
739
  return out;
647
740
  }
741
+ var GEMINI_THINKING_HEADROOM_TOKENS = 16384;
742
+ function thinkingHeadroom() {
743
+ const raw = Number(process.env["CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS"]);
744
+ return Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : GEMINI_THINKING_HEADROOM_TOKENS;
745
+ }
648
746
  function buildGeminiRequest(opts) {
649
747
  const contents = [];
650
748
  let systemText = null;
@@ -663,8 +761,9 @@ function buildGeminiRequest(opts) {
663
761
  const body = {
664
762
  contents,
665
763
  generationConfig: {
666
- maxOutputTokens: opts.maxTokens,
667
- temperature: opts.temperature
764
+ // Answer budget + thinking headroom. No temperature / topP / topK /
765
+ // thinkingBudget, on any model — see the header note.
766
+ maxOutputTokens: opts.maxTokens + thinkingHeadroom()
668
767
  }
669
768
  };
670
769
  if (systemText !== null && systemText !== "") {
@@ -674,8 +773,8 @@ function buildGeminiRequest(opts) {
674
773
  body.generationConfig.responseMimeType = "application/json";
675
774
  body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
676
775
  }
677
- const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
678
- return { url, headers: {}, body };
776
+ const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent`;
777
+ return { url, headers: { "x-goog-api-key": opts.apiKey }, body };
679
778
  }
680
779
  function parseGeminiResponse(opts) {
681
780
  const r = opts.resp ?? {};
@@ -705,16 +804,19 @@ function parseGeminiResponse(opts) {
705
804
  }
706
805
  try {
707
806
  const first = cands[0];
708
- const content = first["content"];
709
- const parts = content["parts"];
807
+ const finishReason = typeof first["finishReason"] === "string" ? first["finishReason"] : void 0;
808
+ const content = first["content"] ?? {};
809
+ const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
710
810
  let text = "";
711
811
  for (const p of parts) {
712
812
  if (p && typeof p === "object") {
713
- const t = p["text"];
813
+ const part = p;
814
+ if (part["thought"] === true) continue;
815
+ const t = part["text"];
714
816
  if (typeof t === "string") text += t;
715
817
  }
716
818
  }
717
- return { text, usage };
819
+ return { text, usage, ...finishReason ? { finishReason } : {} };
718
820
  } catch (e) {
719
821
  throw new ProviderError(
720
822
  "parse",
@@ -743,7 +845,8 @@ async function sendGemini(args) {
743
845
  apiKey: args.apiKey,
744
846
  messages: args.messages,
745
847
  maxTokens: args.maxTokens,
746
- temperature: args.temperature,
848
+ // args.temperature is deliberately NOT forwarded: Gemini ignores it and
849
+ // upcoming models reject it. See the header note.
747
850
  ...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
748
851
  });
749
852
  const doFetch = args.fetchImpl ?? globalThis.fetch;
@@ -758,7 +861,11 @@ async function sendGemini(args) {
758
861
  try {
759
862
  respLike = await doFetch(url, init);
760
863
  } catch (e) {
761
- throw new ProviderError("network", `gemini: fetch failed: ${e.message}`);
864
+ const d = diagnoseNetworkError(e);
865
+ if (!looksLikeNetworkFailure(d)) throw e;
866
+ throw new ProviderError(d.kind, networkErrorMessage("gemini", d), {
867
+ transient: d.transient
868
+ });
762
869
  }
763
870
  const status = respLike.status;
764
871
  if (status >= 200 && status < 300) {
@@ -768,11 +875,18 @@ async function sendGemini(args) {
768
875
  } catch (e) {
769
876
  throw new ProviderError("parse", `gemini: response body not JSON: ${e.message}`);
770
877
  }
771
- const { text, usage } = parseGeminiResponse({
878
+ const { text, usage, finishReason } = parseGeminiResponse({
772
879
  resp: parsed,
773
880
  model: args.model,
774
881
  purpose: args.purpose ?? "worker"
775
882
  });
883
+ if (text.trim() === "" && finishReason === "MAX_TOKENS") {
884
+ throw new ProviderError(
885
+ "parse",
886
+ `gemini: the answer was cut off before any visible text \u2014 thinking used the whole output budget (${usage.completion_tokens} tokens). Raise CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS or the purpose's budget.`,
887
+ { transient: false }
888
+ );
889
+ }
776
890
  return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
777
891
  }
778
892
  const bodyText = await respLike.text().catch(() => "");
@@ -939,7 +1053,11 @@ async function sendOpenAICompatible(args) {
939
1053
  try {
940
1054
  respLike = await doFetch(url, init);
941
1055
  } catch (e) {
942
- throw new ProviderError("network", `${args.provider}: fetch failed: ${e.message}`);
1056
+ const d = diagnoseNetworkError(e);
1057
+ if (!looksLikeNetworkFailure(d)) throw e;
1058
+ throw new ProviderError(d.kind, networkErrorMessage(args.provider, d), {
1059
+ transient: d.transient
1060
+ });
943
1061
  }
944
1062
  const status = respLike.status;
945
1063
  if (status >= 200 && status < 300) {
@@ -967,7 +1085,7 @@ async function sendOpenAICompatible(args) {
967
1085
  // src/providers/registry.ts
968
1086
  var DEFAULT_MODELS = {
969
1087
  anthropic: "claude-opus-5-5",
970
- openai: "gpt-5.6-sol",
1088
+ openai: "gpt-6-sol",
971
1089
  xai: "grok-4-latest",
972
1090
  mistral: "mistral-large-latest",
973
1091
  groq: "llama-3.3-70b-versatile",
@@ -1113,7 +1231,7 @@ import { z } from "zod";
1113
1231
 
1114
1232
  // src/server-meta.ts
1115
1233
  var SERVER_NAME = "crosscheck-agent";
1116
- var SERVER_VERSION = true ? "0.2.26" : "0.0.0-dev";
1234
+ var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
1117
1235
 
1118
1236
  // src/tools/audit.ts
1119
1237
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -1174,27 +1292,27 @@ function extractJson(text) {
1174
1292
  }
1175
1293
 
1176
1294
  // src/core/json-schema.ts
1177
- function validateSchema(value, schema, path12 = "") {
1295
+ function validateSchema(value, schema, path13 = "") {
1178
1296
  const errs = [];
1179
1297
  if ("anyOf" in schema) {
1180
1298
  const subs = schema["anyOf"].map(
1181
- (s) => validateSchema(value, s, path12)
1299
+ (s) => validateSchema(value, s, path13)
1182
1300
  );
1183
1301
  if (!subs.some((e) => e.length === 0)) {
1184
- errs.push(`${path12 || "<root>"}: did not match anyOf`);
1302
+ errs.push(`${path13 || "<root>"}: did not match anyOf`);
1185
1303
  }
1186
1304
  return errs;
1187
1305
  }
1188
1306
  if ("oneOf" in schema) {
1189
- const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path12).length === 0).length;
1307
+ const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path13).length === 0).length;
1190
1308
  if (passed !== 1) {
1191
- errs.push(`${path12 || "<root>"}: matched ${passed} of oneOf, expected 1`);
1309
+ errs.push(`${path13 || "<root>"}: matched ${passed} of oneOf, expected 1`);
1192
1310
  }
1193
1311
  return errs;
1194
1312
  }
1195
1313
  if ("const" in schema && !deepEqual(value, schema["const"])) {
1196
1314
  errs.push(
1197
- `${path12 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
1315
+ `${path13 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
1198
1316
  );
1199
1317
  return errs;
1200
1318
  }
@@ -1204,7 +1322,7 @@ function validateSchema(value, schema, path12 = "") {
1204
1322
  const ok = types.some((tt) => matchesType(value, String(tt)));
1205
1323
  if (!ok) {
1206
1324
  errs.push(
1207
- `${path12 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
1325
+ `${path13 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
1208
1326
  );
1209
1327
  return errs;
1210
1328
  }
@@ -1213,29 +1331,29 @@ function validateSchema(value, schema, path12 = "") {
1213
1331
  if ("enum" in schema) {
1214
1332
  const en = schema["enum"];
1215
1333
  if (!en.some((x) => deepEqual(x, value))) {
1216
- errs.push(`${path12 || "<root>"}: value ${pyRepr(value)} not in enum`);
1334
+ errs.push(`${path13 || "<root>"}: value ${pyRepr(value)} not in enum`);
1217
1335
  }
1218
1336
  }
1219
1337
  if ("minLength" in schema && value.length < schema["minLength"]) {
1220
- errs.push(`${path12 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
1338
+ errs.push(`${path13 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
1221
1339
  }
1222
1340
  }
1223
1341
  if (typeof value === "number" && !Number.isNaN(value)) {
1224
1342
  if ("minimum" in schema && value < schema["minimum"]) {
1225
- errs.push(`${path12 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
1343
+ errs.push(`${path13 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
1226
1344
  }
1227
1345
  if ("maximum" in schema && value > schema["maximum"]) {
1228
- errs.push(`${path12 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
1346
+ errs.push(`${path13 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
1229
1347
  }
1230
1348
  }
1231
1349
  if (Array.isArray(value)) {
1232
1350
  if ("minItems" in schema && value.length < schema["minItems"]) {
1233
- errs.push(`${path12 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
1351
+ errs.push(`${path13 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
1234
1352
  }
1235
1353
  const itemSchema = schema["items"];
1236
1354
  if (isObj(itemSchema)) {
1237
1355
  for (let i = 0; i < value.length; i++) {
1238
- errs.push(...validateSchema(value[i], itemSchema, `${path12}[${i}]`));
1356
+ errs.push(...validateSchema(value[i], itemSchema, `${path13}[${i}]`));
1239
1357
  }
1240
1358
  }
1241
1359
  }
@@ -1244,19 +1362,19 @@ function validateSchema(value, schema, path12 = "") {
1244
1362
  const required = schema["required"] ?? [];
1245
1363
  for (const r of required) {
1246
1364
  if (!(r in value)) {
1247
- errs.push(`${path12 || "<root>"}: missing required key ${pyRepr(r)}`);
1365
+ errs.push(`${path13 || "<root>"}: missing required key ${pyRepr(r)}`);
1248
1366
  }
1249
1367
  }
1250
1368
  if (schema["additionalProperties"] === false) {
1251
1369
  for (const k of Object.keys(value)) {
1252
1370
  if (!(k in props)) {
1253
- errs.push(`${path12 || "<root>"}: unknown key ${pyRepr(k)}`);
1371
+ errs.push(`${path13 || "<root>"}: unknown key ${pyRepr(k)}`);
1254
1372
  }
1255
1373
  }
1256
1374
  }
1257
1375
  for (const [k, v] of Object.entries(value)) {
1258
1376
  const ps = props[k];
1259
- if (ps) errs.push(...validateSchema(v, ps, path12 ? `${path12}.${k}` : k));
1377
+ if (ps) errs.push(...validateSchema(v, ps, path13 ? `${path13}.${k}` : k));
1260
1378
  }
1261
1379
  }
1262
1380
  return errs;
@@ -1336,6 +1454,31 @@ function pyReprType(t) {
1336
1454
  return String(t);
1337
1455
  }
1338
1456
 
1457
+ // src/core/session.ts
1458
+ import { randomUUID } from "crypto";
1459
+ var processSessionId = null;
1460
+ var startedAt = null;
1461
+ function engineSessionId() {
1462
+ if (processSessionId === null) {
1463
+ processSessionId = randomUUID();
1464
+ startedAt = Date.now();
1465
+ }
1466
+ return processSessionId;
1467
+ }
1468
+ function resolveSessionId(callerSupplied) {
1469
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1470
+ return trimmed.length > 0 ? trimmed : engineSessionId();
1471
+ }
1472
+ function localSessionRecordingEnabled(env = globalThis.process?.env ?? {}) {
1473
+ const v = (env["CROSSCHECK_RECORD_SESSIONS"] ?? "").trim().toLowerCase();
1474
+ return !["0", "false", "off", "no"].includes(v);
1475
+ }
1476
+ function recordingSessionId(callerSupplied) {
1477
+ if (localSessionRecordingEnabled()) return resolveSessionId(callerSupplied);
1478
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1479
+ return trimmed.length > 0 ? trimmed : null;
1480
+ }
1481
+
1339
1482
  // src/core/usage.ts
1340
1483
  function emptyUsage(provider, model, purpose = "worker") {
1341
1484
  return {
@@ -1441,11 +1584,11 @@ function withCommas(n) {
1441
1584
  function renderRunSummary(opts) {
1442
1585
  const endedAt = opts.endedAtS ?? Math.trunc(Date.now() / 1e3);
1443
1586
  let scope = "call";
1444
- let startedAt = null;
1587
+ let startedAt2 = null;
1445
1588
  let rows = [];
1446
1589
  if (opts.sessionScope && opts.sessionScope.rows.length > 0) {
1447
1590
  scope = "session";
1448
- startedAt = opts.sessionScope.startedAt;
1591
+ startedAt2 = opts.sessionScope.startedAt;
1449
1592
  rows = opts.sessionScope.rows.map((r) => ({ ...r }));
1450
1593
  } else {
1451
1594
  const byPurpose = /* @__PURE__ */ new Map();
@@ -1476,6 +1619,7 @@ function renderRunSummary(opts) {
1476
1619
  row.cpu_ms += a.cpu_ms ?? 0;
1477
1620
  if (a.cache_hit) row.cache_hits += 1;
1478
1621
  if (a.error) row.errors += 1;
1622
+ if (a.usage?.estimated) row.estimated = true;
1479
1623
  }
1480
1624
  rows = Array.from(byPurpose.values());
1481
1625
  }
@@ -1488,16 +1632,18 @@ function renderRunSummary(opts) {
1488
1632
  wall_ms: rows.reduce((s, r) => s + r.wall_ms, 0),
1489
1633
  cpu_ms: rows.reduce((s, r) => s + r.cpu_ms, 0),
1490
1634
  cache_hits: rows.reduce((s, r) => s + r.cache_hits, 0),
1491
- errors: rows.reduce((s, r) => s + r.errors, 0)
1635
+ errors: rows.reduce((s, r) => s + r.errors, 0),
1636
+ ...rows.some((r) => r.estimated) ? { estimated: true } : {}
1492
1637
  };
1493
1638
  const titleLeft = scope === "session" ? `session: ${opts.sessionId ?? ""}` : `call: ${opts.toolName}`;
1494
- const header = `${titleLeft} (${totals.calls} calls, ${withCommas(totals.total_tokens)} tokens, $${totals.cost_usd.toFixed(4)}, ${(totals.wall_ms / 1e3).toFixed(1)}s wall, ${(totals.cpu_ms / 1e3).toFixed(3)}s cpu)`;
1639
+ const costText = totals.estimated ? `$${totals.cost_usd.toFixed(4)}+ (some calls unpriced)` : `$${totals.cost_usd.toFixed(4)}`;
1640
+ const header = `${titleLeft} (${totals.calls} calls, ${withCommas(totals.total_tokens)} tokens, ${costText}, ${(totals.wall_ms / 1e3).toFixed(1)}s wall, ${(totals.cpu_ms / 1e3).toFixed(3)}s cpu)`;
1495
1641
  const bodyLines = [];
1496
1642
  for (let i = 0; i < rows.length; i++) {
1497
1643
  const r = rows[i];
1498
1644
  const glyph = i === rows.length - 1 ? "`-" : "|-";
1499
1645
  bodyLines.push(
1500
- `${glyph} purpose: ${r.purpose} (calls=${r.calls} tokens=${withCommas(r.total_tokens)} cost=$${r.cost_usd.toFixed(4)} wall=${(r.wall_ms / 1e3).toFixed(1)}s cpu=${(r.cpu_ms / 1e3).toFixed(3)}s)`
1646
+ `${glyph} purpose: ${r.purpose} (calls=${r.calls} tokens=${withCommas(r.total_tokens)} cost=$${r.cost_usd.toFixed(4)}${r.estimated ? "+" : ""} wall=${(r.wall_ms / 1e3).toFixed(1)}s cpu=${(r.cpu_ms / 1e3).toFixed(3)}s)`
1501
1647
  );
1502
1648
  }
1503
1649
  const callByModel = rollupSpendByModel(
@@ -1545,7 +1691,7 @@ function renderRunSummary(opts) {
1545
1691
  tool: opts.toolName,
1546
1692
  scope,
1547
1693
  currency: "USD",
1548
- started_at: startedAt,
1694
+ started_at: startedAt2,
1549
1695
  ended_at: endedAt,
1550
1696
  rows,
1551
1697
  totals,
@@ -1670,14 +1816,15 @@ async function attachUsageBlock(result, answers, opts) {
1670
1816
  delete result["_suppress_run_summary"];
1671
1817
  }
1672
1818
  async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
1673
- if (!sessionId || answers.length === 0) return;
1819
+ const sid = recordingSessionId(sessionId);
1820
+ if (!sid || answers.length === 0) return;
1674
1821
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
1675
1822
  const rows = [];
1676
1823
  for (const a of answers) {
1677
1824
  const u = a.usage;
1678
1825
  if (!u || typeof u.provider !== "string" || u.provider === "") continue;
1679
1826
  rows.push({
1680
- session_id: sessionId,
1827
+ session_id: sid,
1681
1828
  ts: now,
1682
1829
  tool: toolName,
1683
1830
  purpose: u.purpose ?? "worker",
@@ -1700,13 +1847,14 @@ async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
1700
1847
  }
1701
1848
  }
1702
1849
  async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, nowS) {
1703
- if (!sessionId) return;
1850
+ const sid = recordingSessionId(sessionId);
1851
+ if (!sid) return;
1704
1852
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
1705
1853
  try {
1706
- let existing = await storage.getSession(sessionId);
1854
+ let existing = await storage.getSession(sid);
1707
1855
  if (!existing) {
1708
1856
  await storage.upsertSession({
1709
- session_id: sessionId,
1857
+ session_id: sid,
1710
1858
  started_at: now,
1711
1859
  last_at: now,
1712
1860
  calls: 0,
@@ -1719,7 +1867,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
1719
1867
  total_cost_usd: 0,
1720
1868
  total_cpu_ms: 0
1721
1869
  });
1722
- existing = await storage.getSession(sessionId);
1870
+ existing = await storage.getSession(sid);
1723
1871
  }
1724
1872
  if (!existing) return;
1725
1873
  let promptDelta = 0;
@@ -1739,7 +1887,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
1739
1887
  }
1740
1888
  if (a.cache_hit) cacheHitDelta += 1;
1741
1889
  }
1742
- await storage.accumulateSessionTotals(sessionId, {
1890
+ await storage.accumulateSessionTotals(sid, {
1743
1891
  calls: answers.length,
1744
1892
  wall_ms: wallMs,
1745
1893
  cache_hits: cacheHitDelta,
@@ -2687,13 +2835,25 @@ function numberOrNull(v) {
2687
2835
  import { performance as performance2 } from "perf_hooks";
2688
2836
 
2689
2837
  // src/core/co-reason.ts
2690
- var CO_REASON_MODEL = "gpt-5.6-sol";
2838
+ var CO_REASON_MODEL = "gpt-6-sol";
2839
+ var CO_REASON_ALTERNATE = "gpt-6-astra";
2840
+ var LABELS = {
2841
+ "gpt-6-sol": "GPT-6 Sol",
2842
+ "gpt-6-astra": "GPT-6 Astra",
2843
+ "gpt-5.6-sol": "GPT-5.6 Sol"
2844
+ };
2845
+ function coReasonLabel(model) {
2846
+ return LABELS[model] ?? model;
2847
+ }
2848
+ var CO_REASON_LABEL = coReasonLabel(CO_REASON_MODEL);
2691
2849
  var CO_REASON_PROVIDER = "openai";
2692
- var CO_REASON_LABEL = "GPT-5.6";
2693
- function pickCoReasoner(providers, upgradeRequested) {
2850
+ function pickCoReasoner(providers, upgradeRequested, openAiSeatModel) {
2694
2851
  if (!upgradeRequested) return null;
2695
2852
  const base = providers[CO_REASON_PROVIDER];
2696
- return base ? retargetProvider(base, CO_REASON_MODEL) : null;
2853
+ if (!base) return null;
2854
+ const seat = openAiSeatModel ?? base.model;
2855
+ const model = seat === CO_REASON_MODEL ? CO_REASON_ALTERNATE : CO_REASON_MODEL;
2856
+ return retargetProvider(base, model);
2697
2857
  }
2698
2858
  async function coReasonThenInject(opts) {
2699
2859
  const { provider, messages, maxTokens } = opts;
@@ -2919,7 +3079,7 @@ function buildSuggestedUpgrade(toolName, assessment) {
2919
3079
  model: UPGRADE_MODEL,
2920
3080
  label: UPGRADE_LABEL,
2921
3081
  reason: assessment.reason,
2922
- how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}, and \u2014 when an OpenAI key is configured \u2014 add a GPT-5.6 second-opinion pass that ${UPGRADE_LABEL} weighs before finalizing. Other panel seats stay on their normal models.`
3082
+ how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}, and \u2014 when an OpenAI key is configured \u2014 add an OpenAI second-opinion pass that ${UPGRADE_LABEL} weighs before finalizing (the result names which model ran). Other panel seats stay on their normal models.`
2923
3083
  };
2924
3084
  }
2925
3085
 
@@ -3222,8 +3382,9 @@ ${rubricText}`;
3222
3382
  const upgradeRequested = isUpgradeRequested(args);
3223
3383
  const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
3224
3384
  const auditorForCall = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : auditor;
3385
+ const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
3225
3386
  const coReason = await coReasonThenInject({
3226
- provider: pickCoReasoner(opts.providers, upgradeRequested),
3387
+ provider: coProvider,
3227
3388
  messages: msgs,
3228
3389
  maxTokens: 2048,
3229
3390
  purpose: "audit-coreason"
@@ -3307,7 +3468,7 @@ ${rubricText}`;
3307
3468
  model: UPGRADE_MODEL,
3308
3469
  label: UPGRADE_LABEL,
3309
3470
  seat: "auditor",
3310
- ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
3471
+ ...coReasoned ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
3311
3472
  };
3312
3473
  } else if (upgradeRequested) {
3313
3474
  result["reasoning_upgrade"] = {
@@ -4038,8 +4199,12 @@ var SUPER_MODELS = {
4038
4199
  // Fable 5.1 verified present on the account; 5 as the fallback for accounts
4039
4200
  // that haven't been granted 5.1 yet.
4040
4201
  anthropic: ["claude-fable-5-1", UPGRADE_MODEL],
4041
- // Astra when it exists; gpt-5.6 until then. See the note above.
4042
- openai: ["gpt-6-astra", CO_REASON_MODEL],
4202
+ // Astra is live (verified against the account's model list 2026-09-23).
4203
+ // The fallback is named explicitly rather than reusing CO_REASON_MODEL:
4204
+ // that constant means "OpenAI's top reasoning model" for the max-reasoning
4205
+ // co-reasoner, which is a different question from "what should super fall
4206
+ // back to". Sharing the symbol silently coupled two unrelated decisions.
4207
+ openai: ["gpt-6-astra", "gpt-6-sol"],
4043
4208
  // Explicitly left as-is per product decision. Note grok-4-latest is not in
4044
4209
  // xAI's published model list, but it resolves in practice — real panel calls
4045
4210
  // on it succeeded as recently as 2026-08-30 — so it is an unlisted alias
@@ -4654,10 +4819,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
4654
4819
  }
4655
4820
 
4656
4821
  // src/tools/confer.ts
4657
- var DEFERRED_OPTS = [
4658
- // empty — every confer opt runs natively except worker_tools, which
4659
- // is gated below (non-empty list → defer).
4660
- ];
4661
4822
  async function runConfer(args, opts) {
4662
4823
  const callStartedWall = performance3.now();
4663
4824
  const callStartedCpu = process.cpuUsage();
@@ -4673,16 +4834,11 @@ async function runConfer(args, opts) {
4673
4834
  rejectedWorkerTools.push(t);
4674
4835
  }
4675
4836
  }
4676
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
4677
- const needsBridge = DEFERRED_OPTS.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
4678
- if (needsBridge) {
4679
- if (opts.bridge && opts.bridge.toolNames.has("confer")) {
4680
- return await deferConfer(args, opts.bridge);
4681
- }
4837
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
4682
4838
  return errorEnvelope2(
4683
4839
  "CONFER_OPT_NOT_NATIVE",
4684
4840
  "worker_tools requested but innerCallers are not wired",
4685
- "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
4841
+ "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host."
4686
4842
  );
4687
4843
  }
4688
4844
  const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
@@ -5033,21 +5189,6 @@ function unknownProviderError(unknownNames, available) {
5033
5189
  available_now: Object.keys(available).sort()
5034
5190
  };
5035
5191
  }
5036
- async function deferConfer(args, bridge) {
5037
- const r = await bridge.callTool("confer", args);
5038
- const text = r.content[0]?.text;
5039
- if (typeof text === "string") {
5040
- try {
5041
- return JSON.parse(text);
5042
- } catch {
5043
- }
5044
- }
5045
- return errorEnvelope2(
5046
- "CONFER_BRIDGE_BAD_ENVELOPE",
5047
- "bridge returned an unparseable envelope for confer",
5048
- "Check that the Python child is healthy."
5049
- );
5050
- }
5051
5192
  function errorEnvelope2(code, message, hint) {
5052
5193
  return {
5053
5194
  tool: "confer",
@@ -5419,7 +5560,7 @@ function errorEnvelope3(code, message, hint) {
5419
5560
  transient: false
5420
5561
  };
5421
5562
  }
5422
- async function runVerify(args, bridge, fetchConfig) {
5563
+ async function runVerify(args, fetchConfig) {
5423
5564
  const checks = args["checks"];
5424
5565
  if (!Array.isArray(checks) || checks.length === 0) {
5425
5566
  return {
@@ -5431,7 +5572,6 @@ async function runVerify(args, bridge, fetchConfig) {
5431
5572
  )
5432
5573
  };
5433
5574
  }
5434
- void bridge;
5435
5575
  const allowShell = Boolean(args["allow_shell"] ?? false);
5436
5576
  const wallStart = performance4.now();
5437
5577
  const cpuStart = process.cpuUsage();
@@ -5733,7 +5873,6 @@ async function runBench(args, opts) {
5733
5873
  const innerOpts = {
5734
5874
  providers: opts.providers,
5735
5875
  allowlist: opts.allowlist ?? null,
5736
- ...opts.bridge ? { bridge: opts.bridge } : {},
5737
5876
  ...opts.moderator ? { moderator: opts.moderator } : {}
5738
5877
  };
5739
5878
  let inner;
@@ -6365,11 +6504,11 @@ function getNodeCache(cfg, repoRoot, key, nowMs) {
6365
6504
  return null;
6366
6505
  }
6367
6506
  }
6368
- function atomicWriteJson(path12, payload) {
6369
- mkdirSync3(dirname(path12), { recursive: true });
6370
- const tmp = `${path12}.${process.pid}.${Date.now()}.tmp`;
6507
+ function atomicWriteJson(path13, payload) {
6508
+ mkdirSync3(dirname(path13), { recursive: true });
6509
+ const tmp = `${path13}.${process.pid}.${Date.now()}.tmp`;
6371
6510
  writeFileSync3(tmp, JSON.stringify(payload), "utf8");
6372
- renameSync(tmp, path12);
6511
+ renameSync(tmp, path13);
6373
6512
  }
6374
6513
  function putNodeCache(cfg, repoRoot, key, value) {
6375
6514
  if (!cfg || cfg.enabled === false) return;
@@ -6427,7 +6566,6 @@ var EST_TOKENS = {
6427
6566
  med: [1500, 800],
6428
6567
  high: [2500, 1500]
6429
6568
  };
6430
- var DEFERRED_OPTS2 = [];
6431
6569
  var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
6432
6570
  function parseReactiveSignals(output) {
6433
6571
  if (typeof output !== "string" || !output.includes("<signals>")) return [];
@@ -6467,17 +6605,6 @@ async function runOrchestrate(args, opts) {
6467
6605
  );
6468
6606
  if (breakerEnv) return breakerEnv;
6469
6607
  }
6470
- const needsBridge = DEFERRED_OPTS2.some((k) => Boolean(args[k]));
6471
- if (needsBridge) {
6472
- if (opts.bridge && opts.bridge.toolNames.has("orchestrate")) {
6473
- return await deferOrchestrate(args, opts.bridge);
6474
- }
6475
- return errorEnvelope5(
6476
- "ORCHESTRATE_OPT_NOT_NATIVE",
6477
- "this orchestrate opt-in requires the Python bridge in v1",
6478
- "v1 native covers the plain DAG flow + cheap_mode. reactive (mid-flight DAG updates) still defers. Set CROSSCHECK_BRIDGE_PYTHON=1 to enable."
6479
- );
6480
- }
6481
6608
  const goal = typeof args["goal"] === "string" ? args["goal"] : null;
6482
6609
  const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
6483
6610
  if (goal === null === (dagIn === null)) {
@@ -7020,8 +7147,9 @@ ${recombineSys}` : recombineSys },
7020
7147
  provider: synthProvider.name
7021
7148
  } }
7022
7149
  );
7150
+ const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
7023
7151
  const coReason = await coReasonThenInject({
7024
- provider: pickCoReasoner(opts.providers, upgradeRequested),
7152
+ provider: coProvider,
7025
7153
  messages: recMsgs,
7026
7154
  maxTokens,
7027
7155
  purpose: "orchestrate-coreason"
@@ -7080,7 +7208,7 @@ ${recombineSys}` : recombineSys },
7080
7208
  model: UPGRADE_MODEL,
7081
7209
  label: UPGRADE_LABEL,
7082
7210
  seat: "recombine/synthesis",
7083
- ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
7211
+ ...coReasoned ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
7084
7212
  };
7085
7213
  } else if (upgradeRequested) {
7086
7214
  result["reasoning_upgrade"] = {
@@ -7418,21 +7546,6 @@ function resolveProviders3(names, available, allowlist) {
7418
7546
  }
7419
7547
  return out;
7420
7548
  }
7421
- async function deferOrchestrate(args, bridge) {
7422
- const r = await bridge.callTool("orchestrate", args);
7423
- const text = r.content[0]?.text;
7424
- if (typeof text === "string") {
7425
- try {
7426
- return JSON.parse(text);
7427
- } catch {
7428
- }
7429
- }
7430
- return errorEnvelope5(
7431
- "ORCHESTRATE_BRIDGE_BAD_ENVELOPE",
7432
- "bridge returned an unparseable envelope for orchestrate",
7433
- "Check that the Python child is healthy."
7434
- );
7435
- }
7436
7549
  function errorEnvelope5(code, message, hint, kind = "client") {
7437
7550
  return {
7438
7551
  tool: "orchestrate",
@@ -7795,7 +7908,6 @@ ${documentsPayload}`;
7795
7908
  }, {
7796
7909
  providers: opts.providers,
7797
7910
  allowlist: opts.allowlist ?? null,
7798
- ...opts.bridge ? { bridge: opts.bridge } : {},
7799
7911
  ctx
7800
7912
  });
7801
7913
  const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
@@ -7818,7 +7930,6 @@ ${scopeAnswer || "(none)"}
7818
7930
  providers: opts.providers,
7819
7931
  allowlist: opts.allowlist ?? null,
7820
7932
  moderator,
7821
- ...opts.bridge ? { bridge: opts.bridge } : {},
7822
7933
  ctx
7823
7934
  });
7824
7935
  let attempts = 1;
@@ -7853,7 +7964,6 @@ ${scopeAnswer || "(none)"}
7853
7964
  }, {
7854
7965
  providers: opts.providers,
7855
7966
  allowlist: opts.allowlist ?? null,
7856
- ...opts.bridge ? { bridge: opts.bridge } : {},
7857
7967
  ctx
7858
7968
  });
7859
7969
  }
@@ -7876,7 +7986,6 @@ ${scopeAnswer || "(none)"}
7876
7986
  }, {
7877
7987
  providers: opts.providers,
7878
7988
  allowlist: opts.allowlist ?? null,
7879
- ...opts.bridge ? { bridge: opts.bridge } : {},
7880
7989
  ctx
7881
7990
  });
7882
7991
  let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -7901,7 +8010,6 @@ ${documentsPayload}`
7901
8010
  providers: opts.providers,
7902
8011
  allowlist: opts.allowlist ?? null,
7903
8012
  moderator,
7904
- ...opts.bridge ? { bridge: opts.bridge } : {},
7905
8013
  ctx
7906
8014
  }
7907
8015
  );
@@ -7921,7 +8029,6 @@ ${documentsPayload}`
7921
8029
  }, {
7922
8030
  providers: opts.providers,
7923
8031
  allowlist: opts.allowlist ?? null,
7924
- ...opts.bridge ? { bridge: opts.bridge } : {},
7925
8032
  ctx
7926
8033
  });
7927
8034
  overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -8159,11 +8266,6 @@ function errorEnvelope6(toolName, code, message, hint) {
8159
8266
 
8160
8267
  // src/tools/coordinate.ts
8161
8268
  import { performance as performance8 } from "perf_hooks";
8162
- var DEFERRED_OPTS3 = [
8163
- // empty — every coordinate opt runs natively when its deps
8164
- // (storage / innerCallers) are wired. Without them the
8165
- // worker_tools gate still triggers a bridge defer.
8166
- ];
8167
8269
  var COORDINATE_DEFAULT_TEMP = 0.4;
8168
8270
  var ROLE_TURN_SCHEMA = {
8169
8271
  type: "object",
@@ -8218,23 +8320,18 @@ async function runCoordinate(args, opts) {
8218
8320
  rejectedWorkerTools.push(t);
8219
8321
  }
8220
8322
  }
8221
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
8222
- const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
8223
- if (needsBridge) {
8323
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
8224
8324
  if (superRequested) {
8225
8325
  return errorEnvelope7(
8226
8326
  "COORDINATE_SUPER_NOT_NATIVE",
8227
- "super mode requested but worker_tools needs the Python bridge",
8228
- "worker_tools without innerCallers wired defers to the Python bridge, which doesn't support super mode. Drop worker_tools, or wire innerCallers, to use super."
8327
+ "super mode requested with worker_tools, but innerCallers are not wired",
8328
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
8229
8329
  );
8230
8330
  }
8231
- if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
8232
- return await deferCoordinate(args, opts.bridge);
8233
- }
8234
8331
  return errorEnvelope7(
8235
8332
  "COORDINATE_OPT_NOT_NATIVE",
8236
8333
  "worker_tools requested but innerCallers are not wired",
8237
- "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
8334
+ "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host."
8238
8335
  );
8239
8336
  }
8240
8337
  const untrusted = Boolean(args["untrusted_input"]);
@@ -8426,8 +8523,9 @@ CRITIQUES:
8426
8523
  ${critiqueBlock}`
8427
8524
  }
8428
8525
  ];
8526
+ const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
8429
8527
  const coReason = await coReasonThenInject({
8430
- provider: pickCoReasoner(opts.providers, upgradeRequested),
8528
+ provider: coProvider,
8431
8529
  messages: synthMessages,
8432
8530
  maxTokens,
8433
8531
  purpose: "coordinate-coreason"
@@ -8491,7 +8589,7 @@ ${critiqueBlock}`
8491
8589
  model: superRequested ? superPrimary("anthropic") ?? UPGRADE_MODEL : UPGRADE_MODEL,
8492
8590
  label: UPGRADE_LABEL,
8493
8591
  seat: "synthesizer",
8494
- ...coReasonAns ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
8592
+ ...coReasonAns ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
8495
8593
  };
8496
8594
  } else if (upgradeRequested) {
8497
8595
  result["reasoning_upgrade"] = {
@@ -8633,21 +8731,6 @@ function unknownProviderError3(unknownNames, available) {
8633
8731
  available_now: Object.keys(available).sort()
8634
8732
  };
8635
8733
  }
8636
- async function deferCoordinate(args, bridge) {
8637
- const r = await bridge.callTool("coordinate", args);
8638
- const text = r.content[0]?.text;
8639
- if (typeof text === "string") {
8640
- try {
8641
- return JSON.parse(text);
8642
- } catch {
8643
- }
8644
- }
8645
- return errorEnvelope7(
8646
- "COORDINATE_BRIDGE_BAD_ENVELOPE",
8647
- "bridge returned an unparseable envelope for coordinate",
8648
- "Check that the Python child is healthy."
8649
- );
8650
- }
8651
8734
  function errorEnvelope7(code, message, hint) {
8652
8735
  return {
8653
8736
  tool: "coordinate",
@@ -8975,10 +9058,6 @@ function buildModeratorTranscript(transcript) {
8975
9058
 
8976
9059
  // src/tools/debate.ts
8977
9060
  import { performance as performance10 } from "perf_hooks";
8978
- var DEFERRED_OPTS4 = [
8979
- // empty — every debate opt runs natively when its deps
8980
- // (storage / innerCallers) are wired.
8981
- ];
8982
9061
  async function runDebate(args, opts) {
8983
9062
  const callStartedWall = performance10.now();
8984
9063
  const callStartedCpu = process.cpuUsage();
@@ -8996,23 +9075,18 @@ async function runDebate(args, opts) {
8996
9075
  rejectedWorkerTools.push(t);
8997
9076
  }
8998
9077
  }
8999
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
9000
- const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
9001
- if (needsBridge) {
9078
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
9002
9079
  if (superRequested) {
9003
9080
  return errorEnvelope9(
9004
9081
  "DEBATE_SUPER_NOT_NATIVE",
9005
- "super mode requested but worker_tools needs the Python bridge",
9006
- "worker_tools without innerCallers wired defers to the Python bridge, which doesn't support super mode. Drop worker_tools, or wire innerCallers, to use super."
9082
+ "super mode requested with worker_tools, but innerCallers are not wired",
9083
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
9007
9084
  );
9008
9085
  }
9009
- if (opts.bridge && opts.bridge.toolNames.has("debate")) {
9010
- return await deferDebate(args, opts.bridge);
9011
- }
9012
9086
  return errorEnvelope9(
9013
9087
  "DEBATE_OPT_NOT_NATIVE",
9014
9088
  "worker_tools requested but innerCallers are not wired",
9015
- "Native debate covers N-round + plain/structured moderator synthesis + inject_session_memory + auto_panel + extract_claims + early_stop. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
9089
+ "Native debate covers N-round + plain/structured moderator synthesis + inject_session_memory + auto_panel + extract_claims + early_stop. worker_tools needs innerCallers wired by the host."
9016
9090
  );
9017
9091
  }
9018
9092
  const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
@@ -9213,6 +9287,7 @@ ${prior.body}` });
9213
9287
  let synthesisErrors = [];
9214
9288
  let personaMeta = null;
9215
9289
  let coReasoned = false;
9290
+ let coReasonerModel = null;
9216
9291
  if (moderator) {
9217
9292
  const synthProvider = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
9218
9293
  const condensed = buildModeratorTranscript(transcript);
@@ -9240,13 +9315,16 @@ TRANSCRIPT:
9240
9315
  ${condensed}`
9241
9316
  }
9242
9317
  ];
9318
+ const openAiSeat = selected.find((p) => p.name === "openai")?.model;
9319
+ const coProvider = pickCoReasoner(opts.providers, upgradeRequested, openAiSeat);
9243
9320
  const coReason = await coReasonThenInject({
9244
- provider: pickCoReasoner(opts.providers, upgradeRequested),
9321
+ provider: coProvider,
9245
9322
  messages: synthMessages,
9246
9323
  maxTokens,
9247
9324
  purpose: "debate-coreason"
9248
9325
  });
9249
9326
  synthMessages = coReason.messages;
9327
+ coReasonerModel = coProvider?.model ?? null;
9250
9328
  if (coReason.answer) extraAnswers.push(coReason.answer);
9251
9329
  coReasoned = coReason.answer !== null;
9252
9330
  if (structuredOpt) {
@@ -9305,7 +9383,7 @@ ${condensed}`
9305
9383
  model: superRequested ? superPrimary("anthropic") ?? UPGRADE_MODEL : UPGRADE_MODEL,
9306
9384
  label: UPGRADE_LABEL,
9307
9385
  seat: "moderator synthesis",
9308
- ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
9386
+ ...coReasoned && coReasonerModel ? { co_reasoner: { model: coReasonerModel, label: coReasonLabel(coReasonerModel) } } : {}
9309
9387
  };
9310
9388
  } else if (upgradeRequested) {
9311
9389
  result["reasoning_upgrade"] = {
@@ -9445,21 +9523,6 @@ function unknownProviderError5(unknownNames, available) {
9445
9523
  available_now: Object.keys(available).sort()
9446
9524
  };
9447
9525
  }
9448
- async function deferDebate(args, bridge) {
9449
- const r = await bridge.callTool("debate", args);
9450
- const text = r.content[0]?.text;
9451
- if (typeof text === "string") {
9452
- try {
9453
- return JSON.parse(text);
9454
- } catch {
9455
- }
9456
- }
9457
- return errorEnvelope9(
9458
- "DEBATE_BRIDGE_BAD_ENVELOPE",
9459
- "bridge returned an unparseable envelope for debate",
9460
- "Check that the Python child is healthy."
9461
- );
9462
- }
9463
9526
  function errorEnvelope9(code, message, hint) {
9464
9527
  return {
9465
9528
  tool: "debate",
@@ -9479,9 +9542,6 @@ var DEFAULT_DELEGATION_LIMITS = {
9479
9542
  };
9480
9543
  async function runDelegate(args, opts) {
9481
9544
  if (!opts.storage) {
9482
- if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
9483
- return await deferDelegate(args, opts.bridge);
9484
- }
9485
9545
  return errorEnvelope10(
9486
9546
  "DELEGATE_STORAGE_UNAVAILABLE",
9487
9547
  "delegate needs the local database (for quota tracking), which isn't available",
@@ -9553,7 +9613,6 @@ async function runDelegate(args, opts) {
9553
9613
  const innerOpts = {
9554
9614
  providers: opts.providers,
9555
9615
  allowlist: opts.allowlist ?? null,
9556
- ...opts.bridge ? { bridge: opts.bridge } : {},
9557
9616
  ...opts.moderator ? { moderator: opts.moderator } : {}
9558
9617
  };
9559
9618
  let result;
@@ -9592,21 +9651,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
9592
9651
  created_at: nowEpochSeconds
9593
9652
  });
9594
9653
  }
9595
- async function deferDelegate(args, bridge) {
9596
- const r = await bridge.callTool("delegate", args);
9597
- const text = r.content[0]?.text;
9598
- if (typeof text === "string") {
9599
- try {
9600
- return JSON.parse(text);
9601
- } catch {
9602
- }
9603
- }
9604
- return errorEnvelope10(
9605
- "DELEGATE_BRIDGE_BAD_ENVELOPE",
9606
- "bridge returned an unparseable envelope for delegate",
9607
- "Check that the Python child is healthy."
9608
- );
9609
- }
9610
9654
  function errorEnvelope10(code, message, hint) {
9611
9655
  return {
9612
9656
  tool: "delegate",
@@ -9649,9 +9693,6 @@ async function runExplain(args, opts) {
9649
9693
  );
9650
9694
  }
9651
9695
  if (!opts.storage) {
9652
- if (opts.bridge && opts.bridge.toolNames.has("explain")) {
9653
- return await deferExplain(args, opts.bridge);
9654
- }
9655
9696
  return errorEnvelope11(
9656
9697
  "EXPLAIN_STORAGE_UNAVAILABLE",
9657
9698
  "explain needs the local transcript/stats database, which isn't available",
@@ -9933,21 +9974,6 @@ function pyRepr5(v) {
9933
9974
  }
9934
9975
  return String(v);
9935
9976
  }
9936
- async function deferExplain(args, bridge) {
9937
- const r = await bridge.callTool("explain", args);
9938
- const text = r.content[0]?.text;
9939
- if (typeof text === "string") {
9940
- try {
9941
- return JSON.parse(text);
9942
- } catch {
9943
- }
9944
- }
9945
- return errorEnvelope11(
9946
- "EXPLAIN_BRIDGE_BAD_ENVELOPE",
9947
- "bridge returned an unparseable envelope for explain",
9948
- "Check that the Python child is healthy."
9949
- );
9950
- }
9951
9977
  function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
9952
9978
  return {
9953
9979
  tool: "explain",
@@ -10500,9 +10526,6 @@ async function runRecall(args, opts) {
10500
10526
  if (k < 1) k = 1;
10501
10527
  if (k > 50) k = 50;
10502
10528
  if (!opts.storage) {
10503
- if (opts.bridge && opts.bridge.toolNames.has("recall")) {
10504
- return await deferRecall(args, opts.bridge);
10505
- }
10506
10529
  return errorEnvelope12(
10507
10530
  "RECALL_STORAGE_UNAVAILABLE",
10508
10531
  "recall needs the local database, which isn't available",
@@ -10555,21 +10578,6 @@ async function runRecall(args, opts) {
10555
10578
  applied_filters: applied
10556
10579
  };
10557
10580
  }
10558
- async function deferRecall(args, bridge) {
10559
- const r = await bridge.callTool("recall", args);
10560
- const text = r.content[0]?.text;
10561
- if (typeof text === "string") {
10562
- try {
10563
- return JSON.parse(text);
10564
- } catch {
10565
- }
10566
- }
10567
- return errorEnvelope12(
10568
- "RECALL_BRIDGE_BAD_ENVELOPE",
10569
- "bridge returned an unparseable envelope for recall",
10570
- "Check that the Python child is healthy."
10571
- );
10572
- }
10573
10581
  function errorEnvelope12(code, message, hint) {
10574
10582
  return {
10575
10583
  tool: "recall",
@@ -10592,9 +10600,6 @@ async function runRecommendPanel(args, opts) {
10592
10600
  );
10593
10601
  }
10594
10602
  if (!opts.storage) {
10595
- if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
10596
- return await deferRecommendPanel(args, opts.bridge);
10597
- }
10598
10603
  return errorEnvelope13(
10599
10604
  "RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
10600
10605
  "recommend_panel needs the local stats database, which isn't available",
@@ -10657,21 +10662,6 @@ async function runRecommendPanel(args, opts) {
10657
10662
  meta: result.meta
10658
10663
  };
10659
10664
  }
10660
- async function deferRecommendPanel(args, bridge) {
10661
- const r = await bridge.callTool("recommend_panel", args);
10662
- const text = r.content[0]?.text;
10663
- if (typeof text === "string") {
10664
- try {
10665
- return JSON.parse(text);
10666
- } catch {
10667
- }
10668
- }
10669
- return errorEnvelope13(
10670
- "RECOMMEND_PANEL_BRIDGE_BAD_ENVELOPE",
10671
- "bridge returned an unparseable envelope for recommend_panel",
10672
- "Check that the Python child is healthy."
10673
- );
10674
- }
10675
10665
  function errorEnvelope13(code, message, hint) {
10676
10666
  return {
10677
10667
  tool: "recommend_panel",
@@ -10701,9 +10691,6 @@ function toStringArray3(v) {
10701
10691
  import { readFileSync as readFileSync10, existsSync as existsSync8 } from "fs";
10702
10692
  async function runScoreboard(args, opts) {
10703
10693
  if (!opts.storage) {
10704
- if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
10705
- return await deferScoreboard(args, opts.bridge);
10706
- }
10707
10694
  return errorEnvelope14(
10708
10695
  "SCOREBOARD_STORAGE_UNAVAILABLE",
10709
10696
  "scoreboard needs the local stats database, which isn't available",
@@ -10826,21 +10813,6 @@ function clampInt3(raw, min, max, fallback) {
10826
10813
  if (!Number.isFinite(n)) return fallback;
10827
10814
  return Math.min(max, Math.max(min, Math.trunc(n)));
10828
10815
  }
10829
- async function deferScoreboard(args, bridge) {
10830
- const r = await bridge.callTool("scoreboard", args);
10831
- const text = r.content[0]?.text;
10832
- if (typeof text === "string") {
10833
- try {
10834
- return JSON.parse(text);
10835
- } catch {
10836
- }
10837
- }
10838
- return errorEnvelope14(
10839
- "SCOREBOARD_BRIDGE_BAD_ENVELOPE",
10840
- "bridge returned an unparseable envelope for scoreboard",
10841
- "Check that the Python child is healthy."
10842
- );
10843
- }
10844
10816
  function errorEnvelope14(code, message, hint) {
10845
10817
  return {
10846
10818
  tool: "scoreboard",
@@ -10877,9 +10849,6 @@ async function runSessionMemory(args, opts) {
10877
10849
  );
10878
10850
  }
10879
10851
  if (!opts.storage) {
10880
- if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
10881
- return await deferSessionMemory(args, opts.bridge);
10882
- }
10883
10852
  return errorEnvelope15(
10884
10853
  "SESSION_MEMORY_STORAGE_UNAVAILABLE",
10885
10854
  "session_memory needs the local database, which isn't available",
@@ -10984,21 +10953,6 @@ function clampInt4(raw, min, max, fallback) {
10984
10953
  if (!Number.isFinite(n)) return fallback;
10985
10954
  return Math.min(max, Math.max(min, Math.trunc(n)));
10986
10955
  }
10987
- async function deferSessionMemory(args, bridge) {
10988
- const r = await bridge.callTool("session_memory", args);
10989
- const text = r.content[0]?.text;
10990
- if (typeof text === "string") {
10991
- try {
10992
- return JSON.parse(text);
10993
- } catch {
10994
- }
10995
- }
10996
- return errorEnvelope15(
10997
- "SESSION_MEMORY_BRIDGE_BAD_ENVELOPE",
10998
- "bridge returned an unparseable envelope for session_memory",
10999
- "Check that the Python child is healthy."
11000
- );
11001
- }
11002
10956
  function errorEnvelope15(code, message, hint) {
11003
10957
  return {
11004
10958
  tool: "session_memory",
@@ -11329,7 +11283,7 @@ Re-emit the FULL solution. No commentary.`
11329
11283
  model: UPGRADE_MODEL,
11330
11284
  label: UPGRADE_LABEL,
11331
11285
  seat: "solver",
11332
- ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
11286
+ ...coReasoned ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
11333
11287
  };
11334
11288
  } else if (upgradeRequested) {
11335
11289
  result["reasoning_upgrade"] = {
@@ -11618,7 +11572,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11618
11572
  var DEFAULT_PACKAGE = "crosscheck-cli";
11619
11573
  var FETCH_TIMEOUT_MS = 3e3;
11620
11574
  function engineVersion() {
11621
- return true ? "0.2.26" : "0.0.0-dev";
11575
+ return true ? "0.2.28" : "0.0.0-dev";
11622
11576
  }
11623
11577
  function defaultUpdateCachePath() {
11624
11578
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -12390,12 +12344,11 @@ function helpTool() {
12390
12344
  }
12391
12345
  });
12392
12346
  }
12393
- function registerCoreTools(opts = {}) {
12394
- const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
12347
+ function registerCoreTools(o = {}) {
12395
12348
  const tools = /* @__PURE__ */ new Map();
12396
12349
  const list = [
12397
12350
  pingTool(),
12398
- verifyTool(o.bridge, o.fetchConfig),
12351
+ verifyTool(o.fetchConfig),
12399
12352
  pickTool(
12400
12353
  o.providers ?? {},
12401
12354
  o.providerAllowlist ?? null,
@@ -12407,7 +12360,6 @@ function registerCoreTools(opts = {}) {
12407
12360
  auditTool(
12408
12361
  o.providers ?? {},
12409
12362
  o.providerAllowlist ?? null,
12410
- o.bridge,
12411
12363
  o.transcriptsDir,
12412
12364
  o.pricing,
12413
12365
  o.storage,
@@ -12417,7 +12369,6 @@ function registerCoreTools(opts = {}) {
12417
12369
  conferTool(
12418
12370
  o.providers ?? {},
12419
12371
  o.providerAllowlist ?? null,
12420
- o.bridge,
12421
12372
  o.moderatorDefault ?? "anthropic",
12422
12373
  o.pricing,
12423
12374
  o.storage,
@@ -12430,7 +12381,6 @@ function registerCoreTools(opts = {}) {
12430
12381
  debateTool(
12431
12382
  o.providers ?? {},
12432
12383
  o.providerAllowlist ?? null,
12433
- o.bridge,
12434
12384
  buildInnerCallers(o),
12435
12385
  o.storage,
12436
12386
  o.pricing,
@@ -12442,7 +12392,6 @@ function registerCoreTools(opts = {}) {
12442
12392
  coordinateTool(
12443
12393
  o.providers ?? {},
12444
12394
  o.providerAllowlist ?? null,
12445
- o.bridge,
12446
12395
  buildInnerCallers(o),
12447
12396
  o.storage,
12448
12397
  o.circuitBreakers,
@@ -12453,7 +12402,6 @@ function registerCoreTools(opts = {}) {
12453
12402
  triangulateTool(
12454
12403
  o.providers ?? {},
12455
12404
  o.providerAllowlist ?? null,
12456
- o.bridge,
12457
12405
  o.storage,
12458
12406
  o.circuitBreakers,
12459
12407
  o.transcriptsDir,
@@ -12462,7 +12410,6 @@ function registerCoreTools(opts = {}) {
12462
12410
  planTool(
12463
12411
  o.providers ?? {},
12464
12412
  o.providerAllowlist ?? null,
12465
- o.bridge,
12466
12413
  o.storage,
12467
12414
  o.circuitBreakers,
12468
12415
  o.transcriptsDir,
@@ -12471,7 +12418,6 @@ function registerCoreTools(opts = {}) {
12471
12418
  critiqueTool(
12472
12419
  o.providers ?? {},
12473
12420
  o.providerAllowlist ?? null,
12474
- o.bridge,
12475
12421
  o.storage,
12476
12422
  o.circuitBreakers,
12477
12423
  o.transcriptsDir,
@@ -12480,7 +12426,6 @@ function registerCoreTools(opts = {}) {
12480
12426
  reviewTool(
12481
12427
  o.providers ?? {},
12482
12428
  o.providerAllowlist ?? null,
12483
- o.bridge,
12484
12429
  o.storage,
12485
12430
  o.circuitBreakers,
12486
12431
  o.transcriptsDir,
@@ -12488,25 +12433,23 @@ function registerCoreTools(opts = {}) {
12488
12433
  ),
12489
12434
  listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
12490
12435
  modelsTool(o.providers ?? {}, o.activeProviders ?? null),
12491
- recallTool(o.storage, o.bridge),
12492
- sessionMemoryTool(o.storage, o.bridge),
12493
- scoreboardTool(o.storage, o.bridge, o.eventsPath),
12494
- explainTool(o.storage, o.bridge, o.transcriptsDir),
12436
+ recallTool(o.storage),
12437
+ sessionMemoryTool(o.storage),
12438
+ scoreboardTool(o.storage, o.eventsPath),
12439
+ explainTool(o.storage, o.transcriptsDir),
12495
12440
  delegateTool(
12496
12441
  o.providers ?? {},
12497
12442
  o.providerAllowlist ?? null,
12498
12443
  o.storage,
12499
- o.bridge,
12500
12444
  o.moderatorDefault ?? "anthropic"
12501
12445
  ),
12502
12446
  fetchTool(o.storage, o.fetchConfig, o.repoRoot),
12503
- recommendPanelTool(o.providers ?? {}, o.storage, o.bridge),
12447
+ recommendPanelTool(o.providers ?? {}, o.storage),
12504
12448
  updateCrosscheckTool(o.repoRoot ?? null),
12505
12449
  benchTool(
12506
12450
  o.providers ?? {},
12507
12451
  o.providerAllowlist ?? null,
12508
12452
  o.storage,
12509
- o.bridge,
12510
12453
  o.moderatorDefault ?? "anthropic",
12511
12454
  o.benchGoldensDir,
12512
12455
  o.circuitBreakers,
@@ -12517,7 +12460,6 @@ function registerCoreTools(opts = {}) {
12517
12460
  solveTool(
12518
12461
  o.providers ?? {},
12519
12462
  o.providerAllowlist ?? null,
12520
- o.bridge,
12521
12463
  o.storage,
12522
12464
  o.circuitBreakers,
12523
12465
  o.transcriptsDir,
@@ -12526,7 +12468,6 @@ function registerCoreTools(opts = {}) {
12526
12468
  orchestrateTool(
12527
12469
  o.providers ?? {},
12528
12470
  o.providerAllowlist ?? null,
12529
- o.bridge,
12530
12471
  o.moderatorDefault ?? "anthropic",
12531
12472
  o.storage,
12532
12473
  o.pricing,
@@ -12573,7 +12514,6 @@ function createTool(o, toolName, cheapDefault) {
12573
12514
  providers: o.providers ?? {},
12574
12515
  allowlist: o.providerAllowlist ?? null,
12575
12516
  ...o.storage ? { storage: o.storage } : {},
12576
- ...o.bridge ? { bridge: o.bridge } : {},
12577
12517
  ...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
12578
12518
  ...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
12579
12519
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {},
@@ -12582,7 +12522,7 @@ function createTool(o, toolName, cheapDefault) {
12582
12522
  })
12583
12523
  };
12584
12524
  }
12585
- function orchestrateTool(providers, allowlist, bridge, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12525
+ function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12586
12526
  return {
12587
12527
  name: "orchestrate",
12588
12528
  description: "Plan and execute a DAG of LLM subtasks. Either supply a `goal` (planner will draft the DAG) OR a hand-authored `dag`. Workers run topologically; recombine produces a single `final`. Covers the sequential flow, cheap_mode (per-node tier picking), and reactive (mid-flight DAG updates) \u2014 all native.",
@@ -12607,7 +12547,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12607
12547
  providers,
12608
12548
  allowlist,
12609
12549
  moderator,
12610
- ...bridge ? { bridge } : {},
12611
12550
  ...storage ? { storage } : {},
12612
12551
  ...pricing ? { pricing } : {},
12613
12552
  ...breakers ? { breakers } : {},
@@ -12617,7 +12556,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12617
12556
  })
12618
12557
  };
12619
12558
  }
12620
- function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12559
+ function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12621
12560
  return {
12622
12561
  name: "solve",
12623
12562
  description: "Iterative LLM solver. Generates a proposal, verifies it against the supplied verifier, and retries with feedback up to max_attempts. Verifier kinds: regex_response and shell (run in a native sandbox with wall-clock + optional memory/CPU limits). With target_path, returns a unified-diff patch.",
@@ -12639,7 +12578,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
12639
12578
  handler: (args) => runSolve(args, {
12640
12579
  providers,
12641
12580
  allowlist,
12642
- ...bridge ? { bridge } : {},
12643
12581
  ...storage ? { storage } : {},
12644
12582
  ...breakers ? { breakers } : {},
12645
12583
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12678,7 +12616,7 @@ function configPinTool(repoRoot, config2, rejectDriftEnv) {
12678
12616
  }
12679
12617
  };
12680
12618
  }
12681
- function benchTool(providers, allowlist, storage, bridge, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12619
+ function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12682
12620
  return {
12683
12621
  name: "bench",
12684
12622
  description: "Run benchmark goldens against each provider's confer/review output. Each golden: {name, tool_call: confer|review, args, verifiers[]}. Returns per-provider pass/fail/error + a ranking sorted by score. Records ballots into provider_stats when storage is wired (used by triangulate's win-rate weights).",
@@ -12697,7 +12635,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
12697
12635
  allowlist,
12698
12636
  moderator,
12699
12637
  ...storage ? { storage } : {},
12700
- ...bridge ? { bridge } : {},
12701
12638
  ...defaultGoldensDir ? { defaultGoldensDir } : {},
12702
12639
  ...breakers ? { breakers } : {},
12703
12640
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12724,7 +12661,7 @@ function updateCrosscheckTool(repoRoot) {
12724
12661
  }
12725
12662
  };
12726
12663
  }
12727
- function recommendPanelTool(providers, storage, bridge) {
12664
+ function recommendPanelTool(providers, storage) {
12728
12665
  return {
12729
12666
  name: "recommend_panel",
12730
12667
  description: "Recommend a minimal effective panel for a given purpose, based on historical usage_log + provider_stats. Cold-start falls back to the configured panel ordered by win-rate.",
@@ -12742,8 +12679,7 @@ function recommendPanelTool(providers, storage, bridge) {
12742
12679
  },
12743
12680
  handler: (args) => runRecommendPanel(args, {
12744
12681
  providers,
12745
- ...storage ? { storage } : {},
12746
- ...bridge ? { bridge } : {}
12682
+ ...storage ? { storage } : {}
12747
12683
  })
12748
12684
  };
12749
12685
  }
@@ -12768,7 +12704,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
12768
12704
  })
12769
12705
  };
12770
12706
  }
12771
- function delegateTool(providers, allowlist, storage, bridge, moderator) {
12707
+ function delegateTool(providers, allowlist, storage, moderator) {
12772
12708
  return {
12773
12709
  name: "delegate",
12774
12710
  description: "Run a delegable tool (confer | review) restricted to a single named provider, with explicit quota check. Records every attempt (accepted or refused) to the delegations table; quota in the response reflects counts AFTER the current call.",
@@ -12788,12 +12724,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
12788
12724
  providers,
12789
12725
  allowlist,
12790
12726
  moderator,
12791
- ...storage ? { storage } : {},
12792
- ...bridge ? { bridge } : {}
12727
+ ...storage ? { storage } : {}
12793
12728
  })
12794
12729
  };
12795
12730
  }
12796
- function explainTool(storage, bridge, transcriptsDir) {
12731
+ function explainTool(storage, transcriptsDir) {
12797
12732
  return {
12798
12733
  name: "explain",
12799
12734
  description: "Replay a session as a navigable tree with cost/latency annotations. Reads usage_log + optionally walks the transcripts directory for per-tool summaries.",
@@ -12811,12 +12746,11 @@ function explainTool(storage, bridge, transcriptsDir) {
12811
12746
  },
12812
12747
  handler: (args) => runExplain(args, {
12813
12748
  ...storage ? { storage } : {},
12814
- ...bridge ? { bridge } : {},
12815
12749
  ...transcriptsDir ? { transcriptsDir } : {}
12816
12750
  })
12817
12751
  };
12818
12752
  }
12819
- function scoreboardTool(storage, bridge, eventsPath) {
12753
+ function scoreboardTool(storage, eventsPath) {
12820
12754
  return {
12821
12755
  name: "scoreboard",
12822
12756
  description: "Aggregate provider ballot stats + delegation counts + table totals. Supports top_k (rank limit) and recent_limit (tail of events.jsonl when configured). Reads the engine's local stats database (auto-created at <data dir>/db.sqlite).",
@@ -12830,12 +12764,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
12830
12764
  },
12831
12765
  handler: (args) => runScoreboard(args, {
12832
12766
  ...storage ? { storage } : {},
12833
- ...bridge ? { bridge } : {},
12834
12767
  ...eventsPath ? { eventsPath } : {}
12835
12768
  })
12836
12769
  };
12837
12770
  }
12838
- function sessionMemoryTool(storage, bridge) {
12771
+ function sessionMemoryTool(storage) {
12839
12772
  return {
12840
12773
  name: "session_memory",
12841
12774
  description: "CRUD over the per-session working memory ledger. Actions: list, add, mark_stale, clear. Uses the engine's local database (auto-created at <data dir>/db.sqlite).",
@@ -12858,15 +12791,14 @@ function sessionMemoryTool(storage, bridge) {
12858
12791
  required: ["action", "session_id"]
12859
12792
  },
12860
12793
  handler: (args) => runSessionMemory(args, {
12861
- ...storage ? { storage } : {},
12862
- ...bridge ? { bridge } : {}
12794
+ ...storage ? { storage } : {}
12863
12795
  })
12864
12796
  };
12865
12797
  }
12866
- function recallTool(storage, bridge) {
12798
+ function recallTool(storage) {
12867
12799
  return {
12868
12800
  name: "recall",
12869
- description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter; falls back to the Python bridge when not available.",
12801
+ description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter.",
12870
12802
  inputSchema: {
12871
12803
  type: "object",
12872
12804
  additionalProperties: true,
@@ -12880,8 +12812,7 @@ function recallTool(storage, bridge) {
12880
12812
  required: ["query"]
12881
12813
  },
12882
12814
  handler: (args) => runRecall(args, {
12883
- ...storage ? { storage } : {},
12884
- ...bridge ? { bridge } : {}
12815
+ ...storage ? { storage } : {}
12885
12816
  })
12886
12817
  };
12887
12818
  }
@@ -12917,7 +12848,7 @@ function modelsTool(providers, activeProviders) {
12917
12848
  handler: async (args) => runModels(args, { providers, activeProviders })
12918
12849
  };
12919
12850
  }
12920
- function reviewTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12851
+ function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12921
12852
  return {
12922
12853
  name: "review",
12923
12854
  description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
@@ -12936,7 +12867,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12936
12867
  handler: (args) => runReview(args, {
12937
12868
  providers,
12938
12869
  allowlist,
12939
- ...bridge ? { bridge } : {},
12940
12870
  ...storage ? { storage } : {},
12941
12871
  ...breakers ? { breakers } : {},
12942
12872
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12944,7 +12874,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12944
12874
  })
12945
12875
  };
12946
12876
  }
12947
- function critiqueTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12877
+ function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12948
12878
  return {
12949
12879
  name: "critique",
12950
12880
  description: "Have each LLM panelist list the top weaknesses of a proposed answer or approach (severity-rated). Returns per-provider weakness lists + a merged list ordered by severity.",
@@ -12964,7 +12894,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
12964
12894
  handler: (args) => runCritique(args, {
12965
12895
  providers,
12966
12896
  allowlist,
12967
- ...bridge ? { bridge } : {},
12968
12897
  ...storage ? { storage } : {},
12969
12898
  ...breakers ? { breakers } : {},
12970
12899
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12972,7 +12901,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
12972
12901
  })
12973
12902
  };
12974
12903
  }
12975
- function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12904
+ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12976
12905
  return {
12977
12906
  name: "plan",
12978
12907
  description: 'Have an LLM panel debate a step-by-step plan for the stated goal under the given constraints. Returns the debate envelope with a moderator-synthesised plan. Defaults to `mode: "fast"` (2 rounds + early_stop) \u2014 set `mode: "thorough"` for 5 rounds without early_stop. Explicit `max_rounds` / `early_stop` / `early_stop_threshold` always override the mode preset. Use `structured: true` for schema-validated synthesis.',
@@ -12999,7 +12928,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
12999
12928
  handler: (args) => runPlan(args, {
13000
12929
  providers,
13001
12930
  allowlist,
13002
- ...bridge ? { bridge } : {},
13003
12931
  ...storage ? { storage } : {},
13004
12932
  ...breakers ? { breakers } : {},
13005
12933
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13007,7 +12935,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13007
12935
  })
13008
12936
  };
13009
12937
  }
13010
- function triangulateTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12938
+ function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13011
12939
  return {
13012
12940
  name: "triangulate",
13013
12941
  description: "Run a coordinate flow and reshape the output as a consensus + minority report with per-provider weights. v1 uses 1.0 weights (matches a fresh provider_stats DB); future versions thread real win-rate weights when the DB layer ports.",
@@ -13028,7 +12956,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13028
12956
  handler: (args) => runTriangulate(args, {
13029
12957
  providers,
13030
12958
  allowlist,
13031
- ...bridge ? { bridge } : {},
13032
12959
  ...storage ? { storage } : {},
13033
12960
  ...breakers ? { breakers } : {},
13034
12961
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13036,7 +12963,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13036
12963
  })
13037
12964
  };
13038
12965
  }
13039
- function coordinateTool(providers, allowlist, bridge, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
12966
+ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13040
12967
  return {
13041
12968
  name: "coordinate",
13042
12969
  description: "Run a three-role coordination flow (proposer \u2192 critics \u2192 synthesizer) with structured output at every step. Native opts: untrusted_input (canary + neutralize), worker_tools (bounded ReAct on proposer + critic roles; synth never sees inner tools), inject_session_memory (storage-backed working-memory block prepended to the topic).",
@@ -13061,7 +12988,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13061
12988
  handler: (args) => runCoordinate(args, {
13062
12989
  providers,
13063
12990
  allowlist,
13064
- ...bridge ? { bridge } : {},
13065
12991
  innerCallers,
13066
12992
  ...storage ? { storage } : {},
13067
12993
  ...breakers ? { breakers } : {},
@@ -13071,7 +12997,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13071
12997
  })
13072
12998
  };
13073
12999
  }
13074
- function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13000
+ function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13075
13001
  return {
13076
13002
  name: "debate",
13077
13003
  description: "Run a multi-round debate between LLM providers and synthesise the result via a moderator. Native opts: inject_session_memory, auto_panel, worker_tools, structured synthesis (schema-validated), extract_claims (final-round distillation), early_stop (post-round agreement check).",
@@ -13101,7 +13027,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
13101
13027
  handler: (args) => runDebate(args, {
13102
13028
  providers,
13103
13029
  allowlist,
13104
- ...bridge ? { bridge } : {},
13105
13030
  innerCallers,
13106
13031
  ...storage ? { storage } : {},
13107
13032
  ...pricing ? { pricing } : {},
@@ -13121,10 +13046,10 @@ function buildInnerCallers(o) {
13121
13046
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {}
13122
13047
  });
13123
13048
  }
13124
- out.verify = (args) => runVerify(args, o.bridge, o.fetchConfig);
13049
+ out.verify = (args) => runVerify(args, o.fetchConfig);
13125
13050
  return out;
13126
13051
  }
13127
- function conferTool(providers, allowlist, bridge, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13052
+ function conferTool(providers, allowlist, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13128
13053
  return {
13129
13054
  name: "confer",
13130
13055
  description: "Ask a panel of LLM providers the same question; return one answer per provider. Native opts: untrusted_input (canary + neutralization), early_stop (cheap-tier agreement check after first 2 panelists when N>=3), extract_claims (cheap-tier extractor with per-provider support maps), inject_session_memory (storage-backed working-memory block prepended to the first user message), auto_panel (router-driven top-N panel pick), worker_tools (bounded ReAct loop per panelist when innerCallers are wired by the host).",
@@ -13151,7 +13076,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13151
13076
  handler: (args) => runConfer(args, {
13152
13077
  providers,
13153
13078
  allowlist,
13154
- ...bridge ? { bridge } : {},
13155
13079
  moderator,
13156
13080
  ...pricing ? { pricing } : {},
13157
13081
  ...storage ? { storage } : {},
@@ -13163,7 +13087,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13163
13087
  })
13164
13088
  };
13165
13089
  }
13166
- function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storage, breakers, repoRoot) {
13090
+ function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
13167
13091
  return {
13168
13092
  name: "audit",
13169
13093
  description: "Score a piece of output against an audit rubric. Single-judge by default; coalesce-mode (multi-judge consensus) and panel-exhausted self-audit run natively. cheap_mode picks the cheapest 'med'-tier model as auditor when a pricing.json is wired. session_id-only inputs load the latest transcript automatically when a transcripts directory is wired.",
@@ -13189,7 +13113,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
13189
13113
  handler: (args) => runAudit(args, {
13190
13114
  providers,
13191
13115
  allowlist,
13192
- ...bridge ? { bridge } : {},
13193
13116
  ...transcriptsDir ? { transcriptsDir } : {},
13194
13117
  ...pricing ? { pricing } : {},
13195
13118
  ...storage ? { storage } : {},
@@ -13253,7 +13176,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
13253
13176
  })
13254
13177
  };
13255
13178
  }
13256
- function verifyTool(bridge, fetchConfig) {
13179
+ function verifyTool(fetchConfig) {
13257
13180
  return {
13258
13181
  name: "verify",
13259
13182
  description: "Run a list of deterministic property checks against caller-supplied data. No LLM calls; everything is local. Returns per-check {passed, reason} plus all_passed / summary / timing fields. Supports the text kinds (contains, not_contains, regex_match, contains_any, contains_all, min_length), shell (sandboxed subprocess with timeout + Unix pgid isolation), and url_head (HEAD request gated by fetch.url_allowlist). All kinds run natively.",
@@ -13271,7 +13194,7 @@ function verifyTool(bridge, fetchConfig) {
13271
13194
  },
13272
13195
  required: ["checks"]
13273
13196
  },
13274
- handler: (args) => runVerify(args, bridge, fetchConfig)
13197
+ handler: (args) => runVerify(args, fetchConfig)
13275
13198
  };
13276
13199
  }
13277
13200
  function pingTool() {
@@ -13355,6 +13278,64 @@ async function flush() {
13355
13278
  }
13356
13279
  }
13357
13280
 
13281
+ // src/core/process-registry.ts
13282
+ import { mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync13, rmSync, writeFileSync as writeFileSync8 } from "fs";
13283
+ import os2 from "os";
13284
+ import path11 from "path";
13285
+ function registryDir(env = process.env) {
13286
+ const base = env["CROSSCHECK_DATA_DIR"] || path11.join(env["HOME"] ?? env["USERPROFILE"] ?? os2.homedir(), ".crosscheck");
13287
+ return path11.join(base, "procs");
13288
+ }
13289
+ function isAlive(pid) {
13290
+ try {
13291
+ process.kill(pid, 0);
13292
+ return true;
13293
+ } catch (err) {
13294
+ return err.code === "EPERM";
13295
+ }
13296
+ }
13297
+ function listProcesses(installedVersion, env = process.env, now = Date.now()) {
13298
+ const dir = registryDir(env);
13299
+ let files;
13300
+ try {
13301
+ files = readdirSync5(dir).filter((f) => f.endsWith(".json"));
13302
+ } catch {
13303
+ return [];
13304
+ }
13305
+ const out = [];
13306
+ for (const f of files) {
13307
+ let rec;
13308
+ try {
13309
+ rec = JSON.parse(readFileSync13(path11.join(dir, f), "utf8"));
13310
+ } catch {
13311
+ try {
13312
+ rmSync(path11.join(dir, f), { force: true });
13313
+ } catch {
13314
+ }
13315
+ continue;
13316
+ }
13317
+ if (typeof rec.pid !== "number") continue;
13318
+ const alive = isAlive(rec.pid);
13319
+ if (!alive) {
13320
+ try {
13321
+ rmSync(path11.join(dir, f), { force: true });
13322
+ } catch {
13323
+ }
13324
+ continue;
13325
+ }
13326
+ out.push({
13327
+ ...rec,
13328
+ alive,
13329
+ outdated: Boolean(rec.version) && rec.version !== installedVersion,
13330
+ ageMs: Math.max(0, now - (rec.startedAt ?? now))
13331
+ });
13332
+ }
13333
+ return out.sort((a, b) => a.startedAt - b.startedAt);
13334
+ }
13335
+ function processRegistryPath(env = process.env) {
13336
+ return registryDir(env);
13337
+ }
13338
+
13358
13339
  // src/entrypoints/embed.ts
13359
13340
  var KEY_ENV = {
13360
13341
  anthropic: "ANTHROPIC_API_KEY",
@@ -13411,7 +13392,7 @@ function errorOf(answer) {
13411
13392
  }
13412
13393
  function bundledPricingPath() {
13413
13394
  try {
13414
- return path11.join(path11.dirname(fileURLToPath2(import.meta.url)), "pricing.json");
13395
+ return path12.join(path12.dirname(fileURLToPath2(import.meta.url)), "pricing.json");
13415
13396
  } catch {
13416
13397
  return void 0;
13417
13398
  }
@@ -13554,6 +13535,9 @@ export {
13554
13535
  KEY_ENV as __KEY_ENV,
13555
13536
  MODEL_ENV as __MODEL_ENV,
13556
13537
  __test_internals,
13557
- createEmbeddedEngine
13538
+ createEmbeddedEngine,
13539
+ isAlive,
13540
+ listProcesses,
13541
+ processRegistryPath
13558
13542
  };
13559
13543
  //# sourceMappingURL=embed.js.map