crosscheck-mcp 0.2.24 → 0.2.26

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.
@@ -1,50 +1,9 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
3
 
4
- /** A live bridge to a Python crosscheck-agent child. */
5
- interface BridgeHandle {
6
- /** Names of the tools exposed by the Python child (from its
7
- * `tools/list` response). */
8
- readonly toolNames: ReadonlySet<string>;
9
- /** PID of the spawned Python child process, or `null` if the
10
- * transport hasn't started yet / has already closed. Useful for
11
- * shutdown verification and host-side diagnostics. */
12
- readonly pid: number | null;
13
- /** Forward a `tools/call` to the Python child and return the result
14
- * envelope verbatim. */
15
- callTool(name: string, args: Record<string, unknown>): Promise<{
16
- content: {
17
- type: string;
18
- text: string;
19
- }[];
20
- isError?: boolean;
21
- }>;
22
- /** Re-fetch the tool list (in case the child surfaces new tools mid-
23
- * session). Returns the new tool names. */
24
- refreshTools(): Promise<ReadonlySet<string>>;
25
- /** Tear down the bridge cleanly. Idempotent — repeat calls are no-ops. */
26
- close(): Promise<void>;
27
- }
28
-
29
- /** Per-call node-cache config block. Mirrors Python's CFG.node_cache. */
30
- interface NodeCacheCfg {
31
- /** Master enable flag. Defaults to true when the cfg block exists
32
- * in opts; explicitly set false to short-circuit reads + writes. */
33
- enabled?: boolean;
34
- /** Directory to store cache entries. Relative paths are resolved
35
- * against `repoRoot` when supplied; otherwise the CWD. */
36
- dir?: string;
37
- /** Stale-by-mtime threshold (seconds). 0 disables TTL eviction. */
38
- ttl_seconds?: number;
39
- /** Hard cap on the number of JSON entries on disk. 0 disables. */
40
- max_entries?: number;
41
- /** Hard cap on cumulative file size (bytes). 0 disables. */
42
- max_cache_bytes?: number;
43
- }
44
-
45
- interface WorkerToolsCfg {
46
- cost_cap_usd?: unknown;
47
- cost_cap_mode?: unknown;
4
+ interface PricingDoc {
5
+ /** `<provider>` -> `<model>` -> ModelRates. */
6
+ [provider: string]: unknown;
48
7
  }
49
8
 
50
9
  /** sessions row. */
@@ -363,19 +322,6 @@ interface Storage extends StorageRead, StorageWrite {
363
322
  close(): Promise<void>;
364
323
  }
365
324
 
366
- interface BreakerCfg {
367
- max_session_cost_usd?: number;
368
- max_session_tokens?: number;
369
- max_session_wall_seconds?: number;
370
- max_dag_nodes?: number;
371
- max_dag_depth?: number;
372
- }
373
-
374
- interface PricingDoc {
375
- /** `<provider>` -> `<model>` -> ModelRates. */
376
- [provider: string]: unknown;
377
- }
378
-
379
325
  /** One provider call's token + cost record. Mirrors `Usage.to_dict()`
380
326
  * output exactly. */
381
327
  interface Usage {
@@ -451,6 +397,60 @@ interface Provider {
451
397
  send(args: SendArgs): Promise<SendResult>;
452
398
  }
453
399
 
400
+ /** A live bridge to a Python crosscheck-agent child. */
401
+ interface BridgeHandle {
402
+ /** Names of the tools exposed by the Python child (from its
403
+ * `tools/list` response). */
404
+ readonly toolNames: ReadonlySet<string>;
405
+ /** PID of the spawned Python child process, or `null` if the
406
+ * transport hasn't started yet / has already closed. Useful for
407
+ * shutdown verification and host-side diagnostics. */
408
+ readonly pid: number | null;
409
+ /** Forward a `tools/call` to the Python child and return the result
410
+ * envelope verbatim. */
411
+ callTool(name: string, args: Record<string, unknown>): Promise<{
412
+ content: {
413
+ type: string;
414
+ text: string;
415
+ }[];
416
+ isError?: boolean;
417
+ }>;
418
+ /** Re-fetch the tool list (in case the child surfaces new tools mid-
419
+ * session). Returns the new tool names. */
420
+ refreshTools(): Promise<ReadonlySet<string>>;
421
+ /** Tear down the bridge cleanly. Idempotent — repeat calls are no-ops. */
422
+ close(): Promise<void>;
423
+ }
424
+
425
+ /** Per-call node-cache config block. Mirrors Python's CFG.node_cache. */
426
+ interface NodeCacheCfg {
427
+ /** Master enable flag. Defaults to true when the cfg block exists
428
+ * in opts; explicitly set false to short-circuit reads + writes. */
429
+ enabled?: boolean;
430
+ /** Directory to store cache entries. Relative paths are resolved
431
+ * against `repoRoot` when supplied; otherwise the CWD. */
432
+ dir?: string;
433
+ /** Stale-by-mtime threshold (seconds). 0 disables TTL eviction. */
434
+ ttl_seconds?: number;
435
+ /** Hard cap on the number of JSON entries on disk. 0 disables. */
436
+ max_entries?: number;
437
+ /** Hard cap on cumulative file size (bytes). 0 disables. */
438
+ max_cache_bytes?: number;
439
+ }
440
+
441
+ interface WorkerToolsCfg {
442
+ cost_cap_usd?: unknown;
443
+ cost_cap_mode?: unknown;
444
+ }
445
+
446
+ interface BreakerCfg {
447
+ max_session_cost_usd?: number;
448
+ max_session_tokens?: number;
449
+ max_session_wall_seconds?: number;
450
+ max_dag_nodes?: number;
451
+ max_dag_depth?: number;
452
+ }
453
+
454
454
  interface ConfigPinningConfig {
455
455
  /** Pin file location. Repo-relative or absolute. */
456
456
  pin_file?: string;
@@ -1,50 +1,9 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
3
 
4
- /** A live bridge to a Python crosscheck-agent child. */
5
- interface BridgeHandle {
6
- /** Names of the tools exposed by the Python child (from its
7
- * `tools/list` response). */
8
- readonly toolNames: ReadonlySet<string>;
9
- /** PID of the spawned Python child process, or `null` if the
10
- * transport hasn't started yet / has already closed. Useful for
11
- * shutdown verification and host-side diagnostics. */
12
- readonly pid: number | null;
13
- /** Forward a `tools/call` to the Python child and return the result
14
- * envelope verbatim. */
15
- callTool(name: string, args: Record<string, unknown>): Promise<{
16
- content: {
17
- type: string;
18
- text: string;
19
- }[];
20
- isError?: boolean;
21
- }>;
22
- /** Re-fetch the tool list (in case the child surfaces new tools mid-
23
- * session). Returns the new tool names. */
24
- refreshTools(): Promise<ReadonlySet<string>>;
25
- /** Tear down the bridge cleanly. Idempotent — repeat calls are no-ops. */
26
- close(): Promise<void>;
27
- }
28
-
29
- /** Per-call node-cache config block. Mirrors Python's CFG.node_cache. */
30
- interface NodeCacheCfg {
31
- /** Master enable flag. Defaults to true when the cfg block exists
32
- * in opts; explicitly set false to short-circuit reads + writes. */
33
- enabled?: boolean;
34
- /** Directory to store cache entries. Relative paths are resolved
35
- * against `repoRoot` when supplied; otherwise the CWD. */
36
- dir?: string;
37
- /** Stale-by-mtime threshold (seconds). 0 disables TTL eviction. */
38
- ttl_seconds?: number;
39
- /** Hard cap on the number of JSON entries on disk. 0 disables. */
40
- max_entries?: number;
41
- /** Hard cap on cumulative file size (bytes). 0 disables. */
42
- max_cache_bytes?: number;
43
- }
44
-
45
- interface WorkerToolsCfg {
46
- cost_cap_usd?: unknown;
47
- cost_cap_mode?: unknown;
4
+ interface PricingDoc {
5
+ /** `<provider>` -> `<model>` -> ModelRates. */
6
+ [provider: string]: unknown;
48
7
  }
49
8
 
50
9
  /** sessions row. */
@@ -363,19 +322,6 @@ interface Storage extends StorageRead, StorageWrite {
363
322
  close(): Promise<void>;
364
323
  }
365
324
 
366
- interface BreakerCfg {
367
- max_session_cost_usd?: number;
368
- max_session_tokens?: number;
369
- max_session_wall_seconds?: number;
370
- max_dag_nodes?: number;
371
- max_dag_depth?: number;
372
- }
373
-
374
- interface PricingDoc {
375
- /** `<provider>` -> `<model>` -> ModelRates. */
376
- [provider: string]: unknown;
377
- }
378
-
379
325
  /** One provider call's token + cost record. Mirrors `Usage.to_dict()`
380
326
  * output exactly. */
381
327
  interface Usage {
@@ -451,6 +397,60 @@ interface Provider {
451
397
  send(args: SendArgs): Promise<SendResult>;
452
398
  }
453
399
 
400
+ /** A live bridge to a Python crosscheck-agent child. */
401
+ interface BridgeHandle {
402
+ /** Names of the tools exposed by the Python child (from its
403
+ * `tools/list` response). */
404
+ readonly toolNames: ReadonlySet<string>;
405
+ /** PID of the spawned Python child process, or `null` if the
406
+ * transport hasn't started yet / has already closed. Useful for
407
+ * shutdown verification and host-side diagnostics. */
408
+ readonly pid: number | null;
409
+ /** Forward a `tools/call` to the Python child and return the result
410
+ * envelope verbatim. */
411
+ callTool(name: string, args: Record<string, unknown>): Promise<{
412
+ content: {
413
+ type: string;
414
+ text: string;
415
+ }[];
416
+ isError?: boolean;
417
+ }>;
418
+ /** Re-fetch the tool list (in case the child surfaces new tools mid-
419
+ * session). Returns the new tool names. */
420
+ refreshTools(): Promise<ReadonlySet<string>>;
421
+ /** Tear down the bridge cleanly. Idempotent — repeat calls are no-ops. */
422
+ close(): Promise<void>;
423
+ }
424
+
425
+ /** Per-call node-cache config block. Mirrors Python's CFG.node_cache. */
426
+ interface NodeCacheCfg {
427
+ /** Master enable flag. Defaults to true when the cfg block exists
428
+ * in opts; explicitly set false to short-circuit reads + writes. */
429
+ enabled?: boolean;
430
+ /** Directory to store cache entries. Relative paths are resolved
431
+ * against `repoRoot` when supplied; otherwise the CWD. */
432
+ dir?: string;
433
+ /** Stale-by-mtime threshold (seconds). 0 disables TTL eviction. */
434
+ ttl_seconds?: number;
435
+ /** Hard cap on the number of JSON entries on disk. 0 disables. */
436
+ max_entries?: number;
437
+ /** Hard cap on cumulative file size (bytes). 0 disables. */
438
+ max_cache_bytes?: number;
439
+ }
440
+
441
+ interface WorkerToolsCfg {
442
+ cost_cap_usd?: unknown;
443
+ cost_cap_mode?: unknown;
444
+ }
445
+
446
+ interface BreakerCfg {
447
+ max_session_cost_usd?: number;
448
+ max_session_tokens?: number;
449
+ max_session_wall_seconds?: number;
450
+ max_dag_nodes?: number;
451
+ max_dag_depth?: number;
452
+ }
453
+
454
454
  interface ConfigPinningConfig {
455
455
  /** Pin file location. Repo-relative or absolute. */
456
456
  pin_file?: string;
@@ -1062,7 +1062,12 @@ function loadPricing(path16) {
1062
1062
  function modelPricing(pricing, provider, model) {
1063
1063
  const block = pricing[provider];
1064
1064
  if (!block || typeof block !== "object" || Array.isArray(block)) return null;
1065
- const entry = block[model];
1065
+ const table = block;
1066
+ let entry = table[model];
1067
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
1068
+ const best = Object.keys(table).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
1069
+ entry = best !== void 0 ? table[best] : void 0;
1070
+ }
1066
1071
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
1067
1072
  const e = entry;
1068
1073
  return {
@@ -1490,6 +1495,14 @@ async function acquireRateLimit(provider, deps) {
1490
1495
  // src/providers/anthropic.ts
1491
1496
  var ANTHROPIC_API_URL = "https://api.anthropic.com/v1/messages";
1492
1497
  var ANTHROPIC_VERSION_HEADER = "2023-06-01";
1498
+ var ADAPTIVE_THINKING_PREFIXES = [
1499
+ "claude-fable-5",
1500
+ "claude-opus-5-5"
1501
+ ];
1502
+ function rejectsDisabledThinking(model) {
1503
+ const m = model.toLowerCase();
1504
+ return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
1505
+ }
1493
1506
  var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
1494
1507
  function applyPromptCaching(body, env = process.env) {
1495
1508
  const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
@@ -1534,7 +1547,7 @@ function buildAnthropicRequest(opts) {
1534
1547
  }
1535
1548
  applyPromptCaching(body);
1536
1549
  if (isReasoningModel("anthropic", opts.model)) {
1537
- if (opts.model.toLowerCase().startsWith("claude-fable-5")) {
1550
+ if (rejectsDisabledThinking(opts.model)) {
1538
1551
  body.thinking = { type: "adaptive" };
1539
1552
  body.output_config = { effort: "low" };
1540
1553
  } else {
@@ -2056,7 +2069,7 @@ async function sendOpenAICompatible(args) {
2056
2069
 
2057
2070
  // src/providers/registry.ts
2058
2071
  var DEFAULT_MODELS = {
2059
- anthropic: "claude-opus-5",
2072
+ anthropic: "claude-opus-5-5",
2060
2073
  openai: "gpt-5.6-sol",
2061
2074
  xai: "grok-4-latest",
2062
2075
  mistral: "mistral-large-latest",
@@ -2073,7 +2086,12 @@ var DEFAULT_FALLBACKS = {
2073
2086
  // about.
2074
2087
  openai: ["gpt-5"],
2075
2088
  // 3.8 Flash is recent enough that some projects won't have it yet.
2076
- gemini: ["gemini-3.1-pro-preview"]
2089
+ gemini: ["gemini-3.1-pro-preview"],
2090
+ // Opus 5.5 is new enough that an account could still be waiting on it.
2091
+ // Opus 5 is the same family one step back — and this chain is consulted
2092
+ // ONLY for a model-access failure, never for a bad key or a rate limit,
2093
+ // so it can't quietly downgrade anyone who simply hit a 429.
2094
+ anthropic: ["claude-opus-5"]
2077
2095
  };
2078
2096
  var MODEL_ENV_VARS = {
2079
2097
  anthropic: "ANTHROPIC_MODEL",
@@ -2342,7 +2360,7 @@ import { z } from "zod";
2342
2360
  // src/server-meta.ts
2343
2361
  init_esm_shims();
2344
2362
  var SERVER_NAME = "crosscheck-agent";
2345
- var SERVER_VERSION = true ? "0.2.24" : "0.0.0-dev";
2363
+ var SERVER_VERSION = true ? "0.2.26" : "0.0.0-dev";
2346
2364
 
2347
2365
  // src/tools/audit.ts
2348
2366
  init_esm_shims();
@@ -6125,11 +6143,20 @@ ${ctxBody}` });
6125
6143
  });
6126
6144
  };
6127
6145
  const onAnswer = opts.onAnswer;
6128
- const workerCall = onAnswer ? async (p) => {
6146
+ const onPanelistStart = opts.onPanelistStart;
6147
+ const workerCall = onAnswer || onPanelistStart ? async (p) => {
6148
+ if (onPanelistStart) {
6149
+ try {
6150
+ onPanelistStart(p.name, p.model);
6151
+ } catch {
6152
+ }
6153
+ }
6129
6154
  const answer = await dispatchOne(p);
6130
- try {
6131
- onAnswer(answer, p.name);
6132
- } catch {
6155
+ if (onAnswer) {
6156
+ try {
6157
+ onAnswer(answer, p.name);
6158
+ } catch {
6159
+ }
6133
6160
  }
6134
6161
  return answer;
6135
6162
  } : dispatchOne;
@@ -10458,6 +10485,12 @@ ${prior.body}` });
10458
10485
  content: `This is round ${rnd} of ${maxRounds}. Reply for this round.`
10459
10486
  });
10460
10487
  for (const p of selected) {
10488
+ if (opts.onPanelistStart) {
10489
+ try {
10490
+ opts.onPanelistStart(p.name, p.model, rnd);
10491
+ } catch {
10492
+ }
10493
+ }
10461
10494
  const entry = await callPanelist(p, roundMessages);
10462
10495
  const withRound = { ...entry, round: rnd };
10463
10496
  transcript.push(withRound);
@@ -12921,7 +12954,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12921
12954
  var DEFAULT_PACKAGE = "crosscheck-cli";
12922
12955
  var FETCH_TIMEOUT_MS = 3e3;
12923
12956
  function engineVersion() {
12924
- return true ? "0.2.24" : "0.0.0-dev";
12957
+ return true ? "0.2.26" : "0.0.0-dev";
12925
12958
  }
12926
12959
  function defaultUpdateCachePath() {
12927
12960
  const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");