crosscheck-mcp 0.2.27 → 0.2.29

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.cjs CHANGED
@@ -31,13 +31,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/entrypoints/embed.ts
32
32
  var embed_exports = {};
33
33
  __export(embed_exports, {
34
+ ACTIVITY_TEXT_CAP: () => ACTIVITY_TEXT_CAP,
34
35
  DEFAULT_EXCLUDED_PROVIDERS: () => DEFAULT_EXCLUDED_PROVIDERS,
35
36
  DEFAULT_FALLBACKS: () => DEFAULT_FALLBACKS,
36
37
  DEFAULT_MODELS: () => DEFAULT_MODELS,
37
38
  __KEY_ENV: () => KEY_ENV,
38
39
  __MODEL_ENV: () => MODEL_ENV,
39
40
  __test_internals: () => __test_internals,
40
- createEmbeddedEngine: () => createEmbeddedEngine
41
+ createEmbeddedEngine: () => createEmbeddedEngine,
42
+ isAlive: () => isAlive,
43
+ listProcesses: () => listProcesses,
44
+ processRegistryPath: () => processRegistryPath
41
45
  });
42
46
  module.exports = __toCommonJS(embed_exports);
43
47
 
@@ -46,16 +50,17 @@ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${_
46
50
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
47
51
 
48
52
  // src/entrypoints/embed.ts
49
- var import_node_fs15 = require("fs");
50
- var import_node_path14 = __toESM(require("path"), 1);
53
+ var import_node_async_hooks2 = require("async_hooks");
54
+ var import_node_fs16 = require("fs");
55
+ var import_node_path15 = __toESM(require("path"), 1);
51
56
  var import_node_url2 = require("url");
52
57
 
53
58
  // src/core/pricing.ts
54
59
  var import_node_fs = require("fs");
55
- function loadPricing(path12) {
60
+ function loadPricing(path13) {
56
61
  let raw;
57
62
  try {
58
- raw = (0, import_node_fs.readFileSync)(path12, "utf8");
63
+ raw = (0, import_node_fs.readFileSync)(path13, "utf8");
59
64
  } catch {
60
65
  return {};
61
66
  }
@@ -72,20 +77,30 @@ function modelPricing(pricing, provider, model) {
72
77
  const block = pricing[provider];
73
78
  if (!block || typeof block !== "object" || Array.isArray(block)) return null;
74
79
  const table = block;
80
+ if (model.startsWith("_")) return null;
75
81
  let entry = table[model];
76
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
77
- const best = Object.keys(table).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
78
- entry = best !== void 0 ? table[best] : void 0;
82
+ let match = "exact";
83
+ if (!isRates(entry)) {
84
+ 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];
85
+ if (best !== void 0) {
86
+ entry = table[best];
87
+ match = "stamp";
88
+ }
79
89
  }
80
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
90
+ if (!isRates(entry)) return null;
81
91
  const e = entry;
82
92
  return {
83
93
  prompt_per_1k: numberOrZero(e["prompt_per_1k"]),
84
94
  completion_per_1k: numberOrZero(e["completion_per_1k"]),
85
95
  cached_per_1k: numberOrZero(e["cached_per_1k"]),
86
- ...e["estimated"] === true ? { estimated: true } : {}
96
+ ...e["estimated"] === true ? { estimated: true } : {},
97
+ match
87
98
  };
88
99
  }
100
+ var DATE_STAMP = /^-\d{8}$/;
101
+ function isRates(v) {
102
+ return Boolean(v) && typeof v === "object" && !Array.isArray(v);
103
+ }
89
104
  function numberOrZero(v) {
90
105
  if (typeof v === "number" && Number.isFinite(v)) return v;
91
106
  if (typeof v === "string") {
@@ -165,8 +180,20 @@ var PROVIDER_CAPS = {
165
180
  gemini: {
166
181
  family: "gemini",
167
182
  system_role: "separate",
168
- supports_temperature: true,
169
- reasoning_prefixes: ["gemini-3.1-pro", "gemini-3.5-flash", "gemini-2.5-pro"]
183
+ // No sampling, on any Gemini model. Ignored since 3.6 Flash and rejected
184
+ // by upcoming models (Google, 2026-10). "model" means "omit for reasoning
185
+ // models", and every Gemini model is reasoning-class (below) — so this
186
+ // resolves to never, through the same rule the other providers use. The
187
+ // adapter also never sends it; this keeps the record honest for anything
188
+ // else that reads it.
189
+ supports_temperature: "model",
190
+ // EVERY Gemini model is reasoning-class. The old list named three
191
+ // families and missed gemini-3.8-flash — the DEFAULT — so the default
192
+ // model got the small non-reasoning budgets (768 tokens for an audit)
193
+ // while spending up to ~480 tokens of each call thinking. Google's docs
194
+ // say thinking cannot be switched off on current models, so a list of
195
+ // which ones think is a list that can only ever be incomplete.
196
+ reasoning_prefixes: ["gemini-"]
170
197
  },
171
198
  // Qwen's "Max" tier (qwen-v3.8, qwen-v3.7) is a standard instruct/chat
172
199
  // model, not a visible-reasoning model like QwQ — normal temperature and
@@ -289,6 +316,73 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
289
316
  );
290
317
  }
291
318
 
319
+ // src/providers/network-errors.ts
320
+ function codeOf(e) {
321
+ if (!e || typeof e !== "object") return null;
322
+ const c = e.code;
323
+ return typeof c === "string" && c.length > 0 ? c : null;
324
+ }
325
+ function rootCause(e, depth = 0) {
326
+ if (depth > 5 || !e || typeof e !== "object") return e;
327
+ const o = e;
328
+ if (Array.isArray(o.errors) && o.errors.length > 0) {
329
+ const coded = o.errors.find((x) => codeOf(x) !== null);
330
+ return rootCause(coded ?? o.errors[0], depth + 1);
331
+ }
332
+ if (o.cause !== void 0 && o.cause !== null) return rootCause(o.cause, depth + 1);
333
+ return e;
334
+ }
335
+ var BY_CODE = {
336
+ ENOTFOUND: { cause: "dns", detail: "the provider's hostname did not resolve \u2014 DNS, or a typo'd base URL", transient: false, kind: "network" },
337
+ EAI_AGAIN: { cause: "dns", detail: "DNS lookup failed temporarily \u2014 resolver or network is flapping", transient: true, kind: "network" },
338
+ ECONNREFUSED: { cause: "refused", detail: "the connection was refused \u2014 nothing is listening, or a proxy blocked it", transient: false, kind: "network" },
339
+ 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" },
340
+ EPIPE: { cause: "reset", detail: "the connection closed while we were still writing", transient: true, kind: "network" },
341
+ ETIMEDOUT: { cause: "connect_timeout", detail: "the connection timed out before it was established", transient: true, kind: "timeout" },
342
+ EHOSTUNREACH: { cause: "unreachable", detail: "no route to the provider \u2014 VPN, or offline", transient: true, kind: "network" },
343
+ ENETUNREACH: { cause: "unreachable", detail: "the network is unreachable \u2014 offline, or a routing change", transient: true, kind: "network" },
344
+ ENETDOWN: { cause: "unreachable", detail: "the local network is down", transient: true, kind: "network" },
345
+ EPROTO: { cause: "tls", detail: "the TLS handshake failed \u2014 an intercepting proxy, or a protocol mismatch", transient: false, kind: "network" },
346
+ ERR_TLS_CERT_ALTNAME_INVALID: { cause: "tls", detail: "the certificate did not match the hostname \u2014 traffic is being intercepted", transient: false, kind: "network" },
347
+ CERT_HAS_EXPIRED: { cause: "tls", detail: "the server certificate has expired, or this machine's clock is wrong", transient: false, kind: "network" },
348
+ 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" },
349
+ 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" },
350
+ 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" },
351
+ UND_ERR_BODY_TIMEOUT: { cause: "read_timeout", detail: "the response body stalled mid-stream", transient: true, kind: "timeout" },
352
+ UND_ERR_SOCKET: { cause: "reset", detail: "the socket closed unexpectedly", transient: true, kind: "network" },
353
+ UND_ERR_ABORTED: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" },
354
+ ABORT_ERR: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" }
355
+ };
356
+ function diagnoseNetworkError(e) {
357
+ const root = rootCause(e);
358
+ const code = codeOf(root) ?? codeOf(e);
359
+ if (code && BY_CODE[code]) return { ...BY_CODE[code], code };
360
+ const name = root && typeof root === "object" ? root.name : void 0;
361
+ if (name === "AbortError" || name === "TimeoutError") {
362
+ return {
363
+ cause: name === "TimeoutError" ? "read_timeout" : "aborted",
364
+ code: code ?? String(name),
365
+ detail: name === "TimeoutError" ? "the request exceeded its timeout" : "the request was cancelled",
366
+ transient: name === "TimeoutError",
367
+ kind: name === "TimeoutError" ? "timeout" : "network"
368
+ };
369
+ }
370
+ return {
371
+ cause: "unknown",
372
+ code,
373
+ detail: code ? `the connection failed with ${code}` : "the connection failed and the underlying error carried no code",
374
+ transient: true,
375
+ kind: "network"
376
+ };
377
+ }
378
+ function looksLikeNetworkFailure(d) {
379
+ return d.code !== null || d.cause !== "unknown";
380
+ }
381
+ function networkErrorMessage(provider, d) {
382
+ const code = d.code ? ` [${d.code}]` : "";
383
+ return `${provider}: ${d.detail}${code}`;
384
+ }
385
+
292
386
  // src/providers/retry.ts
293
387
  var override = null;
294
388
  function resolveRetryConfig() {
@@ -441,6 +535,52 @@ function rejectsDisabledThinking(model) {
441
535
  const m = model.toLowerCase();
442
536
  return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
443
537
  }
538
+ var NO_FORCED_TOOL_PREFIXES = [
539
+ "claude-fable-5-1",
540
+ "claude-mythos-5-1",
541
+ "claude-opus-5-5",
542
+ "claude-sonnet-5-5"
543
+ ];
544
+ function rejectsForcedToolUse(model) {
545
+ const m = model.toLowerCase();
546
+ return NO_FORCED_TOOL_PREFIXES.some((p) => m.startsWith(p));
547
+ }
548
+ var UNSUPPORTED_SCHEMA_KEYS = /* @__PURE__ */ new Set([
549
+ "minimum",
550
+ "maximum",
551
+ "exclusiveMinimum",
552
+ "exclusiveMaximum",
553
+ "multipleOf",
554
+ "minLength",
555
+ "maxLength",
556
+ "pattern",
557
+ "minItems",
558
+ "maxItems",
559
+ "uniqueItems",
560
+ "minProperties",
561
+ "maxProperties",
562
+ "$schema"
563
+ ]);
564
+ function toStructuredOutputSchema(schema) {
565
+ const walk = (node) => {
566
+ if (Array.isArray(node)) return node.map(walk);
567
+ if (!node || typeof node !== "object") return node;
568
+ const out = {};
569
+ for (const [k, v] of Object.entries(node)) {
570
+ if (UNSUPPORTED_SCHEMA_KEYS.has(k)) continue;
571
+ if (k === "properties" && v && typeof v === "object") {
572
+ out[k] = Object.fromEntries(Object.entries(v).map(([pk, pv]) => [pk, walk(pv)]));
573
+ } else if (["items", "anyOf", "allOf", "oneOf", "not", "$defs", "definitions"].includes(k)) {
574
+ out[k] = k === "$defs" || k === "definitions" ? Object.fromEntries(Object.entries(v ?? {}).map(([dk, dv]) => [dk, walk(dv)])) : walk(v);
575
+ } else {
576
+ out[k] = v;
577
+ }
578
+ }
579
+ if (out["type"] === "object" || "properties" in out) out["additionalProperties"] = false;
580
+ return out;
581
+ };
582
+ return walk(schema);
583
+ }
444
584
  var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
445
585
  function applyPromptCaching(body, env = process.env) {
446
586
  const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
@@ -492,7 +632,12 @@ function buildAnthropicRequest(opts) {
492
632
  body.thinking = { type: "disabled" };
493
633
  }
494
634
  }
495
- if (opts.jsonSchema) {
635
+ if (opts.jsonSchema && rejectsForcedToolUse(opts.model)) {
636
+ body.output_config = {
637
+ ...body.output_config ?? {},
638
+ format: { type: "json_schema", schema: toStructuredOutputSchema(opts.jsonSchema) }
639
+ };
640
+ } else if (opts.jsonSchema) {
496
641
  body.tools = [{
497
642
  name: ANTHROPIC_STRUCTURED_TOOL_NAME,
498
643
  description: "Emit a single JSON object matching the requested schema.",
@@ -611,7 +756,11 @@ async function sendAnthropic(args) {
611
756
  try {
612
757
  respLike = await doFetch(url, init);
613
758
  } catch (e) {
614
- throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
759
+ const d = diagnoseNetworkError(e);
760
+ if (!looksLikeNetworkFailure(d)) throw e;
761
+ throw new ProviderError(d.kind, networkErrorMessage("anthropic", d), {
762
+ transient: d.transient
763
+ });
615
764
  }
616
765
  const status = respLike.status;
617
766
  if (status >= 200 && status < 300) {
@@ -684,6 +833,11 @@ function jsonSchemaToGeminiSchema(schema) {
684
833
  }
685
834
  return out;
686
835
  }
836
+ var GEMINI_THINKING_HEADROOM_TOKENS = 16384;
837
+ function thinkingHeadroom() {
838
+ const raw = Number(process.env["CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS"]);
839
+ return Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : GEMINI_THINKING_HEADROOM_TOKENS;
840
+ }
687
841
  function buildGeminiRequest(opts) {
688
842
  const contents = [];
689
843
  let systemText = null;
@@ -702,8 +856,9 @@ function buildGeminiRequest(opts) {
702
856
  const body = {
703
857
  contents,
704
858
  generationConfig: {
705
- maxOutputTokens: opts.maxTokens,
706
- temperature: opts.temperature
859
+ // Answer budget + thinking headroom. No temperature / topP / topK /
860
+ // thinkingBudget, on any model — see the header note.
861
+ maxOutputTokens: opts.maxTokens + thinkingHeadroom()
707
862
  }
708
863
  };
709
864
  if (systemText !== null && systemText !== "") {
@@ -713,8 +868,8 @@ function buildGeminiRequest(opts) {
713
868
  body.generationConfig.responseMimeType = "application/json";
714
869
  body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
715
870
  }
716
- const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
717
- return { url, headers: {}, body };
871
+ const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent`;
872
+ return { url, headers: { "x-goog-api-key": opts.apiKey }, body };
718
873
  }
719
874
  function parseGeminiResponse(opts) {
720
875
  const r = opts.resp ?? {};
@@ -744,16 +899,19 @@ function parseGeminiResponse(opts) {
744
899
  }
745
900
  try {
746
901
  const first = cands[0];
747
- const content = first["content"];
748
- const parts = content["parts"];
902
+ const finishReason = typeof first["finishReason"] === "string" ? first["finishReason"] : void 0;
903
+ const content = first["content"] ?? {};
904
+ const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
749
905
  let text = "";
750
906
  for (const p of parts) {
751
907
  if (p && typeof p === "object") {
752
- const t = p["text"];
908
+ const part = p;
909
+ if (part["thought"] === true) continue;
910
+ const t = part["text"];
753
911
  if (typeof t === "string") text += t;
754
912
  }
755
913
  }
756
- return { text, usage };
914
+ return { text, usage, ...finishReason ? { finishReason } : {} };
757
915
  } catch (e) {
758
916
  throw new ProviderError(
759
917
  "parse",
@@ -782,7 +940,8 @@ async function sendGemini(args) {
782
940
  apiKey: args.apiKey,
783
941
  messages: args.messages,
784
942
  maxTokens: args.maxTokens,
785
- temperature: args.temperature,
943
+ // args.temperature is deliberately NOT forwarded: Gemini ignores it and
944
+ // upcoming models reject it. See the header note.
786
945
  ...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
787
946
  });
788
947
  const doFetch = args.fetchImpl ?? globalThis.fetch;
@@ -797,7 +956,11 @@ async function sendGemini(args) {
797
956
  try {
798
957
  respLike = await doFetch(url, init);
799
958
  } catch (e) {
800
- throw new ProviderError("network", `gemini: fetch failed: ${e.message}`);
959
+ const d = diagnoseNetworkError(e);
960
+ if (!looksLikeNetworkFailure(d)) throw e;
961
+ throw new ProviderError(d.kind, networkErrorMessage("gemini", d), {
962
+ transient: d.transient
963
+ });
801
964
  }
802
965
  const status = respLike.status;
803
966
  if (status >= 200 && status < 300) {
@@ -807,11 +970,18 @@ async function sendGemini(args) {
807
970
  } catch (e) {
808
971
  throw new ProviderError("parse", `gemini: response body not JSON: ${e.message}`);
809
972
  }
810
- const { text, usage } = parseGeminiResponse({
973
+ const { text, usage, finishReason } = parseGeminiResponse({
811
974
  resp: parsed,
812
975
  model: args.model,
813
976
  purpose: args.purpose ?? "worker"
814
977
  });
978
+ if (text.trim() === "" && finishReason === "MAX_TOKENS") {
979
+ throw new ProviderError(
980
+ "parse",
981
+ `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.`,
982
+ { transient: false }
983
+ );
984
+ }
815
985
  return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
816
986
  }
817
987
  const bodyText = await respLike.text().catch(() => "");
@@ -868,7 +1038,15 @@ function buildOpenAICompatibleRequest(opts) {
868
1038
  json_schema: {
869
1039
  name: "structured_output",
870
1040
  schema: opts.jsonSchema,
871
- strict: true
1041
+ // NOT strict. Strict mode requires `additionalProperties: false` on
1042
+ // every object and every property listed in `required` — the
1043
+ // engine's schemas don't meet that, so every structured OpenAI call
1044
+ // (planner, judges, synthesis) was a 400, unnoticed until the canary
1045
+ // grew a structured check (2026-10-11). Non-strict still shapes the
1046
+ // reply to the schema, and structured.ts validates it against the
1047
+ // full schema regardless, so strictness added a failure mode and no
1048
+ // safety.
1049
+ strict: false
872
1050
  }
873
1051
  };
874
1052
  }
@@ -978,7 +1156,11 @@ async function sendOpenAICompatible(args) {
978
1156
  try {
979
1157
  respLike = await doFetch(url, init);
980
1158
  } catch (e) {
981
- throw new ProviderError("network", `${args.provider}: fetch failed: ${e.message}`);
1159
+ const d = diagnoseNetworkError(e);
1160
+ if (!looksLikeNetworkFailure(d)) throw e;
1161
+ throw new ProviderError(d.kind, networkErrorMessage(args.provider, d), {
1162
+ transient: d.transient
1163
+ });
982
1164
  }
983
1165
  const status = respLike.status;
984
1166
  if (status >= 200 && status < 300) {
@@ -1152,7 +1334,7 @@ var import_zod = require("zod");
1152
1334
 
1153
1335
  // src/server-meta.ts
1154
1336
  var SERVER_NAME = "crosscheck-agent";
1155
- var SERVER_VERSION = true ? "0.2.27" : "0.0.0-dev";
1337
+ var SERVER_VERSION = true ? "0.2.29" : "0.0.0-dev";
1156
1338
 
1157
1339
  // src/tools/audit.ts
1158
1340
  var import_node_fs4 = require("fs");
@@ -1213,27 +1395,27 @@ function extractJson(text) {
1213
1395
  }
1214
1396
 
1215
1397
  // src/core/json-schema.ts
1216
- function validateSchema(value, schema, path12 = "") {
1398
+ function validateSchema(value, schema, path13 = "") {
1217
1399
  const errs = [];
1218
1400
  if ("anyOf" in schema) {
1219
1401
  const subs = schema["anyOf"].map(
1220
- (s) => validateSchema(value, s, path12)
1402
+ (s) => validateSchema(value, s, path13)
1221
1403
  );
1222
1404
  if (!subs.some((e) => e.length === 0)) {
1223
- errs.push(`${path12 || "<root>"}: did not match anyOf`);
1405
+ errs.push(`${path13 || "<root>"}: did not match anyOf`);
1224
1406
  }
1225
1407
  return errs;
1226
1408
  }
1227
1409
  if ("oneOf" in schema) {
1228
- const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path12).length === 0).length;
1410
+ const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path13).length === 0).length;
1229
1411
  if (passed !== 1) {
1230
- errs.push(`${path12 || "<root>"}: matched ${passed} of oneOf, expected 1`);
1412
+ errs.push(`${path13 || "<root>"}: matched ${passed} of oneOf, expected 1`);
1231
1413
  }
1232
1414
  return errs;
1233
1415
  }
1234
1416
  if ("const" in schema && !deepEqual(value, schema["const"])) {
1235
1417
  errs.push(
1236
- `${path12 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
1418
+ `${path13 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
1237
1419
  );
1238
1420
  return errs;
1239
1421
  }
@@ -1243,7 +1425,7 @@ function validateSchema(value, schema, path12 = "") {
1243
1425
  const ok = types.some((tt) => matchesType(value, String(tt)));
1244
1426
  if (!ok) {
1245
1427
  errs.push(
1246
- `${path12 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
1428
+ `${path13 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
1247
1429
  );
1248
1430
  return errs;
1249
1431
  }
@@ -1252,29 +1434,29 @@ function validateSchema(value, schema, path12 = "") {
1252
1434
  if ("enum" in schema) {
1253
1435
  const en = schema["enum"];
1254
1436
  if (!en.some((x) => deepEqual(x, value))) {
1255
- errs.push(`${path12 || "<root>"}: value ${pyRepr(value)} not in enum`);
1437
+ errs.push(`${path13 || "<root>"}: value ${pyRepr(value)} not in enum`);
1256
1438
  }
1257
1439
  }
1258
1440
  if ("minLength" in schema && value.length < schema["minLength"]) {
1259
- errs.push(`${path12 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
1441
+ errs.push(`${path13 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
1260
1442
  }
1261
1443
  }
1262
1444
  if (typeof value === "number" && !Number.isNaN(value)) {
1263
1445
  if ("minimum" in schema && value < schema["minimum"]) {
1264
- errs.push(`${path12 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
1446
+ errs.push(`${path13 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
1265
1447
  }
1266
1448
  if ("maximum" in schema && value > schema["maximum"]) {
1267
- errs.push(`${path12 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
1449
+ errs.push(`${path13 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
1268
1450
  }
1269
1451
  }
1270
1452
  if (Array.isArray(value)) {
1271
1453
  if ("minItems" in schema && value.length < schema["minItems"]) {
1272
- errs.push(`${path12 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
1454
+ errs.push(`${path13 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
1273
1455
  }
1274
1456
  const itemSchema = schema["items"];
1275
1457
  if (isObj(itemSchema)) {
1276
1458
  for (let i = 0; i < value.length; i++) {
1277
- errs.push(...validateSchema(value[i], itemSchema, `${path12}[${i}]`));
1459
+ errs.push(...validateSchema(value[i], itemSchema, `${path13}[${i}]`));
1278
1460
  }
1279
1461
  }
1280
1462
  }
@@ -1283,19 +1465,19 @@ function validateSchema(value, schema, path12 = "") {
1283
1465
  const required = schema["required"] ?? [];
1284
1466
  for (const r of required) {
1285
1467
  if (!(r in value)) {
1286
- errs.push(`${path12 || "<root>"}: missing required key ${pyRepr(r)}`);
1468
+ errs.push(`${path13 || "<root>"}: missing required key ${pyRepr(r)}`);
1287
1469
  }
1288
1470
  }
1289
1471
  if (schema["additionalProperties"] === false) {
1290
1472
  for (const k of Object.keys(value)) {
1291
1473
  if (!(k in props)) {
1292
- errs.push(`${path12 || "<root>"}: unknown key ${pyRepr(k)}`);
1474
+ errs.push(`${path13 || "<root>"}: unknown key ${pyRepr(k)}`);
1293
1475
  }
1294
1476
  }
1295
1477
  }
1296
1478
  for (const [k, v] of Object.entries(value)) {
1297
1479
  const ps = props[k];
1298
- if (ps) errs.push(...validateSchema(v, ps, path12 ? `${path12}.${k}` : k));
1480
+ if (ps) errs.push(...validateSchema(v, ps, path13 ? `${path13}.${k}` : k));
1299
1481
  }
1300
1482
  }
1301
1483
  return errs;
@@ -1375,6 +1557,31 @@ function pyReprType(t) {
1375
1557
  return String(t);
1376
1558
  }
1377
1559
 
1560
+ // src/core/session.ts
1561
+ var import_node_crypto = require("crypto");
1562
+ var processSessionId = null;
1563
+ var startedAt = null;
1564
+ function engineSessionId() {
1565
+ if (processSessionId === null) {
1566
+ processSessionId = (0, import_node_crypto.randomUUID)();
1567
+ startedAt = Date.now();
1568
+ }
1569
+ return processSessionId;
1570
+ }
1571
+ function resolveSessionId(callerSupplied) {
1572
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1573
+ return trimmed.length > 0 ? trimmed : engineSessionId();
1574
+ }
1575
+ function localSessionRecordingEnabled(env = globalThis.process?.env ?? {}) {
1576
+ const v = (env["CROSSCHECK_RECORD_SESSIONS"] ?? "").trim().toLowerCase();
1577
+ return !["0", "false", "off", "no"].includes(v);
1578
+ }
1579
+ function recordingSessionId(callerSupplied) {
1580
+ if (localSessionRecordingEnabled()) return resolveSessionId(callerSupplied);
1581
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1582
+ return trimmed.length > 0 ? trimmed : null;
1583
+ }
1584
+
1378
1585
  // src/core/usage.ts
1379
1586
  function emptyUsage(provider, model, purpose = "worker") {
1380
1587
  return {
@@ -1480,11 +1687,11 @@ function withCommas(n) {
1480
1687
  function renderRunSummary(opts) {
1481
1688
  const endedAt = opts.endedAtS ?? Math.trunc(Date.now() / 1e3);
1482
1689
  let scope = "call";
1483
- let startedAt = null;
1690
+ let startedAt2 = null;
1484
1691
  let rows = [];
1485
1692
  if (opts.sessionScope && opts.sessionScope.rows.length > 0) {
1486
1693
  scope = "session";
1487
- startedAt = opts.sessionScope.startedAt;
1694
+ startedAt2 = opts.sessionScope.startedAt;
1488
1695
  rows = opts.sessionScope.rows.map((r) => ({ ...r }));
1489
1696
  } else {
1490
1697
  const byPurpose = /* @__PURE__ */ new Map();
@@ -1515,6 +1722,7 @@ function renderRunSummary(opts) {
1515
1722
  row.cpu_ms += a.cpu_ms ?? 0;
1516
1723
  if (a.cache_hit) row.cache_hits += 1;
1517
1724
  if (a.error) row.errors += 1;
1725
+ if (a.usage?.estimated) row.estimated = true;
1518
1726
  }
1519
1727
  rows = Array.from(byPurpose.values());
1520
1728
  }
@@ -1527,16 +1735,18 @@ function renderRunSummary(opts) {
1527
1735
  wall_ms: rows.reduce((s, r) => s + r.wall_ms, 0),
1528
1736
  cpu_ms: rows.reduce((s, r) => s + r.cpu_ms, 0),
1529
1737
  cache_hits: rows.reduce((s, r) => s + r.cache_hits, 0),
1530
- errors: rows.reduce((s, r) => s + r.errors, 0)
1738
+ errors: rows.reduce((s, r) => s + r.errors, 0),
1739
+ ...rows.some((r) => r.estimated) ? { estimated: true } : {}
1531
1740
  };
1532
1741
  const titleLeft = scope === "session" ? `session: ${opts.sessionId ?? ""}` : `call: ${opts.toolName}`;
1533
- 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)`;
1742
+ const costText = totals.estimated ? `$${totals.cost_usd.toFixed(4)}+ (some calls unpriced)` : `$${totals.cost_usd.toFixed(4)}`;
1743
+ 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)`;
1534
1744
  const bodyLines = [];
1535
1745
  for (let i = 0; i < rows.length; i++) {
1536
1746
  const r = rows[i];
1537
1747
  const glyph = i === rows.length - 1 ? "`-" : "|-";
1538
1748
  bodyLines.push(
1539
- `${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)`
1749
+ `${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)`
1540
1750
  );
1541
1751
  }
1542
1752
  const callByModel = rollupSpendByModel(
@@ -1584,7 +1794,7 @@ function renderRunSummary(opts) {
1584
1794
  tool: opts.toolName,
1585
1795
  scope,
1586
1796
  currency: "USD",
1587
- started_at: startedAt,
1797
+ started_at: startedAt2,
1588
1798
  ended_at: endedAt,
1589
1799
  rows,
1590
1800
  totals,
@@ -1709,14 +1919,15 @@ async function attachUsageBlock(result, answers, opts) {
1709
1919
  delete result["_suppress_run_summary"];
1710
1920
  }
1711
1921
  async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
1712
- if (!sessionId || answers.length === 0) return;
1922
+ const sid = recordingSessionId(sessionId);
1923
+ if (!sid || answers.length === 0) return;
1713
1924
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
1714
1925
  const rows = [];
1715
1926
  for (const a of answers) {
1716
1927
  const u = a.usage;
1717
1928
  if (!u || typeof u.provider !== "string" || u.provider === "") continue;
1718
1929
  rows.push({
1719
- session_id: sessionId,
1930
+ session_id: sid,
1720
1931
  ts: now,
1721
1932
  tool: toolName,
1722
1933
  purpose: u.purpose ?? "worker",
@@ -1739,13 +1950,14 @@ async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
1739
1950
  }
1740
1951
  }
1741
1952
  async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, nowS) {
1742
- if (!sessionId) return;
1953
+ const sid = recordingSessionId(sessionId);
1954
+ if (!sid) return;
1743
1955
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
1744
1956
  try {
1745
- let existing = await storage.getSession(sessionId);
1957
+ let existing = await storage.getSession(sid);
1746
1958
  if (!existing) {
1747
1959
  await storage.upsertSession({
1748
- session_id: sessionId,
1960
+ session_id: sid,
1749
1961
  started_at: now,
1750
1962
  last_at: now,
1751
1963
  calls: 0,
@@ -1758,7 +1970,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
1758
1970
  total_cost_usd: 0,
1759
1971
  total_cpu_ms: 0
1760
1972
  });
1761
- existing = await storage.getSession(sessionId);
1973
+ existing = await storage.getSession(sid);
1762
1974
  }
1763
1975
  if (!existing) return;
1764
1976
  let promptDelta = 0;
@@ -1778,7 +1990,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
1778
1990
  }
1779
1991
  if (a.cache_hit) cacheHitDelta += 1;
1780
1992
  }
1781
- await storage.accumulateSessionTotals(sessionId, {
1993
+ await storage.accumulateSessionTotals(sid, {
1782
1994
  calls: answers.length,
1783
1995
  wall_ms: wallMs,
1784
1996
  cache_hits: cacheHitDelta,
@@ -2160,7 +2372,7 @@ function buildPersonaInjection(opts) {
2160
2372
  }
2161
2373
 
2162
2374
  // src/core/canary.ts
2163
- var import_node_crypto = require("crypto");
2375
+ var import_node_crypto2 = require("crypto");
2164
2376
 
2165
2377
  // src/core/injection.ts
2166
2378
  var INJECTION_PHRASES_RE = new RegExp(
@@ -2178,8 +2390,8 @@ var UNTRUSTED_SYSTEM_NOTE = "Some inputs in this conversation are wrapped in <un
2178
2390
  function mintCanary() {
2179
2391
  const t = process.hrtime.bigint().toString();
2180
2392
  const pid = String(process.pid);
2181
- const r = (0, import_node_crypto.randomBytes)(16).toString("hex");
2182
- const hex = (0, import_node_crypto.createHash)("sha256").update(`${t}-${pid}-${r}`).digest("hex").slice(0, 16).toUpperCase();
2393
+ const r = (0, import_node_crypto2.randomBytes)(16).toString("hex");
2394
+ const hex = (0, import_node_crypto2.createHash)("sha256").update(`${t}-${pid}-${r}`).digest("hex").slice(0, 16).toUpperCase();
2183
2395
  return `CC_CANARY_${hex}`;
2184
2396
  }
2185
2397
  function wrapUntrusted(content, canary) {
@@ -2366,7 +2578,7 @@ var import_node_fs3 = require("fs");
2366
2578
  var import_node_path2 = __toESM(require("path"), 1);
2367
2579
 
2368
2580
  // src/core/redact.ts
2369
- var import_node_crypto2 = require("crypto");
2581
+ var import_node_crypto3 = require("crypto");
2370
2582
  function builtinRedactionRules() {
2371
2583
  return [
2372
2584
  { pattern: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g, label: "EMAIL", prefix_group: false },
@@ -2393,7 +2605,7 @@ function hmacSuffix(cfg, label, value) {
2393
2605
  const sid = cfg.session_id ?? "";
2394
2606
  const sidBytes = Buffer.from(sid, "utf8");
2395
2607
  const key = Buffer.concat([Buffer.from(secret), sidBytes]);
2396
- const digest = (0, import_node_crypto2.createHmac)("sha256", key).update(`${label}:${value}`, "utf8").digest("hex");
2608
+ const digest = (0, import_node_crypto3.createHmac)("sha256", key).update(`${label}:${value}`, "utf8").digest("hex");
2397
2609
  return digest.slice(0, 8);
2398
2610
  }
2399
2611
  function redactText(s, cfg) {
@@ -4710,10 +4922,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
4710
4922
  }
4711
4923
 
4712
4924
  // src/tools/confer.ts
4713
- var DEFERRED_OPTS = [
4714
- // empty — every confer opt runs natively except worker_tools, which
4715
- // is gated below (non-empty list → defer).
4716
- ];
4717
4925
  async function runConfer(args, opts) {
4718
4926
  const callStartedWall = import_node_perf_hooks2.performance.now();
4719
4927
  const callStartedCpu = process.cpuUsage();
@@ -4729,16 +4937,11 @@ async function runConfer(args, opts) {
4729
4937
  rejectedWorkerTools.push(t);
4730
4938
  }
4731
4939
  }
4732
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
4733
- const needsBridge = DEFERRED_OPTS.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
4734
- if (needsBridge) {
4735
- if (opts.bridge && opts.bridge.toolNames.has("confer")) {
4736
- return await deferConfer(args, opts.bridge);
4737
- }
4940
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
4738
4941
  return errorEnvelope2(
4739
4942
  "CONFER_OPT_NOT_NATIVE",
4740
4943
  "worker_tools requested but innerCallers are not wired",
4741
- "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)."
4944
+ "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host."
4742
4945
  );
4743
4946
  }
4744
4947
  const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
@@ -5089,21 +5292,6 @@ function unknownProviderError(unknownNames, available) {
5089
5292
  available_now: Object.keys(available).sort()
5090
5293
  };
5091
5294
  }
5092
- async function deferConfer(args, bridge) {
5093
- const r = await bridge.callTool("confer", args);
5094
- const text = r.content[0]?.text;
5095
- if (typeof text === "string") {
5096
- try {
5097
- return JSON.parse(text);
5098
- } catch {
5099
- }
5100
- }
5101
- return errorEnvelope2(
5102
- "CONFER_BRIDGE_BAD_ENVELOPE",
5103
- "bridge returned an unparseable envelope for confer",
5104
- "Check that the Python child is healthy."
5105
- );
5106
- }
5107
5295
  function errorEnvelope2(code, message, hint) {
5108
5296
  return {
5109
5297
  tool: "confer",
@@ -5475,7 +5663,7 @@ function errorEnvelope3(code, message, hint) {
5475
5663
  transient: false
5476
5664
  };
5477
5665
  }
5478
- async function runVerify(args, bridge, fetchConfig) {
5666
+ async function runVerify(args, fetchConfig) {
5479
5667
  const checks = args["checks"];
5480
5668
  if (!Array.isArray(checks) || checks.length === 0) {
5481
5669
  return {
@@ -5487,7 +5675,6 @@ async function runVerify(args, bridge, fetchConfig) {
5487
5675
  )
5488
5676
  };
5489
5677
  }
5490
- void bridge;
5491
5678
  const allowShell = Boolean(args["allow_shell"] ?? false);
5492
5679
  const wallStart = import_node_perf_hooks3.performance.now();
5493
5680
  const cpuStart = process.cpuUsage();
@@ -5789,7 +5976,6 @@ async function runBench(args, opts) {
5789
5976
  const innerOpts = {
5790
5977
  providers: opts.providers,
5791
5978
  allowlist: opts.allowlist ?? null,
5792
- ...opts.bridge ? { bridge: opts.bridge } : {},
5793
5979
  ...opts.moderator ? { moderator: opts.moderator } : {}
5794
5980
  };
5795
5981
  let inner;
@@ -6001,7 +6187,7 @@ function isObj4(v) {
6001
6187
  }
6002
6188
 
6003
6189
  // src/tools/config-pin.ts
6004
- var import_node_crypto3 = require("crypto");
6190
+ var import_node_crypto4 = require("crypto");
6005
6191
  var import_node_fs6 = require("fs");
6006
6192
  var import_node_path6 = __toESM(require("path"), 1);
6007
6193
  var DEFAULT_PIN_PATH = ".crosscheck/config_pins.json";
@@ -6156,7 +6342,7 @@ function hashFile(abs) {
6156
6342
  return "";
6157
6343
  }
6158
6344
  const normalized = stripCrBeforeLf(raw);
6159
- return "sha256:" + (0, import_node_crypto3.createHash)("sha256").update(normalized).digest("hex");
6345
+ return "sha256:" + (0, import_node_crypto4.createHash)("sha256").update(normalized).digest("hex");
6160
6346
  }
6161
6347
  function stripCrBeforeLf(buf) {
6162
6348
  const out = [];
@@ -6233,7 +6419,7 @@ function pyRepr2(v) {
6233
6419
  }
6234
6420
 
6235
6421
  // src/tools/create.ts
6236
- var import_node_crypto6 = require("crypto");
6422
+ var import_node_crypto7 = require("crypto");
6237
6423
  var import_node_fs9 = require("fs");
6238
6424
  var import_node_path9 = __toESM(require("path"), 1);
6239
6425
 
@@ -6244,6 +6430,19 @@ var import_node_perf_hooks6 = require("perf_hooks");
6244
6430
  var import_node_async_hooks = require("async_hooks");
6245
6431
  var import_node_perf_hooks5 = require("perf_hooks");
6246
6432
  var progressStorage = new import_node_async_hooks.AsyncLocalStorage();
6433
+ async function withProgress(token, sendNotification, fn) {
6434
+ if (token === void 0 || token === null) {
6435
+ return fn();
6436
+ }
6437
+ const ctx = {
6438
+ token,
6439
+ wallStart: import_node_perf_hooks5.performance.now(),
6440
+ cpuStart: process.cpuUsage(),
6441
+ step: { value: 0 },
6442
+ sendNotification
6443
+ };
6444
+ return progressStorage.run(ctx, fn);
6445
+ }
6247
6446
  async function emitProgress(message, opts) {
6248
6447
  const ctx = progressStorage.getStore();
6249
6448
  const wallStart = ctx ? ctx.wallStart : import_node_perf_hooks5.performance.now();
@@ -6319,7 +6518,7 @@ function isDeadModelError(err) {
6319
6518
  }
6320
6519
 
6321
6520
  // src/core/node-cache.ts
6322
- var import_node_crypto4 = require("crypto");
6521
+ var import_node_crypto5 = require("crypto");
6323
6522
  var import_node_fs7 = require("fs");
6324
6523
  var import_node_path7 = require("path");
6325
6524
  var NODE_CACHE_KEY_VERSION = "v2";
@@ -6346,7 +6545,7 @@ function canonicalizeNodeText(s) {
6346
6545
  return out;
6347
6546
  }
6348
6547
  function sha256Hex(s) {
6349
- return (0, import_node_crypto4.createHash)("sha256").update(s, "utf8").digest("hex");
6548
+ return (0, import_node_crypto5.createHash)("sha256").update(s, "utf8").digest("hex");
6350
6549
  }
6351
6550
  function nodeCacheKey(node, upstreamOutputs, provider, model) {
6352
6551
  const canonUpstream = {};
@@ -6404,11 +6603,11 @@ function getNodeCache(cfg, repoRoot, key, nowMs) {
6404
6603
  return null;
6405
6604
  }
6406
6605
  }
6407
- function atomicWriteJson(path12, payload) {
6408
- (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(path12), { recursive: true });
6409
- const tmp = `${path12}.${process.pid}.${Date.now()}.tmp`;
6606
+ function atomicWriteJson(path13, payload) {
6607
+ (0, import_node_fs7.mkdirSync)((0, import_node_path7.dirname)(path13), { recursive: true });
6608
+ const tmp = `${path13}.${process.pid}.${Date.now()}.tmp`;
6410
6609
  (0, import_node_fs7.writeFileSync)(tmp, JSON.stringify(payload), "utf8");
6411
- (0, import_node_fs7.renameSync)(tmp, path12);
6610
+ (0, import_node_fs7.renameSync)(tmp, path13);
6412
6611
  }
6413
6612
  function putNodeCache(cfg, repoRoot, key, value) {
6414
6613
  if (!cfg || cfg.enabled === false) return;
@@ -6466,7 +6665,6 @@ var EST_TOKENS = {
6466
6665
  med: [1500, 800],
6467
6666
  high: [2500, 1500]
6468
6667
  };
6469
- var DEFERRED_OPTS2 = [];
6470
6668
  var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
6471
6669
  function parseReactiveSignals(output) {
6472
6670
  if (typeof output !== "string" || !output.includes("<signals>")) return [];
@@ -6506,17 +6704,6 @@ async function runOrchestrate(args, opts) {
6506
6704
  );
6507
6705
  if (breakerEnv) return breakerEnv;
6508
6706
  }
6509
- const needsBridge = DEFERRED_OPTS2.some((k) => Boolean(args[k]));
6510
- if (needsBridge) {
6511
- if (opts.bridge && opts.bridge.toolNames.has("orchestrate")) {
6512
- return await deferOrchestrate(args, opts.bridge);
6513
- }
6514
- return errorEnvelope5(
6515
- "ORCHESTRATE_OPT_NOT_NATIVE",
6516
- "this orchestrate opt-in requires the Python bridge in v1",
6517
- "v1 native covers the plain DAG flow + cheap_mode. reactive (mid-flight DAG updates) still defers. Set CROSSCHECK_BRIDGE_PYTHON=1 to enable."
6518
- );
6519
- }
6520
6707
  const goal = typeof args["goal"] === "string" ? args["goal"] : null;
6521
6708
  const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
6522
6709
  if (goal === null === (dagIn === null)) {
@@ -7458,21 +7645,6 @@ function resolveProviders3(names, available, allowlist) {
7458
7645
  }
7459
7646
  return out;
7460
7647
  }
7461
- async function deferOrchestrate(args, bridge) {
7462
- const r = await bridge.callTool("orchestrate", args);
7463
- const text = r.content[0]?.text;
7464
- if (typeof text === "string") {
7465
- try {
7466
- return JSON.parse(text);
7467
- } catch {
7468
- }
7469
- }
7470
- return errorEnvelope5(
7471
- "ORCHESTRATE_BRIDGE_BAD_ENVELOPE",
7472
- "bridge returned an unparseable envelope for orchestrate",
7473
- "Check that the Python child is healthy."
7474
- );
7475
- }
7476
7648
  function errorEnvelope5(code, message, hint, kind = "client") {
7477
7649
  return {
7478
7650
  tool: "orchestrate",
@@ -7520,7 +7692,7 @@ function pyRound6(x) {
7520
7692
  }
7521
7693
 
7522
7694
  // src/tools/fetch.ts
7523
- var import_node_crypto5 = require("crypto");
7695
+ var import_node_crypto6 = require("crypto");
7524
7696
  var import_node_fs8 = require("fs");
7525
7697
  var import_node_path8 = __toESM(require("path"), 1);
7526
7698
  var DEFAULT_CONFIG = {
@@ -7734,10 +7906,10 @@ function extractHost(url) {
7734
7906
  }
7735
7907
  }
7736
7908
  function sha256Hex2(s) {
7737
- return (0, import_node_crypto5.createHash)("sha256").update(s, "utf8").digest("hex");
7909
+ return (0, import_node_crypto6.createHash)("sha256").update(s, "utf8").digest("hex");
7738
7910
  }
7739
7911
  function sha256HexBytes(bytes) {
7740
- return (0, import_node_crypto5.createHash)("sha256").update(bytes).digest("hex");
7912
+ return (0, import_node_crypto6.createHash)("sha256").update(bytes).digest("hex");
7741
7913
  }
7742
7914
  function resolveEvidenceDir(configured, repoRoot) {
7743
7915
  if (import_node_path8.default.isAbsolute(configured)) return configured;
@@ -7790,6 +7962,16 @@ function buildCallContext(args) {
7790
7962
  var CREATE_DOC_MAX_BYTES = 32 * 1024;
7791
7963
  var CREATE_AUDIT_THRESHOLD = 0.7;
7792
7964
  async function runCreate(args, opts) {
7965
+ const subEnvelopes = [];
7966
+ const tracked = (fn) => async (...a) => {
7967
+ const out = await fn(...a);
7968
+ subEnvelopes.push(out);
7969
+ return out;
7970
+ };
7971
+ const confer = tracked(runConfer);
7972
+ const orchestrate = tracked(runOrchestrate);
7973
+ const review = tracked(runReview);
7974
+ const audit = tracked(runAudit);
7793
7975
  const instruction = typeof args["instruction"] === "string" ? args["instruction"] : String(args["instruction"] ?? "");
7794
7976
  if (!instruction) {
7795
7977
  return errorEnvelope6(
@@ -7826,7 +8008,7 @@ ${constraints}
7826
8008
 
7827
8009
  ` : "") + `DOCUMENTS (${okCount} of ${descriptors.length} ingested):
7828
8010
  ${documentsPayload}`;
7829
- const scope = await runConfer({
8011
+ const scope = await confer({
7830
8012
  question: "We are about to orchestrate a full plan->build->review->audit lifecycle for this instruction. List 3-6 concrete sub-tasks (each with a one-line description and a difficulty: low|med|high), any critical assumptions, and any missing-information risks. Be concise and decisive \u2014 your output will be used to build the orchestration DAG.\n\nINSTRUCTION:\n" + instruction,
7831
8013
  context: contextBlock,
7832
8014
  ...providers !== void 0 ? { providers } : {},
@@ -7835,7 +8017,6 @@ ${documentsPayload}`;
7835
8017
  }, {
7836
8018
  providers: opts.providers,
7837
8019
  allowlist: opts.allowlist ?? null,
7838
- ...opts.bridge ? { bridge: opts.bridge } : {},
7839
8020
  ctx
7840
8021
  });
7841
8022
  const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
@@ -7854,11 +8035,10 @@ ${scopeAnswer || "(none)"}
7854
8035
  };
7855
8036
  if (providers !== void 0) orchestrateArgs["providers"] = providers;
7856
8037
  if (planOnly) orchestrateArgs["plan_only"] = true;
7857
- let orchestration = await runOrchestrate(orchestrateArgs, {
8038
+ let orchestration = await orchestrate(orchestrateArgs, {
7858
8039
  providers: opts.providers,
7859
8040
  allowlist: opts.allowlist ?? null,
7860
8041
  moderator,
7861
- ...opts.bridge ? { bridge: opts.bridge } : {},
7862
8042
  ctx
7863
8043
  });
7864
8044
  let attempts = 1;
@@ -7884,7 +8064,7 @@ ${scopeAnswer || "(none)"}
7884
8064
  }
7885
8065
  let reviewEnvelope = null;
7886
8066
  if (!skipReview && typeof orchestration["final"] === "string" && orchestration["final"]) {
7887
- reviewEnvelope = await runReview({
8067
+ reviewEnvelope = await review({
7888
8068
  snippet: orchestration["final"],
7889
8069
  intent: `final deliverable for: ${instruction}`,
7890
8070
  ...providers !== void 0 ? { providers } : {},
@@ -7893,7 +8073,6 @@ ${scopeAnswer || "(none)"}
7893
8073
  }, {
7894
8074
  providers: opts.providers,
7895
8075
  allowlist: opts.allowlist ?? null,
7896
- ...opts.bridge ? { bridge: opts.bridge } : {},
7897
8076
  ctx
7898
8077
  });
7899
8078
  }
@@ -7905,7 +8084,7 @@ ${scopeAnswer || "(none)"}
7905
8084
  const panelExhausted = producingPanel.length > 0 && producingPanel.every(
7906
8085
  (p) => p in opts.providers || Object.keys(opts.providers).includes(p.toLowerCase())
7907
8086
  ) && producingPanel.length >= Object.keys(opts.providers).length;
7908
- auditEnvelope = await runAudit({
8087
+ auditEnvelope = await audit({
7909
8088
  output_to_audit: orchestration["final"],
7910
8089
  producing_panelists: producingPanel,
7911
8090
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -7916,7 +8095,6 @@ ${scopeAnswer || "(none)"}
7916
8095
  }, {
7917
8096
  providers: opts.providers,
7918
8097
  allowlist: opts.allowlist ?? null,
7919
- ...opts.bridge ? { bridge: opts.bridge } : {},
7920
8098
  ctx
7921
8099
  });
7922
8100
  let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -7935,13 +8113,12 @@ ${retryConstraints}
7935
8113
  DOCUMENTS:
7936
8114
  ${documentsPayload}`
7937
8115
  };
7938
- const retryOrchestration = await runOrchestrate(
8116
+ const retryOrchestration = await orchestrate(
7939
8117
  retryOrchestrateArgs,
7940
8118
  {
7941
8119
  providers: opts.providers,
7942
8120
  allowlist: opts.allowlist ?? null,
7943
8121
  moderator,
7944
- ...opts.bridge ? { bridge: opts.bridge } : {},
7945
8122
  ctx
7946
8123
  }
7947
8124
  );
@@ -7950,7 +8127,7 @@ ${documentsPayload}`
7950
8127
  if (typeof retryOrchestration["final"] === "string" && retryOrchestration["final"]) {
7951
8128
  const retryPanel = computeProducingPanel(retryOrchestration);
7952
8129
  const retryPanelExhausted = retryPanel.length > 0 && retryPanel.length >= Object.keys(opts.providers).length;
7953
- auditEnvelope = await runAudit({
8130
+ auditEnvelope = await audit({
7954
8131
  output_to_audit: retryOrchestration["final"],
7955
8132
  producing_panelists: retryPanel,
7956
8133
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -7961,7 +8138,6 @@ ${documentsPayload}`
7961
8138
  }, {
7962
8139
  providers: opts.providers,
7963
8140
  allowlist: opts.allowlist ?? null,
7964
- ...opts.bridge ? { bridge: opts.bridge } : {},
7965
8141
  ctx
7966
8142
  });
7967
8143
  overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -8026,9 +8202,28 @@ ${documentsPayload}`
8026
8202
  ["auditor", "items", "overall_score", "passed", "rubric"]
8027
8203
  ),
8028
8204
  artifacts,
8029
- warnings
8205
+ warnings,
8206
+ ...combinedUsage(subEnvelopes)
8030
8207
  };
8031
8208
  }
8209
+ function combinedUsage(envelopes) {
8210
+ const usages = [];
8211
+ const byCallTiming = [];
8212
+ let wall = 0, cpu = 0;
8213
+ for (const env of envelopes) {
8214
+ const e = env ?? {};
8215
+ const calls = e["usage"]?.["by_call"] ?? [];
8216
+ const t = e["timing"] ?? {};
8217
+ const timing = Array.isArray(t["by_call"]) ? t["by_call"] : [];
8218
+ if (!Array.isArray(calls) || calls.length === 0) continue;
8219
+ usages.push(...calls);
8220
+ if (timing.length === calls.length) byCallTiming.push(...timing);
8221
+ else for (const c of calls) byCallTiming.push({ provider: c.provider, model: c.model, purpose: c.purpose ?? null, wall_ms: 0, cpu_ms: 0, cache_hit: false });
8222
+ wall += Number(t["wall_ms"] ?? 0) || 0;
8223
+ cpu += Number(t["cpu_ms"] ?? 0) || 0;
8224
+ }
8225
+ return { usage: aggregateUsage(usages), timing: { wall_ms: wall, cpu_ms: cpu, by_call: byCallTiming } };
8226
+ }
8032
8227
  async function ingestDocuments(documents, sessionId, opts) {
8033
8228
  if (documents.length === 0) return [];
8034
8229
  const out = [];
@@ -8098,7 +8293,7 @@ async function ingestDocuments(documents, sessionId, opts) {
8098
8293
  source: ref,
8099
8294
  type: "file",
8100
8295
  status: "ok",
8101
- hash: (0, import_node_crypto6.createHash)("sha256").update(text, "utf8").digest("hex"),
8296
+ hash: (0, import_node_crypto7.createHash)("sha256").update(text, "utf8").digest("hex"),
8102
8297
  content: ""
8103
8298
  }, text));
8104
8299
  }
@@ -8135,7 +8330,7 @@ ${d.content}
8135
8330
  function makeSessionId(opts, supplied) {
8136
8331
  if (typeof supplied === "string" && supplied) return supplied;
8137
8332
  const stamp = opts.nowEpochSeconds ? opts.nowEpochSeconds() : Math.floor(Date.now() / 1e3);
8138
- const rnd = opts.randomBytes ? opts.randomBytes() : (0, import_node_crypto6.createHash)("sha256").update(`${stamp}-${process.pid}-${Math.random()}`).digest("hex");
8333
+ const rnd = opts.randomBytes ? opts.randomBytes() : (0, import_node_crypto7.createHash)("sha256").update(`${stamp}-${process.pid}-${Math.random()}`).digest("hex");
8139
8334
  const suffix = rnd.slice(0, 8);
8140
8335
  return `${opts.toolName}-${stamp}-${suffix}`;
8141
8336
  }
@@ -8199,11 +8394,6 @@ function errorEnvelope6(toolName, code, message, hint) {
8199
8394
 
8200
8395
  // src/tools/coordinate.ts
8201
8396
  var import_node_perf_hooks7 = require("perf_hooks");
8202
- var DEFERRED_OPTS3 = [
8203
- // empty — every coordinate opt runs natively when its deps
8204
- // (storage / innerCallers) are wired. Without them the
8205
- // worker_tools gate still triggers a bridge defer.
8206
- ];
8207
8397
  var COORDINATE_DEFAULT_TEMP = 0.4;
8208
8398
  var ROLE_TURN_SCHEMA = {
8209
8399
  type: "object",
@@ -8258,23 +8448,18 @@ async function runCoordinate(args, opts) {
8258
8448
  rejectedWorkerTools.push(t);
8259
8449
  }
8260
8450
  }
8261
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
8262
- const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
8263
- if (needsBridge) {
8451
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
8264
8452
  if (superRequested) {
8265
8453
  return errorEnvelope7(
8266
8454
  "COORDINATE_SUPER_NOT_NATIVE",
8267
- "super mode requested but worker_tools needs the Python bridge",
8268
- "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."
8455
+ "super mode requested with worker_tools, but innerCallers are not wired",
8456
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
8269
8457
  );
8270
8458
  }
8271
- if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
8272
- return await deferCoordinate(args, opts.bridge);
8273
- }
8274
8459
  return errorEnvelope7(
8275
8460
  "COORDINATE_OPT_NOT_NATIVE",
8276
8461
  "worker_tools requested but innerCallers are not wired",
8277
- "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)."
8462
+ "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host."
8278
8463
  );
8279
8464
  }
8280
8465
  const untrusted = Boolean(args["untrusted_input"]);
@@ -8674,21 +8859,6 @@ function unknownProviderError3(unknownNames, available) {
8674
8859
  available_now: Object.keys(available).sort()
8675
8860
  };
8676
8861
  }
8677
- async function deferCoordinate(args, bridge) {
8678
- const r = await bridge.callTool("coordinate", args);
8679
- const text = r.content[0]?.text;
8680
- if (typeof text === "string") {
8681
- try {
8682
- return JSON.parse(text);
8683
- } catch {
8684
- }
8685
- }
8686
- return errorEnvelope7(
8687
- "COORDINATE_BRIDGE_BAD_ENVELOPE",
8688
- "bridge returned an unparseable envelope for coordinate",
8689
- "Check that the Python child is healthy."
8690
- );
8691
- }
8692
8862
  function errorEnvelope7(code, message, hint) {
8693
8863
  return {
8694
8864
  tool: "coordinate",
@@ -9016,10 +9186,6 @@ function buildModeratorTranscript(transcript) {
9016
9186
 
9017
9187
  // src/tools/debate.ts
9018
9188
  var import_node_perf_hooks9 = require("perf_hooks");
9019
- var DEFERRED_OPTS4 = [
9020
- // empty — every debate opt runs natively when its deps
9021
- // (storage / innerCallers) are wired.
9022
- ];
9023
9189
  async function runDebate(args, opts) {
9024
9190
  const callStartedWall = import_node_perf_hooks9.performance.now();
9025
9191
  const callStartedCpu = process.cpuUsage();
@@ -9037,23 +9203,18 @@ async function runDebate(args, opts) {
9037
9203
  rejectedWorkerTools.push(t);
9038
9204
  }
9039
9205
  }
9040
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
9041
- const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
9042
- if (needsBridge) {
9206
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
9043
9207
  if (superRequested) {
9044
9208
  return errorEnvelope9(
9045
9209
  "DEBATE_SUPER_NOT_NATIVE",
9046
- "super mode requested but worker_tools needs the Python bridge",
9047
- "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."
9210
+ "super mode requested with worker_tools, but innerCallers are not wired",
9211
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
9048
9212
  );
9049
9213
  }
9050
- if (opts.bridge && opts.bridge.toolNames.has("debate")) {
9051
- return await deferDebate(args, opts.bridge);
9052
- }
9053
9214
  return errorEnvelope9(
9054
9215
  "DEBATE_OPT_NOT_NATIVE",
9055
9216
  "worker_tools requested but innerCallers are not wired",
9056
- "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)."
9217
+ "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."
9057
9218
  );
9058
9219
  }
9059
9220
  const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
@@ -9490,21 +9651,6 @@ function unknownProviderError5(unknownNames, available) {
9490
9651
  available_now: Object.keys(available).sort()
9491
9652
  };
9492
9653
  }
9493
- async function deferDebate(args, bridge) {
9494
- const r = await bridge.callTool("debate", args);
9495
- const text = r.content[0]?.text;
9496
- if (typeof text === "string") {
9497
- try {
9498
- return JSON.parse(text);
9499
- } catch {
9500
- }
9501
- }
9502
- return errorEnvelope9(
9503
- "DEBATE_BRIDGE_BAD_ENVELOPE",
9504
- "bridge returned an unparseable envelope for debate",
9505
- "Check that the Python child is healthy."
9506
- );
9507
- }
9508
9654
  function errorEnvelope9(code, message, hint) {
9509
9655
  return {
9510
9656
  tool: "debate",
@@ -9524,9 +9670,6 @@ var DEFAULT_DELEGATION_LIMITS = {
9524
9670
  };
9525
9671
  async function runDelegate(args, opts) {
9526
9672
  if (!opts.storage) {
9527
- if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
9528
- return await deferDelegate(args, opts.bridge);
9529
- }
9530
9673
  return errorEnvelope10(
9531
9674
  "DELEGATE_STORAGE_UNAVAILABLE",
9532
9675
  "delegate needs the local database (for quota tracking), which isn't available",
@@ -9598,7 +9741,6 @@ async function runDelegate(args, opts) {
9598
9741
  const innerOpts = {
9599
9742
  providers: opts.providers,
9600
9743
  allowlist: opts.allowlist ?? null,
9601
- ...opts.bridge ? { bridge: opts.bridge } : {},
9602
9744
  ...opts.moderator ? { moderator: opts.moderator } : {}
9603
9745
  };
9604
9746
  let result;
@@ -9637,21 +9779,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
9637
9779
  created_at: nowEpochSeconds
9638
9780
  });
9639
9781
  }
9640
- async function deferDelegate(args, bridge) {
9641
- const r = await bridge.callTool("delegate", args);
9642
- const text = r.content[0]?.text;
9643
- if (typeof text === "string") {
9644
- try {
9645
- return JSON.parse(text);
9646
- } catch {
9647
- }
9648
- }
9649
- return errorEnvelope10(
9650
- "DELEGATE_BRIDGE_BAD_ENVELOPE",
9651
- "bridge returned an unparseable envelope for delegate",
9652
- "Check that the Python child is healthy."
9653
- );
9654
- }
9655
9782
  function errorEnvelope10(code, message, hint) {
9656
9783
  return {
9657
9784
  tool: "delegate",
@@ -9694,9 +9821,6 @@ async function runExplain(args, opts) {
9694
9821
  );
9695
9822
  }
9696
9823
  if (!opts.storage) {
9697
- if (opts.bridge && opts.bridge.toolNames.has("explain")) {
9698
- return await deferExplain(args, opts.bridge);
9699
- }
9700
9824
  return errorEnvelope11(
9701
9825
  "EXPLAIN_STORAGE_UNAVAILABLE",
9702
9826
  "explain needs the local transcript/stats database, which isn't available",
@@ -9978,21 +10102,6 @@ function pyRepr5(v) {
9978
10102
  }
9979
10103
  return String(v);
9980
10104
  }
9981
- async function deferExplain(args, bridge) {
9982
- const r = await bridge.callTool("explain", args);
9983
- const text = r.content[0]?.text;
9984
- if (typeof text === "string") {
9985
- try {
9986
- return JSON.parse(text);
9987
- } catch {
9988
- }
9989
- }
9990
- return errorEnvelope11(
9991
- "EXPLAIN_BRIDGE_BAD_ENVELOPE",
9992
- "bridge returned an unparseable envelope for explain",
9993
- "Check that the Python child is healthy."
9994
- );
9995
- }
9996
10105
  function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
9997
10106
  return {
9998
10107
  tool: "explain",
@@ -10545,9 +10654,6 @@ async function runRecall(args, opts) {
10545
10654
  if (k < 1) k = 1;
10546
10655
  if (k > 50) k = 50;
10547
10656
  if (!opts.storage) {
10548
- if (opts.bridge && opts.bridge.toolNames.has("recall")) {
10549
- return await deferRecall(args, opts.bridge);
10550
- }
10551
10657
  return errorEnvelope12(
10552
10658
  "RECALL_STORAGE_UNAVAILABLE",
10553
10659
  "recall needs the local database, which isn't available",
@@ -10600,21 +10706,6 @@ async function runRecall(args, opts) {
10600
10706
  applied_filters: applied
10601
10707
  };
10602
10708
  }
10603
- async function deferRecall(args, bridge) {
10604
- const r = await bridge.callTool("recall", args);
10605
- const text = r.content[0]?.text;
10606
- if (typeof text === "string") {
10607
- try {
10608
- return JSON.parse(text);
10609
- } catch {
10610
- }
10611
- }
10612
- return errorEnvelope12(
10613
- "RECALL_BRIDGE_BAD_ENVELOPE",
10614
- "bridge returned an unparseable envelope for recall",
10615
- "Check that the Python child is healthy."
10616
- );
10617
- }
10618
10709
  function errorEnvelope12(code, message, hint) {
10619
10710
  return {
10620
10711
  tool: "recall",
@@ -10637,9 +10728,6 @@ async function runRecommendPanel(args, opts) {
10637
10728
  );
10638
10729
  }
10639
10730
  if (!opts.storage) {
10640
- if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
10641
- return await deferRecommendPanel(args, opts.bridge);
10642
- }
10643
10731
  return errorEnvelope13(
10644
10732
  "RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
10645
10733
  "recommend_panel needs the local stats database, which isn't available",
@@ -10702,21 +10790,6 @@ async function runRecommendPanel(args, opts) {
10702
10790
  meta: result.meta
10703
10791
  };
10704
10792
  }
10705
- async function deferRecommendPanel(args, bridge) {
10706
- const r = await bridge.callTool("recommend_panel", args);
10707
- const text = r.content[0]?.text;
10708
- if (typeof text === "string") {
10709
- try {
10710
- return JSON.parse(text);
10711
- } catch {
10712
- }
10713
- }
10714
- return errorEnvelope13(
10715
- "RECOMMEND_PANEL_BRIDGE_BAD_ENVELOPE",
10716
- "bridge returned an unparseable envelope for recommend_panel",
10717
- "Check that the Python child is healthy."
10718
- );
10719
- }
10720
10793
  function errorEnvelope13(code, message, hint) {
10721
10794
  return {
10722
10795
  tool: "recommend_panel",
@@ -10746,9 +10819,6 @@ function toStringArray3(v) {
10746
10819
  var import_node_fs11 = require("fs");
10747
10820
  async function runScoreboard(args, opts) {
10748
10821
  if (!opts.storage) {
10749
- if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
10750
- return await deferScoreboard(args, opts.bridge);
10751
- }
10752
10822
  return errorEnvelope14(
10753
10823
  "SCOREBOARD_STORAGE_UNAVAILABLE",
10754
10824
  "scoreboard needs the local stats database, which isn't available",
@@ -10871,21 +10941,6 @@ function clampInt3(raw, min, max, fallback) {
10871
10941
  if (!Number.isFinite(n)) return fallback;
10872
10942
  return Math.min(max, Math.max(min, Math.trunc(n)));
10873
10943
  }
10874
- async function deferScoreboard(args, bridge) {
10875
- const r = await bridge.callTool("scoreboard", args);
10876
- const text = r.content[0]?.text;
10877
- if (typeof text === "string") {
10878
- try {
10879
- return JSON.parse(text);
10880
- } catch {
10881
- }
10882
- }
10883
- return errorEnvelope14(
10884
- "SCOREBOARD_BRIDGE_BAD_ENVELOPE",
10885
- "bridge returned an unparseable envelope for scoreboard",
10886
- "Check that the Python child is healthy."
10887
- );
10888
- }
10889
10944
  function errorEnvelope14(code, message, hint) {
10890
10945
  return {
10891
10946
  tool: "scoreboard",
@@ -10922,9 +10977,6 @@ async function runSessionMemory(args, opts) {
10922
10977
  );
10923
10978
  }
10924
10979
  if (!opts.storage) {
10925
- if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
10926
- return await deferSessionMemory(args, opts.bridge);
10927
- }
10928
10980
  return errorEnvelope15(
10929
10981
  "SESSION_MEMORY_STORAGE_UNAVAILABLE",
10930
10982
  "session_memory needs the local database, which isn't available",
@@ -11029,21 +11081,6 @@ function clampInt4(raw, min, max, fallback) {
11029
11081
  if (!Number.isFinite(n)) return fallback;
11030
11082
  return Math.min(max, Math.max(min, Math.trunc(n)));
11031
11083
  }
11032
- async function deferSessionMemory(args, bridge) {
11033
- const r = await bridge.callTool("session_memory", args);
11034
- const text = r.content[0]?.text;
11035
- if (typeof text === "string") {
11036
- try {
11037
- return JSON.parse(text);
11038
- } catch {
11039
- }
11040
- }
11041
- return errorEnvelope15(
11042
- "SESSION_MEMORY_BRIDGE_BAD_ENVELOPE",
11043
- "bridge returned an unparseable envelope for session_memory",
11044
- "Check that the Python child is healthy."
11045
- );
11046
- }
11047
11084
  function errorEnvelope15(code, message, hint) {
11048
11085
  return {
11049
11086
  tool: "session_memory",
@@ -11663,7 +11700,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11663
11700
  var DEFAULT_PACKAGE = "crosscheck-cli";
11664
11701
  var FETCH_TIMEOUT_MS = 3e3;
11665
11702
  function engineVersion() {
11666
- return true ? "0.2.27" : "0.0.0-dev";
11703
+ return true ? "0.2.29" : "0.0.0-dev";
11667
11704
  }
11668
11705
  function defaultUpdateCachePath() {
11669
11706
  const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");
@@ -12435,12 +12472,11 @@ function helpTool() {
12435
12472
  }
12436
12473
  });
12437
12474
  }
12438
- function registerCoreTools(opts = {}) {
12439
- const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
12475
+ function registerCoreTools(o = {}) {
12440
12476
  const tools = /* @__PURE__ */ new Map();
12441
12477
  const list = [
12442
12478
  pingTool(),
12443
- verifyTool(o.bridge, o.fetchConfig),
12479
+ verifyTool(o.fetchConfig),
12444
12480
  pickTool(
12445
12481
  o.providers ?? {},
12446
12482
  o.providerAllowlist ?? null,
@@ -12452,7 +12488,6 @@ function registerCoreTools(opts = {}) {
12452
12488
  auditTool(
12453
12489
  o.providers ?? {},
12454
12490
  o.providerAllowlist ?? null,
12455
- o.bridge,
12456
12491
  o.transcriptsDir,
12457
12492
  o.pricing,
12458
12493
  o.storage,
@@ -12462,7 +12497,6 @@ function registerCoreTools(opts = {}) {
12462
12497
  conferTool(
12463
12498
  o.providers ?? {},
12464
12499
  o.providerAllowlist ?? null,
12465
- o.bridge,
12466
12500
  o.moderatorDefault ?? "anthropic",
12467
12501
  o.pricing,
12468
12502
  o.storage,
@@ -12475,7 +12509,6 @@ function registerCoreTools(opts = {}) {
12475
12509
  debateTool(
12476
12510
  o.providers ?? {},
12477
12511
  o.providerAllowlist ?? null,
12478
- o.bridge,
12479
12512
  buildInnerCallers(o),
12480
12513
  o.storage,
12481
12514
  o.pricing,
@@ -12487,7 +12520,6 @@ function registerCoreTools(opts = {}) {
12487
12520
  coordinateTool(
12488
12521
  o.providers ?? {},
12489
12522
  o.providerAllowlist ?? null,
12490
- o.bridge,
12491
12523
  buildInnerCallers(o),
12492
12524
  o.storage,
12493
12525
  o.circuitBreakers,
@@ -12498,7 +12530,6 @@ function registerCoreTools(opts = {}) {
12498
12530
  triangulateTool(
12499
12531
  o.providers ?? {},
12500
12532
  o.providerAllowlist ?? null,
12501
- o.bridge,
12502
12533
  o.storage,
12503
12534
  o.circuitBreakers,
12504
12535
  o.transcriptsDir,
@@ -12507,7 +12538,6 @@ function registerCoreTools(opts = {}) {
12507
12538
  planTool(
12508
12539
  o.providers ?? {},
12509
12540
  o.providerAllowlist ?? null,
12510
- o.bridge,
12511
12541
  o.storage,
12512
12542
  o.circuitBreakers,
12513
12543
  o.transcriptsDir,
@@ -12516,7 +12546,6 @@ function registerCoreTools(opts = {}) {
12516
12546
  critiqueTool(
12517
12547
  o.providers ?? {},
12518
12548
  o.providerAllowlist ?? null,
12519
- o.bridge,
12520
12549
  o.storage,
12521
12550
  o.circuitBreakers,
12522
12551
  o.transcriptsDir,
@@ -12525,7 +12554,6 @@ function registerCoreTools(opts = {}) {
12525
12554
  reviewTool(
12526
12555
  o.providers ?? {},
12527
12556
  o.providerAllowlist ?? null,
12528
- o.bridge,
12529
12557
  o.storage,
12530
12558
  o.circuitBreakers,
12531
12559
  o.transcriptsDir,
@@ -12533,25 +12561,23 @@ function registerCoreTools(opts = {}) {
12533
12561
  ),
12534
12562
  listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
12535
12563
  modelsTool(o.providers ?? {}, o.activeProviders ?? null),
12536
- recallTool(o.storage, o.bridge),
12537
- sessionMemoryTool(o.storage, o.bridge),
12538
- scoreboardTool(o.storage, o.bridge, o.eventsPath),
12539
- explainTool(o.storage, o.bridge, o.transcriptsDir),
12564
+ recallTool(o.storage),
12565
+ sessionMemoryTool(o.storage),
12566
+ scoreboardTool(o.storage, o.eventsPath),
12567
+ explainTool(o.storage, o.transcriptsDir),
12540
12568
  delegateTool(
12541
12569
  o.providers ?? {},
12542
12570
  o.providerAllowlist ?? null,
12543
12571
  o.storage,
12544
- o.bridge,
12545
12572
  o.moderatorDefault ?? "anthropic"
12546
12573
  ),
12547
12574
  fetchTool(o.storage, o.fetchConfig, o.repoRoot),
12548
- recommendPanelTool(o.providers ?? {}, o.storage, o.bridge),
12575
+ recommendPanelTool(o.providers ?? {}, o.storage),
12549
12576
  updateCrosscheckTool(o.repoRoot ?? null),
12550
12577
  benchTool(
12551
12578
  o.providers ?? {},
12552
12579
  o.providerAllowlist ?? null,
12553
12580
  o.storage,
12554
- o.bridge,
12555
12581
  o.moderatorDefault ?? "anthropic",
12556
12582
  o.benchGoldensDir,
12557
12583
  o.circuitBreakers,
@@ -12562,7 +12588,6 @@ function registerCoreTools(opts = {}) {
12562
12588
  solveTool(
12563
12589
  o.providers ?? {},
12564
12590
  o.providerAllowlist ?? null,
12565
- o.bridge,
12566
12591
  o.storage,
12567
12592
  o.circuitBreakers,
12568
12593
  o.transcriptsDir,
@@ -12571,7 +12596,6 @@ function registerCoreTools(opts = {}) {
12571
12596
  orchestrateTool(
12572
12597
  o.providers ?? {},
12573
12598
  o.providerAllowlist ?? null,
12574
- o.bridge,
12575
12599
  o.moderatorDefault ?? "anthropic",
12576
12600
  o.storage,
12577
12601
  o.pricing,
@@ -12618,7 +12642,6 @@ function createTool(o, toolName, cheapDefault) {
12618
12642
  providers: o.providers ?? {},
12619
12643
  allowlist: o.providerAllowlist ?? null,
12620
12644
  ...o.storage ? { storage: o.storage } : {},
12621
- ...o.bridge ? { bridge: o.bridge } : {},
12622
12645
  ...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
12623
12646
  ...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
12624
12647
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {},
@@ -12627,7 +12650,7 @@ function createTool(o, toolName, cheapDefault) {
12627
12650
  })
12628
12651
  };
12629
12652
  }
12630
- function orchestrateTool(providers, allowlist, bridge, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12653
+ function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12631
12654
  return {
12632
12655
  name: "orchestrate",
12633
12656
  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.",
@@ -12652,7 +12675,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12652
12675
  providers,
12653
12676
  allowlist,
12654
12677
  moderator,
12655
- ...bridge ? { bridge } : {},
12656
12678
  ...storage ? { storage } : {},
12657
12679
  ...pricing ? { pricing } : {},
12658
12680
  ...breakers ? { breakers } : {},
@@ -12662,7 +12684,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12662
12684
  })
12663
12685
  };
12664
12686
  }
12665
- function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12687
+ function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12666
12688
  return {
12667
12689
  name: "solve",
12668
12690
  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.",
@@ -12684,7 +12706,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
12684
12706
  handler: (args) => runSolve(args, {
12685
12707
  providers,
12686
12708
  allowlist,
12687
- ...bridge ? { bridge } : {},
12688
12709
  ...storage ? { storage } : {},
12689
12710
  ...breakers ? { breakers } : {},
12690
12711
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12723,7 +12744,7 @@ function configPinTool(repoRoot, config2, rejectDriftEnv) {
12723
12744
  }
12724
12745
  };
12725
12746
  }
12726
- function benchTool(providers, allowlist, storage, bridge, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12747
+ function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
12727
12748
  return {
12728
12749
  name: "bench",
12729
12750
  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).",
@@ -12742,7 +12763,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
12742
12763
  allowlist,
12743
12764
  moderator,
12744
12765
  ...storage ? { storage } : {},
12745
- ...bridge ? { bridge } : {},
12746
12766
  ...defaultGoldensDir ? { defaultGoldensDir } : {},
12747
12767
  ...breakers ? { breakers } : {},
12748
12768
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12769,7 +12789,7 @@ function updateCrosscheckTool(repoRoot) {
12769
12789
  }
12770
12790
  };
12771
12791
  }
12772
- function recommendPanelTool(providers, storage, bridge) {
12792
+ function recommendPanelTool(providers, storage) {
12773
12793
  return {
12774
12794
  name: "recommend_panel",
12775
12795
  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.",
@@ -12787,8 +12807,7 @@ function recommendPanelTool(providers, storage, bridge) {
12787
12807
  },
12788
12808
  handler: (args) => runRecommendPanel(args, {
12789
12809
  providers,
12790
- ...storage ? { storage } : {},
12791
- ...bridge ? { bridge } : {}
12810
+ ...storage ? { storage } : {}
12792
12811
  })
12793
12812
  };
12794
12813
  }
@@ -12813,7 +12832,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
12813
12832
  })
12814
12833
  };
12815
12834
  }
12816
- function delegateTool(providers, allowlist, storage, bridge, moderator) {
12835
+ function delegateTool(providers, allowlist, storage, moderator) {
12817
12836
  return {
12818
12837
  name: "delegate",
12819
12838
  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.",
@@ -12833,12 +12852,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
12833
12852
  providers,
12834
12853
  allowlist,
12835
12854
  moderator,
12836
- ...storage ? { storage } : {},
12837
- ...bridge ? { bridge } : {}
12855
+ ...storage ? { storage } : {}
12838
12856
  })
12839
12857
  };
12840
12858
  }
12841
- function explainTool(storage, bridge, transcriptsDir) {
12859
+ function explainTool(storage, transcriptsDir) {
12842
12860
  return {
12843
12861
  name: "explain",
12844
12862
  description: "Replay a session as a navigable tree with cost/latency annotations. Reads usage_log + optionally walks the transcripts directory for per-tool summaries.",
@@ -12856,12 +12874,11 @@ function explainTool(storage, bridge, transcriptsDir) {
12856
12874
  },
12857
12875
  handler: (args) => runExplain(args, {
12858
12876
  ...storage ? { storage } : {},
12859
- ...bridge ? { bridge } : {},
12860
12877
  ...transcriptsDir ? { transcriptsDir } : {}
12861
12878
  })
12862
12879
  };
12863
12880
  }
12864
- function scoreboardTool(storage, bridge, eventsPath) {
12881
+ function scoreboardTool(storage, eventsPath) {
12865
12882
  return {
12866
12883
  name: "scoreboard",
12867
12884
  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).",
@@ -12875,12 +12892,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
12875
12892
  },
12876
12893
  handler: (args) => runScoreboard(args, {
12877
12894
  ...storage ? { storage } : {},
12878
- ...bridge ? { bridge } : {},
12879
12895
  ...eventsPath ? { eventsPath } : {}
12880
12896
  })
12881
12897
  };
12882
12898
  }
12883
- function sessionMemoryTool(storage, bridge) {
12899
+ function sessionMemoryTool(storage) {
12884
12900
  return {
12885
12901
  name: "session_memory",
12886
12902
  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).",
@@ -12903,15 +12919,14 @@ function sessionMemoryTool(storage, bridge) {
12903
12919
  required: ["action", "session_id"]
12904
12920
  },
12905
12921
  handler: (args) => runSessionMemory(args, {
12906
- ...storage ? { storage } : {},
12907
- ...bridge ? { bridge } : {}
12922
+ ...storage ? { storage } : {}
12908
12923
  })
12909
12924
  };
12910
12925
  }
12911
- function recallTool(storage, bridge) {
12926
+ function recallTool(storage) {
12912
12927
  return {
12913
12928
  name: "recall",
12914
- 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.",
12929
+ description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter.",
12915
12930
  inputSchema: {
12916
12931
  type: "object",
12917
12932
  additionalProperties: true,
@@ -12925,8 +12940,7 @@ function recallTool(storage, bridge) {
12925
12940
  required: ["query"]
12926
12941
  },
12927
12942
  handler: (args) => runRecall(args, {
12928
- ...storage ? { storage } : {},
12929
- ...bridge ? { bridge } : {}
12943
+ ...storage ? { storage } : {}
12930
12944
  })
12931
12945
  };
12932
12946
  }
@@ -12962,7 +12976,7 @@ function modelsTool(providers, activeProviders) {
12962
12976
  handler: async (args) => runModels(args, { providers, activeProviders })
12963
12977
  };
12964
12978
  }
12965
- function reviewTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12979
+ function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12966
12980
  return {
12967
12981
  name: "review",
12968
12982
  description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
@@ -12981,7 +12995,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12981
12995
  handler: (args) => runReview(args, {
12982
12996
  providers,
12983
12997
  allowlist,
12984
- ...bridge ? { bridge } : {},
12985
12998
  ...storage ? { storage } : {},
12986
12999
  ...breakers ? { breakers } : {},
12987
13000
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -12989,7 +13002,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
12989
13002
  })
12990
13003
  };
12991
13004
  }
12992
- function critiqueTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13005
+ function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
12993
13006
  return {
12994
13007
  name: "critique",
12995
13008
  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.",
@@ -13009,7 +13022,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
13009
13022
  handler: (args) => runCritique(args, {
13010
13023
  providers,
13011
13024
  allowlist,
13012
- ...bridge ? { bridge } : {},
13013
13025
  ...storage ? { storage } : {},
13014
13026
  ...breakers ? { breakers } : {},
13015
13027
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13017,7 +13029,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
13017
13029
  })
13018
13030
  };
13019
13031
  }
13020
- function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13032
+ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13021
13033
  return {
13022
13034
  name: "plan",
13023
13035
  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.',
@@ -13044,7 +13056,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13044
13056
  handler: (args) => runPlan(args, {
13045
13057
  providers,
13046
13058
  allowlist,
13047
- ...bridge ? { bridge } : {},
13048
13059
  ...storage ? { storage } : {},
13049
13060
  ...breakers ? { breakers } : {},
13050
13061
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13052,7 +13063,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13052
13063
  })
13053
13064
  };
13054
13065
  }
13055
- function triangulateTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13066
+ function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13056
13067
  return {
13057
13068
  name: "triangulate",
13058
13069
  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.",
@@ -13073,7 +13084,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13073
13084
  handler: (args) => runTriangulate(args, {
13074
13085
  providers,
13075
13086
  allowlist,
13076
- ...bridge ? { bridge } : {},
13077
13087
  ...storage ? { storage } : {},
13078
13088
  ...breakers ? { breakers } : {},
13079
13089
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13081,7 +13091,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13081
13091
  })
13082
13092
  };
13083
13093
  }
13084
- function coordinateTool(providers, allowlist, bridge, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13094
+ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13085
13095
  return {
13086
13096
  name: "coordinate",
13087
13097
  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).",
@@ -13106,7 +13116,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13106
13116
  handler: (args) => runCoordinate(args, {
13107
13117
  providers,
13108
13118
  allowlist,
13109
- ...bridge ? { bridge } : {},
13110
13119
  innerCallers,
13111
13120
  ...storage ? { storage } : {},
13112
13121
  ...breakers ? { breakers } : {},
@@ -13116,7 +13125,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13116
13125
  })
13117
13126
  };
13118
13127
  }
13119
- function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13128
+ function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13120
13129
  return {
13121
13130
  name: "debate",
13122
13131
  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).",
@@ -13146,7 +13155,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
13146
13155
  handler: (args) => runDebate(args, {
13147
13156
  providers,
13148
13157
  allowlist,
13149
- ...bridge ? { bridge } : {},
13150
13158
  innerCallers,
13151
13159
  ...storage ? { storage } : {},
13152
13160
  ...pricing ? { pricing } : {},
@@ -13166,10 +13174,10 @@ function buildInnerCallers(o) {
13166
13174
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {}
13167
13175
  });
13168
13176
  }
13169
- out.verify = (args) => runVerify(args, o.bridge, o.fetchConfig);
13177
+ out.verify = (args) => runVerify(args, o.fetchConfig);
13170
13178
  return out;
13171
13179
  }
13172
- function conferTool(providers, allowlist, bridge, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13180
+ function conferTool(providers, allowlist, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13173
13181
  return {
13174
13182
  name: "confer",
13175
13183
  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).",
@@ -13196,7 +13204,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13196
13204
  handler: (args) => runConfer(args, {
13197
13205
  providers,
13198
13206
  allowlist,
13199
- ...bridge ? { bridge } : {},
13200
13207
  moderator,
13201
13208
  ...pricing ? { pricing } : {},
13202
13209
  ...storage ? { storage } : {},
@@ -13208,7 +13215,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13208
13215
  })
13209
13216
  };
13210
13217
  }
13211
- function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storage, breakers, repoRoot) {
13218
+ function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
13212
13219
  return {
13213
13220
  name: "audit",
13214
13221
  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.",
@@ -13234,7 +13241,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
13234
13241
  handler: (args) => runAudit(args, {
13235
13242
  providers,
13236
13243
  allowlist,
13237
- ...bridge ? { bridge } : {},
13238
13244
  ...transcriptsDir ? { transcriptsDir } : {},
13239
13245
  ...pricing ? { pricing } : {},
13240
13246
  ...storage ? { storage } : {},
@@ -13298,7 +13304,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
13298
13304
  })
13299
13305
  };
13300
13306
  }
13301
- function verifyTool(bridge, fetchConfig) {
13307
+ function verifyTool(fetchConfig) {
13302
13308
  return {
13303
13309
  name: "verify",
13304
13310
  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.",
@@ -13316,7 +13322,7 @@ function verifyTool(bridge, fetchConfig) {
13316
13322
  },
13317
13323
  required: ["checks"]
13318
13324
  },
13319
- handler: (args) => runVerify(args, bridge, fetchConfig)
13325
+ handler: (args) => runVerify(args, fetchConfig)
13320
13326
  };
13321
13327
  }
13322
13328
  function pingTool() {
@@ -13336,7 +13342,7 @@ function pingTool() {
13336
13342
  }
13337
13343
 
13338
13344
  // src/core/telemetry.ts
13339
- var import_node_crypto7 = __toESM(require("crypto"), 1);
13345
+ var import_node_crypto8 = __toESM(require("crypto"), 1);
13340
13346
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13341
13347
  var BATCH_MAX = 100;
13342
13348
  var MAX_QUEUE = 500;
@@ -13400,6 +13406,64 @@ async function flush() {
13400
13406
  }
13401
13407
  }
13402
13408
 
13409
+ // src/core/process-registry.ts
13410
+ var import_node_fs15 = require("fs");
13411
+ var import_node_os3 = __toESM(require("os"), 1);
13412
+ var import_node_path14 = __toESM(require("path"), 1);
13413
+ function registryDir(env = process.env) {
13414
+ const base = env["CROSSCHECK_DATA_DIR"] || import_node_path14.default.join(env["HOME"] ?? env["USERPROFILE"] ?? import_node_os3.default.homedir(), ".crosscheck");
13415
+ return import_node_path14.default.join(base, "procs");
13416
+ }
13417
+ function isAlive(pid) {
13418
+ try {
13419
+ process.kill(pid, 0);
13420
+ return true;
13421
+ } catch (err) {
13422
+ return err.code === "EPERM";
13423
+ }
13424
+ }
13425
+ function listProcesses(installedVersion, env = process.env, now = Date.now()) {
13426
+ const dir = registryDir(env);
13427
+ let files;
13428
+ try {
13429
+ files = (0, import_node_fs15.readdirSync)(dir).filter((f) => f.endsWith(".json"));
13430
+ } catch {
13431
+ return [];
13432
+ }
13433
+ const out = [];
13434
+ for (const f of files) {
13435
+ let rec;
13436
+ try {
13437
+ rec = JSON.parse((0, import_node_fs15.readFileSync)(import_node_path14.default.join(dir, f), "utf8"));
13438
+ } catch {
13439
+ try {
13440
+ (0, import_node_fs15.rmSync)(import_node_path14.default.join(dir, f), { force: true });
13441
+ } catch {
13442
+ }
13443
+ continue;
13444
+ }
13445
+ if (typeof rec.pid !== "number") continue;
13446
+ const alive = isAlive(rec.pid);
13447
+ if (!alive) {
13448
+ try {
13449
+ (0, import_node_fs15.rmSync)(import_node_path14.default.join(dir, f), { force: true });
13450
+ } catch {
13451
+ }
13452
+ continue;
13453
+ }
13454
+ out.push({
13455
+ ...rec,
13456
+ alive,
13457
+ outdated: Boolean(rec.version) && rec.version !== installedVersion,
13458
+ ageMs: Math.max(0, now - (rec.startedAt ?? now))
13459
+ });
13460
+ }
13461
+ return out.sort((a, b) => a.startedAt - b.startedAt);
13462
+ }
13463
+ function processRegistryPath(env = process.env) {
13464
+ return registryDir(env);
13465
+ }
13466
+
13403
13467
  // src/entrypoints/embed.ts
13404
13468
  var KEY_ENV = {
13405
13469
  anthropic: "ANTHROPIC_API_KEY",
@@ -13427,6 +13491,107 @@ var ENGINE_TO_VAULT = { xai: "grok" };
13427
13491
  function vaultId(engineName) {
13428
13492
  return ENGINE_TO_VAULT[engineName] ?? engineName;
13429
13493
  }
13494
+ var ACTIVITY_TEXT_CAP = 8e3;
13495
+ var ASKED_CAP = 280;
13496
+ var runContext = new import_node_async_hooks2.AsyncLocalStorage();
13497
+ var SYNTHESIS_PURPOSES = /* @__PURE__ */ new Set(["synth", "moderator", "recombine", "judge", "unify"]);
13498
+ function exemptFromSkip(ctx, provider, purpose) {
13499
+ return provider === ctx.moderator && SYNTHESIS_PURPOSES.has(purpose);
13500
+ }
13501
+ function skippedError(provider, why, limitMs) {
13502
+ return new ProviderError(
13503
+ "client",
13504
+ why === "timeout" ? `${provider}: stopped after ${Math.round((limitMs ?? 0) / 1e3)}s (your per-model time limit)` : `${provider}: stopped waiting (you skipped it)`,
13505
+ { transient: false }
13506
+ );
13507
+ }
13508
+ function lastUserText(args) {
13509
+ const msgs = args.messages;
13510
+ for (let i = msgs.length - 1; i >= 0; i--) {
13511
+ const m = msgs[i];
13512
+ if (m && m.role === "user" && typeof m.content === "string") {
13513
+ const t = m.content.replace(/\s+/g, " ").trim();
13514
+ return t.length > ASKED_CAP ? `${t.slice(0, ASKED_CAP - 1)}\u2026` : t;
13515
+ }
13516
+ }
13517
+ return "";
13518
+ }
13519
+ function withActivity(p) {
13520
+ const send = p.send.bind(p);
13521
+ return {
13522
+ name: p.name,
13523
+ model: p.model,
13524
+ ...p.fallbackModels ? { fallbackModels: p.fallbackModels } : {},
13525
+ send: async (args) => {
13526
+ const ctx = runContext.getStore();
13527
+ if (!ctx) return send(args);
13528
+ const callId = ctx.nextCallId();
13529
+ const provider = vaultId(p.name);
13530
+ const model = args.modelOverride ?? p.model;
13531
+ const purpose = args.purpose ?? "worker";
13532
+ const started = Date.now();
13533
+ const exempt = exemptFromSkip(ctx, provider, purpose);
13534
+ if (!exempt && ctx.skipped.has(provider)) throw skippedError(provider, "user");
13535
+ ctx.emit({ type: "call.start", runId: ctx.runId, at: started, callId, provider, model, purpose, asked: lastUserText(args) });
13536
+ const controller = new AbortController();
13537
+ if (args.signal) {
13538
+ if (args.signal.aborted) controller.abort(args.signal.reason);
13539
+ else args.signal.addEventListener("abort", () => controller.abort(args.signal.reason), { once: true });
13540
+ }
13541
+ let stopped;
13542
+ if (!exempt) ctx.inflight.set(callId, { provider, purpose, controller });
13543
+ const timer = !exempt && ctx.callTimeoutMs && ctx.callTimeoutMs > 0 ? setTimeout(() => {
13544
+ stopped = "timeout";
13545
+ controller.abort("timeout");
13546
+ }, ctx.callTimeoutMs) : void 0;
13547
+ controller.signal.addEventListener("abort", () => {
13548
+ if (!stopped && controller.signal.reason === "skip") stopped = "user";
13549
+ }, { once: true });
13550
+ try {
13551
+ const res = await send({ ...args, signal: controller.signal });
13552
+ const text = typeof res.text === "string" ? res.text : "";
13553
+ ctx.emit({
13554
+ type: "call.done",
13555
+ runId: ctx.runId,
13556
+ at: Date.now(),
13557
+ callId,
13558
+ provider,
13559
+ model,
13560
+ purpose,
13561
+ ok: true,
13562
+ ms: Date.now() - started,
13563
+ text: text.slice(0, ACTIVITY_TEXT_CAP),
13564
+ truncated: text.length > ACTIVITY_TEXT_CAP,
13565
+ error: null,
13566
+ usage: usageOf(res)
13567
+ });
13568
+ return res;
13569
+ } catch (err) {
13570
+ const out = stopped ? skippedError(provider, stopped, ctx.callTimeoutMs) : err;
13571
+ ctx.emit({
13572
+ type: "call.done",
13573
+ runId: ctx.runId,
13574
+ at: Date.now(),
13575
+ callId,
13576
+ provider,
13577
+ model,
13578
+ purpose,
13579
+ ok: false,
13580
+ ms: Date.now() - started,
13581
+ text: "",
13582
+ truncated: false,
13583
+ error: out instanceof Error ? out.message : String(out),
13584
+ usage: null,
13585
+ ...stopped ? { stopped } : {}
13586
+ });
13587
+ throw out;
13588
+ } finally {
13589
+ if (timer) clearTimeout(timer);
13590
+ ctx.inflight.delete(callId);
13591
+ }
13592
+ }
13593
+ };
13594
+ }
13430
13595
  function usageOf(answer) {
13431
13596
  const u = answer["usage"];
13432
13597
  if (!u || typeof u !== "object") return null;
@@ -13456,12 +13621,14 @@ function errorOf(answer) {
13456
13621
  }
13457
13622
  function bundledPricingPath() {
13458
13623
  try {
13459
- return import_node_path14.default.join(import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
13624
+ return import_node_path15.default.join(import_node_path15.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
13460
13625
  } catch {
13461
13626
  return void 0;
13462
13627
  }
13463
13628
  }
13464
13629
  var runCounter = 0;
13630
+ var callCounter = 0;
13631
+ var nextCallId = () => ++callCounter;
13465
13632
  function nextRunId() {
13466
13633
  runCounter += 1;
13467
13634
  return `run_${Date.now().toString(36)}_${runCounter}`;
@@ -13477,10 +13644,12 @@ function createEmbeddedEngine(opts) {
13477
13644
  if (varName && model) env[varName] = model;
13478
13645
  }
13479
13646
  const pricingPath = [opts.pricingPath, bundledPricingPath()].find(
13480
- (p) => Boolean(p) && (0, import_node_fs15.existsSync)(p)
13647
+ (p) => Boolean(p) && (0, import_node_fs16.existsSync)(p)
13481
13648
  );
13482
13649
  const pricing = pricingPath ? loadPricing(pricingPath) : {};
13483
- const built = buildProviders({ env, pricing });
13650
+ const built = Object.fromEntries(
13651
+ Object.entries(buildProviders({ env, pricing })).map(([name, p]) => [name, withActivity(p)])
13652
+ );
13484
13653
  const moderator = opts.moderator ?? "anthropic";
13485
13654
  const tools = registerCoreTools({ providers: built, pricing });
13486
13655
  const providerIds = Object.keys(built).map(vaultId).sort();
@@ -13497,7 +13666,8 @@ function createEmbeddedEngine(opts) {
13497
13666
  if (!tool) return Promise.reject(new Error(`unknown tool: ${name}`));
13498
13667
  return Promise.resolve(tool.handler(args));
13499
13668
  };
13500
- const run = async (name, args, onEvent) => {
13669
+ const liveRuns = /* @__PURE__ */ new Map();
13670
+ const run = async (name, args, onEvent, runOpts = {}) => {
13501
13671
  const runId = nextRunId();
13502
13672
  const started = Date.now();
13503
13673
  const emit = (e) => {
@@ -13506,6 +13676,78 @@ function createEmbeddedEngine(opts) {
13506
13676
  } catch {
13507
13677
  }
13508
13678
  };
13679
+ const ctx = {
13680
+ runId,
13681
+ emit,
13682
+ nextCallId,
13683
+ skipped: /* @__PURE__ */ new Set(),
13684
+ inflight: /* @__PURE__ */ new Map(),
13685
+ moderator: vaultId(moderator),
13686
+ ...runOpts.callTimeoutMs && runOpts.callTimeoutMs > 0 ? { callTimeoutMs: runOpts.callTimeoutMs } : {}
13687
+ };
13688
+ liveRuns.set(runId, ctx);
13689
+ try {
13690
+ return await runContext.run(ctx, () => withProgress(runId, (n) => {
13691
+ if (n.params.message) emit({ type: "progress", runId, at: Date.now(), message: n.params.message });
13692
+ }, () => runInner(name, args, runId, started, emit)));
13693
+ } finally {
13694
+ liveRuns.delete(runId);
13695
+ }
13696
+ };
13697
+ const skip = (runId, provider) => {
13698
+ const ctx = liveRuns.get(runId);
13699
+ if (!ctx) return 0;
13700
+ ctx.skipped.add(provider);
13701
+ let stopped = 0;
13702
+ for (const call2 of ctx.inflight.values()) {
13703
+ if (call2.provider === provider && !exemptFromSkip(ctx, call2.provider, call2.purpose)) {
13704
+ call2.controller.abort("skip");
13705
+ stopped += 1;
13706
+ }
13707
+ }
13708
+ return stopped;
13709
+ };
13710
+ const ask = async (o) => {
13711
+ const engineName = Object.keys(built).find((n) => vaultId(n) === o.provider);
13712
+ const base = engineName ? built[engineName] : void 0;
13713
+ if (!base) {
13714
+ return { ok: false, text: "", json: null, model: o.model ?? "", error: `No ${o.provider} key is configured, so it can't be asked.` };
13715
+ }
13716
+ const provider = o.model && o.model !== base.model ? retargetProvider(base, o.model) : base;
13717
+ const maxTokens = o.maxTokens ?? 8e3;
13718
+ const doAsk = async () => {
13719
+ if (o.schema) {
13720
+ const res = await requestStructured(provider, o.messages, o.schema, { maxTokens, purpose: o.purpose, maxRetries: 1 });
13721
+ return {
13722
+ ok: res.obj !== null,
13723
+ text: res.answer.response ?? "",
13724
+ json: res.obj,
13725
+ error: res.obj !== null ? null : res.answer.error ?? res.errors.join("; ") ?? "invalid reply",
13726
+ model: provider.model
13727
+ };
13728
+ }
13729
+ const a = await askOne(provider, o.messages, { maxTokens, temperature: 0.3, purpose: o.purpose });
13730
+ return { ok: !a.error, text: a.response ?? "", json: null, error: a.error ?? null, model: provider.model };
13731
+ };
13732
+ if (!o.runId || !o.onEvent) return doAsk();
13733
+ const sink = o.onEvent;
13734
+ const emit = (e) => {
13735
+ try {
13736
+ sink(e);
13737
+ } catch {
13738
+ }
13739
+ };
13740
+ const ctx = {
13741
+ runId: o.runId,
13742
+ emit,
13743
+ nextCallId,
13744
+ skipped: /* @__PURE__ */ new Set(),
13745
+ inflight: /* @__PURE__ */ new Map(),
13746
+ moderator: o.provider
13747
+ };
13748
+ return runContext.run(ctx, doAsk);
13749
+ };
13750
+ const runInner = async (name, args, runId, started, emit) => {
13509
13751
  emit({
13510
13752
  type: "run.start",
13511
13753
  runId,
@@ -13583,8 +13825,16 @@ function createEmbeddedEngine(opts) {
13583
13825
  providers: providerIds,
13584
13826
  models,
13585
13827
  listTools: () => [...tools.keys()],
13828
+ requiredArgs: (name) => {
13829
+ const tool = tools.get(name);
13830
+ if (!tool) return null;
13831
+ const req = tool.inputSchema?.required;
13832
+ return Array.isArray(req) ? req.filter((x) => typeof x === "string") : [];
13833
+ },
13586
13834
  call,
13587
13835
  run,
13836
+ skip,
13837
+ ask,
13588
13838
  close: async () => {
13589
13839
  await flush().catch(() => {
13590
13840
  });
@@ -13594,12 +13844,16 @@ function createEmbeddedEngine(opts) {
13594
13844
  var __test_internals = { usageOf, textOf, errorOf, vaultId };
13595
13845
  // Annotate the CommonJS export names for ESM import in node:
13596
13846
  0 && (module.exports = {
13847
+ ACTIVITY_TEXT_CAP,
13597
13848
  DEFAULT_EXCLUDED_PROVIDERS,
13598
13849
  DEFAULT_FALLBACKS,
13599
13850
  DEFAULT_MODELS,
13600
13851
  __KEY_ENV,
13601
13852
  __MODEL_ENV,
13602
13853
  __test_internals,
13603
- createEmbeddedEngine
13854
+ createEmbeddedEngine,
13855
+ isAlive,
13856
+ listProcesses,
13857
+ processRegistryPath
13604
13858
  });
13605
13859
  //# sourceMappingURL=embed.cjs.map