crosscheck-mcp 0.2.27 → 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) {
@@ -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.27" : "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,
@@ -4671,10 +4819,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
4671
4819
  }
4672
4820
 
4673
4821
  // src/tools/confer.ts
4674
- var DEFERRED_OPTS = [
4675
- // empty — every confer opt runs natively except worker_tools, which
4676
- // is gated below (non-empty list → defer).
4677
- ];
4678
4822
  async function runConfer(args, opts) {
4679
4823
  const callStartedWall = performance3.now();
4680
4824
  const callStartedCpu = process.cpuUsage();
@@ -4690,16 +4834,11 @@ async function runConfer(args, opts) {
4690
4834
  rejectedWorkerTools.push(t);
4691
4835
  }
4692
4836
  }
4693
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
4694
- const needsBridge = DEFERRED_OPTS.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
4695
- if (needsBridge) {
4696
- if (opts.bridge && opts.bridge.toolNames.has("confer")) {
4697
- return await deferConfer(args, opts.bridge);
4698
- }
4837
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
4699
4838
  return errorEnvelope2(
4700
4839
  "CONFER_OPT_NOT_NATIVE",
4701
4840
  "worker_tools requested but innerCallers are not wired",
4702
- "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."
4703
4842
  );
4704
4843
  }
4705
4844
  const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
@@ -5050,21 +5189,6 @@ function unknownProviderError(unknownNames, available) {
5050
5189
  available_now: Object.keys(available).sort()
5051
5190
  };
5052
5191
  }
5053
- async function deferConfer(args, bridge) {
5054
- const r = await bridge.callTool("confer", args);
5055
- const text = r.content[0]?.text;
5056
- if (typeof text === "string") {
5057
- try {
5058
- return JSON.parse(text);
5059
- } catch {
5060
- }
5061
- }
5062
- return errorEnvelope2(
5063
- "CONFER_BRIDGE_BAD_ENVELOPE",
5064
- "bridge returned an unparseable envelope for confer",
5065
- "Check that the Python child is healthy."
5066
- );
5067
- }
5068
5192
  function errorEnvelope2(code, message, hint) {
5069
5193
  return {
5070
5194
  tool: "confer",
@@ -5436,7 +5560,7 @@ function errorEnvelope3(code, message, hint) {
5436
5560
  transient: false
5437
5561
  };
5438
5562
  }
5439
- async function runVerify(args, bridge, fetchConfig) {
5563
+ async function runVerify(args, fetchConfig) {
5440
5564
  const checks = args["checks"];
5441
5565
  if (!Array.isArray(checks) || checks.length === 0) {
5442
5566
  return {
@@ -5448,7 +5572,6 @@ async function runVerify(args, bridge, fetchConfig) {
5448
5572
  )
5449
5573
  };
5450
5574
  }
5451
- void bridge;
5452
5575
  const allowShell = Boolean(args["allow_shell"] ?? false);
5453
5576
  const wallStart = performance4.now();
5454
5577
  const cpuStart = process.cpuUsage();
@@ -5750,7 +5873,6 @@ async function runBench(args, opts) {
5750
5873
  const innerOpts = {
5751
5874
  providers: opts.providers,
5752
5875
  allowlist: opts.allowlist ?? null,
5753
- ...opts.bridge ? { bridge: opts.bridge } : {},
5754
5876
  ...opts.moderator ? { moderator: opts.moderator } : {}
5755
5877
  };
5756
5878
  let inner;
@@ -6382,11 +6504,11 @@ function getNodeCache(cfg, repoRoot, key, nowMs) {
6382
6504
  return null;
6383
6505
  }
6384
6506
  }
6385
- function atomicWriteJson(path12, payload) {
6386
- mkdirSync3(dirname(path12), { recursive: true });
6387
- 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`;
6388
6510
  writeFileSync3(tmp, JSON.stringify(payload), "utf8");
6389
- renameSync(tmp, path12);
6511
+ renameSync(tmp, path13);
6390
6512
  }
6391
6513
  function putNodeCache(cfg, repoRoot, key, value) {
6392
6514
  if (!cfg || cfg.enabled === false) return;
@@ -6444,7 +6566,6 @@ var EST_TOKENS = {
6444
6566
  med: [1500, 800],
6445
6567
  high: [2500, 1500]
6446
6568
  };
6447
- var DEFERRED_OPTS2 = [];
6448
6569
  var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
6449
6570
  function parseReactiveSignals(output) {
6450
6571
  if (typeof output !== "string" || !output.includes("<signals>")) return [];
@@ -6484,17 +6605,6 @@ async function runOrchestrate(args, opts) {
6484
6605
  );
6485
6606
  if (breakerEnv) return breakerEnv;
6486
6607
  }
6487
- const needsBridge = DEFERRED_OPTS2.some((k) => Boolean(args[k]));
6488
- if (needsBridge) {
6489
- if (opts.bridge && opts.bridge.toolNames.has("orchestrate")) {
6490
- return await deferOrchestrate(args, opts.bridge);
6491
- }
6492
- return errorEnvelope5(
6493
- "ORCHESTRATE_OPT_NOT_NATIVE",
6494
- "this orchestrate opt-in requires the Python bridge in v1",
6495
- "v1 native covers the plain DAG flow + cheap_mode. reactive (mid-flight DAG updates) still defers. Set CROSSCHECK_BRIDGE_PYTHON=1 to enable."
6496
- );
6497
- }
6498
6608
  const goal = typeof args["goal"] === "string" ? args["goal"] : null;
6499
6609
  const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
6500
6610
  if (goal === null === (dagIn === null)) {
@@ -7436,21 +7546,6 @@ function resolveProviders3(names, available, allowlist) {
7436
7546
  }
7437
7547
  return out;
7438
7548
  }
7439
- async function deferOrchestrate(args, bridge) {
7440
- const r = await bridge.callTool("orchestrate", args);
7441
- const text = r.content[0]?.text;
7442
- if (typeof text === "string") {
7443
- try {
7444
- return JSON.parse(text);
7445
- } catch {
7446
- }
7447
- }
7448
- return errorEnvelope5(
7449
- "ORCHESTRATE_BRIDGE_BAD_ENVELOPE",
7450
- "bridge returned an unparseable envelope for orchestrate",
7451
- "Check that the Python child is healthy."
7452
- );
7453
- }
7454
7549
  function errorEnvelope5(code, message, hint, kind = "client") {
7455
7550
  return {
7456
7551
  tool: "orchestrate",
@@ -7813,7 +7908,6 @@ ${documentsPayload}`;
7813
7908
  }, {
7814
7909
  providers: opts.providers,
7815
7910
  allowlist: opts.allowlist ?? null,
7816
- ...opts.bridge ? { bridge: opts.bridge } : {},
7817
7911
  ctx
7818
7912
  });
7819
7913
  const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
@@ -7836,7 +7930,6 @@ ${scopeAnswer || "(none)"}
7836
7930
  providers: opts.providers,
7837
7931
  allowlist: opts.allowlist ?? null,
7838
7932
  moderator,
7839
- ...opts.bridge ? { bridge: opts.bridge } : {},
7840
7933
  ctx
7841
7934
  });
7842
7935
  let attempts = 1;
@@ -7871,7 +7964,6 @@ ${scopeAnswer || "(none)"}
7871
7964
  }, {
7872
7965
  providers: opts.providers,
7873
7966
  allowlist: opts.allowlist ?? null,
7874
- ...opts.bridge ? { bridge: opts.bridge } : {},
7875
7967
  ctx
7876
7968
  });
7877
7969
  }
@@ -7894,7 +7986,6 @@ ${scopeAnswer || "(none)"}
7894
7986
  }, {
7895
7987
  providers: opts.providers,
7896
7988
  allowlist: opts.allowlist ?? null,
7897
- ...opts.bridge ? { bridge: opts.bridge } : {},
7898
7989
  ctx
7899
7990
  });
7900
7991
  let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -7919,7 +8010,6 @@ ${documentsPayload}`
7919
8010
  providers: opts.providers,
7920
8011
  allowlist: opts.allowlist ?? null,
7921
8012
  moderator,
7922
- ...opts.bridge ? { bridge: opts.bridge } : {},
7923
8013
  ctx
7924
8014
  }
7925
8015
  );
@@ -7939,7 +8029,6 @@ ${documentsPayload}`
7939
8029
  }, {
7940
8030
  providers: opts.providers,
7941
8031
  allowlist: opts.allowlist ?? null,
7942
- ...opts.bridge ? { bridge: opts.bridge } : {},
7943
8032
  ctx
7944
8033
  });
7945
8034
  overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -8177,11 +8266,6 @@ function errorEnvelope6(toolName, code, message, hint) {
8177
8266
 
8178
8267
  // src/tools/coordinate.ts
8179
8268
  import { performance as performance8 } from "perf_hooks";
8180
- var DEFERRED_OPTS3 = [
8181
- // empty — every coordinate opt runs natively when its deps
8182
- // (storage / innerCallers) are wired. Without them the
8183
- // worker_tools gate still triggers a bridge defer.
8184
- ];
8185
8269
  var COORDINATE_DEFAULT_TEMP = 0.4;
8186
8270
  var ROLE_TURN_SCHEMA = {
8187
8271
  type: "object",
@@ -8236,23 +8320,18 @@ async function runCoordinate(args, opts) {
8236
8320
  rejectedWorkerTools.push(t);
8237
8321
  }
8238
8322
  }
8239
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
8240
- const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
8241
- if (needsBridge) {
8323
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
8242
8324
  if (superRequested) {
8243
8325
  return errorEnvelope7(
8244
8326
  "COORDINATE_SUPER_NOT_NATIVE",
8245
- "super mode requested but worker_tools needs the Python bridge",
8246
- "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."
8247
8329
  );
8248
8330
  }
8249
- if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
8250
- return await deferCoordinate(args, opts.bridge);
8251
- }
8252
8331
  return errorEnvelope7(
8253
8332
  "COORDINATE_OPT_NOT_NATIVE",
8254
8333
  "worker_tools requested but innerCallers are not wired",
8255
- "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."
8256
8335
  );
8257
8336
  }
8258
8337
  const untrusted = Boolean(args["untrusted_input"]);
@@ -8652,21 +8731,6 @@ function unknownProviderError3(unknownNames, available) {
8652
8731
  available_now: Object.keys(available).sort()
8653
8732
  };
8654
8733
  }
8655
- async function deferCoordinate(args, bridge) {
8656
- const r = await bridge.callTool("coordinate", args);
8657
- const text = r.content[0]?.text;
8658
- if (typeof text === "string") {
8659
- try {
8660
- return JSON.parse(text);
8661
- } catch {
8662
- }
8663
- }
8664
- return errorEnvelope7(
8665
- "COORDINATE_BRIDGE_BAD_ENVELOPE",
8666
- "bridge returned an unparseable envelope for coordinate",
8667
- "Check that the Python child is healthy."
8668
- );
8669
- }
8670
8734
  function errorEnvelope7(code, message, hint) {
8671
8735
  return {
8672
8736
  tool: "coordinate",
@@ -8994,10 +9058,6 @@ function buildModeratorTranscript(transcript) {
8994
9058
 
8995
9059
  // src/tools/debate.ts
8996
9060
  import { performance as performance10 } from "perf_hooks";
8997
- var DEFERRED_OPTS4 = [
8998
- // empty — every debate opt runs natively when its deps
8999
- // (storage / innerCallers) are wired.
9000
- ];
9001
9061
  async function runDebate(args, opts) {
9002
9062
  const callStartedWall = performance10.now();
9003
9063
  const callStartedCpu = process.cpuUsage();
@@ -9015,23 +9075,18 @@ async function runDebate(args, opts) {
9015
9075
  rejectedWorkerTools.push(t);
9016
9076
  }
9017
9077
  }
9018
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
9019
- const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
9020
- if (needsBridge) {
9078
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
9021
9079
  if (superRequested) {
9022
9080
  return errorEnvelope9(
9023
9081
  "DEBATE_SUPER_NOT_NATIVE",
9024
- "super mode requested but worker_tools needs the Python bridge",
9025
- "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."
9026
9084
  );
9027
9085
  }
9028
- if (opts.bridge && opts.bridge.toolNames.has("debate")) {
9029
- return await deferDebate(args, opts.bridge);
9030
- }
9031
9086
  return errorEnvelope9(
9032
9087
  "DEBATE_OPT_NOT_NATIVE",
9033
9088
  "worker_tools requested but innerCallers are not wired",
9034
- "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."
9035
9090
  );
9036
9091
  }
9037
9092
  const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
@@ -9468,21 +9523,6 @@ function unknownProviderError5(unknownNames, available) {
9468
9523
  available_now: Object.keys(available).sort()
9469
9524
  };
9470
9525
  }
9471
- async function deferDebate(args, bridge) {
9472
- const r = await bridge.callTool("debate", args);
9473
- const text = r.content[0]?.text;
9474
- if (typeof text === "string") {
9475
- try {
9476
- return JSON.parse(text);
9477
- } catch {
9478
- }
9479
- }
9480
- return errorEnvelope9(
9481
- "DEBATE_BRIDGE_BAD_ENVELOPE",
9482
- "bridge returned an unparseable envelope for debate",
9483
- "Check that the Python child is healthy."
9484
- );
9485
- }
9486
9526
  function errorEnvelope9(code, message, hint) {
9487
9527
  return {
9488
9528
  tool: "debate",
@@ -9502,9 +9542,6 @@ var DEFAULT_DELEGATION_LIMITS = {
9502
9542
  };
9503
9543
  async function runDelegate(args, opts) {
9504
9544
  if (!opts.storage) {
9505
- if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
9506
- return await deferDelegate(args, opts.bridge);
9507
- }
9508
9545
  return errorEnvelope10(
9509
9546
  "DELEGATE_STORAGE_UNAVAILABLE",
9510
9547
  "delegate needs the local database (for quota tracking), which isn't available",
@@ -9576,7 +9613,6 @@ async function runDelegate(args, opts) {
9576
9613
  const innerOpts = {
9577
9614
  providers: opts.providers,
9578
9615
  allowlist: opts.allowlist ?? null,
9579
- ...opts.bridge ? { bridge: opts.bridge } : {},
9580
9616
  ...opts.moderator ? { moderator: opts.moderator } : {}
9581
9617
  };
9582
9618
  let result;
@@ -9615,21 +9651,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
9615
9651
  created_at: nowEpochSeconds
9616
9652
  });
9617
9653
  }
9618
- async function deferDelegate(args, bridge) {
9619
- const r = await bridge.callTool("delegate", args);
9620
- const text = r.content[0]?.text;
9621
- if (typeof text === "string") {
9622
- try {
9623
- return JSON.parse(text);
9624
- } catch {
9625
- }
9626
- }
9627
- return errorEnvelope10(
9628
- "DELEGATE_BRIDGE_BAD_ENVELOPE",
9629
- "bridge returned an unparseable envelope for delegate",
9630
- "Check that the Python child is healthy."
9631
- );
9632
- }
9633
9654
  function errorEnvelope10(code, message, hint) {
9634
9655
  return {
9635
9656
  tool: "delegate",
@@ -9672,9 +9693,6 @@ async function runExplain(args, opts) {
9672
9693
  );
9673
9694
  }
9674
9695
  if (!opts.storage) {
9675
- if (opts.bridge && opts.bridge.toolNames.has("explain")) {
9676
- return await deferExplain(args, opts.bridge);
9677
- }
9678
9696
  return errorEnvelope11(
9679
9697
  "EXPLAIN_STORAGE_UNAVAILABLE",
9680
9698
  "explain needs the local transcript/stats database, which isn't available",
@@ -9956,21 +9974,6 @@ function pyRepr5(v) {
9956
9974
  }
9957
9975
  return String(v);
9958
9976
  }
9959
- async function deferExplain(args, bridge) {
9960
- const r = await bridge.callTool("explain", args);
9961
- const text = r.content[0]?.text;
9962
- if (typeof text === "string") {
9963
- try {
9964
- return JSON.parse(text);
9965
- } catch {
9966
- }
9967
- }
9968
- return errorEnvelope11(
9969
- "EXPLAIN_BRIDGE_BAD_ENVELOPE",
9970
- "bridge returned an unparseable envelope for explain",
9971
- "Check that the Python child is healthy."
9972
- );
9973
- }
9974
9977
  function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
9975
9978
  return {
9976
9979
  tool: "explain",
@@ -10523,9 +10526,6 @@ async function runRecall(args, opts) {
10523
10526
  if (k < 1) k = 1;
10524
10527
  if (k > 50) k = 50;
10525
10528
  if (!opts.storage) {
10526
- if (opts.bridge && opts.bridge.toolNames.has("recall")) {
10527
- return await deferRecall(args, opts.bridge);
10528
- }
10529
10529
  return errorEnvelope12(
10530
10530
  "RECALL_STORAGE_UNAVAILABLE",
10531
10531
  "recall needs the local database, which isn't available",
@@ -10578,21 +10578,6 @@ async function runRecall(args, opts) {
10578
10578
  applied_filters: applied
10579
10579
  };
10580
10580
  }
10581
- async function deferRecall(args, bridge) {
10582
- const r = await bridge.callTool("recall", args);
10583
- const text = r.content[0]?.text;
10584
- if (typeof text === "string") {
10585
- try {
10586
- return JSON.parse(text);
10587
- } catch {
10588
- }
10589
- }
10590
- return errorEnvelope12(
10591
- "RECALL_BRIDGE_BAD_ENVELOPE",
10592
- "bridge returned an unparseable envelope for recall",
10593
- "Check that the Python child is healthy."
10594
- );
10595
- }
10596
10581
  function errorEnvelope12(code, message, hint) {
10597
10582
  return {
10598
10583
  tool: "recall",
@@ -10615,9 +10600,6 @@ async function runRecommendPanel(args, opts) {
10615
10600
  );
10616
10601
  }
10617
10602
  if (!opts.storage) {
10618
- if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
10619
- return await deferRecommendPanel(args, opts.bridge);
10620
- }
10621
10603
  return errorEnvelope13(
10622
10604
  "RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
10623
10605
  "recommend_panel needs the local stats database, which isn't available",
@@ -10680,21 +10662,6 @@ async function runRecommendPanel(args, opts) {
10680
10662
  meta: result.meta
10681
10663
  };
10682
10664
  }
10683
- async function deferRecommendPanel(args, bridge) {
10684
- const r = await bridge.callTool("recommend_panel", args);
10685
- const text = r.content[0]?.text;
10686
- if (typeof text === "string") {
10687
- try {
10688
- return JSON.parse(text);
10689
- } catch {
10690
- }
10691
- }
10692
- return errorEnvelope13(
10693
- "RECOMMEND_PANEL_BRIDGE_BAD_ENVELOPE",
10694
- "bridge returned an unparseable envelope for recommend_panel",
10695
- "Check that the Python child is healthy."
10696
- );
10697
- }
10698
10665
  function errorEnvelope13(code, message, hint) {
10699
10666
  return {
10700
10667
  tool: "recommend_panel",
@@ -10724,9 +10691,6 @@ function toStringArray3(v) {
10724
10691
  import { readFileSync as readFileSync10, existsSync as existsSync8 } from "fs";
10725
10692
  async function runScoreboard(args, opts) {
10726
10693
  if (!opts.storage) {
10727
- if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
10728
- return await deferScoreboard(args, opts.bridge);
10729
- }
10730
10694
  return errorEnvelope14(
10731
10695
  "SCOREBOARD_STORAGE_UNAVAILABLE",
10732
10696
  "scoreboard needs the local stats database, which isn't available",
@@ -10849,21 +10813,6 @@ function clampInt3(raw, min, max, fallback) {
10849
10813
  if (!Number.isFinite(n)) return fallback;
10850
10814
  return Math.min(max, Math.max(min, Math.trunc(n)));
10851
10815
  }
10852
- async function deferScoreboard(args, bridge) {
10853
- const r = await bridge.callTool("scoreboard", args);
10854
- const text = r.content[0]?.text;
10855
- if (typeof text === "string") {
10856
- try {
10857
- return JSON.parse(text);
10858
- } catch {
10859
- }
10860
- }
10861
- return errorEnvelope14(
10862
- "SCOREBOARD_BRIDGE_BAD_ENVELOPE",
10863
- "bridge returned an unparseable envelope for scoreboard",
10864
- "Check that the Python child is healthy."
10865
- );
10866
- }
10867
10816
  function errorEnvelope14(code, message, hint) {
10868
10817
  return {
10869
10818
  tool: "scoreboard",
@@ -10900,9 +10849,6 @@ async function runSessionMemory(args, opts) {
10900
10849
  );
10901
10850
  }
10902
10851
  if (!opts.storage) {
10903
- if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
10904
- return await deferSessionMemory(args, opts.bridge);
10905
- }
10906
10852
  return errorEnvelope15(
10907
10853
  "SESSION_MEMORY_STORAGE_UNAVAILABLE",
10908
10854
  "session_memory needs the local database, which isn't available",
@@ -11007,21 +10953,6 @@ function clampInt4(raw, min, max, fallback) {
11007
10953
  if (!Number.isFinite(n)) return fallback;
11008
10954
  return Math.min(max, Math.max(min, Math.trunc(n)));
11009
10955
  }
11010
- async function deferSessionMemory(args, bridge) {
11011
- const r = await bridge.callTool("session_memory", args);
11012
- const text = r.content[0]?.text;
11013
- if (typeof text === "string") {
11014
- try {
11015
- return JSON.parse(text);
11016
- } catch {
11017
- }
11018
- }
11019
- return errorEnvelope15(
11020
- "SESSION_MEMORY_BRIDGE_BAD_ENVELOPE",
11021
- "bridge returned an unparseable envelope for session_memory",
11022
- "Check that the Python child is healthy."
11023
- );
11024
- }
11025
10956
  function errorEnvelope15(code, message, hint) {
11026
10957
  return {
11027
10958
  tool: "session_memory",
@@ -11641,7 +11572,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11641
11572
  var DEFAULT_PACKAGE = "crosscheck-cli";
11642
11573
  var FETCH_TIMEOUT_MS = 3e3;
11643
11574
  function engineVersion() {
11644
- return true ? "0.2.27" : "0.0.0-dev";
11575
+ return true ? "0.2.28" : "0.0.0-dev";
11645
11576
  }
11646
11577
  function defaultUpdateCachePath() {
11647
11578
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -12413,12 +12344,11 @@ function helpTool() {
12413
12344
  }
12414
12345
  });
12415
12346
  }
12416
- function registerCoreTools(opts = {}) {
12417
- const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
12347
+ function registerCoreTools(o = {}) {
12418
12348
  const tools = /* @__PURE__ */ new Map();
12419
12349
  const list = [
12420
12350
  pingTool(),
12421
- verifyTool(o.bridge, o.fetchConfig),
12351
+ verifyTool(o.fetchConfig),
12422
12352
  pickTool(
12423
12353
  o.providers ?? {},
12424
12354
  o.providerAllowlist ?? null,
@@ -12430,7 +12360,6 @@ function registerCoreTools(opts = {}) {
12430
12360
  auditTool(
12431
12361
  o.providers ?? {},
12432
12362
  o.providerAllowlist ?? null,
12433
- o.bridge,
12434
12363
  o.transcriptsDir,
12435
12364
  o.pricing,
12436
12365
  o.storage,
@@ -12440,7 +12369,6 @@ function registerCoreTools(opts = {}) {
12440
12369
  conferTool(
12441
12370
  o.providers ?? {},
12442
12371
  o.providerAllowlist ?? null,
12443
- o.bridge,
12444
12372
  o.moderatorDefault ?? "anthropic",
12445
12373
  o.pricing,
12446
12374
  o.storage,
@@ -12453,7 +12381,6 @@ function registerCoreTools(opts = {}) {
12453
12381
  debateTool(
12454
12382
  o.providers ?? {},
12455
12383
  o.providerAllowlist ?? null,
12456
- o.bridge,
12457
12384
  buildInnerCallers(o),
12458
12385
  o.storage,
12459
12386
  o.pricing,
@@ -12465,7 +12392,6 @@ function registerCoreTools(opts = {}) {
12465
12392
  coordinateTool(
12466
12393
  o.providers ?? {},
12467
12394
  o.providerAllowlist ?? null,
12468
- o.bridge,
12469
12395
  buildInnerCallers(o),
12470
12396
  o.storage,
12471
12397
  o.circuitBreakers,
@@ -12476,7 +12402,6 @@ function registerCoreTools(opts = {}) {
12476
12402
  triangulateTool(
12477
12403
  o.providers ?? {},
12478
12404
  o.providerAllowlist ?? null,
12479
- o.bridge,
12480
12405
  o.storage,
12481
12406
  o.circuitBreakers,
12482
12407
  o.transcriptsDir,
@@ -12485,7 +12410,6 @@ function registerCoreTools(opts = {}) {
12485
12410
  planTool(
12486
12411
  o.providers ?? {},
12487
12412
  o.providerAllowlist ?? null,
12488
- o.bridge,
12489
12413
  o.storage,
12490
12414
  o.circuitBreakers,
12491
12415
  o.transcriptsDir,
@@ -12494,7 +12418,6 @@ function registerCoreTools(opts = {}) {
12494
12418
  critiqueTool(
12495
12419
  o.providers ?? {},
12496
12420
  o.providerAllowlist ?? null,
12497
- o.bridge,
12498
12421
  o.storage,
12499
12422
  o.circuitBreakers,
12500
12423
  o.transcriptsDir,
@@ -12503,7 +12426,6 @@ function registerCoreTools(opts = {}) {
12503
12426
  reviewTool(
12504
12427
  o.providers ?? {},
12505
12428
  o.providerAllowlist ?? null,
12506
- o.bridge,
12507
12429
  o.storage,
12508
12430
  o.circuitBreakers,
12509
12431
  o.transcriptsDir,
@@ -12511,25 +12433,23 @@ function registerCoreTools(opts = {}) {
12511
12433
  ),
12512
12434
  listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
12513
12435
  modelsTool(o.providers ?? {}, o.activeProviders ?? null),
12514
- recallTool(o.storage, o.bridge),
12515
- sessionMemoryTool(o.storage, o.bridge),
12516
- scoreboardTool(o.storage, o.bridge, o.eventsPath),
12517
- 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),
12518
12440
  delegateTool(
12519
12441
  o.providers ?? {},
12520
12442
  o.providerAllowlist ?? null,
12521
12443
  o.storage,
12522
- o.bridge,
12523
12444
  o.moderatorDefault ?? "anthropic"
12524
12445
  ),
12525
12446
  fetchTool(o.storage, o.fetchConfig, o.repoRoot),
12526
- recommendPanelTool(o.providers ?? {}, o.storage, o.bridge),
12447
+ recommendPanelTool(o.providers ?? {}, o.storage),
12527
12448
  updateCrosscheckTool(o.repoRoot ?? null),
12528
12449
  benchTool(
12529
12450
  o.providers ?? {},
12530
12451
  o.providerAllowlist ?? null,
12531
12452
  o.storage,
12532
- o.bridge,
12533
12453
  o.moderatorDefault ?? "anthropic",
12534
12454
  o.benchGoldensDir,
12535
12455
  o.circuitBreakers,
@@ -12540,7 +12460,6 @@ function registerCoreTools(opts = {}) {
12540
12460
  solveTool(
12541
12461
  o.providers ?? {},
12542
12462
  o.providerAllowlist ?? null,
12543
- o.bridge,
12544
12463
  o.storage,
12545
12464
  o.circuitBreakers,
12546
12465
  o.transcriptsDir,
@@ -12549,7 +12468,6 @@ function registerCoreTools(opts = {}) {
12549
12468
  orchestrateTool(
12550
12469
  o.providers ?? {},
12551
12470
  o.providerAllowlist ?? null,
12552
- o.bridge,
12553
12471
  o.moderatorDefault ?? "anthropic",
12554
12472
  o.storage,
12555
12473
  o.pricing,
@@ -12596,7 +12514,6 @@ function createTool(o, toolName, cheapDefault) {
12596
12514
  providers: o.providers ?? {},
12597
12515
  allowlist: o.providerAllowlist ?? null,
12598
12516
  ...o.storage ? { storage: o.storage } : {},
12599
- ...o.bridge ? { bridge: o.bridge } : {},
12600
12517
  ...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
12601
12518
  ...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
12602
12519
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {},
@@ -12605,7 +12522,7 @@ function createTool(o, toolName, cheapDefault) {
12605
12522
  })
12606
12523
  };
12607
12524
  }
12608
- function orchestrateTool(providers, allowlist, bridge, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12525
+ function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12609
12526
  return {
12610
12527
  name: "orchestrate",
12611
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.",
@@ -12630,7 +12547,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12630
12547
  providers,
12631
12548
  allowlist,
12632
12549
  moderator,
12633
- ...bridge ? { bridge } : {},
12634
12550
  ...storage ? { storage } : {},
12635
12551
  ...pricing ? { pricing } : {},
12636
12552
  ...breakers ? { breakers } : {},
@@ -12640,7 +12556,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12640
12556
  })
12641
12557
  };
12642
12558
  }
12643
- function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12559
+ function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12644
12560
  return {
12645
12561
  name: "solve",
12646
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.",
@@ -12662,7 +12578,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
12662
12578
  handler: (args) => runSolve(args, {
12663
12579
  providers,
12664
12580
  allowlist,
12665
- ...bridge ? { bridge } : {},
12666
12581
  ...storage ? { storage } : {},
12667
12582
  ...breakers ? { breakers } : {},
12668
12583
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12701,7 +12616,7 @@ function configPinTool(repoRoot, config2, rejectDriftEnv) {
12701
12616
  }
12702
12617
  };
12703
12618
  }
12704
- function benchTool(providers, allowlist, storage, bridge, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12619
+ function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12705
12620
  return {
12706
12621
  name: "bench",
12707
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).",
@@ -12720,7 +12635,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
12720
12635
  allowlist,
12721
12636
  moderator,
12722
12637
  ...storage ? { storage } : {},
12723
- ...bridge ? { bridge } : {},
12724
12638
  ...defaultGoldensDir ? { defaultGoldensDir } : {},
12725
12639
  ...breakers ? { breakers } : {},
12726
12640
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12747,7 +12661,7 @@ function updateCrosscheckTool(repoRoot) {
12747
12661
  }
12748
12662
  };
12749
12663
  }
12750
- function recommendPanelTool(providers, storage, bridge) {
12664
+ function recommendPanelTool(providers, storage) {
12751
12665
  return {
12752
12666
  name: "recommend_panel",
12753
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.",
@@ -12765,8 +12679,7 @@ function recommendPanelTool(providers, storage, bridge) {
12765
12679
  },
12766
12680
  handler: (args) => runRecommendPanel(args, {
12767
12681
  providers,
12768
- ...storage ? { storage } : {},
12769
- ...bridge ? { bridge } : {}
12682
+ ...storage ? { storage } : {}
12770
12683
  })
12771
12684
  };
12772
12685
  }
@@ -12791,7 +12704,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
12791
12704
  })
12792
12705
  };
12793
12706
  }
12794
- function delegateTool(providers, allowlist, storage, bridge, moderator) {
12707
+ function delegateTool(providers, allowlist, storage, moderator) {
12795
12708
  return {
12796
12709
  name: "delegate",
12797
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.",
@@ -12811,12 +12724,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
12811
12724
  providers,
12812
12725
  allowlist,
12813
12726
  moderator,
12814
- ...storage ? { storage } : {},
12815
- ...bridge ? { bridge } : {}
12727
+ ...storage ? { storage } : {}
12816
12728
  })
12817
12729
  };
12818
12730
  }
12819
- function explainTool(storage, bridge, transcriptsDir) {
12731
+ function explainTool(storage, transcriptsDir) {
12820
12732
  return {
12821
12733
  name: "explain",
12822
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.",
@@ -12834,12 +12746,11 @@ function explainTool(storage, bridge, transcriptsDir) {
12834
12746
  },
12835
12747
  handler: (args) => runExplain(args, {
12836
12748
  ...storage ? { storage } : {},
12837
- ...bridge ? { bridge } : {},
12838
12749
  ...transcriptsDir ? { transcriptsDir } : {}
12839
12750
  })
12840
12751
  };
12841
12752
  }
12842
- function scoreboardTool(storage, bridge, eventsPath) {
12753
+ function scoreboardTool(storage, eventsPath) {
12843
12754
  return {
12844
12755
  name: "scoreboard",
12845
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).",
@@ -12853,12 +12764,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
12853
12764
  },
12854
12765
  handler: (args) => runScoreboard(args, {
12855
12766
  ...storage ? { storage } : {},
12856
- ...bridge ? { bridge } : {},
12857
12767
  ...eventsPath ? { eventsPath } : {}
12858
12768
  })
12859
12769
  };
12860
12770
  }
12861
- function sessionMemoryTool(storage, bridge) {
12771
+ function sessionMemoryTool(storage) {
12862
12772
  return {
12863
12773
  name: "session_memory",
12864
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).",
@@ -12881,15 +12791,14 @@ function sessionMemoryTool(storage, bridge) {
12881
12791
  required: ["action", "session_id"]
12882
12792
  },
12883
12793
  handler: (args) => runSessionMemory(args, {
12884
- ...storage ? { storage } : {},
12885
- ...bridge ? { bridge } : {}
12794
+ ...storage ? { storage } : {}
12886
12795
  })
12887
12796
  };
12888
12797
  }
12889
- function recallTool(storage, bridge) {
12798
+ function recallTool(storage) {
12890
12799
  return {
12891
12800
  name: "recall",
12892
- 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.",
12893
12802
  inputSchema: {
12894
12803
  type: "object",
12895
12804
  additionalProperties: true,
@@ -12903,8 +12812,7 @@ function recallTool(storage, bridge) {
12903
12812
  required: ["query"]
12904
12813
  },
12905
12814
  handler: (args) => runRecall(args, {
12906
- ...storage ? { storage } : {},
12907
- ...bridge ? { bridge } : {}
12815
+ ...storage ? { storage } : {}
12908
12816
  })
12909
12817
  };
12910
12818
  }
@@ -12940,7 +12848,7 @@ function modelsTool(providers, activeProviders) {
12940
12848
  handler: async (args) => runModels(args, { providers, activeProviders })
12941
12849
  };
12942
12850
  }
12943
- function reviewTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12851
+ function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12944
12852
  return {
12945
12853
  name: "review",
12946
12854
  description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
@@ -12959,7 +12867,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12959
12867
  handler: (args) => runReview(args, {
12960
12868
  providers,
12961
12869
  allowlist,
12962
- ...bridge ? { bridge } : {},
12963
12870
  ...storage ? { storage } : {},
12964
12871
  ...breakers ? { breakers } : {},
12965
12872
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12967,7 +12874,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12967
12874
  })
12968
12875
  };
12969
12876
  }
12970
- function critiqueTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12877
+ function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12971
12878
  return {
12972
12879
  name: "critique",
12973
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.",
@@ -12987,7 +12894,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
12987
12894
  handler: (args) => runCritique(args, {
12988
12895
  providers,
12989
12896
  allowlist,
12990
- ...bridge ? { bridge } : {},
12991
12897
  ...storage ? { storage } : {},
12992
12898
  ...breakers ? { breakers } : {},
12993
12899
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12995,7 +12901,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
12995
12901
  })
12996
12902
  };
12997
12903
  }
12998
- function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12904
+ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12999
12905
  return {
13000
12906
  name: "plan",
13001
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.',
@@ -13022,7 +12928,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13022
12928
  handler: (args) => runPlan(args, {
13023
12929
  providers,
13024
12930
  allowlist,
13025
- ...bridge ? { bridge } : {},
13026
12931
  ...storage ? { storage } : {},
13027
12932
  ...breakers ? { breakers } : {},
13028
12933
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13030,7 +12935,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13030
12935
  })
13031
12936
  };
13032
12937
  }
13033
- function triangulateTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12938
+ function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13034
12939
  return {
13035
12940
  name: "triangulate",
13036
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.",
@@ -13051,7 +12956,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13051
12956
  handler: (args) => runTriangulate(args, {
13052
12957
  providers,
13053
12958
  allowlist,
13054
- ...bridge ? { bridge } : {},
13055
12959
  ...storage ? { storage } : {},
13056
12960
  ...breakers ? { breakers } : {},
13057
12961
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13059,7 +12963,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13059
12963
  })
13060
12964
  };
13061
12965
  }
13062
- function coordinateTool(providers, allowlist, bridge, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
12966
+ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13063
12967
  return {
13064
12968
  name: "coordinate",
13065
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).",
@@ -13084,7 +12988,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13084
12988
  handler: (args) => runCoordinate(args, {
13085
12989
  providers,
13086
12990
  allowlist,
13087
- ...bridge ? { bridge } : {},
13088
12991
  innerCallers,
13089
12992
  ...storage ? { storage } : {},
13090
12993
  ...breakers ? { breakers } : {},
@@ -13094,7 +12997,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13094
12997
  })
13095
12998
  };
13096
12999
  }
13097
- function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13000
+ function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13098
13001
  return {
13099
13002
  name: "debate",
13100
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).",
@@ -13124,7 +13027,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
13124
13027
  handler: (args) => runDebate(args, {
13125
13028
  providers,
13126
13029
  allowlist,
13127
- ...bridge ? { bridge } : {},
13128
13030
  innerCallers,
13129
13031
  ...storage ? { storage } : {},
13130
13032
  ...pricing ? { pricing } : {},
@@ -13144,10 +13046,10 @@ function buildInnerCallers(o) {
13144
13046
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {}
13145
13047
  });
13146
13048
  }
13147
- out.verify = (args) => runVerify(args, o.bridge, o.fetchConfig);
13049
+ out.verify = (args) => runVerify(args, o.fetchConfig);
13148
13050
  return out;
13149
13051
  }
13150
- 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) {
13151
13053
  return {
13152
13054
  name: "confer",
13153
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).",
@@ -13174,7 +13076,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13174
13076
  handler: (args) => runConfer(args, {
13175
13077
  providers,
13176
13078
  allowlist,
13177
- ...bridge ? { bridge } : {},
13178
13079
  moderator,
13179
13080
  ...pricing ? { pricing } : {},
13180
13081
  ...storage ? { storage } : {},
@@ -13186,7 +13087,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13186
13087
  })
13187
13088
  };
13188
13089
  }
13189
- function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storage, breakers, repoRoot) {
13090
+ function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
13190
13091
  return {
13191
13092
  name: "audit",
13192
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.",
@@ -13212,7 +13113,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
13212
13113
  handler: (args) => runAudit(args, {
13213
13114
  providers,
13214
13115
  allowlist,
13215
- ...bridge ? { bridge } : {},
13216
13116
  ...transcriptsDir ? { transcriptsDir } : {},
13217
13117
  ...pricing ? { pricing } : {},
13218
13118
  ...storage ? { storage } : {},
@@ -13276,7 +13176,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
13276
13176
  })
13277
13177
  };
13278
13178
  }
13279
- function verifyTool(bridge, fetchConfig) {
13179
+ function verifyTool(fetchConfig) {
13280
13180
  return {
13281
13181
  name: "verify",
13282
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.",
@@ -13294,7 +13194,7 @@ function verifyTool(bridge, fetchConfig) {
13294
13194
  },
13295
13195
  required: ["checks"]
13296
13196
  },
13297
- handler: (args) => runVerify(args, bridge, fetchConfig)
13197
+ handler: (args) => runVerify(args, fetchConfig)
13298
13198
  };
13299
13199
  }
13300
13200
  function pingTool() {
@@ -13378,6 +13278,64 @@ async function flush() {
13378
13278
  }
13379
13279
  }
13380
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
+
13381
13339
  // src/entrypoints/embed.ts
13382
13340
  var KEY_ENV = {
13383
13341
  anthropic: "ANTHROPIC_API_KEY",
@@ -13434,7 +13392,7 @@ function errorOf(answer) {
13434
13392
  }
13435
13393
  function bundledPricingPath() {
13436
13394
  try {
13437
- return path11.join(path11.dirname(fileURLToPath2(import.meta.url)), "pricing.json");
13395
+ return path12.join(path12.dirname(fileURLToPath2(import.meta.url)), "pricing.json");
13438
13396
  } catch {
13439
13397
  return void 0;
13440
13398
  }
@@ -13577,6 +13535,9 @@ export {
13577
13535
  KEY_ENV as __KEY_ENV,
13578
13536
  MODEL_ENV as __MODEL_ENV,
13579
13537
  __test_internals,
13580
- createEmbeddedEngine
13538
+ createEmbeddedEngine,
13539
+ isAlive,
13540
+ listProcesses,
13541
+ processRegistryPath
13581
13542
  };
13582
13543
  //# sourceMappingURL=embed.js.map