crosscheck-mcp 0.2.28 → 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.
@@ -891,6 +891,52 @@ function rejectsDisabledThinking(model) {
891
891
  const m = model.toLowerCase();
892
892
  return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
893
893
  }
894
+ var NO_FORCED_TOOL_PREFIXES = [
895
+ "claude-fable-5-1",
896
+ "claude-mythos-5-1",
897
+ "claude-opus-5-5",
898
+ "claude-sonnet-5-5"
899
+ ];
900
+ function rejectsForcedToolUse(model) {
901
+ const m = model.toLowerCase();
902
+ return NO_FORCED_TOOL_PREFIXES.some((p) => m.startsWith(p));
903
+ }
904
+ var UNSUPPORTED_SCHEMA_KEYS = /* @__PURE__ */ new Set([
905
+ "minimum",
906
+ "maximum",
907
+ "exclusiveMinimum",
908
+ "exclusiveMaximum",
909
+ "multipleOf",
910
+ "minLength",
911
+ "maxLength",
912
+ "pattern",
913
+ "minItems",
914
+ "maxItems",
915
+ "uniqueItems",
916
+ "minProperties",
917
+ "maxProperties",
918
+ "$schema"
919
+ ]);
920
+ function toStructuredOutputSchema(schema) {
921
+ const walk = (node) => {
922
+ if (Array.isArray(node)) return node.map(walk);
923
+ if (!node || typeof node !== "object") return node;
924
+ const out = {};
925
+ for (const [k, v] of Object.entries(node)) {
926
+ if (UNSUPPORTED_SCHEMA_KEYS.has(k)) continue;
927
+ if (k === "properties" && v && typeof v === "object") {
928
+ out[k] = Object.fromEntries(Object.entries(v).map(([pk, pv]) => [pk, walk(pv)]));
929
+ } else if (["items", "anyOf", "allOf", "oneOf", "not", "$defs", "definitions"].includes(k)) {
930
+ out[k] = k === "$defs" || k === "definitions" ? Object.fromEntries(Object.entries(v ?? {}).map(([dk, dv]) => [dk, walk(dv)])) : walk(v);
931
+ } else {
932
+ out[k] = v;
933
+ }
934
+ }
935
+ if (out["type"] === "object" || "properties" in out) out["additionalProperties"] = false;
936
+ return out;
937
+ };
938
+ return walk(schema);
939
+ }
894
940
  var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
895
941
  function applyPromptCaching(body, env = process.env) {
896
942
  const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
@@ -942,7 +988,12 @@ function buildAnthropicRequest(opts) {
942
988
  body.thinking = { type: "disabled" };
943
989
  }
944
990
  }
945
- if (opts.jsonSchema) {
991
+ if (opts.jsonSchema && rejectsForcedToolUse(opts.model)) {
992
+ body.output_config = {
993
+ ...body.output_config ?? {},
994
+ format: { type: "json_schema", schema: toStructuredOutputSchema(opts.jsonSchema) }
995
+ };
996
+ } else if (opts.jsonSchema) {
946
997
  body.tools = [{
947
998
  name: ANTHROPIC_STRUCTURED_TOOL_NAME,
948
999
  description: "Emit a single JSON object matching the requested schema.",
@@ -1343,7 +1394,15 @@ function buildOpenAICompatibleRequest(opts) {
1343
1394
  json_schema: {
1344
1395
  name: "structured_output",
1345
1396
  schema: opts.jsonSchema,
1346
- strict: true
1397
+ // NOT strict. Strict mode requires `additionalProperties: false` on
1398
+ // every object and every property listed in `required` — the
1399
+ // engine's schemas don't meet that, so every structured OpenAI call
1400
+ // (planner, judges, synthesis) was a 400, unnoticed until the canary
1401
+ // grew a structured check (2026-10-11). Non-strict still shapes the
1402
+ // reply to the schema, and structured.ts validates it against the
1403
+ // full schema regardless, so strictness added a failure mode and no
1404
+ // safety.
1405
+ strict: false
1347
1406
  }
1348
1407
  };
1349
1408
  }
@@ -1631,7 +1690,7 @@ import { z } from "zod";
1631
1690
 
1632
1691
  // src/server-meta.ts
1633
1692
  var SERVER_NAME = "crosscheck-agent";
1634
- var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
1693
+ var SERVER_VERSION = true ? "0.2.29" : "0.0.0-dev";
1635
1694
 
1636
1695
  // src/tools/audit.ts
1637
1696
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -8263,6 +8322,16 @@ function buildCallContext(args) {
8263
8322
  var CREATE_DOC_MAX_BYTES = 32 * 1024;
8264
8323
  var CREATE_AUDIT_THRESHOLD = 0.7;
8265
8324
  async function runCreate(args, opts) {
8325
+ const subEnvelopes = [];
8326
+ const tracked = (fn) => async (...a) => {
8327
+ const out = await fn(...a);
8328
+ subEnvelopes.push(out);
8329
+ return out;
8330
+ };
8331
+ const confer = tracked(runConfer);
8332
+ const orchestrate = tracked(runOrchestrate);
8333
+ const review = tracked(runReview);
8334
+ const audit = tracked(runAudit);
8266
8335
  const instruction = typeof args["instruction"] === "string" ? args["instruction"] : String(args["instruction"] ?? "");
8267
8336
  if (!instruction) {
8268
8337
  return errorEnvelope6(
@@ -8299,7 +8368,7 @@ ${constraints}
8299
8368
 
8300
8369
  ` : "") + `DOCUMENTS (${okCount} of ${descriptors.length} ingested):
8301
8370
  ${documentsPayload}`;
8302
- const scope = await runConfer({
8371
+ const scope = await confer({
8303
8372
  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,
8304
8373
  context: contextBlock,
8305
8374
  ...providers !== void 0 ? { providers } : {},
@@ -8326,7 +8395,7 @@ ${scopeAnswer || "(none)"}
8326
8395
  };
8327
8396
  if (providers !== void 0) orchestrateArgs["providers"] = providers;
8328
8397
  if (planOnly) orchestrateArgs["plan_only"] = true;
8329
- let orchestration = await runOrchestrate(orchestrateArgs, {
8398
+ let orchestration = await orchestrate(orchestrateArgs, {
8330
8399
  providers: opts.providers,
8331
8400
  allowlist: opts.allowlist ?? null,
8332
8401
  moderator,
@@ -8355,7 +8424,7 @@ ${scopeAnswer || "(none)"}
8355
8424
  }
8356
8425
  let reviewEnvelope = null;
8357
8426
  if (!skipReview && typeof orchestration["final"] === "string" && orchestration["final"]) {
8358
- reviewEnvelope = await runReview({
8427
+ reviewEnvelope = await review({
8359
8428
  snippet: orchestration["final"],
8360
8429
  intent: `final deliverable for: ${instruction}`,
8361
8430
  ...providers !== void 0 ? { providers } : {},
@@ -8375,7 +8444,7 @@ ${scopeAnswer || "(none)"}
8375
8444
  const panelExhausted = producingPanel.length > 0 && producingPanel.every(
8376
8445
  (p) => p in opts.providers || Object.keys(opts.providers).includes(p.toLowerCase())
8377
8446
  ) && producingPanel.length >= Object.keys(opts.providers).length;
8378
- auditEnvelope = await runAudit({
8447
+ auditEnvelope = await audit({
8379
8448
  output_to_audit: orchestration["final"],
8380
8449
  producing_panelists: producingPanel,
8381
8450
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8404,7 +8473,7 @@ ${retryConstraints}
8404
8473
  DOCUMENTS:
8405
8474
  ${documentsPayload}`
8406
8475
  };
8407
- const retryOrchestration = await runOrchestrate(
8476
+ const retryOrchestration = await orchestrate(
8408
8477
  retryOrchestrateArgs,
8409
8478
  {
8410
8479
  providers: opts.providers,
@@ -8418,7 +8487,7 @@ ${documentsPayload}`
8418
8487
  if (typeof retryOrchestration["final"] === "string" && retryOrchestration["final"]) {
8419
8488
  const retryPanel = computeProducingPanel(retryOrchestration);
8420
8489
  const retryPanelExhausted = retryPanel.length > 0 && retryPanel.length >= Object.keys(opts.providers).length;
8421
- auditEnvelope = await runAudit({
8490
+ auditEnvelope = await audit({
8422
8491
  output_to_audit: retryOrchestration["final"],
8423
8492
  producing_panelists: retryPanel,
8424
8493
  ...auditRubric !== void 0 ? { rubric: auditRubric } : {},
@@ -8493,9 +8562,28 @@ ${documentsPayload}`
8493
8562
  ["auditor", "items", "overall_score", "passed", "rubric"]
8494
8563
  ),
8495
8564
  artifacts,
8496
- warnings
8565
+ warnings,
8566
+ ...combinedUsage(subEnvelopes)
8497
8567
  };
8498
8568
  }
8569
+ function combinedUsage(envelopes) {
8570
+ const usages = [];
8571
+ const byCallTiming = [];
8572
+ let wall = 0, cpu = 0;
8573
+ for (const env of envelopes) {
8574
+ const e = env ?? {};
8575
+ const calls = e["usage"]?.["by_call"] ?? [];
8576
+ const t = e["timing"] ?? {};
8577
+ const timing = Array.isArray(t["by_call"]) ? t["by_call"] : [];
8578
+ if (!Array.isArray(calls) || calls.length === 0) continue;
8579
+ usages.push(...calls);
8580
+ if (timing.length === calls.length) byCallTiming.push(...timing);
8581
+ 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 });
8582
+ wall += Number(t["wall_ms"] ?? 0) || 0;
8583
+ cpu += Number(t["cpu_ms"] ?? 0) || 0;
8584
+ }
8585
+ return { usage: aggregateUsage(usages), timing: { wall_ms: wall, cpu_ms: cpu, by_call: byCallTiming } };
8586
+ }
8499
8587
  async function ingestDocuments(documents, sessionId, opts) {
8500
8588
  if (documents.length === 0) return [];
8501
8589
  const out = [];
@@ -11972,7 +12060,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11972
12060
  var DEFAULT_PACKAGE = "crosscheck-cli";
11973
12061
  var FETCH_TIMEOUT_MS = 3e3;
11974
12062
  function engineVersion() {
11975
- return true ? "0.2.28" : "0.0.0-dev";
12063
+ return true ? "0.2.29" : "0.0.0-dev";
11976
12064
  }
11977
12065
  function defaultUpdateCachePath() {
11978
12066
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");