crosscheck-mcp 0.1.8 → 0.1.9

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.
@@ -942,8 +942,8 @@ __export(node_stdio_exports, {
942
942
  });
943
943
  module.exports = __toCommonJS(node_stdio_exports);
944
944
  init_cjs_shims();
945
- var import_node_fs14 = require("fs");
946
- var import_node_path14 = __toESM(require("path"), 1);
945
+ var import_node_fs15 = require("fs");
946
+ var import_node_path15 = __toESM(require("path"), 1);
947
947
  var import_node_url2 = require("url");
948
948
  var import_stdio2 = require("@modelcontextprotocol/sdk/server/stdio.js");
949
949
 
@@ -1104,10 +1104,10 @@ var StderrEmitter = class {
1104
1104
  }
1105
1105
  };
1106
1106
  var FileEmitter = class {
1107
- constructor(path11) {
1108
- this.path = path11;
1107
+ constructor(path12) {
1108
+ this.path = path12;
1109
1109
  try {
1110
- (0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(path11), { recursive: true });
1110
+ (0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(path12), { recursive: true });
1111
1111
  } catch {
1112
1112
  }
1113
1113
  }
@@ -1140,13 +1140,13 @@ var NullEmitter = class {
1140
1140
  function buildDefaultEmitter(env) {
1141
1141
  const mode = (env["CROSSCHECK_EVENTS"] ?? "stderr").toLowerCase();
1142
1142
  if (mode === "off") return new NullEmitter();
1143
- const path11 = env["CROSSCHECK_EVENTS_PATH"];
1143
+ const path12 = env["CROSSCHECK_EVENTS_PATH"];
1144
1144
  if (mode === "file") {
1145
- return path11 ? new FileEmitter(path11) : new NullEmitter();
1145
+ return path12 ? new FileEmitter(path12) : new NullEmitter();
1146
1146
  }
1147
1147
  if (mode === "both") {
1148
1148
  const ems = [new StderrEmitter()];
1149
- if (path11) ems.push(new FileEmitter(path11));
1149
+ if (path12) ems.push(new FileEmitter(path12));
1150
1150
  return new TeeEmitter(ems);
1151
1151
  }
1152
1152
  return new StderrEmitter();
@@ -1195,10 +1195,10 @@ function envelopeBytes(v) {
1195
1195
  // src/core/pricing.ts
1196
1196
  init_cjs_shims();
1197
1197
  var import_node_fs2 = require("fs");
1198
- function loadPricing(path11) {
1198
+ function loadPricing(path12) {
1199
1199
  let raw;
1200
1200
  try {
1201
- raw = (0, import_node_fs2.readFileSync)(path11, "utf8");
1201
+ raw = (0, import_node_fs2.readFileSync)(path12, "utf8");
1202
1202
  } catch {
1203
1203
  return {};
1204
1204
  }
@@ -2070,27 +2070,27 @@ function extractJson(text) {
2070
2070
 
2071
2071
  // src/core/json-schema.ts
2072
2072
  init_cjs_shims();
2073
- function validateSchema(value, schema, path11 = "") {
2073
+ function validateSchema(value, schema, path12 = "") {
2074
2074
  const errs = [];
2075
2075
  if ("anyOf" in schema) {
2076
2076
  const subs = schema["anyOf"].map(
2077
- (s) => validateSchema(value, s, path11)
2077
+ (s) => validateSchema(value, s, path12)
2078
2078
  );
2079
2079
  if (!subs.some((e) => e.length === 0)) {
2080
- errs.push(`${path11 || "<root>"}: did not match anyOf`);
2080
+ errs.push(`${path12 || "<root>"}: did not match anyOf`);
2081
2081
  }
2082
2082
  return errs;
2083
2083
  }
2084
2084
  if ("oneOf" in schema) {
2085
- const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path11).length === 0).length;
2085
+ const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path12).length === 0).length;
2086
2086
  if (passed !== 1) {
2087
- errs.push(`${path11 || "<root>"}: matched ${passed} of oneOf, expected 1`);
2087
+ errs.push(`${path12 || "<root>"}: matched ${passed} of oneOf, expected 1`);
2088
2088
  }
2089
2089
  return errs;
2090
2090
  }
2091
2091
  if ("const" in schema && !deepEqual(value, schema["const"])) {
2092
2092
  errs.push(
2093
- `${path11 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
2093
+ `${path12 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
2094
2094
  );
2095
2095
  return errs;
2096
2096
  }
@@ -2100,7 +2100,7 @@ function validateSchema(value, schema, path11 = "") {
2100
2100
  const ok = types.some((tt) => matchesType(value, String(tt)));
2101
2101
  if (!ok) {
2102
2102
  errs.push(
2103
- `${path11 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
2103
+ `${path12 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
2104
2104
  );
2105
2105
  return errs;
2106
2106
  }
@@ -2109,29 +2109,29 @@ function validateSchema(value, schema, path11 = "") {
2109
2109
  if ("enum" in schema) {
2110
2110
  const en = schema["enum"];
2111
2111
  if (!en.some((x) => deepEqual(x, value))) {
2112
- errs.push(`${path11 || "<root>"}: value ${pyRepr(value)} not in enum`);
2112
+ errs.push(`${path12 || "<root>"}: value ${pyRepr(value)} not in enum`);
2113
2113
  }
2114
2114
  }
2115
2115
  if ("minLength" in schema && value.length < schema["minLength"]) {
2116
- errs.push(`${path11 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
2116
+ errs.push(`${path12 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
2117
2117
  }
2118
2118
  }
2119
2119
  if (typeof value === "number" && !Number.isNaN(value)) {
2120
2120
  if ("minimum" in schema && value < schema["minimum"]) {
2121
- errs.push(`${path11 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
2121
+ errs.push(`${path12 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
2122
2122
  }
2123
2123
  if ("maximum" in schema && value > schema["maximum"]) {
2124
- errs.push(`${path11 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
2124
+ errs.push(`${path12 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
2125
2125
  }
2126
2126
  }
2127
2127
  if (Array.isArray(value)) {
2128
2128
  if ("minItems" in schema && value.length < schema["minItems"]) {
2129
- errs.push(`${path11 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
2129
+ errs.push(`${path12 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
2130
2130
  }
2131
2131
  const itemSchema = schema["items"];
2132
2132
  if (isObj(itemSchema)) {
2133
2133
  for (let i = 0; i < value.length; i++) {
2134
- errs.push(...validateSchema(value[i], itemSchema, `${path11}[${i}]`));
2134
+ errs.push(...validateSchema(value[i], itemSchema, `${path12}[${i}]`));
2135
2135
  }
2136
2136
  }
2137
2137
  }
@@ -2140,19 +2140,19 @@ function validateSchema(value, schema, path11 = "") {
2140
2140
  const required = schema["required"] ?? [];
2141
2141
  for (const r of required) {
2142
2142
  if (!(r in value)) {
2143
- errs.push(`${path11 || "<root>"}: missing required key ${pyRepr(r)}`);
2143
+ errs.push(`${path12 || "<root>"}: missing required key ${pyRepr(r)}`);
2144
2144
  }
2145
2145
  }
2146
2146
  if (schema["additionalProperties"] === false) {
2147
2147
  for (const k of Object.keys(value)) {
2148
2148
  if (!(k in props)) {
2149
- errs.push(`${path11 || "<root>"}: unknown key ${pyRepr(k)}`);
2149
+ errs.push(`${path12 || "<root>"}: unknown key ${pyRepr(k)}`);
2150
2150
  }
2151
2151
  }
2152
2152
  }
2153
2153
  for (const [k, v] of Object.entries(value)) {
2154
2154
  const ps = props[k];
2155
- if (ps) errs.push(...validateSchema(v, ps, path11 ? `${path11}.${k}` : k));
2155
+ if (ps) errs.push(...validateSchema(v, ps, path12 ? `${path12}.${k}` : k));
2156
2156
  }
2157
2157
  }
2158
2158
  return errs;
@@ -6615,11 +6615,11 @@ function getNodeCache(cfg, repoRoot, key, nowMs) {
6615
6615
  return null;
6616
6616
  }
6617
6617
  }
6618
- function atomicWriteJson(path11, payload) {
6619
- (0, import_node_fs7.mkdirSync)((0, import_node_path8.dirname)(path11), { recursive: true });
6620
- const tmp = `${path11}.${process.pid}.${Date.now()}.tmp`;
6618
+ function atomicWriteJson(path12, payload) {
6619
+ (0, import_node_fs7.mkdirSync)((0, import_node_path8.dirname)(path12), { recursive: true });
6620
+ const tmp = `${path12}.${process.pid}.${Date.now()}.tmp`;
6621
6621
  (0, import_node_fs7.writeFileSync)(tmp, JSON.stringify(payload), "utf8");
6622
- (0, import_node_fs7.renameSync)(tmp, path11);
6622
+ (0, import_node_fs7.renameSync)(tmp, path12);
6623
6623
  }
6624
6624
  function putNodeCache(cfg, repoRoot, key, value) {
6625
6625
  if (!cfg || cfg.enabled === false) return;
@@ -11330,8 +11330,110 @@ function pyRepr7(v) {
11330
11330
  // src/tools/update-crosscheck.ts
11331
11331
  init_cjs_shims();
11332
11332
  var import_node_child_process2 = require("child_process");
11333
+ var import_node_fs13 = require("fs");
11334
+ var import_node_path13 = __toESM(require("path"), 1);
11335
+
11336
+ // src/core/update-notify.ts
11337
+ init_cjs_shims();
11333
11338
  var import_node_fs12 = require("fs");
11339
+ var import_node_os2 = __toESM(require("os"), 1);
11334
11340
  var import_node_path12 = __toESM(require("path"), 1);
11341
+ var NPM_REGISTRY = "https://registry.npmjs.org";
11342
+ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11343
+ var DEFAULT_PACKAGE = "crosscheck-cli";
11344
+ var FETCH_TIMEOUT_MS = 3e3;
11345
+ function engineVersion() {
11346
+ return true ? "0.1.9" : "0.0.0-dev";
11347
+ }
11348
+ function defaultUpdateCachePath() {
11349
+ const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");
11350
+ return import_node_path12.default.join(base, "update_check.json");
11351
+ }
11352
+ function isNewer(latest, current) {
11353
+ const a = parseTriple(latest);
11354
+ const b = parseTriple(current);
11355
+ for (let i = 0; i < 3; i += 1) {
11356
+ if (a[i] !== b[i]) return a[i] > b[i];
11357
+ }
11358
+ return false;
11359
+ }
11360
+ function parseTriple(v) {
11361
+ const parts = (v.split("-")[0] ?? "").split(".").map((n) => Number.parseInt(n, 10) || 0);
11362
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
11363
+ }
11364
+ function buildNotice(pkg, current, latest) {
11365
+ return {
11366
+ update_available: true,
11367
+ package: pkg,
11368
+ current_version: current,
11369
+ latest_version: latest,
11370
+ message: `crosscheck ${latest} is available \u2014 you're on ${current}. To upgrade, run:
11371
+
11372
+ npm install -g crosscheck-cli@latest
11373
+
11374
+ then reconnect the crosscheck MCP server (run \`/mcp\` in Claude Code, or restart your session) so the new version loads. Ask the user whether they'd like to upgrade now before doing anything else.`,
11375
+ ask_user: true
11376
+ };
11377
+ }
11378
+ function readCache(cachePath2) {
11379
+ try {
11380
+ if (!(0, import_node_fs12.existsSync)(cachePath2)) return null;
11381
+ const data = JSON.parse((0, import_node_fs12.readFileSync)(cachePath2, "utf8"));
11382
+ if (data && typeof data === "object" && !Array.isArray(data)) {
11383
+ return data;
11384
+ }
11385
+ return null;
11386
+ } catch {
11387
+ return null;
11388
+ }
11389
+ }
11390
+ function writeCache(cachePath2, record2) {
11391
+ try {
11392
+ (0, import_node_fs12.mkdirSync)(import_node_path12.default.dirname(cachePath2), { recursive: true });
11393
+ (0, import_node_fs12.writeFileSync)(cachePath2, JSON.stringify(record2, null, 2), "utf8");
11394
+ } catch {
11395
+ }
11396
+ }
11397
+ async function fetchLatest(fetchFn, pkg) {
11398
+ try {
11399
+ const resp = await fetchFn(`${NPM_REGISTRY}/${pkg}/latest`, {
11400
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
11401
+ headers: { Accept: "application/json" }
11402
+ });
11403
+ if (!resp.ok) return null;
11404
+ const data = await resp.json();
11405
+ return typeof data?.version === "string" ? data.version : null;
11406
+ } catch {
11407
+ return null;
11408
+ }
11409
+ }
11410
+ async function maybeCheckForUpdate(opts) {
11411
+ const now = opts.nowEpochSeconds ? opts.nowEpochSeconds() : Math.floor(Date.now() / 1e3);
11412
+ const pkg = opts.packageName ?? DEFAULT_PACKAGE;
11413
+ const cachePath2 = opts.cachePath ?? defaultUpdateCachePath();
11414
+ const minInterval = opts.minIntervalSeconds ?? CHECK_INTERVAL_SECONDS;
11415
+ const fetchFn = opts.httpFetch ?? globalThis.fetch;
11416
+ const cached = readCache(cachePath2);
11417
+ const fresh = cached !== null && typeof cached.checked_at === "number" && now - cached.checked_at < minInterval && cached.current_version === opts.currentVersion && cached.package === pkg;
11418
+ if (fresh) return cached;
11419
+ const latest = await fetchLatest(fetchFn, pkg);
11420
+ if (latest === null) {
11421
+ return cached;
11422
+ }
11423
+ const updateAvailable = isNewer(latest, opts.currentVersion);
11424
+ const record2 = {
11425
+ checked_at: now,
11426
+ package: pkg,
11427
+ current_version: opts.currentVersion,
11428
+ latest_version: latest,
11429
+ update_available: updateAvailable,
11430
+ ...updateAvailable ? { notice: buildNotice(pkg, opts.currentVersion, latest) } : {}
11431
+ };
11432
+ writeCache(cachePath2, record2);
11433
+ return record2;
11434
+ }
11435
+
11436
+ // src/tools/update-crosscheck.ts
11335
11437
  var UPDATE_REMOTE_REPO = "fxspeiser/crosscheck-agent";
11336
11438
  var UPDATE_REMOTE_URL = `https://github.com/${UPDATE_REMOTE_REPO}`;
11337
11439
  var UPDATE_API_URL = `https://api.github.com/repos/${UPDATE_REMOTE_REPO}/commits/main`;
@@ -11341,7 +11443,7 @@ async function runUpdateCrosscheck(args, opts) {
11341
11443
  const gitRun = opts.gitRun ?? defaultGitRun(opts.repoRoot);
11342
11444
  const fetchFn = opts.httpFetch ?? globalThis.fetch;
11343
11445
  const now = opts.nowEpochSeconds ? opts.nowEpochSeconds() : Math.floor(Date.now() / 1e3);
11344
- const cachePath2 = opts.cachePath ?? import_node_path12.default.join(opts.repoRoot, ".crosscheck", "update_check.json");
11446
+ const cachePath2 = opts.cachePath ?? import_node_path13.default.join(opts.repoRoot, ".crosscheck", "update_check.json");
11345
11447
  const local = readLocalSha(gitRun);
11346
11448
  if (!local) {
11347
11449
  return {
@@ -11513,8 +11615,8 @@ function gitRelationship(gitRun, local, remote) {
11513
11615
  }
11514
11616
  function writeUpdateCache(p, payload) {
11515
11617
  try {
11516
- (0, import_node_fs12.mkdirSync)(import_node_path12.default.dirname(p), { recursive: true });
11517
- (0, import_node_fs12.writeFileSync)(p, JSON.stringify(payload, null, 2), "utf8");
11618
+ (0, import_node_fs13.mkdirSync)(import_node_path13.default.dirname(p), { recursive: true });
11619
+ (0, import_node_fs13.writeFileSync)(p, JSON.stringify(payload, null, 2), "utf8");
11518
11620
  } catch {
11519
11621
  }
11520
11622
  }
@@ -11530,6 +11632,43 @@ function buildUpdateNotice(local, remote, behindCount) {
11530
11632
  ask_user: true
11531
11633
  };
11532
11634
  }
11635
+ async function npmUpdateFallback(opts) {
11636
+ const cliVersion = process.env["CROSSCHECK_CLI_VERSION"];
11637
+ const currentVersion = cliVersion ?? engineVersion();
11638
+ const pkg = cliVersion ? "crosscheck-cli" : "crosscheck-mcp";
11639
+ const rec = await maybeCheckForUpdate({
11640
+ currentVersion,
11641
+ packageName: pkg,
11642
+ minIntervalSeconds: 0,
11643
+ // explicit invocation → always check fresh
11644
+ ...opts?.httpFetch ? { httpFetch: opts.httpFetch } : {},
11645
+ ...opts?.nowEpochSeconds ? { nowEpochSeconds: opts.nowEpochSeconds } : {},
11646
+ ...opts?.cachePath ? { cachePath: opts.cachePath } : {}
11647
+ });
11648
+ const base = {
11649
+ tool: "update_crosscheck",
11650
+ install_type: "npm",
11651
+ package: pkg,
11652
+ current_version: currentVersion
11653
+ };
11654
+ if (!rec || rec.latest_version === null) {
11655
+ return {
11656
+ ...base,
11657
+ status: "error",
11658
+ reason: "could not reach the npm registry to check for updates."
11659
+ };
11660
+ }
11661
+ if (rec.update_available) {
11662
+ return {
11663
+ ...base,
11664
+ status: "update_available",
11665
+ latest_version: rec.latest_version,
11666
+ install_command: "npm install -g crosscheck-cli@latest",
11667
+ next_step: "Run `npm install -g crosscheck-cli@latest`, then reconnect the crosscheck MCP server (run `/mcp` in Claude Code, or restart your session) so the new version loads. Ask the user before upgrading."
11668
+ };
11669
+ }
11670
+ return { ...base, status: "up_to_date", latest_version: rec.latest_version };
11671
+ }
11533
11672
  function withTimeout2(promise, ms) {
11534
11673
  return new Promise((resolve2, reject) => {
11535
11674
  const t = setTimeout(() => reject(new Error(`timeout after ${ms / 1e3}s`)), ms);
@@ -11945,7 +12084,7 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
11945
12084
  function updateCrosscheckTool(repoRoot) {
11946
12085
  return {
11947
12086
  name: "update_crosscheck",
11948
- description: "Compare local git HEAD to remote GitHub main HEAD and report the relationship (equal / ahead / behind / diverged / unknown). With apply=true, fast-forwards via git pull --ff-only when the local is strictly behind. Restart of the MCP connection is required after a successful update.",
12087
+ description: "Check whether a newer version of crosscheck is available and report how to upgrade. For npm installs (the default), compares the running version to the published `latest` on npm and returns the `npm install -g crosscheck-cli@latest` upgrade command. For a git checkout, compares local HEAD to remote GitHub main (equal / ahead / behind / diverged) and, with apply=true, fast-forwards via git pull --ff-only. A reconnect of the MCP server is required after upgrading.",
11949
12088
  inputSchema: {
11950
12089
  type: "object",
11951
12090
  additionalProperties: true,
@@ -11955,12 +12094,7 @@ function updateCrosscheckTool(repoRoot) {
11955
12094
  },
11956
12095
  handler: async (args) => {
11957
12096
  if (!repoRoot) {
11958
- return {
11959
- tool: "update_crosscheck",
11960
- status: "error",
11961
- reason: "could not determine repo root; the entrypoint did not supply a repoRoot. crosscheck-agent must be installed as a git checkout for in-place updates.",
11962
- remote_url: "https://github.com/fxspeiser/crosscheck-agent"
11963
- };
12097
+ return npmUpdateFallback();
11964
12098
  }
11965
12099
  return runUpdateCrosscheck(args, { repoRoot });
11966
12100
  }
@@ -12497,8 +12631,8 @@ function pingTool() {
12497
12631
 
12498
12632
  // src/core/wrappers.ts
12499
12633
  init_cjs_shims();
12500
- var import_node_fs13 = require("fs");
12501
- var import_node_path13 = __toESM(require("path"), 1);
12634
+ var import_node_fs14 = require("fs");
12635
+ var import_node_path14 = __toESM(require("path"), 1);
12502
12636
  function configPinGate(toolName, opts) {
12503
12637
  if (toolName === "config_pin") return null;
12504
12638
  if (!opts || !opts.repoRoot) return null;
@@ -12527,12 +12661,11 @@ function configPinGate(toolName, opts) {
12527
12661
  pin_file: drift.pin_file
12528
12662
  };
12529
12663
  }
12530
- var updateCheckedThisProcess = false;
12531
12664
  var cachedUpdateNotice = null;
12532
12665
  function readUpdateCache(cachePath2) {
12533
12666
  try {
12534
- if (!(0, import_node_fs13.existsSync)(cachePath2)) return null;
12535
- const data = JSON.parse((0, import_node_fs13.readFileSync)(cachePath2, "utf8"));
12667
+ if (!(0, import_node_fs14.existsSync)(cachePath2)) return null;
12668
+ const data = JSON.parse((0, import_node_fs14.readFileSync)(cachePath2, "utf8"));
12536
12669
  if (data && typeof data === "object" && !Array.isArray(data)) return data;
12537
12670
  return null;
12538
12671
  } catch {
@@ -12543,10 +12676,8 @@ function attachUpdateNotice(result, toolName, opts) {
12543
12676
  if (!result || typeof result !== "object" || Array.isArray(result)) return;
12544
12677
  if (toolName === "update_crosscheck") return;
12545
12678
  if ("update_notice" in result) return;
12546
- if (!opts || !opts.repoRoot) return;
12547
- if (!updateCheckedThisProcess) {
12548
- updateCheckedThisProcess = true;
12549
- const cachePath2 = opts.cachePath ?? import_node_path13.default.join(opts.repoRoot, ".crosscheck", "update_check.json");
12679
+ if (cachedUpdateNotice === null) {
12680
+ const cachePath2 = opts?.cachePath ?? (opts?.repoRoot ? import_node_path14.default.join(opts.repoRoot, ".crosscheck", "update_check.json") : defaultUpdateCachePath());
12550
12681
  const cached = readUpdateCache(cachePath2);
12551
12682
  if (cached && cached.update_available && cached.notice && typeof cached.notice === "object") {
12552
12683
  cachedUpdateNotice = cached.notice;
@@ -12559,7 +12690,16 @@ function attachUpdateNotice(result, toolName, opts) {
12559
12690
 
12560
12691
  // src/server.ts
12561
12692
  var SERVER_NAME = "crosscheck-agent";
12562
- var SERVER_VERSION = true ? "0.1.8" : "0.0.0-dev";
12693
+ var SERVER_VERSION = true ? "0.1.9" : "0.0.0-dev";
12694
+ function extractRunSummaryText(out) {
12695
+ if (out === null || typeof out !== "object" || Array.isArray(out)) return void 0;
12696
+ const rs = out["run_summary"];
12697
+ if (rs === null || typeof rs !== "object" || Array.isArray(rs)) return void 0;
12698
+ const text = rs["text"];
12699
+ if (typeof text !== "string") return void 0;
12700
+ const trimmed = text.trim();
12701
+ return trimmed === "" ? void 0 : text;
12702
+ }
12563
12703
  function createServer(opts = {}) {
12564
12704
  const server = new import_server2.Server(
12565
12705
  { name: SERVER_NAME, version: SERVER_VERSION },
@@ -12654,9 +12794,10 @@ function createServer(opts = {}) {
12654
12794
  };
12655
12795
  if (typeof errCode === "string") ev.error_code = errCode;
12656
12796
  emitEvent(ev);
12657
- return {
12658
- content: [{ type: "text", text: JSON.stringify(out, null, 2) }]
12659
- };
12797
+ const summary = extractRunSummaryText(out);
12798
+ const jsonBlock = { type: "text", text: JSON.stringify(out, null, 2) };
12799
+ const content = summary !== void 0 ? [{ type: "text", text: summary }, jsonBlock] : [jsonBlock];
12800
+ return { content };
12660
12801
  } catch (e) {
12661
12802
  const durationMs = Number(
12662
12803
  (process.hrtime.bigint() - startedHr) / 1000000n
@@ -12729,7 +12870,7 @@ async function main() {
12729
12870
  installShutdownHandlers(bridge);
12730
12871
  const bundledPricing = (() => {
12731
12872
  try {
12732
- return import_node_path14.default.join(import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
12873
+ return import_node_path15.default.join(import_node_path15.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl)), "pricing.json");
12733
12874
  } catch {
12734
12875
  return void 0;
12735
12876
  }
@@ -12738,7 +12879,7 @@ async function main() {
12738
12879
  process.env["CROSSCHECK_PRICING_PATH"],
12739
12880
  resolveRepoFile("config/pricing.json"),
12740
12881
  bundledPricing
12741
- ].find((p) => p && (0, import_node_fs14.existsSync)(p));
12882
+ ].find((p) => p && (0, import_node_fs15.existsSync)(p));
12742
12883
  const pricing = pricingPath ? loadPricing(pricingPath) : {};
12743
12884
  const providers = buildProviders({ env: process.env, pricing });
12744
12885
  if (Object.keys(providers).length > 0) {
@@ -12752,7 +12893,7 @@ async function main() {
12752
12893
  const dbPath = process.env["CROSSCHECK_DB_PATH"] ?? resolveRepoFile(".crosscheck/db.sqlite");
12753
12894
  if (dbPath) {
12754
12895
  try {
12755
- (0, import_node_fs14.mkdirSync)(import_node_path14.default.dirname(dbPath), { recursive: true });
12896
+ (0, import_node_fs15.mkdirSync)(import_node_path15.default.dirname(dbPath), { recursive: true });
12756
12897
  const { openBetterSqliteStorage: openBetterSqliteStorage2 } = await Promise.resolve().then(() => (init_better_sqlite3(), better_sqlite3_exports));
12757
12898
  storage = openBetterSqliteStorage2({ path: dbPath });
12758
12899
  await storage.migrate();
@@ -12816,9 +12957,9 @@ function installShutdownHandlers(bridge) {
12816
12957
  function resolveRepoFile(rel) {
12817
12958
  let dir = __dirname;
12818
12959
  for (let i = 0; i < 8; i++) {
12819
- const candidate = import_node_path14.default.join(dir, rel);
12820
- if ((0, import_node_fs14.existsSync)(candidate)) return candidate;
12821
- const parent = import_node_path14.default.dirname(dir);
12960
+ const candidate = import_node_path15.default.join(dir, rel);
12961
+ if ((0, import_node_fs15.existsSync)(candidate)) return candidate;
12962
+ const parent = import_node_path15.default.dirname(dir);
12822
12963
  if (parent === dir) break;
12823
12964
  dir = parent;
12824
12965
  }
@@ -12827,8 +12968,8 @@ function resolveRepoFile(rel) {
12827
12968
  function findGitRoot(startDir) {
12828
12969
  let dir = startDir;
12829
12970
  for (let i = 0; i < 12; i++) {
12830
- if ((0, import_node_fs14.existsSync)(import_node_path14.default.join(dir, ".git"))) return dir;
12831
- const parent = import_node_path14.default.dirname(dir);
12971
+ if ((0, import_node_fs15.existsSync)(import_node_path15.default.join(dir, ".git"))) return dir;
12972
+ const parent = import_node_path15.default.dirname(dir);
12832
12973
  if (parent === dir) break;
12833
12974
  dir = parent;
12834
12975
  }