crosscheck-mcp 0.2.15 → 0.2.16
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/browser-ext.cjs +2 -2
- package/dist/browser-ext.js +2 -2
- package/dist/node-stdio.cjs +425 -192
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.js +424 -191
- package/dist/node-stdio.js.map +1 -1
- package/package.json +1 -1
package/dist/node-stdio.js
CHANGED
|
@@ -934,8 +934,8 @@ var init_better_sqlite3 = __esm({
|
|
|
934
934
|
|
|
935
935
|
// src/entrypoints/node-stdio.ts
|
|
936
936
|
init_esm_shims();
|
|
937
|
-
import { existsSync as
|
|
938
|
-
import
|
|
937
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync10 } from "fs";
|
|
938
|
+
import path15 from "path";
|
|
939
939
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
940
940
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
941
941
|
|
|
@@ -952,10 +952,10 @@ var StderrEmitter = class {
|
|
|
952
952
|
}
|
|
953
953
|
};
|
|
954
954
|
var FileEmitter = class {
|
|
955
|
-
constructor(
|
|
956
|
-
this.path =
|
|
955
|
+
constructor(path16) {
|
|
956
|
+
this.path = path16;
|
|
957
957
|
try {
|
|
958
|
-
mkdirSync(dirname(
|
|
958
|
+
mkdirSync(dirname(path16), { recursive: true });
|
|
959
959
|
} catch {
|
|
960
960
|
}
|
|
961
961
|
}
|
|
@@ -988,13 +988,13 @@ var NullEmitter = class {
|
|
|
988
988
|
function buildDefaultEmitter(env) {
|
|
989
989
|
const mode = (env["CROSSCHECK_EVENTS"] ?? "stderr").toLowerCase();
|
|
990
990
|
if (mode === "off") return new NullEmitter();
|
|
991
|
-
const
|
|
991
|
+
const path16 = env["CROSSCHECK_EVENTS_PATH"];
|
|
992
992
|
if (mode === "file") {
|
|
993
|
-
return
|
|
993
|
+
return path16 ? new FileEmitter(path16) : new NullEmitter();
|
|
994
994
|
}
|
|
995
995
|
if (mode === "both") {
|
|
996
996
|
const ems = [new StderrEmitter()];
|
|
997
|
-
if (
|
|
997
|
+
if (path16) ems.push(new FileEmitter(path16));
|
|
998
998
|
return new TeeEmitter(ems);
|
|
999
999
|
}
|
|
1000
1000
|
return new StderrEmitter();
|
|
@@ -1043,10 +1043,10 @@ function envelopeBytes(v) {
|
|
|
1043
1043
|
// src/core/pricing.ts
|
|
1044
1044
|
init_esm_shims();
|
|
1045
1045
|
import { readFileSync } from "fs";
|
|
1046
|
-
function loadPricing(
|
|
1046
|
+
function loadPricing(path16) {
|
|
1047
1047
|
let raw;
|
|
1048
1048
|
try {
|
|
1049
|
-
raw = readFileSync(
|
|
1049
|
+
raw = readFileSync(path16, "utf8");
|
|
1050
1050
|
} catch {
|
|
1051
1051
|
return {};
|
|
1052
1052
|
}
|
|
@@ -1302,8 +1302,8 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
|
|
|
1302
1302
|
// src/providers/retry.ts
|
|
1303
1303
|
init_esm_shims();
|
|
1304
1304
|
var override = null;
|
|
1305
|
-
function setRetryConfig(
|
|
1306
|
-
override =
|
|
1305
|
+
function setRetryConfig(cfg2) {
|
|
1306
|
+
override = cfg2;
|
|
1307
1307
|
}
|
|
1308
1308
|
function resolveRetryConfig() {
|
|
1309
1309
|
const envInt = (k, d) => {
|
|
@@ -1365,21 +1365,21 @@ function defaultSleep(ms, signal) {
|
|
|
1365
1365
|
signal?.addEventListener?.("abort", onAbort);
|
|
1366
1366
|
});
|
|
1367
1367
|
}
|
|
1368
|
-
async function sendWithRetry(attemptOnce,
|
|
1368
|
+
async function sendWithRetry(attemptOnce, cfg2, signal, deps) {
|
|
1369
1369
|
const sleep = deps?.sleepImpl ?? ((ms) => defaultSleep(ms, signal));
|
|
1370
1370
|
const rand = deps?.random ?? Math.random;
|
|
1371
1371
|
let lastErr;
|
|
1372
|
-
for (let attempt = 1; attempt <=
|
|
1372
|
+
for (let attempt = 1; attempt <= cfg2.maxAttempts; attempt += 1) {
|
|
1373
1373
|
try {
|
|
1374
1374
|
const result = await attemptOnce();
|
|
1375
1375
|
return { ...result, attempts: attempt };
|
|
1376
1376
|
} catch (e) {
|
|
1377
1377
|
lastErr = e;
|
|
1378
1378
|
const pe = e instanceof ProviderError ? e : null;
|
|
1379
|
-
if (pe?.transient !== true || attempt >=
|
|
1380
|
-
let backoffMs = pe.retryAfterS !== void 0 ? pe.retryAfterS * 1e3 :
|
|
1381
|
-
backoffMs += rand() *
|
|
1382
|
-
backoffMs = Math.min(backoffMs,
|
|
1379
|
+
if (pe?.transient !== true || attempt >= cfg2.maxAttempts) throw e;
|
|
1380
|
+
let backoffMs = pe.retryAfterS !== void 0 ? pe.retryAfterS * 1e3 : cfg2.backoffBaseMs * 2 ** (attempt - 1);
|
|
1381
|
+
backoffMs += rand() * cfg2.backoffBaseMs;
|
|
1382
|
+
backoffMs = Math.min(backoffMs, cfg2.maxBackoffMs);
|
|
1383
1383
|
await sleep(backoffMs);
|
|
1384
1384
|
}
|
|
1385
1385
|
}
|
|
@@ -1391,8 +1391,8 @@ init_esm_shims();
|
|
|
1391
1391
|
var DEFAULT_SPEC = { capacity: 5, refillPerSec: 5 };
|
|
1392
1392
|
var MAX_WAIT_SLICE_MS = 250;
|
|
1393
1393
|
var override2 = null;
|
|
1394
|
-
function setRateLimitConfig(
|
|
1395
|
-
override2 =
|
|
1394
|
+
function setRateLimitConfig(cfg2) {
|
|
1395
|
+
override2 = cfg2;
|
|
1396
1396
|
buckets.clear();
|
|
1397
1397
|
}
|
|
1398
1398
|
function disabled() {
|
|
@@ -2018,9 +2018,9 @@ function detectStalePins(env) {
|
|
|
2018
2018
|
const out = [];
|
|
2019
2019
|
for (const [provider, envVar] of Object.entries(MODEL_ENV_VARS)) {
|
|
2020
2020
|
const pinned = env[envVar];
|
|
2021
|
-
const
|
|
2022
|
-
if (pinned &&
|
|
2023
|
-
out.push({ provider, envVar, pinned, current });
|
|
2021
|
+
const current2 = DEFAULT_MODELS[provider];
|
|
2022
|
+
if (pinned && current2 && pinned !== current2) {
|
|
2023
|
+
out.push({ provider, envVar, pinned, current: current2 });
|
|
2024
2024
|
}
|
|
2025
2025
|
}
|
|
2026
2026
|
return out;
|
|
@@ -2254,7 +2254,7 @@ import { z } from "zod";
|
|
|
2254
2254
|
// src/server-meta.ts
|
|
2255
2255
|
init_esm_shims();
|
|
2256
2256
|
var SERVER_NAME = "crosscheck-agent";
|
|
2257
|
-
var SERVER_VERSION = true ? "0.2.
|
|
2257
|
+
var SERVER_VERSION = true ? "0.2.16" : "0.0.0-dev";
|
|
2258
2258
|
|
|
2259
2259
|
// src/tools/audit.ts
|
|
2260
2260
|
init_esm_shims();
|
|
@@ -2321,27 +2321,27 @@ function extractJson(text) {
|
|
|
2321
2321
|
|
|
2322
2322
|
// src/core/json-schema.ts
|
|
2323
2323
|
init_esm_shims();
|
|
2324
|
-
function validateSchema(value, schema,
|
|
2324
|
+
function validateSchema(value, schema, path16 = "") {
|
|
2325
2325
|
const errs = [];
|
|
2326
2326
|
if ("anyOf" in schema) {
|
|
2327
2327
|
const subs = schema["anyOf"].map(
|
|
2328
|
-
(s) => validateSchema(value, s,
|
|
2328
|
+
(s) => validateSchema(value, s, path16)
|
|
2329
2329
|
);
|
|
2330
2330
|
if (!subs.some((e) => e.length === 0)) {
|
|
2331
|
-
errs.push(`${
|
|
2331
|
+
errs.push(`${path16 || "<root>"}: did not match anyOf`);
|
|
2332
2332
|
}
|
|
2333
2333
|
return errs;
|
|
2334
2334
|
}
|
|
2335
2335
|
if ("oneOf" in schema) {
|
|
2336
|
-
const passed = schema["oneOf"].filter((s) => validateSchema(value, s,
|
|
2336
|
+
const passed = schema["oneOf"].filter((s) => validateSchema(value, s, path16).length === 0).length;
|
|
2337
2337
|
if (passed !== 1) {
|
|
2338
|
-
errs.push(`${
|
|
2338
|
+
errs.push(`${path16 || "<root>"}: matched ${passed} of oneOf, expected 1`);
|
|
2339
2339
|
}
|
|
2340
2340
|
return errs;
|
|
2341
2341
|
}
|
|
2342
2342
|
if ("const" in schema && !deepEqual(value, schema["const"])) {
|
|
2343
2343
|
errs.push(
|
|
2344
|
-
`${
|
|
2344
|
+
`${path16 || "<root>"}: expected const ${pyRepr(schema["const"])}, got ${pyRepr(value)}`
|
|
2345
2345
|
);
|
|
2346
2346
|
return errs;
|
|
2347
2347
|
}
|
|
@@ -2351,7 +2351,7 @@ function validateSchema(value, schema, path15 = "") {
|
|
|
2351
2351
|
const ok = types.some((tt) => matchesType(value, String(tt)));
|
|
2352
2352
|
if (!ok) {
|
|
2353
2353
|
errs.push(
|
|
2354
|
-
`${
|
|
2354
|
+
`${path16 || "<root>"}: expected type ${pyReprType(t)}, got ${pyTypeName(value)}`
|
|
2355
2355
|
);
|
|
2356
2356
|
return errs;
|
|
2357
2357
|
}
|
|
@@ -2360,29 +2360,29 @@ function validateSchema(value, schema, path15 = "") {
|
|
|
2360
2360
|
if ("enum" in schema) {
|
|
2361
2361
|
const en = schema["enum"];
|
|
2362
2362
|
if (!en.some((x) => deepEqual(x, value))) {
|
|
2363
|
-
errs.push(`${
|
|
2363
|
+
errs.push(`${path16 || "<root>"}: value ${pyRepr(value)} not in enum`);
|
|
2364
2364
|
}
|
|
2365
2365
|
}
|
|
2366
2366
|
if ("minLength" in schema && value.length < schema["minLength"]) {
|
|
2367
|
-
errs.push(`${
|
|
2367
|
+
errs.push(`${path16 || "<root>"}: shorter than minLength ${schema["minLength"]}`);
|
|
2368
2368
|
}
|
|
2369
2369
|
}
|
|
2370
2370
|
if (typeof value === "number" && !Number.isNaN(value)) {
|
|
2371
2371
|
if ("minimum" in schema && value < schema["minimum"]) {
|
|
2372
|
-
errs.push(`${
|
|
2372
|
+
errs.push(`${path16 || "<root>"}: ${value} < minimum ${schema["minimum"]}`);
|
|
2373
2373
|
}
|
|
2374
2374
|
if ("maximum" in schema && value > schema["maximum"]) {
|
|
2375
|
-
errs.push(`${
|
|
2375
|
+
errs.push(`${path16 || "<root>"}: ${value} > maximum ${schema["maximum"]}`);
|
|
2376
2376
|
}
|
|
2377
2377
|
}
|
|
2378
2378
|
if (Array.isArray(value)) {
|
|
2379
2379
|
if ("minItems" in schema && value.length < schema["minItems"]) {
|
|
2380
|
-
errs.push(`${
|
|
2380
|
+
errs.push(`${path16 || "<root>"}: fewer items than minItems ${schema["minItems"]}`);
|
|
2381
2381
|
}
|
|
2382
2382
|
const itemSchema = schema["items"];
|
|
2383
2383
|
if (isObj(itemSchema)) {
|
|
2384
2384
|
for (let i = 0; i < value.length; i++) {
|
|
2385
|
-
errs.push(...validateSchema(value[i], itemSchema, `${
|
|
2385
|
+
errs.push(...validateSchema(value[i], itemSchema, `${path16}[${i}]`));
|
|
2386
2386
|
}
|
|
2387
2387
|
}
|
|
2388
2388
|
}
|
|
@@ -2391,19 +2391,19 @@ function validateSchema(value, schema, path15 = "") {
|
|
|
2391
2391
|
const required = schema["required"] ?? [];
|
|
2392
2392
|
for (const r of required) {
|
|
2393
2393
|
if (!(r in value)) {
|
|
2394
|
-
errs.push(`${
|
|
2394
|
+
errs.push(`${path16 || "<root>"}: missing required key ${pyRepr(r)}`);
|
|
2395
2395
|
}
|
|
2396
2396
|
}
|
|
2397
2397
|
if (schema["additionalProperties"] === false) {
|
|
2398
2398
|
for (const k of Object.keys(value)) {
|
|
2399
2399
|
if (!(k in props)) {
|
|
2400
|
-
errs.push(`${
|
|
2400
|
+
errs.push(`${path16 || "<root>"}: unknown key ${pyRepr(k)}`);
|
|
2401
2401
|
}
|
|
2402
2402
|
}
|
|
2403
2403
|
}
|
|
2404
2404
|
for (const [k, v] of Object.entries(value)) {
|
|
2405
2405
|
const ps = props[k];
|
|
2406
|
-
if (ps) errs.push(...validateSchema(v, ps,
|
|
2406
|
+
if (ps) errs.push(...validateSchema(v, ps, path16 ? `${path16}.${k}` : k));
|
|
2407
2407
|
}
|
|
2408
2408
|
}
|
|
2409
2409
|
return errs;
|
|
@@ -2904,8 +2904,8 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
|
|
|
2904
2904
|
// src/core/budgets.ts
|
|
2905
2905
|
init_esm_shims();
|
|
2906
2906
|
var operatorBudgets = null;
|
|
2907
|
-
function setOperatorBudgets(
|
|
2908
|
-
operatorBudgets =
|
|
2907
|
+
function setOperatorBudgets(cfg2) {
|
|
2908
|
+
operatorBudgets = cfg2;
|
|
2909
2909
|
}
|
|
2910
2910
|
function operatorCeiling(purpose, provider) {
|
|
2911
2911
|
const direct = operatorBudgets?.token_budgets?.[purpose];
|
|
@@ -3106,8 +3106,8 @@ function isPersonaId(s) {
|
|
|
3106
3106
|
return PERSONA_IDS.includes(s);
|
|
3107
3107
|
}
|
|
3108
3108
|
var personaConfig = null;
|
|
3109
|
-
function setPersonaConfig(
|
|
3110
|
-
personaConfig =
|
|
3109
|
+
function setPersonaConfig(cfg2) {
|
|
3110
|
+
personaConfig = cfg2;
|
|
3111
3111
|
}
|
|
3112
3112
|
var processFirstCallConsumed = false;
|
|
3113
3113
|
var sessionsSeen = /* @__PURE__ */ new Set();
|
|
@@ -3174,8 +3174,8 @@ function routePersona(prompt, toolName) {
|
|
|
3174
3174
|
return { id: "engineering", scores };
|
|
3175
3175
|
}
|
|
3176
3176
|
function resolvePersona(opts) {
|
|
3177
|
-
const
|
|
3178
|
-
if (
|
|
3177
|
+
const cfg2 = opts.config ?? personaConfig;
|
|
3178
|
+
if (cfg2?.enabled === false) return { id: null, source: "disabled", bypassed: true };
|
|
3179
3179
|
const explicit = opts.explicit?.trim().toLowerCase();
|
|
3180
3180
|
if (explicit === "none" || explicit === "off") {
|
|
3181
3181
|
return { id: null, source: "none", bypassed: true };
|
|
@@ -3221,12 +3221,12 @@ function readIfExists(p) {
|
|
|
3221
3221
|
}
|
|
3222
3222
|
}
|
|
3223
3223
|
function loadPersonaBody(id, opts) {
|
|
3224
|
-
const
|
|
3225
|
-
const cacheKey = `${id}|${opts?.repoRoot ?? ""}|${
|
|
3224
|
+
const cfg2 = opts?.config ?? personaConfig;
|
|
3225
|
+
const cacheKey = `${id}|${opts?.repoRoot ?? ""}|${cfg2?.dir ?? ""}`;
|
|
3226
3226
|
const cached = bodyCache.get(cacheKey);
|
|
3227
3227
|
if (cached !== void 0) return cached;
|
|
3228
3228
|
const candidates = [];
|
|
3229
|
-
if (
|
|
3229
|
+
if (cfg2?.dir) candidates.push(path2.join(cfg2.dir, `${id}.md`));
|
|
3230
3230
|
if (opts?.repoRoot) candidates.push(path2.join(opts.repoRoot, ".crosscheck", "personas", `${id}.md`));
|
|
3231
3231
|
if (id === "engineering" && opts?.repoRoot) candidates.push(path2.join(opts.repoRoot, "CLAUDE.md"));
|
|
3232
3232
|
const bundled = bundledPersonasDir();
|
|
@@ -3276,9 +3276,9 @@ function buildPersonaInjection(opts) {
|
|
|
3276
3276
|
|
|
3277
3277
|
// src/core/utils.ts
|
|
3278
3278
|
init_esm_shims();
|
|
3279
|
-
function checkSessionBreakers(session,
|
|
3279
|
+
function checkSessionBreakers(session, cfg2) {
|
|
3280
3280
|
if (!session || typeof session !== "object") return null;
|
|
3281
|
-
const c =
|
|
3281
|
+
const c = cfg2 ?? {};
|
|
3282
3282
|
const costCap = Number(c.max_session_cost_usd ?? 0);
|
|
3283
3283
|
if (costCap > 0 && Number(session.total_cost_usd ?? 0) >= costCap) {
|
|
3284
3284
|
return {
|
|
@@ -3302,10 +3302,10 @@ function checkSessionBreakers(session, cfg) {
|
|
|
3302
3302
|
}
|
|
3303
3303
|
return null;
|
|
3304
3304
|
}
|
|
3305
|
-
function checkDagBreakers(dag,
|
|
3305
|
+
function checkDagBreakers(dag, cfg2) {
|
|
3306
3306
|
if (!dag || typeof dag !== "object") return null;
|
|
3307
3307
|
const nodes = Array.isArray(dag.nodes) ? dag.nodes : [];
|
|
3308
|
-
const c =
|
|
3308
|
+
const c = cfg2 ?? {};
|
|
3309
3309
|
const maxNodes = Math.trunc(Number(c.max_dag_nodes ?? 0));
|
|
3310
3310
|
if (maxNodes > 0 && nodes.length > maxNodes) {
|
|
3311
3311
|
return {
|
|
@@ -3390,8 +3390,8 @@ function breakerEnvelope(toolName, trip, sessionId) {
|
|
|
3390
3390
|
transient: false
|
|
3391
3391
|
};
|
|
3392
3392
|
}
|
|
3393
|
-
async function maybeBreakerEnvelope(storage, sessionId, toolName,
|
|
3394
|
-
if (!sessionId || !storage || !
|
|
3393
|
+
async function maybeBreakerEnvelope(storage, sessionId, toolName, cfg2, extras) {
|
|
3394
|
+
if (!sessionId || !storage || !cfg2) return null;
|
|
3395
3395
|
let session;
|
|
3396
3396
|
try {
|
|
3397
3397
|
session = await storage.getSession(sessionId) ?? null;
|
|
@@ -3399,13 +3399,13 @@ async function maybeBreakerEnvelope(storage, sessionId, toolName, cfg, extras) {
|
|
|
3399
3399
|
return null;
|
|
3400
3400
|
}
|
|
3401
3401
|
const target = extras && extras.length > 0 ? projectSessionWithAnswers(session, extras) : session;
|
|
3402
|
-
const trip = checkSessionBreakers(target,
|
|
3402
|
+
const trip = checkSessionBreakers(target, cfg2);
|
|
3403
3403
|
if (!trip) return null;
|
|
3404
3404
|
return breakerEnvelope(toolName, trip, sessionId);
|
|
3405
3405
|
}
|
|
3406
|
-
function maybeDagBreakerEnvelope(dag, toolName,
|
|
3407
|
-
if (!
|
|
3408
|
-
const trip = checkDagBreakers(dag ?? null,
|
|
3406
|
+
function maybeDagBreakerEnvelope(dag, toolName, cfg2, sessionId) {
|
|
3407
|
+
if (!cfg2) return null;
|
|
3408
|
+
const trip = checkDagBreakers(dag ?? null, cfg2);
|
|
3409
3409
|
if (!trip) return null;
|
|
3410
3410
|
return breakerEnvelope(toolName, trip, sessionId);
|
|
3411
3411
|
}
|
|
@@ -3428,9 +3428,9 @@ function builtinRedactionRules() {
|
|
|
3428
3428
|
{ pattern: /\b(?:\d{4}[ -]?){3}\d{4}\b/g, label: "CARD", prefix_group: false }
|
|
3429
3429
|
];
|
|
3430
3430
|
}
|
|
3431
|
-
function compileRules(
|
|
3431
|
+
function compileRules(cfg2) {
|
|
3432
3432
|
const rules = builtinRedactionRules();
|
|
3433
|
-
const extras =
|
|
3433
|
+
const extras = cfg2?.patterns_extra ?? [];
|
|
3434
3434
|
for (const src of extras) {
|
|
3435
3435
|
try {
|
|
3436
3436
|
rules.push({ pattern: new RegExp(src, "g"), label: "EXTRA", prefix_group: false });
|
|
@@ -3439,25 +3439,25 @@ function compileRules(cfg) {
|
|
|
3439
3439
|
}
|
|
3440
3440
|
return { rules };
|
|
3441
3441
|
}
|
|
3442
|
-
function hmacSuffix(
|
|
3443
|
-
const secret =
|
|
3444
|
-
const sid =
|
|
3442
|
+
function hmacSuffix(cfg2, label, value) {
|
|
3443
|
+
const secret = cfg2.hmac_secret ?? Buffer.alloc(0);
|
|
3444
|
+
const sid = cfg2.session_id ?? "";
|
|
3445
3445
|
const sidBytes = Buffer.from(sid, "utf8");
|
|
3446
3446
|
const key = Buffer.concat([Buffer.from(secret), sidBytes]);
|
|
3447
3447
|
const digest = createHmac("sha256", key).update(`${label}:${value}`, "utf8").digest("hex");
|
|
3448
3448
|
return digest.slice(0, 8);
|
|
3449
3449
|
}
|
|
3450
|
-
function redactText(s,
|
|
3450
|
+
function redactText(s, cfg2) {
|
|
3451
3451
|
if (typeof s !== "string" || s.length === 0) return s;
|
|
3452
|
-
if (
|
|
3453
|
-
const { rules } = compileRules(
|
|
3454
|
-
const hmacMode = Boolean(
|
|
3452
|
+
if (cfg2 && cfg2.enabled === false) return s;
|
|
3453
|
+
const { rules } = compileRules(cfg2);
|
|
3454
|
+
const hmacMode = Boolean(cfg2?.hmac_tokens);
|
|
3455
3455
|
let out = s;
|
|
3456
3456
|
for (const { pattern, label, prefix_group } of rules) {
|
|
3457
3457
|
pattern.lastIndex = 0;
|
|
3458
3458
|
if (hmacMode) {
|
|
3459
3459
|
out = out.replace(pattern, (match, ...args) => {
|
|
3460
|
-
const suffix = hmacSuffix(
|
|
3460
|
+
const suffix = hmacSuffix(cfg2 ?? {}, label, match);
|
|
3461
3461
|
const token = `[REDACTED_${label}:${suffix}]`;
|
|
3462
3462
|
if (prefix_group) {
|
|
3463
3463
|
const g1 = args[0];
|
|
@@ -3477,23 +3477,23 @@ function redactText(s, cfg) {
|
|
|
3477
3477
|
}
|
|
3478
3478
|
return out;
|
|
3479
3479
|
}
|
|
3480
|
-
function redactObj(obj,
|
|
3481
|
-
if (typeof obj === "string") return redactText(obj,
|
|
3480
|
+
function redactObj(obj, cfg2) {
|
|
3481
|
+
if (typeof obj === "string") return redactText(obj, cfg2);
|
|
3482
3482
|
if (Array.isArray(obj)) {
|
|
3483
|
-
return obj.map((v) => redactObj(v,
|
|
3483
|
+
return obj.map((v) => redactObj(v, cfg2));
|
|
3484
3484
|
}
|
|
3485
3485
|
if (obj && typeof obj === "object") {
|
|
3486
3486
|
const out = {};
|
|
3487
3487
|
for (const [k, v] of Object.entries(obj)) {
|
|
3488
|
-
out[k] = redactObj(v,
|
|
3488
|
+
out[k] = redactObj(v, cfg2);
|
|
3489
3489
|
}
|
|
3490
3490
|
return out;
|
|
3491
3491
|
}
|
|
3492
3492
|
return obj;
|
|
3493
3493
|
}
|
|
3494
3494
|
var globalRedaction = null;
|
|
3495
|
-
function setRedactionConfig(
|
|
3496
|
-
globalRedaction =
|
|
3495
|
+
function setRedactionConfig(cfg2) {
|
|
3496
|
+
globalRedaction = cfg2;
|
|
3497
3497
|
}
|
|
3498
3498
|
function getRedactionConfig() {
|
|
3499
3499
|
return globalRedaction ?? void 0;
|
|
@@ -4743,8 +4743,8 @@ function neutralizeInjection(s) {
|
|
|
4743
4743
|
|
|
4744
4744
|
// src/core/worker.ts
|
|
4745
4745
|
var WORKER_TOOL_COST_CAP_MODES = ["warn", "enforce", "off"];
|
|
4746
|
-
function workerToolCostCapDefaults(callerCapUsd, callerMode,
|
|
4747
|
-
const cfgObj =
|
|
4746
|
+
function workerToolCostCapDefaults(callerCapUsd, callerMode, cfg2) {
|
|
4747
|
+
const cfgObj = cfg2 ?? {};
|
|
4748
4748
|
let capRaw = callerCapUsd !== void 0 && callerCapUsd !== null ? callerCapUsd : cfgObj.cost_cap_usd;
|
|
4749
4749
|
let cap;
|
|
4750
4750
|
if (capRaw === void 0 || capRaw === null) {
|
|
@@ -6355,7 +6355,7 @@ function tryKill(child, signal, isUnix) {
|
|
|
6355
6355
|
init_esm_shims();
|
|
6356
6356
|
function shlexSplit(s) {
|
|
6357
6357
|
const out = [];
|
|
6358
|
-
let
|
|
6358
|
+
let current2 = "";
|
|
6359
6359
|
let hasCurrent = false;
|
|
6360
6360
|
let mode = "normal";
|
|
6361
6361
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -6373,7 +6373,7 @@ function shlexSplit(s) {
|
|
|
6373
6373
|
}
|
|
6374
6374
|
if (ch === "\\") {
|
|
6375
6375
|
if (i + 1 < s.length) {
|
|
6376
|
-
|
|
6376
|
+
current2 += s[i + 1];
|
|
6377
6377
|
i++;
|
|
6378
6378
|
hasCurrent = true;
|
|
6379
6379
|
}
|
|
@@ -6381,13 +6381,13 @@ function shlexSplit(s) {
|
|
|
6381
6381
|
}
|
|
6382
6382
|
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
6383
6383
|
if (hasCurrent) {
|
|
6384
|
-
out.push(
|
|
6385
|
-
|
|
6384
|
+
out.push(current2);
|
|
6385
|
+
current2 = "";
|
|
6386
6386
|
hasCurrent = false;
|
|
6387
6387
|
}
|
|
6388
6388
|
continue;
|
|
6389
6389
|
}
|
|
6390
|
-
|
|
6390
|
+
current2 += ch;
|
|
6391
6391
|
hasCurrent = true;
|
|
6392
6392
|
continue;
|
|
6393
6393
|
}
|
|
@@ -6396,7 +6396,7 @@ function shlexSplit(s) {
|
|
|
6396
6396
|
mode = "normal";
|
|
6397
6397
|
continue;
|
|
6398
6398
|
}
|
|
6399
|
-
|
|
6399
|
+
current2 += ch;
|
|
6400
6400
|
continue;
|
|
6401
6401
|
}
|
|
6402
6402
|
if (mode === "double") {
|
|
@@ -6407,21 +6407,21 @@ function shlexSplit(s) {
|
|
|
6407
6407
|
if (ch === "\\") {
|
|
6408
6408
|
const nxt = s[i + 1];
|
|
6409
6409
|
if (nxt === "$" || nxt === "`" || nxt === '"' || nxt === "\\" || nxt === "\n") {
|
|
6410
|
-
|
|
6410
|
+
current2 += nxt;
|
|
6411
6411
|
i++;
|
|
6412
6412
|
continue;
|
|
6413
6413
|
}
|
|
6414
|
-
|
|
6414
|
+
current2 += "\\";
|
|
6415
6415
|
continue;
|
|
6416
6416
|
}
|
|
6417
|
-
|
|
6417
|
+
current2 += ch;
|
|
6418
6418
|
continue;
|
|
6419
6419
|
}
|
|
6420
6420
|
}
|
|
6421
6421
|
if (mode !== "normal") {
|
|
6422
6422
|
throw new Error("unmatched quote");
|
|
6423
6423
|
}
|
|
6424
|
-
if (hasCurrent) out.push(
|
|
6424
|
+
if (hasCurrent) out.push(current2);
|
|
6425
6425
|
return out;
|
|
6426
6426
|
}
|
|
6427
6427
|
|
|
@@ -7136,16 +7136,16 @@ function computeDrift(opts) {
|
|
|
7136
7136
|
const absPath = resolvePinPath(opts);
|
|
7137
7137
|
const doc = loadDoc(absPath);
|
|
7138
7138
|
const pinned = doc && typeof doc === "object" && doc["pins"] && typeof doc["pins"] === "object" ? doc["pins"] : {};
|
|
7139
|
-
const
|
|
7139
|
+
const current2 = computeCurrent(opts);
|
|
7140
7140
|
const drift = [];
|
|
7141
7141
|
for (const [p, h] of Object.entries(pinned)) {
|
|
7142
|
-
if (
|
|
7142
|
+
if (current2[p] && current2[p] !== h) drift.push(p);
|
|
7143
7143
|
}
|
|
7144
|
-
const missingFromPin = Object.keys(
|
|
7145
|
-
const missingFiles = Object.keys(pinned).filter((p) => !(p in
|
|
7144
|
+
const missingFromPin = Object.keys(current2).filter((p) => !(p in pinned));
|
|
7145
|
+
const missingFiles = Object.keys(pinned).filter((p) => !(p in current2));
|
|
7146
7146
|
return {
|
|
7147
7147
|
pinned,
|
|
7148
|
-
current,
|
|
7148
|
+
current: current2,
|
|
7149
7149
|
drift: drift.sort(),
|
|
7150
7150
|
missing_from_pin: missingFromPin.sort(),
|
|
7151
7151
|
missing_files: missingFiles.sort(),
|
|
@@ -7440,19 +7440,19 @@ function sortKeyJsonifyTopLevel(json) {
|
|
|
7440
7440
|
for (const k of Object.keys(obj).sort()) sorted[k] = obj[k];
|
|
7441
7441
|
return JSON.stringify(sorted);
|
|
7442
7442
|
}
|
|
7443
|
-
function resolveCacheDir(
|
|
7444
|
-
const raw =
|
|
7443
|
+
function resolveCacheDir(cfg2, repoRoot) {
|
|
7444
|
+
const raw = cfg2.dir ?? ".crosscheck/node_cache";
|
|
7445
7445
|
if (isAbsolute(raw)) return raw;
|
|
7446
7446
|
return resolve(repoRoot ?? process.cwd(), raw);
|
|
7447
7447
|
}
|
|
7448
|
-
function cachePath(
|
|
7449
|
-
return join3(resolveCacheDir(
|
|
7448
|
+
function cachePath(cfg2, repoRoot, key) {
|
|
7449
|
+
return join3(resolveCacheDir(cfg2, repoRoot), key.slice(0, 2), `${key}.json`);
|
|
7450
7450
|
}
|
|
7451
|
-
function getNodeCache(
|
|
7452
|
-
if (!
|
|
7453
|
-
const p = cachePath(
|
|
7451
|
+
function getNodeCache(cfg2, repoRoot, key, nowMs) {
|
|
7452
|
+
if (!cfg2 || cfg2.enabled === false) return null;
|
|
7453
|
+
const p = cachePath(cfg2, repoRoot, key);
|
|
7454
7454
|
if (!existsSync4(p)) return null;
|
|
7455
|
-
const ttlS =
|
|
7455
|
+
const ttlS = cfg2.ttl_seconds ?? 604800;
|
|
7456
7456
|
try {
|
|
7457
7457
|
const st = statSync4(p);
|
|
7458
7458
|
if (ttlS > 0) {
|
|
@@ -7470,21 +7470,21 @@ function getNodeCache(cfg, repoRoot, key, nowMs) {
|
|
|
7470
7470
|
return null;
|
|
7471
7471
|
}
|
|
7472
7472
|
}
|
|
7473
|
-
function atomicWriteJson(
|
|
7474
|
-
mkdirSync4(dirname2(
|
|
7475
|
-
const tmp = `${
|
|
7473
|
+
function atomicWriteJson(path16, payload) {
|
|
7474
|
+
mkdirSync4(dirname2(path16), { recursive: true });
|
|
7475
|
+
const tmp = `${path16}.${process.pid}.${Date.now()}.tmp`;
|
|
7476
7476
|
writeFileSync3(tmp, JSON.stringify(payload), "utf8");
|
|
7477
|
-
renameSync(tmp,
|
|
7477
|
+
renameSync(tmp, path16);
|
|
7478
7478
|
}
|
|
7479
|
-
function putNodeCache(
|
|
7480
|
-
if (!
|
|
7479
|
+
function putNodeCache(cfg2, repoRoot, key, value) {
|
|
7480
|
+
if (!cfg2 || cfg2.enabled === false) return;
|
|
7481
7481
|
try {
|
|
7482
|
-
const p = cachePath(
|
|
7482
|
+
const p = cachePath(cfg2, repoRoot, key);
|
|
7483
7483
|
atomicWriteJson(p, value);
|
|
7484
|
-
const maxEntries =
|
|
7485
|
-
const maxBytes =
|
|
7484
|
+
const maxEntries = cfg2.max_entries ?? 2e3;
|
|
7485
|
+
const maxBytes = cfg2.max_cache_bytes ?? 100 * 1024 * 1024;
|
|
7486
7486
|
if (maxEntries <= 0 && maxBytes <= 0) return;
|
|
7487
|
-
const base = resolveCacheDir(
|
|
7487
|
+
const base = resolveCacheDir(cfg2, repoRoot);
|
|
7488
7488
|
if (!existsSync4(base)) return;
|
|
7489
7489
|
const entries = [];
|
|
7490
7490
|
let totalBytes = 0;
|
|
@@ -8602,31 +8602,31 @@ async function runFetch(args, opts) {
|
|
|
8602
8602
|
const url = String(args["url"] ?? "");
|
|
8603
8603
|
const force = Boolean(args["force_refresh"]);
|
|
8604
8604
|
const sessionId = typeof args["session_id"] === "string" ? args["session_id"] : null;
|
|
8605
|
-
const
|
|
8605
|
+
const cfg2 = { ...DEFAULT_CONFIG, ...opts.config ?? {} };
|
|
8606
8606
|
const base = { tool: "fetch", url };
|
|
8607
|
-
if (!
|
|
8607
|
+
if (!cfg2.enabled) {
|
|
8608
8608
|
return { ...base, accepted: false, reason: "fetch is disabled" };
|
|
8609
8609
|
}
|
|
8610
8610
|
if (!(url.startsWith("https://") || url.startsWith("http://"))) {
|
|
8611
8611
|
return { ...base, accepted: false, reason: "only http/https schemes are supported" };
|
|
8612
8612
|
}
|
|
8613
|
-
if (
|
|
8613
|
+
if (cfg2.url_allowlist.length === 0) {
|
|
8614
8614
|
return {
|
|
8615
8615
|
...base,
|
|
8616
8616
|
accepted: false,
|
|
8617
8617
|
reason: "fetch.url_allowlist is empty; no URLs may be fetched"
|
|
8618
8618
|
};
|
|
8619
8619
|
}
|
|
8620
|
-
if (!isUrlAllowed(url,
|
|
8620
|
+
if (!isUrlAllowed(url, cfg2.url_allowlist)) {
|
|
8621
8621
|
return {
|
|
8622
8622
|
...base,
|
|
8623
8623
|
accepted: false,
|
|
8624
8624
|
reason: "url is not covered by fetch.url_allowlist",
|
|
8625
|
-
allowlist:
|
|
8625
|
+
allowlist: cfg2.url_allowlist
|
|
8626
8626
|
};
|
|
8627
8627
|
}
|
|
8628
|
-
const maxBytesSession = Math.max(0,
|
|
8629
|
-
const maxUniqueHosts = Math.max(0,
|
|
8628
|
+
const maxBytesSession = Math.max(0, cfg2.max_bytes_per_session);
|
|
8629
|
+
const maxUniqueHosts = Math.max(0, cfg2.max_unique_hosts_per_session);
|
|
8630
8630
|
const host = extractHost(url);
|
|
8631
8631
|
if (sessionId && opts.storage && (maxBytesSession > 0 || maxUniqueHosts > 0)) {
|
|
8632
8632
|
const { total_bytes, unique_hosts } = await opts.storage.getFetchEgressTotals(sessionId);
|
|
@@ -8666,7 +8666,7 @@ async function runFetch(args, opts) {
|
|
|
8666
8666
|
}
|
|
8667
8667
|
}
|
|
8668
8668
|
}
|
|
8669
|
-
const evDir = resolveEvidenceDir(
|
|
8669
|
+
const evDir = resolveEvidenceDir(cfg2.evidence_dir, opts.repoRoot);
|
|
8670
8670
|
const urlHash16 = sha256Hex2(url).slice(0, 16);
|
|
8671
8671
|
const metaPath = path6.join(evDir, `by-url-${urlHash16}.json`);
|
|
8672
8672
|
if (existsSync5(metaPath) && !force) {
|
|
@@ -8688,7 +8688,7 @@ async function runFetch(args, opts) {
|
|
|
8688
8688
|
try {
|
|
8689
8689
|
response = await withTimeout(
|
|
8690
8690
|
fetchFn(url, { headers: { "User-Agent": "crosscheck-agent/0.1" } }),
|
|
8691
|
-
|
|
8691
|
+
cfg2.timeout_s * 1e3
|
|
8692
8692
|
);
|
|
8693
8693
|
} catch (e) {
|
|
8694
8694
|
return {
|
|
@@ -8714,8 +8714,8 @@ async function runFetch(args, opts) {
|
|
|
8714
8714
|
const reader = response.body?.getReader?.();
|
|
8715
8715
|
if (!reader) {
|
|
8716
8716
|
const buf = await response.arrayBuffer();
|
|
8717
|
-
if (buf.byteLength >
|
|
8718
|
-
return { ...base, accepted: false, reason: `response exceeds max_bytes=${
|
|
8717
|
+
if (buf.byteLength > cfg2.max_bytes) {
|
|
8718
|
+
return { ...base, accepted: false, reason: `response exceeds max_bytes=${cfg2.max_bytes}` };
|
|
8719
8719
|
}
|
|
8720
8720
|
data = new Uint8Array(buf);
|
|
8721
8721
|
} else {
|
|
@@ -8727,7 +8727,7 @@ async function runFetch(args, opts) {
|
|
|
8727
8727
|
if (done) break;
|
|
8728
8728
|
if (value) {
|
|
8729
8729
|
total += value.byteLength;
|
|
8730
|
-
if (total >
|
|
8730
|
+
if (total > cfg2.max_bytes) {
|
|
8731
8731
|
exceeded = true;
|
|
8732
8732
|
await reader.cancel().catch(() => {
|
|
8733
8733
|
});
|
|
@@ -8737,7 +8737,7 @@ async function runFetch(args, opts) {
|
|
|
8737
8737
|
}
|
|
8738
8738
|
}
|
|
8739
8739
|
if (exceeded) {
|
|
8740
|
-
return { ...base, accepted: false, reason: `response exceeds max_bytes=${
|
|
8740
|
+
return { ...base, accepted: false, reason: `response exceeds max_bytes=${cfg2.max_bytes}` };
|
|
8741
8741
|
}
|
|
8742
8742
|
data = new Uint8Array(total);
|
|
8743
8743
|
let offset = 0;
|
|
@@ -12591,15 +12591,15 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
12591
12591
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
12592
12592
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
12593
12593
|
function engineVersion() {
|
|
12594
|
-
return true ? "0.2.
|
|
12594
|
+
return true ? "0.2.16" : "0.0.0-dev";
|
|
12595
12595
|
}
|
|
12596
12596
|
function defaultUpdateCachePath() {
|
|
12597
12597
|
const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");
|
|
12598
12598
|
return path10.join(base, "update_check.json");
|
|
12599
12599
|
}
|
|
12600
|
-
function isNewer(latest,
|
|
12600
|
+
function isNewer(latest, current2) {
|
|
12601
12601
|
const a = parseTriple(latest);
|
|
12602
|
-
const b = parseTriple(
|
|
12602
|
+
const b = parseTriple(current2);
|
|
12603
12603
|
for (let i = 0; i < 3; i += 1) {
|
|
12604
12604
|
if (a[i] !== b[i]) return a[i] > b[i];
|
|
12605
12605
|
}
|
|
@@ -12609,13 +12609,13 @@ function parseTriple(v) {
|
|
|
12609
12609
|
const parts = (v.split("-")[0] ?? "").split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
12610
12610
|
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
12611
12611
|
}
|
|
12612
|
-
function buildNotice(pkg,
|
|
12612
|
+
function buildNotice(pkg, current2, latest) {
|
|
12613
12613
|
return {
|
|
12614
12614
|
update_available: true,
|
|
12615
12615
|
package: pkg,
|
|
12616
|
-
current_version:
|
|
12616
|
+
current_version: current2,
|
|
12617
12617
|
latest_version: latest,
|
|
12618
|
-
message: `crosscheck ${latest} is available \u2014 you're on ${
|
|
12618
|
+
message: `crosscheck ${latest} is available \u2014 you're on ${current2}. To upgrade, run:
|
|
12619
12619
|
|
|
12620
12620
|
npm install -g crosscheck-cli@latest
|
|
12621
12621
|
|
|
@@ -14302,13 +14302,214 @@ function attachUpdateNotice(result, toolName, opts) {
|
|
|
14302
14302
|
|
|
14303
14303
|
// src/core/telemetry.ts
|
|
14304
14304
|
init_esm_shims();
|
|
14305
|
+
import crypto4 from "crypto";
|
|
14306
|
+
|
|
14307
|
+
// src/core/segments.ts
|
|
14308
|
+
init_esm_shims();
|
|
14309
|
+
import crypto3 from "crypto";
|
|
14310
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
|
|
14311
|
+
import path13 from "path";
|
|
14312
|
+
|
|
14313
|
+
// src/core/git-context.ts
|
|
14314
|
+
init_esm_shims();
|
|
14315
|
+
import { execFileSync } from "child_process";
|
|
14305
14316
|
import crypto2 from "crypto";
|
|
14317
|
+
var TRUNK_BRANCHES = /* @__PURE__ */ new Set([
|
|
14318
|
+
"main",
|
|
14319
|
+
"master",
|
|
14320
|
+
"dev",
|
|
14321
|
+
"develop",
|
|
14322
|
+
"trunk"
|
|
14323
|
+
]);
|
|
14324
|
+
function git(args, cwd) {
|
|
14325
|
+
try {
|
|
14326
|
+
return execFileSync("git", args, {
|
|
14327
|
+
cwd,
|
|
14328
|
+
encoding: "utf8",
|
|
14329
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
14330
|
+
timeout: 2e3
|
|
14331
|
+
}).trim();
|
|
14332
|
+
} catch {
|
|
14333
|
+
return null;
|
|
14334
|
+
}
|
|
14335
|
+
}
|
|
14336
|
+
function repoIdentity(cwd) {
|
|
14337
|
+
const root = git(["rev-list", "--max-parents=0", "HEAD"], cwd);
|
|
14338
|
+
if (root) return `root:${root.split("\n").pop().trim()}`;
|
|
14339
|
+
const remote = git(["config", "--get", "remote.origin.url"], cwd);
|
|
14340
|
+
if (remote) return `remote:${remote}`;
|
|
14341
|
+
const top = git(["rev-parse", "--show-toplevel"], cwd);
|
|
14342
|
+
return top ? `path:${top}` : null;
|
|
14343
|
+
}
|
|
14344
|
+
function fingerprintOf(seatKey, parts) {
|
|
14345
|
+
return crypto2.createHmac("sha256", seatKey).update(parts.join("\0")).digest("hex");
|
|
14346
|
+
}
|
|
14347
|
+
function readGitContext(seatKey, cwd) {
|
|
14348
|
+
try {
|
|
14349
|
+
const inside = git(["rev-parse", "--is-inside-work-tree"], cwd);
|
|
14350
|
+
if (inside !== "true") return { signal: "no_repo" };
|
|
14351
|
+
const repo = repoIdentity(cwd);
|
|
14352
|
+
if (!repo) return { signal: "no_repo" };
|
|
14353
|
+
const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
14354
|
+
if (!branch || branch === "HEAD") {
|
|
14355
|
+
const wt = git(["rev-parse", "--show-toplevel"], cwd) ?? cwd;
|
|
14356
|
+
return {
|
|
14357
|
+
fingerprint: fingerprintOf(seatKey, [repo, "worktree", wt]),
|
|
14358
|
+
signal: "worktree",
|
|
14359
|
+
localLabel: `worktree:${wt}`
|
|
14360
|
+
};
|
|
14361
|
+
}
|
|
14362
|
+
if (TRUNK_BRANCHES.has(branch)) {
|
|
14363
|
+
return {
|
|
14364
|
+
fingerprint: fingerprintOf(seatKey, [repo, "trunk"]),
|
|
14365
|
+
signal: "trunk",
|
|
14366
|
+
localLabel: `${branch} (maintenance)`
|
|
14367
|
+
};
|
|
14368
|
+
}
|
|
14369
|
+
return {
|
|
14370
|
+
fingerprint: fingerprintOf(seatKey, [repo, "branch", branch]),
|
|
14371
|
+
signal: "branch",
|
|
14372
|
+
localLabel: branch
|
|
14373
|
+
};
|
|
14374
|
+
} catch {
|
|
14375
|
+
return { signal: "no_repo" };
|
|
14376
|
+
}
|
|
14377
|
+
}
|
|
14378
|
+
function sameContext(a, b) {
|
|
14379
|
+
return a.fingerprint === b.fingerprint && a.signal === b.signal;
|
|
14380
|
+
}
|
|
14381
|
+
|
|
14382
|
+
// src/core/segments.ts
|
|
14383
|
+
var POST_TIMEOUT_MS = 5e3;
|
|
14384
|
+
function canonicalSegmentBody(s) {
|
|
14385
|
+
return [
|
|
14386
|
+
s.segmentId,
|
|
14387
|
+
s.seatId,
|
|
14388
|
+
s.orgId,
|
|
14389
|
+
s.sessionId,
|
|
14390
|
+
String(s.seq),
|
|
14391
|
+
s.fingerprint ?? "",
|
|
14392
|
+
s.signal,
|
|
14393
|
+
s.startedAt,
|
|
14394
|
+
s.endedAt ?? ""
|
|
14395
|
+
].join("|");
|
|
14396
|
+
}
|
|
14397
|
+
function signSegment(seatKey, s) {
|
|
14398
|
+
return crypto3.createHmac("sha256", seatKey).update(canonicalSegmentBody(s)).digest("hex");
|
|
14399
|
+
}
|
|
14400
|
+
var cfgResolved = false;
|
|
14401
|
+
var cfg = null;
|
|
14306
14402
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14403
|
+
function getConfig() {
|
|
14404
|
+
if (cfgResolved) return cfg;
|
|
14405
|
+
cfgResolved = true;
|
|
14406
|
+
if (process.env["CROSSCHECK_TELEMETRY"] === "off") return cfg = null;
|
|
14407
|
+
const base = process.env["CROSSCHECK_TELEMETRY_URL"];
|
|
14408
|
+
const seatId = process.env["CROSSCHECK_SEAT_ID"];
|
|
14409
|
+
const orgId = process.env["CROSSCHECK_ORG_ID"];
|
|
14410
|
+
const seatKey = process.env["CROSSCHECK_SEAT_HMAC_KEY"];
|
|
14411
|
+
if (!base || !seatId || !orgId || !seatKey) return cfg = null;
|
|
14412
|
+
if (!UUID_RE.test(seatId) || !UUID_RE.test(orgId)) return cfg = null;
|
|
14413
|
+
const sessionId = process.env["CLAUDE_SESSION_ID"] || process.env["CLAUDE_CODE_SESSION_ID"] || `engine-${crypto3.randomUUID()}`;
|
|
14414
|
+
cfg = {
|
|
14415
|
+
url: base.replace(/\/telemetry\/?$/, "/segments"),
|
|
14416
|
+
seatId,
|
|
14417
|
+
orgId,
|
|
14418
|
+
seatKey,
|
|
14419
|
+
sessionId
|
|
14420
|
+
};
|
|
14421
|
+
return cfg;
|
|
14422
|
+
}
|
|
14423
|
+
var current = null;
|
|
14424
|
+
var nextSeq = 0;
|
|
14425
|
+
function currentFingerprint() {
|
|
14426
|
+
return current?.context.fingerprint;
|
|
14427
|
+
}
|
|
14428
|
+
function rememberLabel(context) {
|
|
14429
|
+
if (!context.fingerprint || !context.localLabel) return;
|
|
14430
|
+
try {
|
|
14431
|
+
const dir = process.env["CROSSCHECK_DATA_DIR"] || path13.join(process.env["HOME"] ?? process.env["USERPROFILE"] ?? ".", ".crosscheck");
|
|
14432
|
+
const file = path13.join(dir, "features.json");
|
|
14433
|
+
let map = {};
|
|
14434
|
+
if (existsSync12(file)) {
|
|
14435
|
+
try {
|
|
14436
|
+
const parsed = JSON.parse(readFileSync14(file, "utf8"));
|
|
14437
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) map = parsed;
|
|
14438
|
+
} catch {
|
|
14439
|
+
}
|
|
14440
|
+
}
|
|
14441
|
+
map[context.fingerprint] = {
|
|
14442
|
+
label: context.localLabel,
|
|
14443
|
+
lastSeen: (/* @__PURE__ */ new Date()).toISOString()
|
|
14444
|
+
};
|
|
14445
|
+
mkdirSync9(dir, { recursive: true });
|
|
14446
|
+
writeFileSync8(file, `${JSON.stringify(map, null, 2)}
|
|
14447
|
+
`, "utf8");
|
|
14448
|
+
} catch {
|
|
14449
|
+
}
|
|
14450
|
+
}
|
|
14451
|
+
async function post(url, segments) {
|
|
14452
|
+
try {
|
|
14453
|
+
await fetch(url, {
|
|
14454
|
+
method: "POST",
|
|
14455
|
+
headers: { "content-type": "application/json" },
|
|
14456
|
+
body: JSON.stringify({ segments }),
|
|
14457
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS)
|
|
14458
|
+
});
|
|
14459
|
+
} catch {
|
|
14460
|
+
}
|
|
14461
|
+
}
|
|
14462
|
+
function emit(c, seg, endedAt) {
|
|
14463
|
+
const payload = {
|
|
14464
|
+
segmentId: seg.segmentId,
|
|
14465
|
+
seatId: c.seatId,
|
|
14466
|
+
orgId: c.orgId,
|
|
14467
|
+
sessionId: c.sessionId,
|
|
14468
|
+
seq: seg.seq,
|
|
14469
|
+
...seg.context.fingerprint ? { fingerprint: seg.context.fingerprint } : {},
|
|
14470
|
+
signal: seg.context.signal,
|
|
14471
|
+
startedAt: seg.startedAt,
|
|
14472
|
+
...endedAt ? { endedAt } : {}
|
|
14473
|
+
};
|
|
14474
|
+
const signatureHmac = signSegment(c.seatKey, payload);
|
|
14475
|
+
void post(c.url, [{ ...payload, signatureHmac }]);
|
|
14476
|
+
}
|
|
14477
|
+
function syncSegment(cwd) {
|
|
14478
|
+
try {
|
|
14479
|
+
const c = getConfig();
|
|
14480
|
+
if (!c) return;
|
|
14481
|
+
const context = readGitContext(c.seatKey, cwd ?? process.cwd());
|
|
14482
|
+
if (current && sameContext(current.context, context)) return;
|
|
14483
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
14484
|
+
if (current) emit(c, current, now);
|
|
14485
|
+
current = {
|
|
14486
|
+
segmentId: crypto3.randomUUID(),
|
|
14487
|
+
seq: nextSeq++,
|
|
14488
|
+
context,
|
|
14489
|
+
startedAt: now
|
|
14490
|
+
};
|
|
14491
|
+
rememberLabel(context);
|
|
14492
|
+
emit(c, current);
|
|
14493
|
+
} catch {
|
|
14494
|
+
}
|
|
14495
|
+
}
|
|
14496
|
+
function closeSegment() {
|
|
14497
|
+
try {
|
|
14498
|
+
const c = getConfig();
|
|
14499
|
+
if (!c || !current) return;
|
|
14500
|
+
emit(c, current, (/* @__PURE__ */ new Date()).toISOString());
|
|
14501
|
+
current = null;
|
|
14502
|
+
} catch {
|
|
14503
|
+
}
|
|
14504
|
+
}
|
|
14505
|
+
|
|
14506
|
+
// src/core/telemetry.ts
|
|
14507
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14307
14508
|
var BATCH_MAX = 100;
|
|
14308
14509
|
var FLUSH_BATCH_AT = 25;
|
|
14309
14510
|
var FLUSH_INTERVAL_MS = 15e3;
|
|
14310
14511
|
var MAX_QUEUE = 500;
|
|
14311
|
-
var
|
|
14512
|
+
var POST_TIMEOUT_MS2 = 5e3;
|
|
14312
14513
|
var PROVIDER_TO_SCHEMA = {
|
|
14313
14514
|
anthropic: "anthropic",
|
|
14314
14515
|
openai: "openai",
|
|
@@ -14338,7 +14539,7 @@ function toolToPattern(toolName) {
|
|
|
14338
14539
|
return TOOL_TO_PATTERN[String(toolName).toLowerCase()] ?? "other";
|
|
14339
14540
|
}
|
|
14340
14541
|
function canonicalEventBody(e) {
|
|
14341
|
-
|
|
14542
|
+
const base = [
|
|
14342
14543
|
e.eventId,
|
|
14343
14544
|
e.seatId,
|
|
14344
14545
|
e.orgId,
|
|
@@ -14353,13 +14554,22 @@ function canonicalEventBody(e) {
|
|
|
14353
14554
|
e.status,
|
|
14354
14555
|
e.errorClass ?? ""
|
|
14355
14556
|
].join("|");
|
|
14557
|
+
if (e.runId === void 0 && e.purpose === void 0 && e.fingerprint === void 0) {
|
|
14558
|
+
return base;
|
|
14559
|
+
}
|
|
14560
|
+
return [base, e.runId ?? "", e.purpose ?? "", e.fingerprint ?? ""].join("|");
|
|
14561
|
+
}
|
|
14562
|
+
function normalizePurpose(v) {
|
|
14563
|
+
if (typeof v !== "string") return void 0;
|
|
14564
|
+
const slug = v.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-").slice(0, 32);
|
|
14565
|
+
return /^[a-z0-9][a-z0-9_-]*$/.test(slug) ? slug : void 0;
|
|
14356
14566
|
}
|
|
14357
14567
|
function signEvent(seatSigningKey, e) {
|
|
14358
|
-
return
|
|
14568
|
+
return crypto4.createHmac("sha256", seatSigningKey).update(canonicalEventBody(e)).digest("hex");
|
|
14359
14569
|
}
|
|
14360
14570
|
var configResolved = false;
|
|
14361
14571
|
var config = null;
|
|
14362
|
-
function
|
|
14572
|
+
function getConfig2() {
|
|
14363
14573
|
if (configResolved) return config;
|
|
14364
14574
|
configResolved = true;
|
|
14365
14575
|
if (process.env["CROSSCHECK_TELEMETRY"] === "off") return config = null;
|
|
@@ -14368,7 +14578,7 @@ function getConfig() {
|
|
|
14368
14578
|
const orgId = process.env["CROSSCHECK_ORG_ID"];
|
|
14369
14579
|
const seatKey = process.env["CROSSCHECK_SEAT_HMAC_KEY"];
|
|
14370
14580
|
if (!url || !seatId || !orgId || !seatKey) return config = null;
|
|
14371
|
-
if (!
|
|
14581
|
+
if (!UUID_RE2.test(seatId) || !UUID_RE2.test(orgId)) return config = null;
|
|
14372
14582
|
config = { url, seatId, orgId, seatKey };
|
|
14373
14583
|
return config;
|
|
14374
14584
|
}
|
|
@@ -14403,7 +14613,10 @@ function usageEventsFromEnvelope(out, toolName) {
|
|
|
14403
14613
|
completionTokens: intNonNeg(u.completion_tokens),
|
|
14404
14614
|
costUsdEstimate: cost,
|
|
14405
14615
|
latencyMs,
|
|
14406
|
-
status: "ok"
|
|
14616
|
+
status: "ok",
|
|
14617
|
+
// Envelopes have carried `purpose` per call all along (debate /
|
|
14618
|
+
// debate-coreason / synth / worker); it just was never forwarded.
|
|
14619
|
+
purpose: normalizePurpose(u.purpose)
|
|
14407
14620
|
});
|
|
14408
14621
|
}
|
|
14409
14622
|
return events;
|
|
@@ -14418,11 +14631,11 @@ function scheduleFlush() {
|
|
|
14418
14631
|
}, FLUSH_INTERVAL_MS);
|
|
14419
14632
|
if (typeof flushTimer.unref === "function") flushTimer.unref();
|
|
14420
14633
|
}
|
|
14421
|
-
function enqueue(
|
|
14634
|
+
function enqueue(cfg2, input, runId, fingerprint) {
|
|
14422
14635
|
const base = {
|
|
14423
|
-
eventId:
|
|
14424
|
-
seatId:
|
|
14425
|
-
orgId:
|
|
14636
|
+
eventId: crypto4.randomUUID(),
|
|
14637
|
+
seatId: cfg2.seatId,
|
|
14638
|
+
orgId: cfg2.orgId,
|
|
14426
14639
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14427
14640
|
provider: input.provider,
|
|
14428
14641
|
model: input.model,
|
|
@@ -14431,9 +14644,17 @@ function enqueue(cfg, input) {
|
|
|
14431
14644
|
completionTokens: input.completionTokens,
|
|
14432
14645
|
costUsdEstimate: input.costUsdEstimate,
|
|
14433
14646
|
latencyMs: input.latencyMs,
|
|
14434
|
-
status: input.status
|
|
14435
|
-
|
|
14436
|
-
|
|
14647
|
+
status: input.status,
|
|
14648
|
+
runId,
|
|
14649
|
+
// Omit entirely (not "") when unknown, so the canonical body stays
|
|
14650
|
+
// consistent with what the server reconstructs from the JSON.
|
|
14651
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose },
|
|
14652
|
+
// Panel attribution is EXACT: we know the active git segment at emit
|
|
14653
|
+
// time, so there is no time-join and no ambiguity window — unlike host
|
|
14654
|
+
// tokens, which can only be matched by session and timestamp.
|
|
14655
|
+
...fingerprint === void 0 ? {} : { fingerprint }
|
|
14656
|
+
};
|
|
14657
|
+
const signatureHmac = signEvent(cfg2.seatKey, base);
|
|
14437
14658
|
queue.push({ ...base, signatureHmac });
|
|
14438
14659
|
if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
|
|
14439
14660
|
if (queue.length >= FLUSH_BATCH_AT) void flush();
|
|
@@ -14441,10 +14662,14 @@ function enqueue(cfg, input) {
|
|
|
14441
14662
|
}
|
|
14442
14663
|
function recordUsage(out, toolName) {
|
|
14443
14664
|
try {
|
|
14444
|
-
const
|
|
14445
|
-
if (!
|
|
14665
|
+
const cfg2 = getConfig2();
|
|
14666
|
+
if (!cfg2) return;
|
|
14446
14667
|
if (toolName === "update_crosscheck") return;
|
|
14447
|
-
|
|
14668
|
+
const runId = crypto4.randomUUID();
|
|
14669
|
+
const fingerprint = currentFingerprint();
|
|
14670
|
+
for (const ev of usageEventsFromEnvelope(out, toolName)) {
|
|
14671
|
+
enqueue(cfg2, ev, runId, fingerprint);
|
|
14672
|
+
}
|
|
14448
14673
|
} catch {
|
|
14449
14674
|
}
|
|
14450
14675
|
}
|
|
@@ -14455,7 +14680,7 @@ async function postBatch(url, batch) {
|
|
|
14455
14680
|
method: "POST",
|
|
14456
14681
|
headers: { "content-type": "application/json" },
|
|
14457
14682
|
body: JSON.stringify({ events: batch }),
|
|
14458
|
-
signal: AbortSignal.timeout(
|
|
14683
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS2)
|
|
14459
14684
|
});
|
|
14460
14685
|
} catch {
|
|
14461
14686
|
queue.unshift(...batch);
|
|
@@ -14477,15 +14702,15 @@ async function postBatch(url, batch) {
|
|
|
14477
14702
|
if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
|
|
14478
14703
|
}
|
|
14479
14704
|
async function flush() {
|
|
14480
|
-
const
|
|
14481
|
-
if (!
|
|
14705
|
+
const cfg2 = getConfig2();
|
|
14706
|
+
if (!cfg2) return;
|
|
14482
14707
|
if (flushTimer) {
|
|
14483
14708
|
clearTimeout(flushTimer);
|
|
14484
14709
|
flushTimer = null;
|
|
14485
14710
|
}
|
|
14486
14711
|
while (queue.length > 0) {
|
|
14487
14712
|
const batch = queue.splice(0, BATCH_MAX);
|
|
14488
|
-
await postBatch(
|
|
14713
|
+
await postBatch(cfg2.url, batch);
|
|
14489
14714
|
if (queue.length > 0 && queue[0] === batch[0]) break;
|
|
14490
14715
|
}
|
|
14491
14716
|
}
|
|
@@ -14553,6 +14778,7 @@ function createServer(opts = {}) {
|
|
|
14553
14778
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14554
14779
|
const startedHr = process.hrtime.bigint();
|
|
14555
14780
|
const id = nextEventId();
|
|
14781
|
+
syncSegment(opts.repoRoot);
|
|
14556
14782
|
const gateBlock = configPinGate(name, {
|
|
14557
14783
|
...opts.repoRoot ? { repoRoot: opts.repoRoot } : {},
|
|
14558
14784
|
...opts.configPinning ? { config: opts.configPinning } : {},
|
|
@@ -14634,6 +14860,13 @@ function createServer(opts = {}) {
|
|
|
14634
14860
|
async function connectAndServe(transport, opts = {}) {
|
|
14635
14861
|
const server = createServer(opts);
|
|
14636
14862
|
await server.connect(transport);
|
|
14863
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
14864
|
+
process.once(sig, () => {
|
|
14865
|
+
closeSegment();
|
|
14866
|
+
process.exit(0);
|
|
14867
|
+
});
|
|
14868
|
+
}
|
|
14869
|
+
process.once("beforeExit", () => closeSegment());
|
|
14637
14870
|
const cliVersion = process.env["CROSSCHECK_CLI_VERSION"];
|
|
14638
14871
|
void maybeCheckForUpdate({
|
|
14639
14872
|
currentVersion: cliVersion ?? SERVER_VERSION,
|
|
@@ -14671,8 +14904,8 @@ function buildToolRegistry(opts) {
|
|
|
14671
14904
|
|
|
14672
14905
|
// src/core/config-file.ts
|
|
14673
14906
|
init_esm_shims();
|
|
14674
|
-
import { existsSync as
|
|
14675
|
-
import
|
|
14907
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
|
|
14908
|
+
import path14 from "path";
|
|
14676
14909
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
14677
14910
|
function asObj(v) {
|
|
14678
14911
|
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
@@ -14700,18 +14933,18 @@ function pickNums(src, keys) {
|
|
|
14700
14933
|
}
|
|
14701
14934
|
function findConfigFile(opts) {
|
|
14702
14935
|
const direct = opts.explicitPath ?? process.env["CROSSCHECK_CONFIG_PATH"];
|
|
14703
|
-
if (direct) return
|
|
14936
|
+
if (direct) return existsSync13(direct) ? direct : void 0;
|
|
14704
14937
|
const candidates = [];
|
|
14705
14938
|
let dir = opts.startDir;
|
|
14706
14939
|
for (let i = 0; dir && i < 8; i += 1) {
|
|
14707
|
-
candidates.push(
|
|
14708
|
-
const parent =
|
|
14940
|
+
candidates.push(path14.join(dir, "crosscheck.config.json"));
|
|
14941
|
+
const parent = path14.dirname(dir);
|
|
14709
14942
|
if (parent === dir) break;
|
|
14710
14943
|
dir = parent;
|
|
14711
14944
|
}
|
|
14712
|
-
if (opts.repoRoot) candidates.push(
|
|
14713
|
-
if (opts.dataDir) candidates.push(
|
|
14714
|
-
return candidates.find((p) =>
|
|
14945
|
+
if (opts.repoRoot) candidates.push(path14.join(opts.repoRoot, "crosscheck.config.json"));
|
|
14946
|
+
if (opts.dataDir) candidates.push(path14.join(opts.dataDir, "crosscheck.config.json"));
|
|
14947
|
+
return candidates.find((p) => existsSync13(p));
|
|
14715
14948
|
}
|
|
14716
14949
|
function mapConfig(raw, sourcePath) {
|
|
14717
14950
|
const result = { sourcePath };
|
|
@@ -14728,16 +14961,16 @@ function mapConfig(raw, sourcePath) {
|
|
|
14728
14961
|
}
|
|
14729
14962
|
const nc = asObj(raw["node_cache"]);
|
|
14730
14963
|
if (nc) {
|
|
14731
|
-
const
|
|
14964
|
+
const cfg2 = {
|
|
14732
14965
|
...pickNums(nc, ["ttl_seconds", "max_entries", "max_cache_bytes"])
|
|
14733
14966
|
};
|
|
14734
|
-
if (bool(nc["enabled"]) !== void 0)
|
|
14735
|
-
if (str(nc["dir"]) !== void 0)
|
|
14736
|
-
result.nodeCache =
|
|
14967
|
+
if (bool(nc["enabled"]) !== void 0) cfg2.enabled = bool(nc["enabled"]);
|
|
14968
|
+
if (str(nc["dir"]) !== void 0) cfg2.dir = str(nc["dir"]);
|
|
14969
|
+
result.nodeCache = cfg2;
|
|
14737
14970
|
}
|
|
14738
14971
|
const f = asObj(raw["fetch"]);
|
|
14739
14972
|
if (f) {
|
|
14740
|
-
const
|
|
14973
|
+
const cfg2 = {
|
|
14741
14974
|
...pickNums(f, [
|
|
14742
14975
|
"max_bytes",
|
|
14743
14976
|
"max_bytes_per_session",
|
|
@@ -14745,10 +14978,10 @@ function mapConfig(raw, sourcePath) {
|
|
|
14745
14978
|
"timeout_s"
|
|
14746
14979
|
])
|
|
14747
14980
|
};
|
|
14748
|
-
if (bool(f["enabled"]) !== void 0)
|
|
14749
|
-
if (strArr(f["url_allowlist"]) !== void 0)
|
|
14750
|
-
if (str(f["evidence_dir"]) !== void 0)
|
|
14751
|
-
result.fetchConfig =
|
|
14981
|
+
if (bool(f["enabled"]) !== void 0) cfg2.enabled = bool(f["enabled"]);
|
|
14982
|
+
if (strArr(f["url_allowlist"]) !== void 0) cfg2.url_allowlist = strArr(f["url_allowlist"]);
|
|
14983
|
+
if (str(f["evidence_dir"]) !== void 0) cfg2.evidence_dir = str(f["evidence_dir"]);
|
|
14984
|
+
result.fetchConfig = cfg2;
|
|
14752
14985
|
}
|
|
14753
14986
|
if ("provider_allowlist" in raw) {
|
|
14754
14987
|
const pa = raw["provider_allowlist"];
|
|
@@ -14772,10 +15005,10 @@ function mapConfig(raw, sourcePath) {
|
|
|
14772
15005
|
if (retries) {
|
|
14773
15006
|
const maxAttempts = num(retries["max_attempts"]);
|
|
14774
15007
|
const baseS = num(retries["backoff_base_s"]);
|
|
14775
|
-
const
|
|
14776
|
-
if (maxAttempts !== void 0)
|
|
14777
|
-
if (baseS !== void 0)
|
|
14778
|
-
if (Object.keys(
|
|
15008
|
+
const cfg2 = {};
|
|
15009
|
+
if (maxAttempts !== void 0) cfg2.maxAttempts = Math.max(1, Math.trunc(maxAttempts));
|
|
15010
|
+
if (baseS !== void 0) cfg2.backoffBaseMs = Math.round(baseS * 1e3);
|
|
15011
|
+
if (Object.keys(cfg2).length > 0) setRetryConfig(cfg2);
|
|
14779
15012
|
}
|
|
14780
15013
|
const rl = asObj(raw["rate_limits"]);
|
|
14781
15014
|
if (rl) {
|
|
@@ -14801,22 +15034,22 @@ function mapConfig(raw, sourcePath) {
|
|
|
14801
15034
|
}
|
|
14802
15035
|
const red = asObj(raw["redaction"]);
|
|
14803
15036
|
if (red) {
|
|
14804
|
-
const
|
|
14805
|
-
if (bool(red["enabled"]) !== void 0)
|
|
15037
|
+
const cfg2 = {};
|
|
15038
|
+
if (bool(red["enabled"]) !== void 0) cfg2.enabled = bool(red["enabled"]);
|
|
14806
15039
|
const extras = strArr(red["patterns_extra"]);
|
|
14807
|
-
if (extras && extras.length > 0)
|
|
15040
|
+
if (extras && extras.length > 0) cfg2.patterns_extra = extras;
|
|
14808
15041
|
if (bool(red["hmac_tokens"]) === true) {
|
|
14809
|
-
|
|
14810
|
-
|
|
15042
|
+
cfg2.hmac_tokens = true;
|
|
15043
|
+
cfg2.hmac_secret = randomBytes2(32);
|
|
14811
15044
|
}
|
|
14812
|
-
if (Object.keys(
|
|
15045
|
+
if (Object.keys(cfg2).length > 0) setRedactionConfig(cfg2);
|
|
14813
15046
|
}
|
|
14814
15047
|
const personas = asObj(raw["personas"]);
|
|
14815
15048
|
if (personas) {
|
|
14816
|
-
const
|
|
14817
|
-
if (bool(personas["enabled"]) !== void 0)
|
|
14818
|
-
if (str(personas["dir"]) !== void 0)
|
|
14819
|
-
if (Object.keys(
|
|
15049
|
+
const cfg2 = {};
|
|
15050
|
+
if (bool(personas["enabled"]) !== void 0) cfg2.enabled = bool(personas["enabled"]);
|
|
15051
|
+
if (str(personas["dir"]) !== void 0) cfg2.dir = str(personas["dir"]);
|
|
15052
|
+
if (Object.keys(cfg2).length > 0) setPersonaConfig(cfg2);
|
|
14820
15053
|
}
|
|
14821
15054
|
return result;
|
|
14822
15055
|
}
|
|
@@ -14825,7 +15058,7 @@ function loadConfigFile(opts) {
|
|
|
14825
15058
|
if (!file) return null;
|
|
14826
15059
|
let raw;
|
|
14827
15060
|
try {
|
|
14828
|
-
raw = JSON.parse(
|
|
15061
|
+
raw = JSON.parse(readFileSync15(file, "utf8"));
|
|
14829
15062
|
} catch (e) {
|
|
14830
15063
|
try {
|
|
14831
15064
|
process.stderr.write(
|
|
@@ -14845,7 +15078,7 @@ function loadConfigFile(opts) {
|
|
|
14845
15078
|
var SHUTDOWN_TIMEOUT_MS = 2e3;
|
|
14846
15079
|
async function main() {
|
|
14847
15080
|
enforceLicenseOrExit();
|
|
14848
|
-
const cfgDataDir = process.env["CROSSCHECK_DATA_DIR"] ||
|
|
15081
|
+
const cfgDataDir = process.env["CROSSCHECK_DATA_DIR"] || path15.join(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".crosscheck");
|
|
14849
15082
|
const configFile = loadConfigFile({
|
|
14850
15083
|
startDir: process.cwd(),
|
|
14851
15084
|
repoRoot: findGitRoot(__dirname),
|
|
@@ -14870,7 +15103,7 @@ async function main() {
|
|
|
14870
15103
|
installShutdownHandlers();
|
|
14871
15104
|
const bundledPricing = (() => {
|
|
14872
15105
|
try {
|
|
14873
|
-
return
|
|
15106
|
+
return path15.join(path15.dirname(fileURLToPath3(import.meta.url)), "pricing.json");
|
|
14874
15107
|
} catch {
|
|
14875
15108
|
return void 0;
|
|
14876
15109
|
}
|
|
@@ -14879,7 +15112,7 @@ async function main() {
|
|
|
14879
15112
|
process.env["CROSSCHECK_PRICING_PATH"],
|
|
14880
15113
|
resolveRepoFile("config/pricing.json"),
|
|
14881
15114
|
bundledPricing
|
|
14882
|
-
].find((p) => p &&
|
|
15115
|
+
].find((p) => p && existsSync14(p));
|
|
14883
15116
|
const pricing = pricingPath ? loadPricing(pricingPath) : {};
|
|
14884
15117
|
const providers = buildProviders({ env: process.env, pricing });
|
|
14885
15118
|
if (Object.keys(providers).length > 0) {
|
|
@@ -14897,10 +15130,10 @@ async function main() {
|
|
|
14897
15130
|
}
|
|
14898
15131
|
let storage;
|
|
14899
15132
|
if (process.env["CROSSCHECK_DB_DISABLED"] !== "1") {
|
|
14900
|
-
const dbPath = process.env["CROSSCHECK_DB_PATH"] ?? resolveRepoFile(".crosscheck/db.sqlite") ??
|
|
15133
|
+
const dbPath = process.env["CROSSCHECK_DB_PATH"] ?? resolveRepoFile(".crosscheck/db.sqlite") ?? path15.join(cfgDataDir, "db.sqlite");
|
|
14901
15134
|
if (dbPath) {
|
|
14902
15135
|
try {
|
|
14903
|
-
|
|
15136
|
+
mkdirSync10(path15.dirname(dbPath), { recursive: true });
|
|
14904
15137
|
const { openBetterSqliteStorage: openBetterSqliteStorage2 } = await Promise.resolve().then(() => (init_better_sqlite3(), better_sqlite3_exports));
|
|
14905
15138
|
storage = openBetterSqliteStorage2({ path: dbPath });
|
|
14906
15139
|
await storage.migrate();
|
|
@@ -14968,9 +15201,9 @@ function installShutdownHandlers() {
|
|
|
14968
15201
|
function resolveRepoFile(rel) {
|
|
14969
15202
|
let dir = __dirname;
|
|
14970
15203
|
for (let i = 0; i < 8; i++) {
|
|
14971
|
-
const candidate =
|
|
14972
|
-
if (
|
|
14973
|
-
const parent =
|
|
15204
|
+
const candidate = path15.join(dir, rel);
|
|
15205
|
+
if (existsSync14(candidate)) return candidate;
|
|
15206
|
+
const parent = path15.dirname(dir);
|
|
14974
15207
|
if (parent === dir) break;
|
|
14975
15208
|
dir = parent;
|
|
14976
15209
|
}
|
|
@@ -14979,8 +15212,8 @@ function resolveRepoFile(rel) {
|
|
|
14979
15212
|
function findGitRoot(startDir) {
|
|
14980
15213
|
let dir = startDir;
|
|
14981
15214
|
for (let i = 0; i < 12; i++) {
|
|
14982
|
-
if (
|
|
14983
|
-
const parent =
|
|
15215
|
+
if (existsSync14(path15.join(dir, ".git"))) return dir;
|
|
15216
|
+
const parent = path15.dirname(dir);
|
|
14984
15217
|
if (parent === dir) break;
|
|
14985
15218
|
dir = parent;
|
|
14986
15219
|
}
|