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.
@@ -934,8 +934,8 @@ var init_better_sqlite3 = __esm({
934
934
 
935
935
  // src/entrypoints/node-stdio.ts
936
936
  init_esm_shims();
937
- import { existsSync as existsSync14, mkdirSync as mkdirSync10 } from "fs";
938
- import path15 from "path";
937
+ import { existsSync as existsSync14, mkdirSync as mkdirSync11 } from "fs";
938
+ import path16 from "path";
939
939
  import { fileURLToPath as fileURLToPath3 } from "url";
940
940
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
941
941
 
@@ -952,10 +952,10 @@ var StderrEmitter = class {
952
952
  }
953
953
  };
954
954
  var FileEmitter = class {
955
- constructor(path16) {
956
- this.path = path16;
955
+ constructor(path17) {
956
+ this.path = path17;
957
957
  try {
958
- mkdirSync(dirname(path16), { recursive: true });
958
+ mkdirSync(dirname(path17), { recursive: true });
959
959
  } catch {
960
960
  }
961
961
  }
@@ -988,13 +988,13 @@ var NullEmitter = class {
988
988
  function buildDefaultEmitter(env) {
989
989
  const mode = (env["CROSSCHECK_EVENTS"] ?? "stderr").toLowerCase();
990
990
  if (mode === "off") return new NullEmitter();
991
- const path16 = env["CROSSCHECK_EVENTS_PATH"];
991
+ const path17 = env["CROSSCHECK_EVENTS_PATH"];
992
992
  if (mode === "file") {
993
- return path16 ? new FileEmitter(path16) : new NullEmitter();
993
+ return path17 ? new FileEmitter(path17) : new NullEmitter();
994
994
  }
995
995
  if (mode === "both") {
996
996
  const ems = [new StderrEmitter()];
997
- if (path16) ems.push(new FileEmitter(path16));
997
+ if (path17) ems.push(new FileEmitter(path17));
998
998
  return new TeeEmitter(ems);
999
999
  }
1000
1000
  return new StderrEmitter();
@@ -1043,10 +1043,10 @@ function envelopeBytes(v) {
1043
1043
  // src/core/pricing.ts
1044
1044
  init_esm_shims();
1045
1045
  import { readFileSync } from "fs";
1046
- function loadPricing(path16) {
1046
+ function loadPricing(path17) {
1047
1047
  let raw;
1048
1048
  try {
1049
- raw = readFileSync(path16, "utf8");
1049
+ raw = readFileSync(path17, "utf8");
1050
1050
  } catch {
1051
1051
  return {};
1052
1052
  }
@@ -1063,20 +1063,30 @@ function modelPricing(pricing, provider, model) {
1063
1063
  const block = pricing[provider];
1064
1064
  if (!block || typeof block !== "object" || Array.isArray(block)) return null;
1065
1065
  const table = block;
1066
+ if (model.startsWith("_")) return null;
1066
1067
  let entry = table[model];
1067
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
1068
- const best = Object.keys(table).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
1069
- entry = best !== void 0 ? table[best] : void 0;
1068
+ let match = "exact";
1069
+ if (!isRates(entry)) {
1070
+ 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];
1071
+ if (best !== void 0) {
1072
+ entry = table[best];
1073
+ match = "stamp";
1074
+ }
1070
1075
  }
1071
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
1076
+ if (!isRates(entry)) return null;
1072
1077
  const e = entry;
1073
1078
  return {
1074
1079
  prompt_per_1k: numberOrZero(e["prompt_per_1k"]),
1075
1080
  completion_per_1k: numberOrZero(e["completion_per_1k"]),
1076
1081
  cached_per_1k: numberOrZero(e["cached_per_1k"]),
1077
- ...e["estimated"] === true ? { estimated: true } : {}
1082
+ ...e["estimated"] === true ? { estimated: true } : {},
1083
+ match
1078
1084
  };
1079
1085
  }
1086
+ var DATE_STAMP = /^-\d{8}$/;
1087
+ function isRates(v) {
1088
+ return Boolean(v) && typeof v === "object" && !Array.isArray(v);
1089
+ }
1080
1090
  function numberOrZero(v) {
1081
1091
  if (typeof v === "number" && Number.isFinite(v)) return v;
1082
1092
  if (typeof v === "string") {
@@ -1216,8 +1226,20 @@ var PROVIDER_CAPS = {
1216
1226
  gemini: {
1217
1227
  family: "gemini",
1218
1228
  system_role: "separate",
1219
- supports_temperature: true,
1220
- reasoning_prefixes: ["gemini-3.1-pro", "gemini-3.5-flash", "gemini-2.5-pro"]
1229
+ // No sampling, on any Gemini model. Ignored since 3.6 Flash and rejected
1230
+ // by upcoming models (Google, 2026-10). "model" means "omit for reasoning
1231
+ // models", and every Gemini model is reasoning-class (below) — so this
1232
+ // resolves to never, through the same rule the other providers use. The
1233
+ // adapter also never sends it; this keeps the record honest for anything
1234
+ // else that reads it.
1235
+ supports_temperature: "model",
1236
+ // EVERY Gemini model is reasoning-class. The old list named three
1237
+ // families and missed gemini-3.8-flash — the DEFAULT — so the default
1238
+ // model got the small non-reasoning budgets (768 tokens for an audit)
1239
+ // while spending up to ~480 tokens of each call thinking. Google's docs
1240
+ // say thinking cannot be switched off on current models, so a list of
1241
+ // which ones think is a list that can only ever be incomplete.
1242
+ reasoning_prefixes: ["gemini-"]
1221
1243
  },
1222
1244
  // Qwen's "Max" tier (qwen-v3.8, qwen-v3.7) is a standard instruct/chat
1223
1245
  // model, not a visible-reasoning model like QwQ — normal temperature and
@@ -1342,6 +1364,74 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
1342
1364
  );
1343
1365
  }
1344
1366
 
1367
+ // src/providers/network-errors.ts
1368
+ init_esm_shims();
1369
+ function codeOf(e) {
1370
+ if (!e || typeof e !== "object") return null;
1371
+ const c = e.code;
1372
+ return typeof c === "string" && c.length > 0 ? c : null;
1373
+ }
1374
+ function rootCause(e, depth = 0) {
1375
+ if (depth > 5 || !e || typeof e !== "object") return e;
1376
+ const o = e;
1377
+ if (Array.isArray(o.errors) && o.errors.length > 0) {
1378
+ const coded = o.errors.find((x) => codeOf(x) !== null);
1379
+ return rootCause(coded ?? o.errors[0], depth + 1);
1380
+ }
1381
+ if (o.cause !== void 0 && o.cause !== null) return rootCause(o.cause, depth + 1);
1382
+ return e;
1383
+ }
1384
+ var BY_CODE = {
1385
+ ENOTFOUND: { cause: "dns", detail: "the provider's hostname did not resolve \u2014 DNS, or a typo'd base URL", transient: false, kind: "network" },
1386
+ EAI_AGAIN: { cause: "dns", detail: "DNS lookup failed temporarily \u2014 resolver or network is flapping", transient: true, kind: "network" },
1387
+ ECONNREFUSED: { cause: "refused", detail: "the connection was refused \u2014 nothing is listening, or a proxy blocked it", transient: false, kind: "network" },
1388
+ 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" },
1389
+ EPIPE: { cause: "reset", detail: "the connection closed while we were still writing", transient: true, kind: "network" },
1390
+ ETIMEDOUT: { cause: "connect_timeout", detail: "the connection timed out before it was established", transient: true, kind: "timeout" },
1391
+ EHOSTUNREACH: { cause: "unreachable", detail: "no route to the provider \u2014 VPN, or offline", transient: true, kind: "network" },
1392
+ ENETUNREACH: { cause: "unreachable", detail: "the network is unreachable \u2014 offline, or a routing change", transient: true, kind: "network" },
1393
+ ENETDOWN: { cause: "unreachable", detail: "the local network is down", transient: true, kind: "network" },
1394
+ EPROTO: { cause: "tls", detail: "the TLS handshake failed \u2014 an intercepting proxy, or a protocol mismatch", transient: false, kind: "network" },
1395
+ ERR_TLS_CERT_ALTNAME_INVALID: { cause: "tls", detail: "the certificate did not match the hostname \u2014 traffic is being intercepted", transient: false, kind: "network" },
1396
+ CERT_HAS_EXPIRED: { cause: "tls", detail: "the server certificate has expired, or this machine's clock is wrong", transient: false, kind: "network" },
1397
+ 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" },
1398
+ 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" },
1399
+ 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" },
1400
+ UND_ERR_BODY_TIMEOUT: { cause: "read_timeout", detail: "the response body stalled mid-stream", transient: true, kind: "timeout" },
1401
+ UND_ERR_SOCKET: { cause: "reset", detail: "the socket closed unexpectedly", transient: true, kind: "network" },
1402
+ UND_ERR_ABORTED: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" },
1403
+ ABORT_ERR: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" }
1404
+ };
1405
+ function diagnoseNetworkError(e) {
1406
+ const root = rootCause(e);
1407
+ const code = codeOf(root) ?? codeOf(e);
1408
+ if (code && BY_CODE[code]) return { ...BY_CODE[code], code };
1409
+ const name = root && typeof root === "object" ? root.name : void 0;
1410
+ if (name === "AbortError" || name === "TimeoutError") {
1411
+ return {
1412
+ cause: name === "TimeoutError" ? "read_timeout" : "aborted",
1413
+ code: code ?? String(name),
1414
+ detail: name === "TimeoutError" ? "the request exceeded its timeout" : "the request was cancelled",
1415
+ transient: name === "TimeoutError",
1416
+ kind: name === "TimeoutError" ? "timeout" : "network"
1417
+ };
1418
+ }
1419
+ return {
1420
+ cause: "unknown",
1421
+ code,
1422
+ detail: code ? `the connection failed with ${code}` : "the connection failed and the underlying error carried no code",
1423
+ transient: true,
1424
+ kind: "network"
1425
+ };
1426
+ }
1427
+ function looksLikeNetworkFailure(d) {
1428
+ return d.code !== null || d.cause !== "unknown";
1429
+ }
1430
+ function networkErrorMessage(provider, d) {
1431
+ const code = d.code ? ` [${d.code}]` : "";
1432
+ return `${provider}: ${d.detail}${code}`;
1433
+ }
1434
+
1345
1435
  // src/providers/retry.ts
1346
1436
  init_esm_shims();
1347
1437
  var override = null;
@@ -1673,7 +1763,11 @@ async function sendAnthropic(args) {
1673
1763
  try {
1674
1764
  respLike = await doFetch(url, init);
1675
1765
  } catch (e) {
1676
- throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
1766
+ const d = diagnoseNetworkError(e);
1767
+ if (!looksLikeNetworkFailure(d)) throw e;
1768
+ throw new ProviderError(d.kind, networkErrorMessage("anthropic", d), {
1769
+ transient: d.transient
1770
+ });
1677
1771
  }
1678
1772
  const status = respLike.status;
1679
1773
  if (status >= 200 && status < 300) {
@@ -1747,6 +1841,11 @@ function jsonSchemaToGeminiSchema(schema) {
1747
1841
  }
1748
1842
  return out;
1749
1843
  }
1844
+ var GEMINI_THINKING_HEADROOM_TOKENS = 16384;
1845
+ function thinkingHeadroom() {
1846
+ const raw = Number(process.env["CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS"]);
1847
+ return Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : GEMINI_THINKING_HEADROOM_TOKENS;
1848
+ }
1750
1849
  function buildGeminiRequest(opts) {
1751
1850
  const contents = [];
1752
1851
  let systemText = null;
@@ -1765,8 +1864,9 @@ function buildGeminiRequest(opts) {
1765
1864
  const body = {
1766
1865
  contents,
1767
1866
  generationConfig: {
1768
- maxOutputTokens: opts.maxTokens,
1769
- temperature: opts.temperature
1867
+ // Answer budget + thinking headroom. No temperature / topP / topK /
1868
+ // thinkingBudget, on any model — see the header note.
1869
+ maxOutputTokens: opts.maxTokens + thinkingHeadroom()
1770
1870
  }
1771
1871
  };
1772
1872
  if (systemText !== null && systemText !== "") {
@@ -1776,8 +1876,8 @@ function buildGeminiRequest(opts) {
1776
1876
  body.generationConfig.responseMimeType = "application/json";
1777
1877
  body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
1778
1878
  }
1779
- const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
1780
- return { url, headers: {}, body };
1879
+ const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent`;
1880
+ return { url, headers: { "x-goog-api-key": opts.apiKey }, body };
1781
1881
  }
1782
1882
  function parseGeminiResponse(opts) {
1783
1883
  const r = opts.resp ?? {};
@@ -1807,16 +1907,19 @@ function parseGeminiResponse(opts) {
1807
1907
  }
1808
1908
  try {
1809
1909
  const first = cands[0];
1810
- const content = first["content"];
1811
- const parts = content["parts"];
1910
+ const finishReason = typeof first["finishReason"] === "string" ? first["finishReason"] : void 0;
1911
+ const content = first["content"] ?? {};
1912
+ const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
1812
1913
  let text = "";
1813
1914
  for (const p of parts) {
1814
1915
  if (p && typeof p === "object") {
1815
- const t = p["text"];
1916
+ const part = p;
1917
+ if (part["thought"] === true) continue;
1918
+ const t = part["text"];
1816
1919
  if (typeof t === "string") text += t;
1817
1920
  }
1818
1921
  }
1819
- return { text, usage };
1922
+ return { text, usage, ...finishReason ? { finishReason } : {} };
1820
1923
  } catch (e) {
1821
1924
  throw new ProviderError(
1822
1925
  "parse",
@@ -1845,7 +1948,8 @@ async function sendGemini(args) {
1845
1948
  apiKey: args.apiKey,
1846
1949
  messages: args.messages,
1847
1950
  maxTokens: args.maxTokens,
1848
- temperature: args.temperature,
1951
+ // args.temperature is deliberately NOT forwarded: Gemini ignores it and
1952
+ // upcoming models reject it. See the header note.
1849
1953
  ...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
1850
1954
  });
1851
1955
  const doFetch = args.fetchImpl ?? globalThis.fetch;
@@ -1860,7 +1964,11 @@ async function sendGemini(args) {
1860
1964
  try {
1861
1965
  respLike = await doFetch(url, init);
1862
1966
  } catch (e) {
1863
- throw new ProviderError("network", `gemini: fetch failed: ${e.message}`);
1967
+ const d = diagnoseNetworkError(e);
1968
+ if (!looksLikeNetworkFailure(d)) throw e;
1969
+ throw new ProviderError(d.kind, networkErrorMessage("gemini", d), {
1970
+ transient: d.transient
1971
+ });
1864
1972
  }
1865
1973
  const status = respLike.status;
1866
1974
  if (status >= 200 && status < 300) {
@@ -1870,11 +1978,18 @@ async function sendGemini(args) {
1870
1978
  } catch (e) {
1871
1979
  throw new ProviderError("parse", `gemini: response body not JSON: ${e.message}`);
1872
1980
  }
1873
- const { text, usage } = parseGeminiResponse({
1981
+ const { text, usage, finishReason } = parseGeminiResponse({
1874
1982
  resp: parsed,
1875
1983
  model: args.model,
1876
1984
  purpose: args.purpose ?? "worker"
1877
1985
  });
1986
+ if (text.trim() === "" && finishReason === "MAX_TOKENS") {
1987
+ throw new ProviderError(
1988
+ "parse",
1989
+ `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.`,
1990
+ { transient: false }
1991
+ );
1992
+ }
1878
1993
  return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
1879
1994
  }
1880
1995
  const bodyText = await respLike.text().catch(() => "");
@@ -2042,7 +2157,11 @@ async function sendOpenAICompatible(args) {
2042
2157
  try {
2043
2158
  respLike = await doFetch(url, init);
2044
2159
  } catch (e) {
2045
- throw new ProviderError("network", `${args.provider}: fetch failed: ${e.message}`);
2160
+ const d = diagnoseNetworkError(e);
2161
+ if (!looksLikeNetworkFailure(d)) throw e;
2162
+ throw new ProviderError(d.kind, networkErrorMessage(args.provider, d), {
2163
+ transient: d.transient
2164
+ });
2046
2165
  }
2047
2166
  const status = respLike.status;
2048
2167
  if (status >= 200 && status < 300) {
@@ -2230,50 +2349,6 @@ import {
2230
2349
  ListToolsRequestSchema
2231
2350
  } from "@modelcontextprotocol/sdk/types.js";
2232
2351
 
2233
- // src/bridge/index.ts
2234
- init_esm_shims();
2235
-
2236
- // src/bridge/proxy-tools.ts
2237
- init_esm_shims();
2238
- function buildPythonProxies(bridge) {
2239
- const proxies = /* @__PURE__ */ new Map();
2240
- for (const name of bridge.toolNames) {
2241
- proxies.set(name, makeProxy(bridge, name));
2242
- }
2243
- return proxies;
2244
- }
2245
- function makeProxy(bridge, name) {
2246
- return {
2247
- name,
2248
- description: `(forwarded to Python crosscheck-agent) ${name}`,
2249
- // We don't carry the per-tool input schema across the bridge in
2250
- // route-all mode — the TS server is a transparent forwarder, so
2251
- // arg validation happens on the Python side. inputSchema is left
2252
- // permissive; the Python validator throws structured errors that
2253
- // tunnel back through `callTool()`.
2254
- inputSchema: {
2255
- type: "object",
2256
- additionalProperties: true,
2257
- description: `Forwarded to Python \u2014 see Python tool '${name}' for full schema.`
2258
- },
2259
- handler: async (args) => {
2260
- const r = await bridge.callTool(name, args);
2261
- if (!r.content.length) {
2262
- return {};
2263
- }
2264
- const first = r.content[0];
2265
- if (first.type === "text" && first.text) {
2266
- try {
2267
- return JSON.parse(first.text);
2268
- } catch {
2269
- return { text: first.text };
2270
- }
2271
- }
2272
- return { content: r.content };
2273
- }
2274
- };
2275
- }
2276
-
2277
2352
  // src/instructions.ts
2278
2353
  init_esm_shims();
2279
2354
  var ROUTABLE_TOOLS = [
@@ -2360,7 +2435,7 @@ import { z } from "zod";
2360
2435
  // src/server-meta.ts
2361
2436
  init_esm_shims();
2362
2437
  var SERVER_NAME = "crosscheck-agent";
2363
- var SERVER_VERSION = true ? "0.2.27" : "0.0.0-dev";
2438
+ var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
2364
2439
 
2365
2440
  // src/tools/audit.ts
2366
2441
  init_esm_shims();
@@ -2427,27 +2502,27 @@ function extractJson(text) {
2427
2502
 
2428
2503
  // src/core/json-schema.ts
2429
2504
  init_esm_shims();
2430
- function validateSchema(value, schema, path16 = "") {
2505
+ function validateSchema(value, schema, path17 = "") {
2431
2506
  const errs = [];
2432
2507
  if ("anyOf" in schema) {
2433
2508
  const subs = schema["anyOf"].map(
2434
- (s) => validateSchema(value, s, path16)
2509
+ (s) => validateSchema(value, s, path17)
2435
2510
  );
2436
2511
  if (!subs.some((e) => e.length === 0)) {
2437
- errs.push(`${path16 || "<root>"}: did not match anyOf`);
2512
+ errs.push(`${path17 || "<root>"}: did not match anyOf`);
2438
2513
  }
2439
2514
  return errs;
2440
2515
  }
2441
2516
  if ("oneOf" in schema) {
2442
- const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path16).length === 0).length;
2517
+ const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path17).length === 0).length;
2443
2518
  if (passed !== 1) {
2444
- errs.push(`${path16 || "<root>"}: matched ${passed} of oneOf, expected 1`);
2519
+ errs.push(`${path17 || "<root>"}: matched ${passed} of oneOf, expected 1`);
2445
2520
  }
2446
2521
  return errs;
2447
2522
  }
2448
2523
  if ("const" in schema && !deepEqual(value, schema["const"])) {
2449
2524
  errs.push(
2450
- `${path16 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
2525
+ `${path17 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
2451
2526
  );
2452
2527
  return errs;
2453
2528
  }
@@ -2457,7 +2532,7 @@ function validateSchema(value, schema, path16 = "") {
2457
2532
  const ok = types.some((tt) => matchesType(value, String(tt)));
2458
2533
  if (!ok) {
2459
2534
  errs.push(
2460
- `${path16 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
2535
+ `${path17 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
2461
2536
  );
2462
2537
  return errs;
2463
2538
  }
@@ -2466,29 +2541,29 @@ function validateSchema(value, schema, path16 = "") {
2466
2541
  if ("enum" in schema) {
2467
2542
  const en = schema["enum"];
2468
2543
  if (!en.some((x) => deepEqual(x, value))) {
2469
- errs.push(`${path16 || "<root>"}: value ${pyRepr(value)} not in enum`);
2544
+ errs.push(`${path17 || "<root>"}: value ${pyRepr(value)} not in enum`);
2470
2545
  }
2471
2546
  }
2472
2547
  if ("minLength" in schema && value.length < schema["minLength"]) {
2473
- errs.push(`${path16 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
2548
+ errs.push(`${path17 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
2474
2549
  }
2475
2550
  }
2476
2551
  if (typeof value === "number" && !Number.isNaN(value)) {
2477
2552
  if ("minimum" in schema && value < schema["minimum"]) {
2478
- errs.push(`${path16 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
2553
+ errs.push(`${path17 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
2479
2554
  }
2480
2555
  if ("maximum" in schema && value > schema["maximum"]) {
2481
- errs.push(`${path16 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
2556
+ errs.push(`${path17 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
2482
2557
  }
2483
2558
  }
2484
2559
  if (Array.isArray(value)) {
2485
2560
  if ("minItems" in schema && value.length < schema["minItems"]) {
2486
- errs.push(`${path16 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
2561
+ errs.push(`${path17 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
2487
2562
  }
2488
2563
  const itemSchema = schema["items"];
2489
2564
  if (isObj(itemSchema)) {
2490
2565
  for (let i = 0; i < value.length; i++) {
2491
- errs.push(...validateSchema(value[i], itemSchema, `${path16}[${i}]`));
2566
+ errs.push(...validateSchema(value[i], itemSchema, `${path17}[${i}]`));
2492
2567
  }
2493
2568
  }
2494
2569
  }
@@ -2497,19 +2572,19 @@ function validateSchema(value, schema, path16 = "") {
2497
2572
  const required = schema["required"] ?? [];
2498
2573
  for (const r of required) {
2499
2574
  if (!(r in value)) {
2500
- errs.push(`${path16 || "<root>"}: missing required key ${pyRepr(r)}`);
2575
+ errs.push(`${path17 || "<root>"}: missing required key ${pyRepr(r)}`);
2501
2576
  }
2502
2577
  }
2503
2578
  if (schema["additionalProperties"] === false) {
2504
2579
  for (const k of Object.keys(value)) {
2505
2580
  if (!(k in props)) {
2506
- errs.push(`${path16 || "<root>"}: unknown key ${pyRepr(k)}`);
2581
+ errs.push(`${path17 || "<root>"}: unknown key ${pyRepr(k)}`);
2507
2582
  }
2508
2583
  }
2509
2584
  }
2510
2585
  for (const [k, v] of Object.entries(value)) {
2511
2586
  const ps = props[k];
2512
- if (ps) errs.push(...validateSchema(v, ps, path16 ? `${path16}.${k}` : k));
2587
+ if (ps) errs.push(...validateSchema(v, ps, path17 ? `${path17}.${k}` : k));
2513
2588
  }
2514
2589
  }
2515
2590
  return errs;
@@ -2591,6 +2666,34 @@ function pyReprType(t) {
2591
2666
 
2592
2667
  // src/core/usage.ts
2593
2668
  init_esm_shims();
2669
+
2670
+ // src/core/session.ts
2671
+ init_esm_shims();
2672
+ import { randomUUID } from "crypto";
2673
+ var processSessionId = null;
2674
+ var startedAt = null;
2675
+ function engineSessionId() {
2676
+ if (processSessionId === null) {
2677
+ processSessionId = randomUUID();
2678
+ startedAt = Date.now();
2679
+ }
2680
+ return processSessionId;
2681
+ }
2682
+ function resolveSessionId(callerSupplied) {
2683
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
2684
+ return trimmed.length > 0 ? trimmed : engineSessionId();
2685
+ }
2686
+ function localSessionRecordingEnabled(env = globalThis.process?.env ?? {}) {
2687
+ const v = (env["CROSSCHECK_RECORD_SESSIONS"] ?? "").trim().toLowerCase();
2688
+ return !["0", "false", "off", "no"].includes(v);
2689
+ }
2690
+ function recordingSessionId(callerSupplied) {
2691
+ if (localSessionRecordingEnabled()) return resolveSessionId(callerSupplied);
2692
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
2693
+ return trimmed.length > 0 ? trimmed : null;
2694
+ }
2695
+
2696
+ // src/core/usage.ts
2594
2697
  function emptyUsage(provider, model, purpose = "worker") {
2595
2698
  return {
2596
2699
  provider,
@@ -2695,11 +2798,11 @@ function withCommas(n) {
2695
2798
  function renderRunSummary(opts) {
2696
2799
  const endedAt = opts.endedAtS ?? Math.trunc(Date.now() / 1e3);
2697
2800
  let scope = "call";
2698
- let startedAt = null;
2801
+ let startedAt2 = null;
2699
2802
  let rows = [];
2700
2803
  if (opts.sessionScope && opts.sessionScope.rows.length > 0) {
2701
2804
  scope = "session";
2702
- startedAt = opts.sessionScope.startedAt;
2805
+ startedAt2 = opts.sessionScope.startedAt;
2703
2806
  rows = opts.sessionScope.rows.map((r) => ({ ...r }));
2704
2807
  } else {
2705
2808
  const byPurpose = /* @__PURE__ */ new Map();
@@ -2730,6 +2833,7 @@ function renderRunSummary(opts) {
2730
2833
  row.cpu_ms += a.cpu_ms ?? 0;
2731
2834
  if (a.cache_hit) row.cache_hits += 1;
2732
2835
  if (a.error) row.errors += 1;
2836
+ if (a.usage?.estimated) row.estimated = true;
2733
2837
  }
2734
2838
  rows = Array.from(byPurpose.values());
2735
2839
  }
@@ -2742,16 +2846,18 @@ function renderRunSummary(opts) {
2742
2846
  wall_ms: rows.reduce((s, r) => s + r.wall_ms, 0),
2743
2847
  cpu_ms: rows.reduce((s, r) => s + r.cpu_ms, 0),
2744
2848
  cache_hits: rows.reduce((s, r) => s + r.cache_hits, 0),
2745
- errors: rows.reduce((s, r) => s + r.errors, 0)
2849
+ errors: rows.reduce((s, r) => s + r.errors, 0),
2850
+ ...rows.some((r) => r.estimated) ? { estimated: true } : {}
2746
2851
  };
2747
2852
  const titleLeft = scope === "session" ? `session: ${opts.sessionId ?? ""}` : `call: ${opts.toolName}`;
2748
- 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)`;
2853
+ const costText = totals.estimated ? `$${totals.cost_usd.toFixed(4)}+ (some calls unpriced)` : `$${totals.cost_usd.toFixed(4)}`;
2854
+ 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)`;
2749
2855
  const bodyLines = [];
2750
2856
  for (let i = 0; i < rows.length; i++) {
2751
2857
  const r = rows[i];
2752
2858
  const glyph = i === rows.length - 1 ? "`-" : "|-";
2753
2859
  bodyLines.push(
2754
- `${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)`
2860
+ `${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)`
2755
2861
  );
2756
2862
  }
2757
2863
  const callByModel = rollupSpendByModel(
@@ -2799,7 +2905,7 @@ function renderRunSummary(opts) {
2799
2905
  tool: opts.toolName,
2800
2906
  scope,
2801
2907
  currency: "USD",
2802
- started_at: startedAt,
2908
+ started_at: startedAt2,
2803
2909
  ended_at: endedAt,
2804
2910
  rows,
2805
2911
  totals,
@@ -2924,14 +3030,15 @@ async function attachUsageBlock(result, answers, opts) {
2924
3030
  delete result["_suppress_run_summary"];
2925
3031
  }
2926
3032
  async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
2927
- if (!sessionId || answers.length === 0) return;
3033
+ const sid = recordingSessionId(sessionId);
3034
+ if (!sid || answers.length === 0) return;
2928
3035
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
2929
3036
  const rows = [];
2930
3037
  for (const a of answers) {
2931
3038
  const u = a.usage;
2932
3039
  if (!u || typeof u.provider !== "string" || u.provider === "") continue;
2933
3040
  rows.push({
2934
- session_id: sessionId,
3041
+ session_id: sid,
2935
3042
  ts: now,
2936
3043
  tool: toolName,
2937
3044
  purpose: u.purpose ?? "worker",
@@ -2954,13 +3061,14 @@ async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
2954
3061
  }
2955
3062
  }
2956
3063
  async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, nowS) {
2957
- if (!sessionId) return;
3064
+ const sid = recordingSessionId(sessionId);
3065
+ if (!sid) return;
2958
3066
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
2959
3067
  try {
2960
- let existing = await storage.getSession(sessionId);
3068
+ let existing = await storage.getSession(sid);
2961
3069
  if (!existing) {
2962
3070
  await storage.upsertSession({
2963
- session_id: sessionId,
3071
+ session_id: sid,
2964
3072
  started_at: now,
2965
3073
  last_at: now,
2966
3074
  calls: 0,
@@ -2973,7 +3081,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
2973
3081
  total_cost_usd: 0,
2974
3082
  total_cpu_ms: 0
2975
3083
  });
2976
- existing = await storage.getSession(sessionId);
3084
+ existing = await storage.getSession(sid);
2977
3085
  }
2978
3086
  if (!existing) return;
2979
3087
  let promptDelta = 0;
@@ -2993,7 +3101,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
2993
3101
  }
2994
3102
  if (a.cache_hit) cacheHitDelta += 1;
2995
3103
  }
2996
- await storage.accumulateSessionTotals(sessionId, {
3104
+ await storage.accumulateSessionTotals(sid, {
2997
3105
  calls: answers.length,
2998
3106
  wall_ms: wallMs,
2999
3107
  cache_hits: cacheHitDelta,
@@ -5962,10 +6070,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
5962
6070
  }
5963
6071
 
5964
6072
  // src/tools/confer.ts
5965
- var DEFERRED_OPTS = [
5966
- // empty — every confer opt runs natively except worker_tools, which
5967
- // is gated below (non-empty list → defer).
5968
- ];
5969
6073
  async function runConfer(args, opts) {
5970
6074
  const callStartedWall = performance3.now();
5971
6075
  const callStartedCpu = process.cpuUsage();
@@ -5981,16 +6085,11 @@ async function runConfer(args, opts) {
5981
6085
  rejectedWorkerTools.push(t);
5982
6086
  }
5983
6087
  }
5984
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
5985
- const needsBridge = DEFERRED_OPTS.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
5986
- if (needsBridge) {
5987
- if (opts.bridge && opts.bridge.toolNames.has("confer")) {
5988
- return await deferConfer(args, opts.bridge);
5989
- }
6088
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
5990
6089
  return errorEnvelope2(
5991
6090
  "CONFER_OPT_NOT_NATIVE",
5992
6091
  "worker_tools requested but innerCallers are not wired",
5993
- "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)."
6092
+ "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host."
5994
6093
  );
5995
6094
  }
5996
6095
  const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
@@ -6341,21 +6440,6 @@ function unknownProviderError(unknownNames, available) {
6341
6440
  available_now: Object.keys(available).sort()
6342
6441
  };
6343
6442
  }
6344
- async function deferConfer(args, bridge) {
6345
- const r = await bridge.callTool("confer", args);
6346
- const text = r.content[0]?.text;
6347
- if (typeof text === "string") {
6348
- try {
6349
- return JSON.parse(text);
6350
- } catch {
6351
- }
6352
- }
6353
- return errorEnvelope2(
6354
- "CONFER_BRIDGE_BAD_ENVELOPE",
6355
- "bridge returned an unparseable envelope for confer",
6356
- "Check that the Python child is healthy."
6357
- );
6358
- }
6359
6443
  function errorEnvelope2(code, message, hint) {
6360
6444
  return {
6361
6445
  tool: "confer",
@@ -6731,7 +6815,7 @@ function errorEnvelope3(code, message, hint) {
6731
6815
  transient: false
6732
6816
  };
6733
6817
  }
6734
- async function runVerify(args, bridge, fetchConfig) {
6818
+ async function runVerify(args, fetchConfig) {
6735
6819
  const checks = args["checks"];
6736
6820
  if (!Array.isArray(checks) || checks.length === 0) {
6737
6821
  return {
@@ -6743,7 +6827,6 @@ async function runVerify(args, bridge, fetchConfig) {
6743
6827
  )
6744
6828
  };
6745
6829
  }
6746
- void bridge;
6747
6830
  const allowShell = Boolean(args["allow_shell"] ?? false);
6748
6831
  const wallStart = performance4.now();
6749
6832
  const cpuStart = process.cpuUsage();
@@ -7045,7 +7128,6 @@ async function runBench(args, opts) {
7045
7128
  const innerOpts = {
7046
7129
  providers: opts.providers,
7047
7130
  allowlist: opts.allowlist ?? null,
7048
- ...opts.bridge ? { bridge: opts.bridge } : {},
7049
7131
  ...opts.moderator ? { moderator: opts.moderator } : {}
7050
7132
  };
7051
7133
  let inner;
@@ -7696,11 +7778,11 @@ function getNodeCache(cfg2, repoRoot, key, nowMs) {
7696
7778
  return null;
7697
7779
  }
7698
7780
  }
7699
- function atomicWriteJson(path16, payload) {
7700
- mkdirSync4(dirname2(path16), { recursive: true });
7701
- const tmp = `${path16}.${process.pid}.${Date.now()}.tmp`;
7781
+ function atomicWriteJson(path17, payload) {
7782
+ mkdirSync4(dirname2(path17), { recursive: true });
7783
+ const tmp = `${path17}.${process.pid}.${Date.now()}.tmp`;
7702
7784
  writeFileSync3(tmp, JSON.stringify(payload), "utf8");
7703
- renameSync(tmp, path16);
7785
+ renameSync(tmp, path17);
7704
7786
  }
7705
7787
  function putNodeCache(cfg2, repoRoot, key, value) {
7706
7788
  if (!cfg2 || cfg2.enabled === false) return;
@@ -7758,7 +7840,6 @@ var EST_TOKENS = {
7758
7840
  med: [1500, 800],
7759
7841
  high: [2500, 1500]
7760
7842
  };
7761
- var DEFERRED_OPTS2 = [];
7762
7843
  var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
7763
7844
  function parseReactiveSignals(output) {
7764
7845
  if (typeof output !== "string" || !output.includes("<signals>")) return [];
@@ -7798,17 +7879,6 @@ async function runOrchestrate(args, opts) {
7798
7879
  );
7799
7880
  if (breakerEnv) return breakerEnv;
7800
7881
  }
7801
- const needsBridge = DEFERRED_OPTS2.some((k) => Boolean(args[k]));
7802
- if (needsBridge) {
7803
- if (opts.bridge && opts.bridge.toolNames.has("orchestrate")) {
7804
- return await deferOrchestrate(args, opts.bridge);
7805
- }
7806
- return errorEnvelope5(
7807
- "ORCHESTRATE_OPT_NOT_NATIVE",
7808
- "this orchestrate opt-in requires the Python bridge in v1",
7809
- "v1 native covers the plain DAG flow + cheap_mode. reactive (mid-flight DAG updates) still defers. Set CROSSCHECK_BRIDGE_PYTHON=1 to enable."
7810
- );
7811
- }
7812
7882
  const goal = typeof args["goal"] === "string" ? args["goal"] : null;
7813
7883
  const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
7814
7884
  if (goal === null === (dagIn === null)) {
@@ -8750,21 +8820,6 @@ function resolveProviders3(names, available, allowlist) {
8750
8820
  }
8751
8821
  return out;
8752
8822
  }
8753
- async function deferOrchestrate(args, bridge) {
8754
- const r = await bridge.callTool("orchestrate", args);
8755
- const text = r.content[0]?.text;
8756
- if (typeof text === "string") {
8757
- try {
8758
- return JSON.parse(text);
8759
- } catch {
8760
- }
8761
- }
8762
- return errorEnvelope5(
8763
- "ORCHESTRATE_BRIDGE_BAD_ENVELOPE",
8764
- "bridge returned an unparseable envelope for orchestrate",
8765
- "Check that the Python child is healthy."
8766
- );
8767
- }
8768
8823
  function errorEnvelope5(code, message, hint, kind = "client") {
8769
8824
  return {
8770
8825
  tool: "orchestrate",
@@ -9129,7 +9184,6 @@ ${documentsPayload}`;
9129
9184
  }, {
9130
9185
  providers: opts.providers,
9131
9186
  allowlist: opts.allowlist ?? null,
9132
- ...opts.bridge ? { bridge: opts.bridge } : {},
9133
9187
  ctx
9134
9188
  });
9135
9189
  const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
@@ -9152,7 +9206,6 @@ ${scopeAnswer || "(none)"}
9152
9206
  providers: opts.providers,
9153
9207
  allowlist: opts.allowlist ?? null,
9154
9208
  moderator,
9155
- ...opts.bridge ? { bridge: opts.bridge } : {},
9156
9209
  ctx
9157
9210
  });
9158
9211
  let attempts = 1;
@@ -9187,7 +9240,6 @@ ${scopeAnswer || "(none)"}
9187
9240
  }, {
9188
9241
  providers: opts.providers,
9189
9242
  allowlist: opts.allowlist ?? null,
9190
- ...opts.bridge ? { bridge: opts.bridge } : {},
9191
9243
  ctx
9192
9244
  });
9193
9245
  }
@@ -9210,7 +9262,6 @@ ${scopeAnswer || "(none)"}
9210
9262
  }, {
9211
9263
  providers: opts.providers,
9212
9264
  allowlist: opts.allowlist ?? null,
9213
- ...opts.bridge ? { bridge: opts.bridge } : {},
9214
9265
  ctx
9215
9266
  });
9216
9267
  let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -9235,7 +9286,6 @@ ${documentsPayload}`
9235
9286
  providers: opts.providers,
9236
9287
  allowlist: opts.allowlist ?? null,
9237
9288
  moderator,
9238
- ...opts.bridge ? { bridge: opts.bridge } : {},
9239
9289
  ctx
9240
9290
  }
9241
9291
  );
@@ -9255,7 +9305,6 @@ ${documentsPayload}`
9255
9305
  }, {
9256
9306
  providers: opts.providers,
9257
9307
  allowlist: opts.allowlist ?? null,
9258
- ...opts.bridge ? { bridge: opts.bridge } : {},
9259
9308
  ctx
9260
9309
  });
9261
9310
  overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -9494,11 +9543,6 @@ function errorEnvelope6(toolName, code, message, hint) {
9494
9543
  // src/tools/coordinate.ts
9495
9544
  init_esm_shims();
9496
9545
  import { performance as performance8 } from "perf_hooks";
9497
- var DEFERRED_OPTS3 = [
9498
- // empty — every coordinate opt runs natively when its deps
9499
- // (storage / innerCallers) are wired. Without them the
9500
- // worker_tools gate still triggers a bridge defer.
9501
- ];
9502
9546
  var COORDINATE_DEFAULT_TEMP = 0.4;
9503
9547
  var ROLE_TURN_SCHEMA = {
9504
9548
  type: "object",
@@ -9553,23 +9597,18 @@ async function runCoordinate(args, opts) {
9553
9597
  rejectedWorkerTools.push(t);
9554
9598
  }
9555
9599
  }
9556
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
9557
- const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
9558
- if (needsBridge) {
9600
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
9559
9601
  if (superRequested) {
9560
9602
  return errorEnvelope7(
9561
9603
  "COORDINATE_SUPER_NOT_NATIVE",
9562
- "super mode requested but worker_tools needs the Python bridge",
9563
- "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."
9604
+ "super mode requested with worker_tools, but innerCallers are not wired",
9605
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
9564
9606
  );
9565
9607
  }
9566
- if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
9567
- return await deferCoordinate(args, opts.bridge);
9568
- }
9569
9608
  return errorEnvelope7(
9570
9609
  "COORDINATE_OPT_NOT_NATIVE",
9571
9610
  "worker_tools requested but innerCallers are not wired",
9572
- "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)."
9611
+ "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host."
9573
9612
  );
9574
9613
  }
9575
9614
  const untrusted = Boolean(args["untrusted_input"]);
@@ -9969,21 +10008,6 @@ function unknownProviderError3(unknownNames, available) {
9969
10008
  available_now: Object.keys(available).sort()
9970
10009
  };
9971
10010
  }
9972
- async function deferCoordinate(args, bridge) {
9973
- const r = await bridge.callTool("coordinate", args);
9974
- const text = r.content[0]?.text;
9975
- if (typeof text === "string") {
9976
- try {
9977
- return JSON.parse(text);
9978
- } catch {
9979
- }
9980
- }
9981
- return errorEnvelope7(
9982
- "COORDINATE_BRIDGE_BAD_ENVELOPE",
9983
- "bridge returned an unparseable envelope for coordinate",
9984
- "Check that the Python child is healthy."
9985
- );
9986
- }
9987
10011
  function errorEnvelope7(code, message, hint) {
9988
10012
  return {
9989
10013
  tool: "coordinate",
@@ -10316,10 +10340,6 @@ function buildModeratorTranscript(transcript) {
10316
10340
 
10317
10341
  // src/tools/debate.ts
10318
10342
  import { performance as performance10 } from "perf_hooks";
10319
- var DEFERRED_OPTS4 = [
10320
- // empty — every debate opt runs natively when its deps
10321
- // (storage / innerCallers) are wired.
10322
- ];
10323
10343
  async function runDebate(args, opts) {
10324
10344
  const callStartedWall = performance10.now();
10325
10345
  const callStartedCpu = process.cpuUsage();
@@ -10337,23 +10357,18 @@ async function runDebate(args, opts) {
10337
10357
  rejectedWorkerTools.push(t);
10338
10358
  }
10339
10359
  }
10340
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
10341
- const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
10342
- if (needsBridge) {
10360
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
10343
10361
  if (superRequested) {
10344
10362
  return errorEnvelope9(
10345
10363
  "DEBATE_SUPER_NOT_NATIVE",
10346
- "super mode requested but worker_tools needs the Python bridge",
10347
- "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."
10364
+ "super mode requested with worker_tools, but innerCallers are not wired",
10365
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
10348
10366
  );
10349
10367
  }
10350
- if (opts.bridge && opts.bridge.toolNames.has("debate")) {
10351
- return await deferDebate(args, opts.bridge);
10352
- }
10353
10368
  return errorEnvelope9(
10354
10369
  "DEBATE_OPT_NOT_NATIVE",
10355
10370
  "worker_tools requested but innerCallers are not wired",
10356
- "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)."
10371
+ "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."
10357
10372
  );
10358
10373
  }
10359
10374
  const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
@@ -10790,21 +10805,6 @@ function unknownProviderError5(unknownNames, available) {
10790
10805
  available_now: Object.keys(available).sort()
10791
10806
  };
10792
10807
  }
10793
- async function deferDebate(args, bridge) {
10794
- const r = await bridge.callTool("debate", args);
10795
- const text = r.content[0]?.text;
10796
- if (typeof text === "string") {
10797
- try {
10798
- return JSON.parse(text);
10799
- } catch {
10800
- }
10801
- }
10802
- return errorEnvelope9(
10803
- "DEBATE_BRIDGE_BAD_ENVELOPE",
10804
- "bridge returned an unparseable envelope for debate",
10805
- "Check that the Python child is healthy."
10806
- );
10807
- }
10808
10808
  function errorEnvelope9(code, message, hint) {
10809
10809
  return {
10810
10810
  tool: "debate",
@@ -10825,9 +10825,6 @@ var DEFAULT_DELEGATION_LIMITS = {
10825
10825
  };
10826
10826
  async function runDelegate(args, opts) {
10827
10827
  if (!opts.storage) {
10828
- if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
10829
- return await deferDelegate(args, opts.bridge);
10830
- }
10831
10828
  return errorEnvelope10(
10832
10829
  "DELEGATE_STORAGE_UNAVAILABLE",
10833
10830
  "delegate needs the local database (for quota tracking), which isn't available",
@@ -10899,7 +10896,6 @@ async function runDelegate(args, opts) {
10899
10896
  const innerOpts = {
10900
10897
  providers: opts.providers,
10901
10898
  allowlist: opts.allowlist ?? null,
10902
- ...opts.bridge ? { bridge: opts.bridge } : {},
10903
10899
  ...opts.moderator ? { moderator: opts.moderator } : {}
10904
10900
  };
10905
10901
  let result;
@@ -10938,21 +10934,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
10938
10934
  created_at: nowEpochSeconds
10939
10935
  });
10940
10936
  }
10941
- async function deferDelegate(args, bridge) {
10942
- const r = await bridge.callTool("delegate", args);
10943
- const text = r.content[0]?.text;
10944
- if (typeof text === "string") {
10945
- try {
10946
- return JSON.parse(text);
10947
- } catch {
10948
- }
10949
- }
10950
- return errorEnvelope10(
10951
- "DELEGATE_BRIDGE_BAD_ENVELOPE",
10952
- "bridge returned an unparseable envelope for delegate",
10953
- "Check that the Python child is healthy."
10954
- );
10955
- }
10956
10937
  function errorEnvelope10(code, message, hint) {
10957
10938
  return {
10958
10939
  tool: "delegate",
@@ -10996,9 +10977,6 @@ async function runExplain(args, opts) {
10996
10977
  );
10997
10978
  }
10998
10979
  if (!opts.storage) {
10999
- if (opts.bridge && opts.bridge.toolNames.has("explain")) {
11000
- return await deferExplain(args, opts.bridge);
11001
- }
11002
10980
  return errorEnvelope11(
11003
10981
  "EXPLAIN_STORAGE_UNAVAILABLE",
11004
10982
  "explain needs the local transcript/stats database, which isn't available",
@@ -11280,21 +11258,6 @@ function pyRepr5(v) {
11280
11258
  }
11281
11259
  return String(v);
11282
11260
  }
11283
- async function deferExplain(args, bridge) {
11284
- const r = await bridge.callTool("explain", args);
11285
- const text = r.content[0]?.text;
11286
- if (typeof text === "string") {
11287
- try {
11288
- return JSON.parse(text);
11289
- } catch {
11290
- }
11291
- }
11292
- return errorEnvelope11(
11293
- "EXPLAIN_BRIDGE_BAD_ENVELOPE",
11294
- "bridge returned an unparseable envelope for explain",
11295
- "Check that the Python child is healthy."
11296
- );
11297
- }
11298
11261
  function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
11299
11262
  return {
11300
11263
  tool: "explain",
@@ -11852,9 +11815,6 @@ async function runRecall(args, opts) {
11852
11815
  if (k < 1) k = 1;
11853
11816
  if (k > 50) k = 50;
11854
11817
  if (!opts.storage) {
11855
- if (opts.bridge && opts.bridge.toolNames.has("recall")) {
11856
- return await deferRecall(args, opts.bridge);
11857
- }
11858
11818
  return errorEnvelope12(
11859
11819
  "RECALL_STORAGE_UNAVAILABLE",
11860
11820
  "recall needs the local database, which isn't available",
@@ -11907,21 +11867,6 @@ async function runRecall(args, opts) {
11907
11867
  applied_filters: applied
11908
11868
  };
11909
11869
  }
11910
- async function deferRecall(args, bridge) {
11911
- const r = await bridge.callTool("recall", args);
11912
- const text = r.content[0]?.text;
11913
- if (typeof text === "string") {
11914
- try {
11915
- return JSON.parse(text);
11916
- } catch {
11917
- }
11918
- }
11919
- return errorEnvelope12(
11920
- "RECALL_BRIDGE_BAD_ENVELOPE",
11921
- "bridge returned an unparseable envelope for recall",
11922
- "Check that the Python child is healthy."
11923
- );
11924
- }
11925
11870
  function errorEnvelope12(code, message, hint) {
11926
11871
  return {
11927
11872
  tool: "recall",
@@ -11945,9 +11890,6 @@ async function runRecommendPanel(args, opts) {
11945
11890
  );
11946
11891
  }
11947
11892
  if (!opts.storage) {
11948
- if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
11949
- return await deferRecommendPanel(args, opts.bridge);
11950
- }
11951
11893
  return errorEnvelope13(
11952
11894
  "RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
11953
11895
  "recommend_panel needs the local stats database, which isn't available",
@@ -12010,21 +11952,6 @@ async function runRecommendPanel(args, opts) {
12010
11952
  meta: result.meta
12011
11953
  };
12012
11954
  }
12013
- async function deferRecommendPanel(args, bridge) {
12014
- const r = await bridge.callTool("recommend_panel", args);
12015
- const text = r.content[0]?.text;
12016
- if (typeof text === "string") {
12017
- try {
12018
- return JSON.parse(text);
12019
- } catch {
12020
- }
12021
- }
12022
- return errorEnvelope13(
12023
- "RECOMMEND_PANEL_BRIDGE_BAD_ENVELOPE",
12024
- "bridge returned an unparseable envelope for recommend_panel",
12025
- "Check that the Python child is healthy."
12026
- );
12027
- }
12028
11955
  function errorEnvelope13(code, message, hint) {
12029
11956
  return {
12030
11957
  tool: "recommend_panel",
@@ -12055,9 +11982,6 @@ init_esm_shims();
12055
11982
  import { readFileSync as readFileSync10, existsSync as existsSync8 } from "fs";
12056
11983
  async function runScoreboard(args, opts) {
12057
11984
  if (!opts.storage) {
12058
- if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
12059
- return await deferScoreboard(args, opts.bridge);
12060
- }
12061
11985
  return errorEnvelope14(
12062
11986
  "SCOREBOARD_STORAGE_UNAVAILABLE",
12063
11987
  "scoreboard needs the local stats database, which isn't available",
@@ -12180,21 +12104,6 @@ function clampInt3(raw, min, max, fallback) {
12180
12104
  if (!Number.isFinite(n)) return fallback;
12181
12105
  return Math.min(max, Math.max(min, Math.trunc(n)));
12182
12106
  }
12183
- async function deferScoreboard(args, bridge) {
12184
- const r = await bridge.callTool("scoreboard", args);
12185
- const text = r.content[0]?.text;
12186
- if (typeof text === "string") {
12187
- try {
12188
- return JSON.parse(text);
12189
- } catch {
12190
- }
12191
- }
12192
- return errorEnvelope14(
12193
- "SCOREBOARD_BRIDGE_BAD_ENVELOPE",
12194
- "bridge returned an unparseable envelope for scoreboard",
12195
- "Check that the Python child is healthy."
12196
- );
12197
- }
12198
12107
  function errorEnvelope14(code, message, hint) {
12199
12108
  return {
12200
12109
  tool: "scoreboard",
@@ -12232,9 +12141,6 @@ async function runSessionMemory(args, opts) {
12232
12141
  );
12233
12142
  }
12234
12143
  if (!opts.storage) {
12235
- if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
12236
- return await deferSessionMemory(args, opts.bridge);
12237
- }
12238
12144
  return errorEnvelope15(
12239
12145
  "SESSION_MEMORY_STORAGE_UNAVAILABLE",
12240
12146
  "session_memory needs the local database, which isn't available",
@@ -12339,21 +12245,6 @@ function clampInt4(raw, min, max, fallback) {
12339
12245
  if (!Number.isFinite(n)) return fallback;
12340
12246
  return Math.min(max, Math.max(min, Math.trunc(n)));
12341
12247
  }
12342
- async function deferSessionMemory(args, bridge) {
12343
- const r = await bridge.callTool("session_memory", args);
12344
- const text = r.content[0]?.text;
12345
- if (typeof text === "string") {
12346
- try {
12347
- return JSON.parse(text);
12348
- } catch {
12349
- }
12350
- }
12351
- return errorEnvelope15(
12352
- "SESSION_MEMORY_BRIDGE_BAD_ENVELOPE",
12353
- "bridge returned an unparseable envelope for session_memory",
12354
- "Check that the Python child is healthy."
12355
- );
12356
- }
12357
12248
  function errorEnvelope15(code, message, hint) {
12358
12249
  return {
12359
12250
  tool: "session_memory",
@@ -12977,7 +12868,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12977
12868
  var DEFAULT_PACKAGE = "crosscheck-cli";
12978
12869
  var FETCH_TIMEOUT_MS = 3e3;
12979
12870
  function engineVersion() {
12980
- return true ? "0.2.27" : "0.0.0-dev";
12871
+ return true ? "0.2.28" : "0.0.0-dev";
12981
12872
  }
12982
12873
  function defaultUpdateCachePath() {
12983
12874
  const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -13751,12 +13642,11 @@ function helpTool() {
13751
13642
  }
13752
13643
  });
13753
13644
  }
13754
- function registerCoreTools(opts = {}) {
13755
- const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
13645
+ function registerCoreTools(o = {}) {
13756
13646
  const tools = /* @__PURE__ */ new Map();
13757
13647
  const list = [
13758
13648
  pingTool(),
13759
- verifyTool(o.bridge, o.fetchConfig),
13649
+ verifyTool(o.fetchConfig),
13760
13650
  pickTool(
13761
13651
  o.providers ?? {},
13762
13652
  o.providerAllowlist ?? null,
@@ -13768,7 +13658,6 @@ function registerCoreTools(opts = {}) {
13768
13658
  auditTool(
13769
13659
  o.providers ?? {},
13770
13660
  o.providerAllowlist ?? null,
13771
- o.bridge,
13772
13661
  o.transcriptsDir,
13773
13662
  o.pricing,
13774
13663
  o.storage,
@@ -13778,7 +13667,6 @@ function registerCoreTools(opts = {}) {
13778
13667
  conferTool(
13779
13668
  o.providers ?? {},
13780
13669
  o.providerAllowlist ?? null,
13781
- o.bridge,
13782
13670
  o.moderatorDefault ?? "anthropic",
13783
13671
  o.pricing,
13784
13672
  o.storage,
@@ -13791,7 +13679,6 @@ function registerCoreTools(opts = {}) {
13791
13679
  debateTool(
13792
13680
  o.providers ?? {},
13793
13681
  o.providerAllowlist ?? null,
13794
- o.bridge,
13795
13682
  buildInnerCallers(o),
13796
13683
  o.storage,
13797
13684
  o.pricing,
@@ -13803,7 +13690,6 @@ function registerCoreTools(opts = {}) {
13803
13690
  coordinateTool(
13804
13691
  o.providers ?? {},
13805
13692
  o.providerAllowlist ?? null,
13806
- o.bridge,
13807
13693
  buildInnerCallers(o),
13808
13694
  o.storage,
13809
13695
  o.circuitBreakers,
@@ -13814,7 +13700,6 @@ function registerCoreTools(opts = {}) {
13814
13700
  triangulateTool(
13815
13701
  o.providers ?? {},
13816
13702
  o.providerAllowlist ?? null,
13817
- o.bridge,
13818
13703
  o.storage,
13819
13704
  o.circuitBreakers,
13820
13705
  o.transcriptsDir,
@@ -13823,7 +13708,6 @@ function registerCoreTools(opts = {}) {
13823
13708
  planTool(
13824
13709
  o.providers ?? {},
13825
13710
  o.providerAllowlist ?? null,
13826
- o.bridge,
13827
13711
  o.storage,
13828
13712
  o.circuitBreakers,
13829
13713
  o.transcriptsDir,
@@ -13832,7 +13716,6 @@ function registerCoreTools(opts = {}) {
13832
13716
  critiqueTool(
13833
13717
  o.providers ?? {},
13834
13718
  o.providerAllowlist ?? null,
13835
- o.bridge,
13836
13719
  o.storage,
13837
13720
  o.circuitBreakers,
13838
13721
  o.transcriptsDir,
@@ -13841,7 +13724,6 @@ function registerCoreTools(opts = {}) {
13841
13724
  reviewTool(
13842
13725
  o.providers ?? {},
13843
13726
  o.providerAllowlist ?? null,
13844
- o.bridge,
13845
13727
  o.storage,
13846
13728
  o.circuitBreakers,
13847
13729
  o.transcriptsDir,
@@ -13849,25 +13731,23 @@ function registerCoreTools(opts = {}) {
13849
13731
  ),
13850
13732
  listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
13851
13733
  modelsTool(o.providers ?? {}, o.activeProviders ?? null),
13852
- recallTool(o.storage, o.bridge),
13853
- sessionMemoryTool(o.storage, o.bridge),
13854
- scoreboardTool(o.storage, o.bridge, o.eventsPath),
13855
- explainTool(o.storage, o.bridge, o.transcriptsDir),
13734
+ recallTool(o.storage),
13735
+ sessionMemoryTool(o.storage),
13736
+ scoreboardTool(o.storage, o.eventsPath),
13737
+ explainTool(o.storage, o.transcriptsDir),
13856
13738
  delegateTool(
13857
13739
  o.providers ?? {},
13858
13740
  o.providerAllowlist ?? null,
13859
13741
  o.storage,
13860
- o.bridge,
13861
13742
  o.moderatorDefault ?? "anthropic"
13862
13743
  ),
13863
13744
  fetchTool(o.storage, o.fetchConfig, o.repoRoot),
13864
- recommendPanelTool(o.providers ?? {}, o.storage, o.bridge),
13745
+ recommendPanelTool(o.providers ?? {}, o.storage),
13865
13746
  updateCrosscheckTool(o.repoRoot ?? null),
13866
13747
  benchTool(
13867
13748
  o.providers ?? {},
13868
13749
  o.providerAllowlist ?? null,
13869
13750
  o.storage,
13870
- o.bridge,
13871
13751
  o.moderatorDefault ?? "anthropic",
13872
13752
  o.benchGoldensDir,
13873
13753
  o.circuitBreakers,
@@ -13878,7 +13758,6 @@ function registerCoreTools(opts = {}) {
13878
13758
  solveTool(
13879
13759
  o.providers ?? {},
13880
13760
  o.providerAllowlist ?? null,
13881
- o.bridge,
13882
13761
  o.storage,
13883
13762
  o.circuitBreakers,
13884
13763
  o.transcriptsDir,
@@ -13887,7 +13766,6 @@ function registerCoreTools(opts = {}) {
13887
13766
  orchestrateTool(
13888
13767
  o.providers ?? {},
13889
13768
  o.providerAllowlist ?? null,
13890
- o.bridge,
13891
13769
  o.moderatorDefault ?? "anthropic",
13892
13770
  o.storage,
13893
13771
  o.pricing,
@@ -13934,7 +13812,6 @@ function createTool(o, toolName, cheapDefault) {
13934
13812
  providers: o.providers ?? {},
13935
13813
  allowlist: o.providerAllowlist ?? null,
13936
13814
  ...o.storage ? { storage: o.storage } : {},
13937
- ...o.bridge ? { bridge: o.bridge } : {},
13938
13815
  ...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
13939
13816
  ...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
13940
13817
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {},
@@ -13943,7 +13820,7 @@ function createTool(o, toolName, cheapDefault) {
13943
13820
  })
13944
13821
  };
13945
13822
  }
13946
- function orchestrateTool(providers, allowlist, bridge, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
13823
+ function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
13947
13824
  return {
13948
13825
  name: "orchestrate",
13949
13826
  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.",
@@ -13968,7 +13845,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
13968
13845
  providers,
13969
13846
  allowlist,
13970
13847
  moderator,
13971
- ...bridge ? { bridge } : {},
13972
13848
  ...storage ? { storage } : {},
13973
13849
  ...pricing ? { pricing } : {},
13974
13850
  ...breakers ? { breakers } : {},
@@ -13978,7 +13854,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
13978
13854
  })
13979
13855
  };
13980
13856
  }
13981
- function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13857
+ function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13982
13858
  return {
13983
13859
  name: "solve",
13984
13860
  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.",
@@ -14000,7 +13876,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
14000
13876
  handler: (args) => runSolve(args, {
14001
13877
  providers,
14002
13878
  allowlist,
14003
- ...bridge ? { bridge } : {},
14004
13879
  ...storage ? { storage } : {},
14005
13880
  ...breakers ? { breakers } : {},
14006
13881
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14039,7 +13914,7 @@ function configPinTool(repoRoot, config2, rejectDriftEnv) {
14039
13914
  }
14040
13915
  };
14041
13916
  }
14042
- function benchTool(providers, allowlist, storage, bridge, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
13917
+ function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
14043
13918
  return {
14044
13919
  name: "bench",
14045
13920
  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).",
@@ -14058,7 +13933,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
14058
13933
  allowlist,
14059
13934
  moderator,
14060
13935
  ...storage ? { storage } : {},
14061
- ...bridge ? { bridge } : {},
14062
13936
  ...defaultGoldensDir ? { defaultGoldensDir } : {},
14063
13937
  ...breakers ? { breakers } : {},
14064
13938
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14085,7 +13959,7 @@ function updateCrosscheckTool(repoRoot) {
14085
13959
  }
14086
13960
  };
14087
13961
  }
14088
- function recommendPanelTool(providers, storage, bridge) {
13962
+ function recommendPanelTool(providers, storage) {
14089
13963
  return {
14090
13964
  name: "recommend_panel",
14091
13965
  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.",
@@ -14103,8 +13977,7 @@ function recommendPanelTool(providers, storage, bridge) {
14103
13977
  },
14104
13978
  handler: (args) => runRecommendPanel(args, {
14105
13979
  providers,
14106
- ...storage ? { storage } : {},
14107
- ...bridge ? { bridge } : {}
13980
+ ...storage ? { storage } : {}
14108
13981
  })
14109
13982
  };
14110
13983
  }
@@ -14129,7 +14002,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
14129
14002
  })
14130
14003
  };
14131
14004
  }
14132
- function delegateTool(providers, allowlist, storage, bridge, moderator) {
14005
+ function delegateTool(providers, allowlist, storage, moderator) {
14133
14006
  return {
14134
14007
  name: "delegate",
14135
14008
  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.",
@@ -14149,12 +14022,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
14149
14022
  providers,
14150
14023
  allowlist,
14151
14024
  moderator,
14152
- ...storage ? { storage } : {},
14153
- ...bridge ? { bridge } : {}
14025
+ ...storage ? { storage } : {}
14154
14026
  })
14155
14027
  };
14156
14028
  }
14157
- function explainTool(storage, bridge, transcriptsDir) {
14029
+ function explainTool(storage, transcriptsDir) {
14158
14030
  return {
14159
14031
  name: "explain",
14160
14032
  description: "Replay a session as a navigable tree with cost/latency annotations. Reads usage_log + optionally walks the transcripts directory for per-tool summaries.",
@@ -14172,12 +14044,11 @@ function explainTool(storage, bridge, transcriptsDir) {
14172
14044
  },
14173
14045
  handler: (args) => runExplain(args, {
14174
14046
  ...storage ? { storage } : {},
14175
- ...bridge ? { bridge } : {},
14176
14047
  ...transcriptsDir ? { transcriptsDir } : {}
14177
14048
  })
14178
14049
  };
14179
14050
  }
14180
- function scoreboardTool(storage, bridge, eventsPath) {
14051
+ function scoreboardTool(storage, eventsPath) {
14181
14052
  return {
14182
14053
  name: "scoreboard",
14183
14054
  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).",
@@ -14191,12 +14062,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
14191
14062
  },
14192
14063
  handler: (args) => runScoreboard(args, {
14193
14064
  ...storage ? { storage } : {},
14194
- ...bridge ? { bridge } : {},
14195
14065
  ...eventsPath ? { eventsPath } : {}
14196
14066
  })
14197
14067
  };
14198
14068
  }
14199
- function sessionMemoryTool(storage, bridge) {
14069
+ function sessionMemoryTool(storage) {
14200
14070
  return {
14201
14071
  name: "session_memory",
14202
14072
  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).",
@@ -14219,15 +14089,14 @@ function sessionMemoryTool(storage, bridge) {
14219
14089
  required: ["action", "session_id"]
14220
14090
  },
14221
14091
  handler: (args) => runSessionMemory(args, {
14222
- ...storage ? { storage } : {},
14223
- ...bridge ? { bridge } : {}
14092
+ ...storage ? { storage } : {}
14224
14093
  })
14225
14094
  };
14226
14095
  }
14227
- function recallTool(storage, bridge) {
14096
+ function recallTool(storage) {
14228
14097
  return {
14229
14098
  name: "recall",
14230
- 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.",
14099
+ description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter.",
14231
14100
  inputSchema: {
14232
14101
  type: "object",
14233
14102
  additionalProperties: true,
@@ -14241,8 +14110,7 @@ function recallTool(storage, bridge) {
14241
14110
  required: ["query"]
14242
14111
  },
14243
14112
  handler: (args) => runRecall(args, {
14244
- ...storage ? { storage } : {},
14245
- ...bridge ? { bridge } : {}
14113
+ ...storage ? { storage } : {}
14246
14114
  })
14247
14115
  };
14248
14116
  }
@@ -14278,7 +14146,7 @@ function modelsTool(providers, activeProviders) {
14278
14146
  handler: async (args) => runModels(args, { providers, activeProviders })
14279
14147
  };
14280
14148
  }
14281
- function reviewTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
14149
+ function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
14282
14150
  return {
14283
14151
  name: "review",
14284
14152
  description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
@@ -14297,7 +14165,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
14297
14165
  handler: (args) => runReview(args, {
14298
14166
  providers,
14299
14167
  allowlist,
14300
- ...bridge ? { bridge } : {},
14301
14168
  ...storage ? { storage } : {},
14302
14169
  ...breakers ? { breakers } : {},
14303
14170
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14305,7 +14172,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
14305
14172
  })
14306
14173
  };
14307
14174
  }
14308
- function critiqueTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
14175
+ function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
14309
14176
  return {
14310
14177
  name: "critique",
14311
14178
  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.",
@@ -14325,7 +14192,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
14325
14192
  handler: (args) => runCritique(args, {
14326
14193
  providers,
14327
14194
  allowlist,
14328
- ...bridge ? { bridge } : {},
14329
14195
  ...storage ? { storage } : {},
14330
14196
  ...breakers ? { breakers } : {},
14331
14197
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14333,7 +14199,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
14333
14199
  })
14334
14200
  };
14335
14201
  }
14336
- function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
14202
+ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
14337
14203
  return {
14338
14204
  name: "plan",
14339
14205
  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.',
@@ -14360,7 +14226,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
14360
14226
  handler: (args) => runPlan(args, {
14361
14227
  providers,
14362
14228
  allowlist,
14363
- ...bridge ? { bridge } : {},
14364
14229
  ...storage ? { storage } : {},
14365
14230
  ...breakers ? { breakers } : {},
14366
14231
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14368,7 +14233,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
14368
14233
  })
14369
14234
  };
14370
14235
  }
14371
- function triangulateTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
14236
+ function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
14372
14237
  return {
14373
14238
  name: "triangulate",
14374
14239
  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.",
@@ -14389,7 +14254,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
14389
14254
  handler: (args) => runTriangulate(args, {
14390
14255
  providers,
14391
14256
  allowlist,
14392
- ...bridge ? { bridge } : {},
14393
14257
  ...storage ? { storage } : {},
14394
14258
  ...breakers ? { breakers } : {},
14395
14259
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -14397,7 +14261,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
14397
14261
  })
14398
14262
  };
14399
14263
  }
14400
- function coordinateTool(providers, allowlist, bridge, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14264
+ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14401
14265
  return {
14402
14266
  name: "coordinate",
14403
14267
  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).",
@@ -14422,7 +14286,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
14422
14286
  handler: (args) => runCoordinate(args, {
14423
14287
  providers,
14424
14288
  allowlist,
14425
- ...bridge ? { bridge } : {},
14426
14289
  innerCallers,
14427
14290
  ...storage ? { storage } : {},
14428
14291
  ...breakers ? { breakers } : {},
@@ -14432,7 +14295,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
14432
14295
  })
14433
14296
  };
14434
14297
  }
14435
- function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14298
+ function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14436
14299
  return {
14437
14300
  name: "debate",
14438
14301
  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).",
@@ -14462,7 +14325,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
14462
14325
  handler: (args) => runDebate(args, {
14463
14326
  providers,
14464
14327
  allowlist,
14465
- ...bridge ? { bridge } : {},
14466
14328
  innerCallers,
14467
14329
  ...storage ? { storage } : {},
14468
14330
  ...pricing ? { pricing } : {},
@@ -14482,10 +14344,10 @@ function buildInnerCallers(o) {
14482
14344
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {}
14483
14345
  });
14484
14346
  }
14485
- out.verify = (args) => runVerify(args, o.bridge, o.fetchConfig);
14347
+ out.verify = (args) => runVerify(args, o.fetchConfig);
14486
14348
  return out;
14487
14349
  }
14488
- function conferTool(providers, allowlist, bridge, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14350
+ function conferTool(providers, allowlist, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
14489
14351
  return {
14490
14352
  name: "confer",
14491
14353
  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).",
@@ -14512,7 +14374,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
14512
14374
  handler: (args) => runConfer(args, {
14513
14375
  providers,
14514
14376
  allowlist,
14515
- ...bridge ? { bridge } : {},
14516
14377
  moderator,
14517
14378
  ...pricing ? { pricing } : {},
14518
14379
  ...storage ? { storage } : {},
@@ -14524,7 +14385,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
14524
14385
  })
14525
14386
  };
14526
14387
  }
14527
- function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storage, breakers, repoRoot) {
14388
+ function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
14528
14389
  return {
14529
14390
  name: "audit",
14530
14391
  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.",
@@ -14550,7 +14411,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
14550
14411
  handler: (args) => runAudit(args, {
14551
14412
  providers,
14552
14413
  allowlist,
14553
- ...bridge ? { bridge } : {},
14554
14414
  ...transcriptsDir ? { transcriptsDir } : {},
14555
14415
  ...pricing ? { pricing } : {},
14556
14416
  ...storage ? { storage } : {},
@@ -14614,7 +14474,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
14614
14474
  })
14615
14475
  };
14616
14476
  }
14617
- function verifyTool(bridge, fetchConfig) {
14477
+ function verifyTool(fetchConfig) {
14618
14478
  return {
14619
14479
  name: "verify",
14620
14480
  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.",
@@ -14632,7 +14492,7 @@ function verifyTool(bridge, fetchConfig) {
14632
14492
  },
14633
14493
  required: ["checks"]
14634
14494
  },
14635
- handler: (args) => runVerify(args, bridge, fetchConfig)
14495
+ handler: (args) => runVerify(args, fetchConfig)
14636
14496
  };
14637
14497
  }
14638
14498
  function pingTool() {
@@ -14964,10 +14824,12 @@ function canonicalEventBody(e) {
14964
14824
  e.status,
14965
14825
  e.errorClass ?? ""
14966
14826
  ].join("|");
14967
- if (e.runId === void 0 && e.purpose === void 0 && e.fingerprint === void 0) {
14968
- return base;
14969
- }
14970
- return [base, e.runId ?? "", e.purpose ?? "", e.fingerprint ?? ""].join("|");
14827
+ const hasV2 = e.runId !== void 0 || e.purpose !== void 0 || e.fingerprint !== void 0;
14828
+ const hasV3 = e.sessionId !== void 0;
14829
+ if (!hasV2 && !hasV3) return base;
14830
+ const parts = [base, e.runId ?? "", e.purpose ?? "", e.fingerprint ?? ""];
14831
+ if (hasV3) parts.push(e.sessionId ?? "");
14832
+ return parts.join("|");
14971
14833
  }
14972
14834
  function normalizePurpose(v) {
14973
14835
  if (typeof v !== "string") return void 0;
@@ -15085,7 +14947,7 @@ function scheduleFlush() {
15085
14947
  }, FLUSH_INTERVAL_MS);
15086
14948
  if (typeof flushTimer.unref === "function") flushTimer.unref();
15087
14949
  }
15088
- function enqueue(cfg2, input, runId, fingerprint) {
14950
+ function enqueue(cfg2, input, runId, fingerprint, sessionId) {
15089
14951
  const base = {
15090
14952
  eventId: crypto4.randomUUID(),
15091
14953
  seatId: cfg2.seatId,
@@ -15104,6 +14966,7 @@ function enqueue(cfg2, input, runId, fingerprint) {
15104
14966
  // omitting keeps the JSON honest about what we actually know.
15105
14967
  ...input.errorClass === void 0 ? {} : { errorClass: input.errorClass },
15106
14968
  runId,
14969
+ sessionId,
15107
14970
  // Omit entirely (not "") when unknown, so the canonical body stays
15108
14971
  // consistent with what the server reconstructs from the JSON.
15109
14972
  ...input.purpose === void 0 ? {} : { purpose: input.purpose },
@@ -15118,15 +14981,23 @@ function enqueue(cfg2, input, runId, fingerprint) {
15118
14981
  if (queue.length >= FLUSH_BATCH_AT) void flush();
15119
14982
  else scheduleFlush();
15120
14983
  }
14984
+ function sessionIdFromEnvelope(out) {
14985
+ if (!out || typeof out !== "object") return null;
14986
+ const rs = out["run_summary"];
14987
+ if (!rs || typeof rs !== "object") return null;
14988
+ const v = rs["session_id"];
14989
+ return typeof v === "string" && v.trim().length > 0 ? v : null;
14990
+ }
15121
14991
  function recordUsage(out, toolName) {
15122
14992
  try {
15123
14993
  const cfg2 = getConfig2();
15124
14994
  if (!cfg2) return;
15125
14995
  if (toolName === "update_crosscheck") return;
15126
14996
  const runId = crypto4.randomUUID();
14997
+ const sessionId = resolveSessionId(sessionIdFromEnvelope(out));
15127
14998
  const fingerprint = currentFingerprint();
15128
14999
  for (const ev of usageEventsFromEnvelope(out, toolName)) {
15129
- enqueue(cfg2, ev, runId, fingerprint);
15000
+ enqueue(cfg2, ev, runId, fingerprint, sessionId);
15130
15001
  }
15131
15002
  } catch {
15132
15003
  }
@@ -15233,7 +15104,7 @@ function createServer(opts = {}) {
15233
15104
  throw new Error(`unknown tool: ${name}`);
15234
15105
  }
15235
15106
  const args = req.params.arguments ?? {};
15236
- const startedAt = (/* @__PURE__ */ new Date()).toISOString();
15107
+ const startedAt2 = (/* @__PURE__ */ new Date()).toISOString();
15237
15108
  const startedHr = process.hrtime.bigint();
15238
15109
  const id = nextEventId();
15239
15110
  syncSegment(opts.repoRoot);
@@ -15247,7 +15118,7 @@ function createServer(opts = {}) {
15247
15118
  event: "tool_invoke",
15248
15119
  id,
15249
15120
  tool: name,
15250
- started_at: startedAt,
15121
+ started_at: startedAt2,
15251
15122
  duration_ms: 0,
15252
15123
  status: "ok",
15253
15124
  args_keys: topLevelKeys(args),
@@ -15281,7 +15152,7 @@ function createServer(opts = {}) {
15281
15152
  event: "tool_invoke",
15282
15153
  id,
15283
15154
  tool: name,
15284
- started_at: startedAt,
15155
+ started_at: startedAt2,
15285
15156
  duration_ms: durationMs,
15286
15157
  status: "ok",
15287
15158
  args_keys: topLevelKeys(args),
@@ -15303,7 +15174,7 @@ function createServer(opts = {}) {
15303
15174
  event: "tool_invoke",
15304
15175
  id,
15305
15176
  tool: name,
15306
- started_at: startedAt,
15177
+ started_at: startedAt2,
15307
15178
  duration_ms: durationMs,
15308
15179
  status: "error",
15309
15180
  args_keys: topLevelKeys(args),
@@ -15334,7 +15205,6 @@ async function connectAndServe(transport, opts = {}) {
15334
15205
  }
15335
15206
  function buildToolRegistry(opts) {
15336
15207
  const registerOpts = {};
15337
- if (opts.bridge) registerOpts.bridge = opts.bridge;
15338
15208
  if (opts.providers) registerOpts.providers = opts.providers;
15339
15209
  if (opts.providerAllowlist !== void 0)
15340
15210
  registerOpts.providerAllowlist = opts.providerAllowlist;
@@ -15351,13 +15221,7 @@ function buildToolRegistry(opts) {
15351
15221
  if (opts.moderatorDefault) registerOpts.moderatorDefault = opts.moderatorDefault;
15352
15222
  if (opts.benchGoldensDir) registerOpts.benchGoldensDir = opts.benchGoldensDir;
15353
15223
  if (opts.eventsPath) registerOpts.eventsPath = opts.eventsPath;
15354
- const tools = registerCoreTools(registerOpts);
15355
- if (!opts.bridge) return tools;
15356
- const proxies = buildPythonProxies(opts.bridge);
15357
- for (const [name, proxy] of proxies) {
15358
- if (!tools.has(name)) tools.set(name, proxy);
15359
- }
15360
- return tools;
15224
+ return registerCoreTools(registerOpts);
15361
15225
  }
15362
15226
 
15363
15227
  // src/core/config-file.ts
@@ -15532,14 +15396,39 @@ function loadConfigFile(opts) {
15532
15396
  return mapConfig(obj, file);
15533
15397
  }
15534
15398
 
15399
+ // src/core/process-registry.ts
15400
+ init_esm_shims();
15401
+ import { mkdirSync as mkdirSync10, readdirSync as readdirSync5, readFileSync as readFileSync16, rmSync, writeFileSync as writeFileSync9 } from "fs";
15402
+ import os2 from "os";
15403
+ import path15 from "path";
15404
+ function registryDir(env = process.env) {
15405
+ const base = env["CROSSCHECK_DATA_DIR"] || path15.join(env["HOME"] ?? env["USERPROFILE"] ?? os2.homedir(), ".crosscheck");
15406
+ return path15.join(base, "procs");
15407
+ }
15408
+ function registerProcess(rec, env = process.env) {
15409
+ try {
15410
+ const dir = registryDir(env);
15411
+ mkdirSync10(dir, { recursive: true, mode: 448 });
15412
+ writeFileSync9(path15.join(dir, `${rec.pid}.json`), JSON.stringify(rec), { mode: 384 });
15413
+ } catch {
15414
+ }
15415
+ }
15416
+ function unregisterProcess(pid = process.pid, env = process.env) {
15417
+ try {
15418
+ rmSync(path15.join(registryDir(env), `${pid}.json`), { force: true });
15419
+ } catch {
15420
+ }
15421
+ }
15422
+
15535
15423
  // src/entrypoints/node-stdio.ts
15424
+ var HERE = typeof __dirname !== "undefined" ? __dirname : path16.dirname(fileURLToPath3(import.meta.url));
15536
15425
  var SHUTDOWN_TIMEOUT_MS = 2e3;
15537
15426
  async function main() {
15538
15427
  enforceLicenseOrExit();
15539
- const cfgDataDir = process.env["CROSSCHECK_DATA_DIR"] || path15.join(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".crosscheck");
15428
+ const cfgDataDir = process.env["CROSSCHECK_DATA_DIR"] || path16.join(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".crosscheck");
15540
15429
  const configFile = loadConfigFile({
15541
15430
  startDir: process.cwd(),
15542
- repoRoot: findGitRoot(__dirname),
15431
+ repoRoot: findGitRoot(HERE),
15543
15432
  dataDir: cfgDataDir
15544
15433
  });
15545
15434
  if (configFile) {
@@ -15553,15 +15442,17 @@ async function main() {
15553
15442
  `);
15554
15443
  }
15555
15444
  setEventEmitter(buildDefaultEmitter(process.env));
15556
- if (process.env["CROSSCHECK_BRIDGE_PYTHON"] === "1") {
15557
- process.stderr.write(
15558
- "crosscheck-agent: CROSSCHECK_BRIDGE_PYTHON is deprecated and ignored \u2014 the engine is native-only.\n"
15559
- );
15560
- }
15561
15445
  installShutdownHandlers();
15446
+ registerProcess({
15447
+ pid: process.pid,
15448
+ version: SERVER_VERSION,
15449
+ startedAt: Date.now(),
15450
+ ppid: process.ppid,
15451
+ sessionId: engineSessionId()
15452
+ });
15562
15453
  const bundledPricing = (() => {
15563
15454
  try {
15564
- return path15.join(path15.dirname(fileURLToPath3(import.meta.url)), "pricing.json");
15455
+ return path16.join(path16.dirname(fileURLToPath3(import.meta.url)), "pricing.json");
15565
15456
  } catch {
15566
15457
  return void 0;
15567
15458
  }
@@ -15588,10 +15479,10 @@ async function main() {
15588
15479
  }
15589
15480
  let storage;
15590
15481
  if (process.env["CROSSCHECK_DB_DISABLED"] !== "1") {
15591
- const dbPath = process.env["CROSSCHECK_DB_PATH"] ?? resolveRepoFile(".crosscheck/db.sqlite") ?? path15.join(cfgDataDir, "db.sqlite");
15482
+ const dbPath = process.env["CROSSCHECK_DB_PATH"] ?? resolveRepoFile(".crosscheck/db.sqlite") ?? path16.join(cfgDataDir, "db.sqlite");
15592
15483
  if (dbPath) {
15593
15484
  try {
15594
- mkdirSync10(path15.dirname(dbPath), { recursive: true });
15485
+ mkdirSync11(path16.dirname(dbPath), { recursive: true });
15595
15486
  const { openBetterSqliteStorage: openBetterSqliteStorage2 } = await Promise.resolve().then(() => (init_better_sqlite3(), better_sqlite3_exports));
15596
15487
  storage = openBetterSqliteStorage2({ path: dbPath });
15597
15488
  await storage.migrate();
@@ -15609,7 +15500,7 @@ async function main() {
15609
15500
  }
15610
15501
  }
15611
15502
  const transcriptsDir = configFile?.logTranscripts === false ? void 0 : process.env["CROSSCHECK_TRANSCRIPTS_DIR"] ?? configFile?.transcriptsDir ?? resolveRepoFile(".crosscheck/transcripts");
15612
- const repoRoot = process.env["CROSSCHECK_REPO_ROOT"] ?? findGitRoot(__dirname);
15503
+ const repoRoot = process.env["CROSSCHECK_REPO_ROOT"] ?? findGitRoot(HERE);
15613
15504
  const transport = new StdioServerTransport();
15614
15505
  const serverOpts = { providers };
15615
15506
  if (storage) serverOpts.storage = storage;
@@ -15639,6 +15530,7 @@ function installShutdownHandlers() {
15639
15530
  new Promise((resolve2) => setTimeout(resolve2, SHUTDOWN_TIMEOUT_MS))
15640
15531
  ]).catch(() => {
15641
15532
  });
15533
+ unregisterProcess();
15642
15534
  process.stderr.write(`crosscheck-agent: shutdown (${reason})
15643
15535
  `);
15644
15536
  process.exit(0);
@@ -15657,11 +15549,11 @@ function installShutdownHandlers() {
15657
15549
  });
15658
15550
  }
15659
15551
  function resolveRepoFile(rel) {
15660
- let dir = __dirname;
15552
+ let dir = HERE;
15661
15553
  for (let i = 0; i < 8; i++) {
15662
- const candidate = path15.join(dir, rel);
15554
+ const candidate = path16.join(dir, rel);
15663
15555
  if (existsSync14(candidate)) return candidate;
15664
- const parent = path15.dirname(dir);
15556
+ const parent = path16.dirname(dir);
15665
15557
  if (parent === dir) break;
15666
15558
  dir = parent;
15667
15559
  }
@@ -15670,8 +15562,8 @@ function resolveRepoFile(rel) {
15670
15562
  function findGitRoot(startDir) {
15671
15563
  let dir = startDir;
15672
15564
  for (let i = 0; i < 12; i++) {
15673
- if (existsSync14(path15.join(dir, ".git"))) return dir;
15674
- const parent = path15.dirname(dir);
15565
+ if (existsSync14(path16.join(dir, ".git"))) return dir;
15566
+ const parent = path16.dirname(dir);
15675
15567
  if (parent === dir) break;
15676
15568
  dir = parent;
15677
15569
  }
@@ -15681,7 +15573,7 @@ var isMainEntry = (() => {
15681
15573
  try {
15682
15574
  const argv1 = process.argv[1];
15683
15575
  if (!argv1) return false;
15684
- return /(?:\/|\\)node-stdio\.(?:js|cjs|mjs)$/.test(argv1);
15576
+ return /(?:\/|\\)node-stdio\.(?:js|cjs|mjs|ts)$/.test(argv1);
15685
15577
  } catch {
15686
15578
  return false;
15687
15579
  }