crosscheck-mcp 0.1.9 → 0.1.10
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/node-stdio.cjs +209 -15
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.js +209 -15
- package/dist/node-stdio.js.map +1 -1
- package/package.json +1 -1
package/dist/node-stdio.cjs
CHANGED
|
@@ -7449,14 +7449,14 @@ function detectCycle(nodes) {
|
|
|
7449
7449
|
indeg[id] = (indeg[id] ?? 0) + 1;
|
|
7450
7450
|
}
|
|
7451
7451
|
}
|
|
7452
|
-
const
|
|
7452
|
+
const queue2 = Object.keys(indeg).filter((id) => indeg[id] === 0);
|
|
7453
7453
|
let processed = 0;
|
|
7454
|
-
while (
|
|
7455
|
-
const id =
|
|
7454
|
+
while (queue2.length > 0) {
|
|
7455
|
+
const id = queue2.shift();
|
|
7456
7456
|
processed++;
|
|
7457
7457
|
for (const next of consumers[id] ?? []) {
|
|
7458
7458
|
indeg[next] = (indeg[next] ?? 0) - 1;
|
|
7459
|
-
if (indeg[next] === 0)
|
|
7459
|
+
if (indeg[next] === 0) queue2.push(next);
|
|
7460
7460
|
}
|
|
7461
7461
|
}
|
|
7462
7462
|
return processed === Object.keys(byId).length ? null : "cycle detected (Kahn's algorithm didn't process all nodes)";
|
|
@@ -7495,13 +7495,13 @@ function topologicalSort(nodesById) {
|
|
|
7495
7495
|
}
|
|
7496
7496
|
}
|
|
7497
7497
|
const order = [];
|
|
7498
|
-
const
|
|
7499
|
-
while (
|
|
7500
|
-
const id =
|
|
7498
|
+
const queue2 = Object.keys(indeg).filter((id) => indeg[id] === 0);
|
|
7499
|
+
while (queue2.length > 0) {
|
|
7500
|
+
const id = queue2.shift();
|
|
7501
7501
|
order.push(id);
|
|
7502
7502
|
for (const next of consumers[id] ?? []) {
|
|
7503
7503
|
indeg[next] = (indeg[next] ?? 0) - 1;
|
|
7504
|
-
if (indeg[next] === 0)
|
|
7504
|
+
if (indeg[next] === 0) queue2.push(next);
|
|
7505
7505
|
}
|
|
7506
7506
|
}
|
|
7507
7507
|
return order;
|
|
@@ -11343,7 +11343,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
11343
11343
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
11344
11344
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
11345
11345
|
function engineVersion() {
|
|
11346
|
-
return true ? "0.1.
|
|
11346
|
+
return true ? "0.1.10" : "0.0.0-dev";
|
|
11347
11347
|
}
|
|
11348
11348
|
function defaultUpdateCachePath() {
|
|
11349
11349
|
const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");
|
|
@@ -12023,7 +12023,7 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
|
|
|
12023
12023
|
})
|
|
12024
12024
|
};
|
|
12025
12025
|
}
|
|
12026
|
-
function configPinTool(repoRoot,
|
|
12026
|
+
function configPinTool(repoRoot, config2, rejectDriftEnv) {
|
|
12027
12027
|
return {
|
|
12028
12028
|
name: "config_pin",
|
|
12029
12029
|
description: "CRUD over the config-pinning ledger. Tracks SHA256s of the canonical config files (config/pricing.json, etc.) and detects drift. Actions: show, set, accept_drift, clear. The actual drift-rejection gate is wired separately in the host.",
|
|
@@ -12048,7 +12048,7 @@ function configPinTool(repoRoot, config, rejectDriftEnv) {
|
|
|
12048
12048
|
}
|
|
12049
12049
|
return runConfigPin(args, {
|
|
12050
12050
|
repoRoot,
|
|
12051
|
-
...
|
|
12051
|
+
...config2 ? { config: config2 } : {},
|
|
12052
12052
|
rejectDriftEnv
|
|
12053
12053
|
});
|
|
12054
12054
|
}
|
|
@@ -12688,9 +12688,194 @@ function attachUpdateNotice(result, toolName, opts) {
|
|
|
12688
12688
|
}
|
|
12689
12689
|
}
|
|
12690
12690
|
|
|
12691
|
+
// src/core/telemetry.ts
|
|
12692
|
+
init_cjs_shims();
|
|
12693
|
+
var import_node_crypto7 = __toESM(require("crypto"), 1);
|
|
12694
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12695
|
+
var BATCH_MAX = 100;
|
|
12696
|
+
var FLUSH_BATCH_AT = 25;
|
|
12697
|
+
var FLUSH_INTERVAL_MS = 15e3;
|
|
12698
|
+
var MAX_QUEUE = 500;
|
|
12699
|
+
var POST_TIMEOUT_MS = 5e3;
|
|
12700
|
+
var PROVIDER_TO_SCHEMA = {
|
|
12701
|
+
anthropic: "anthropic",
|
|
12702
|
+
openai: "openai",
|
|
12703
|
+
gemini: "gemini",
|
|
12704
|
+
xai: "grok",
|
|
12705
|
+
grok: "grok"
|
|
12706
|
+
};
|
|
12707
|
+
var TOOL_TO_PATTERN = {
|
|
12708
|
+
confer: "confer",
|
|
12709
|
+
debate: "debate",
|
|
12710
|
+
audit: "audit",
|
|
12711
|
+
plan: "plan",
|
|
12712
|
+
pick: "panel_pick",
|
|
12713
|
+
verify: "verify",
|
|
12714
|
+
critique: "critique",
|
|
12715
|
+
solve: "solve"
|
|
12716
|
+
};
|
|
12717
|
+
function providerToSchema(provider) {
|
|
12718
|
+
return PROVIDER_TO_SCHEMA[String(provider).toLowerCase()] ?? null;
|
|
12719
|
+
}
|
|
12720
|
+
function toolToPattern(toolName) {
|
|
12721
|
+
return TOOL_TO_PATTERN[String(toolName).toLowerCase()] ?? "other";
|
|
12722
|
+
}
|
|
12723
|
+
function canonicalEventBody(e) {
|
|
12724
|
+
return [
|
|
12725
|
+
e.eventId,
|
|
12726
|
+
e.seatId,
|
|
12727
|
+
e.orgId,
|
|
12728
|
+
e.ts,
|
|
12729
|
+
e.provider,
|
|
12730
|
+
e.model,
|
|
12731
|
+
e.pattern,
|
|
12732
|
+
String(e.promptTokens),
|
|
12733
|
+
String(e.completionTokens),
|
|
12734
|
+
e.costUsdEstimate.toFixed(6),
|
|
12735
|
+
String(e.latencyMs),
|
|
12736
|
+
e.status,
|
|
12737
|
+
e.errorClass ?? ""
|
|
12738
|
+
].join("|");
|
|
12739
|
+
}
|
|
12740
|
+
function signEvent(seatSigningKey, e) {
|
|
12741
|
+
return import_node_crypto7.default.createHmac("sha256", seatSigningKey).update(canonicalEventBody(e)).digest("hex");
|
|
12742
|
+
}
|
|
12743
|
+
var configResolved = false;
|
|
12744
|
+
var config = null;
|
|
12745
|
+
function getConfig() {
|
|
12746
|
+
if (configResolved) return config;
|
|
12747
|
+
configResolved = true;
|
|
12748
|
+
if (process.env["CROSSCHECK_TELEMETRY"] === "off") return config = null;
|
|
12749
|
+
const url = process.env["CROSSCHECK_TELEMETRY_URL"];
|
|
12750
|
+
const seatId = process.env["CROSSCHECK_SEAT_ID"];
|
|
12751
|
+
const orgId = process.env["CROSSCHECK_ORG_ID"];
|
|
12752
|
+
const seatKey = process.env["CROSSCHECK_SEAT_HMAC_KEY"];
|
|
12753
|
+
if (!url || !seatId || !orgId || !seatKey) return config = null;
|
|
12754
|
+
if (!UUID_RE.test(seatId) || !UUID_RE.test(orgId)) return config = null;
|
|
12755
|
+
config = { url, seatId, orgId, seatKey };
|
|
12756
|
+
return config;
|
|
12757
|
+
}
|
|
12758
|
+
function intNonNeg(v) {
|
|
12759
|
+
const n = Math.trunc(Number(v));
|
|
12760
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
12761
|
+
}
|
|
12762
|
+
function usageEventsFromEnvelope(out, toolName) {
|
|
12763
|
+
if (!out || typeof out !== "object" || Array.isArray(out)) return [];
|
|
12764
|
+
const usage = out["usage"];
|
|
12765
|
+
if (!usage || typeof usage !== "object") return [];
|
|
12766
|
+
const byCall = usage["by_call"];
|
|
12767
|
+
if (!Array.isArray(byCall) || byCall.length === 0) return [];
|
|
12768
|
+
const timing = out["timing"];
|
|
12769
|
+
const timingByCall = timing && typeof timing === "object" ? timing["by_call"] : void 0;
|
|
12770
|
+
const latencies = Array.isArray(timingByCall) ? timingByCall : [];
|
|
12771
|
+
const aligned = latencies.length === byCall.length;
|
|
12772
|
+
const pattern = toolToPattern(toolName);
|
|
12773
|
+
const events = [];
|
|
12774
|
+
for (let i = 0; i < byCall.length; i += 1) {
|
|
12775
|
+
const u = byCall[i];
|
|
12776
|
+
const provider = providerToSchema(String(u.provider ?? ""));
|
|
12777
|
+
if (!provider) continue;
|
|
12778
|
+
const model = String(u.model ?? "").slice(0, 128) || "unknown";
|
|
12779
|
+
const cost = Math.max(0, Number(u.cost_usd) || 0);
|
|
12780
|
+
const latencyMs = aligned ? intNonNeg(latencies[i]?.["wall_ms"]) : 0;
|
|
12781
|
+
events.push({
|
|
12782
|
+
provider,
|
|
12783
|
+
model,
|
|
12784
|
+
pattern,
|
|
12785
|
+
promptTokens: intNonNeg(u.prompt_tokens),
|
|
12786
|
+
completionTokens: intNonNeg(u.completion_tokens),
|
|
12787
|
+
costUsdEstimate: cost,
|
|
12788
|
+
latencyMs,
|
|
12789
|
+
status: "ok"
|
|
12790
|
+
});
|
|
12791
|
+
}
|
|
12792
|
+
return events;
|
|
12793
|
+
}
|
|
12794
|
+
var queue = [];
|
|
12795
|
+
var flushTimer = null;
|
|
12796
|
+
function scheduleFlush() {
|
|
12797
|
+
if (flushTimer) return;
|
|
12798
|
+
flushTimer = setTimeout(() => {
|
|
12799
|
+
flushTimer = null;
|
|
12800
|
+
void flush();
|
|
12801
|
+
}, FLUSH_INTERVAL_MS);
|
|
12802
|
+
if (typeof flushTimer.unref === "function") flushTimer.unref();
|
|
12803
|
+
}
|
|
12804
|
+
function enqueue(cfg, input) {
|
|
12805
|
+
const base = {
|
|
12806
|
+
eventId: import_node_crypto7.default.randomUUID(),
|
|
12807
|
+
seatId: cfg.seatId,
|
|
12808
|
+
orgId: cfg.orgId,
|
|
12809
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12810
|
+
provider: input.provider,
|
|
12811
|
+
model: input.model,
|
|
12812
|
+
pattern: input.pattern,
|
|
12813
|
+
promptTokens: input.promptTokens,
|
|
12814
|
+
completionTokens: input.completionTokens,
|
|
12815
|
+
costUsdEstimate: input.costUsdEstimate,
|
|
12816
|
+
latencyMs: input.latencyMs,
|
|
12817
|
+
status: input.status
|
|
12818
|
+
};
|
|
12819
|
+
const signatureHmac = signEvent(cfg.seatKey, base);
|
|
12820
|
+
queue.push({ ...base, signatureHmac });
|
|
12821
|
+
if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
|
|
12822
|
+
if (queue.length >= FLUSH_BATCH_AT) void flush();
|
|
12823
|
+
else scheduleFlush();
|
|
12824
|
+
}
|
|
12825
|
+
function recordUsage(out, toolName) {
|
|
12826
|
+
try {
|
|
12827
|
+
const cfg = getConfig();
|
|
12828
|
+
if (!cfg) return;
|
|
12829
|
+
if (toolName === "update_crosscheck") return;
|
|
12830
|
+
for (const ev of usageEventsFromEnvelope(out, toolName)) enqueue(cfg, ev);
|
|
12831
|
+
} catch {
|
|
12832
|
+
}
|
|
12833
|
+
}
|
|
12834
|
+
async function postBatch(url, batch) {
|
|
12835
|
+
let resp;
|
|
12836
|
+
try {
|
|
12837
|
+
resp = await fetch(url, {
|
|
12838
|
+
method: "POST",
|
|
12839
|
+
headers: { "content-type": "application/json" },
|
|
12840
|
+
body: JSON.stringify({ events: batch }),
|
|
12841
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS)
|
|
12842
|
+
});
|
|
12843
|
+
} catch {
|
|
12844
|
+
queue.unshift(...batch);
|
|
12845
|
+
if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
|
|
12846
|
+
return;
|
|
12847
|
+
}
|
|
12848
|
+
if (resp.ok) return;
|
|
12849
|
+
if (resp.status === 400) {
|
|
12850
|
+
try {
|
|
12851
|
+
process.stderr.write(
|
|
12852
|
+
`crosscheck-agent: telemetry batch rejected (400), dropped ${batch.length} event(s)
|
|
12853
|
+
`
|
|
12854
|
+
);
|
|
12855
|
+
} catch {
|
|
12856
|
+
}
|
|
12857
|
+
return;
|
|
12858
|
+
}
|
|
12859
|
+
queue.unshift(...batch);
|
|
12860
|
+
if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
|
|
12861
|
+
}
|
|
12862
|
+
async function flush() {
|
|
12863
|
+
const cfg = getConfig();
|
|
12864
|
+
if (!cfg) return;
|
|
12865
|
+
if (flushTimer) {
|
|
12866
|
+
clearTimeout(flushTimer);
|
|
12867
|
+
flushTimer = null;
|
|
12868
|
+
}
|
|
12869
|
+
while (queue.length > 0) {
|
|
12870
|
+
const batch = queue.splice(0, BATCH_MAX);
|
|
12871
|
+
await postBatch(cfg.url, batch);
|
|
12872
|
+
if (queue.length > 0 && queue[0] === batch[0]) break;
|
|
12873
|
+
}
|
|
12874
|
+
}
|
|
12875
|
+
|
|
12691
12876
|
// src/server.ts
|
|
12692
12877
|
var SERVER_NAME = "crosscheck-agent";
|
|
12693
|
-
var SERVER_VERSION = true ? "0.1.
|
|
12878
|
+
var SERVER_VERSION = true ? "0.1.10" : "0.0.0-dev";
|
|
12694
12879
|
function extractRunSummaryText(out) {
|
|
12695
12880
|
if (out === null || typeof out !== "object" || Array.isArray(out)) return void 0;
|
|
12696
12881
|
const rs = out["run_summary"];
|
|
@@ -12772,10 +12957,9 @@ function createServer(opts = {}) {
|
|
|
12772
12957
|
() => tool.handler(args)
|
|
12773
12958
|
);
|
|
12774
12959
|
if (out && typeof out === "object" && !Array.isArray(out)) {
|
|
12775
|
-
attachUpdateNotice(out, name
|
|
12776
|
-
...opts.repoRoot ? { repoRoot: opts.repoRoot } : {}
|
|
12777
|
-
});
|
|
12960
|
+
attachUpdateNotice(out, name);
|
|
12778
12961
|
}
|
|
12962
|
+
recordUsage(out, name);
|
|
12779
12963
|
const durationMs = Number(
|
|
12780
12964
|
(process.hrtime.bigint() - startedHr) / 1000000n
|
|
12781
12965
|
);
|
|
@@ -12822,6 +13006,11 @@ function createServer(opts = {}) {
|
|
|
12822
13006
|
async function connectAndServe(transport, opts = {}) {
|
|
12823
13007
|
const server = createServer(opts);
|
|
12824
13008
|
await server.connect(transport);
|
|
13009
|
+
const cliVersion = process.env["CROSSCHECK_CLI_VERSION"];
|
|
13010
|
+
void maybeCheckForUpdate({
|
|
13011
|
+
currentVersion: cliVersion ?? SERVER_VERSION,
|
|
13012
|
+
packageName: cliVersion ? "crosscheck-cli" : "crosscheck-mcp"
|
|
13013
|
+
});
|
|
12825
13014
|
return server;
|
|
12826
13015
|
}
|
|
12827
13016
|
function buildToolRegistry(opts) {
|
|
@@ -12937,6 +13126,11 @@ function installShutdownHandlers(bridge) {
|
|
|
12937
13126
|
]).catch(() => {
|
|
12938
13127
|
});
|
|
12939
13128
|
}
|
|
13129
|
+
await Promise.race([
|
|
13130
|
+
flush(),
|
|
13131
|
+
new Promise((resolve2) => setTimeout(resolve2, SHUTDOWN_TIMEOUT_MS))
|
|
13132
|
+
]).catch(() => {
|
|
13133
|
+
});
|
|
12940
13134
|
process.stderr.write(`crosscheck-agent: shutdown (${reason})
|
|
12941
13135
|
`);
|
|
12942
13136
|
process.exit(0);
|