ultra11y 5.40.2 → 5.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { realpathSync as realpathSync6, writeFileSync as writeFileSync21, mkdirSync as mkdirSync18, existsSync as existsSync38, readFileSync as readFileSync34, appendFileSync, copyFileSync as copyFileSync4 } from "fs";
5
- import { join as join53, relative as relative6, resolve as resolve16, sep as sep7, dirname as dirname16 } from "path";
4
+ import { realpathSync as realpathSync7, writeFileSync as writeFileSync21, mkdirSync as mkdirSync18, existsSync as existsSync38, readFileSync as readFileSync34, appendFileSync, copyFileSync as copyFileSync4 } from "fs";
5
+ import { join as join53, relative as relative6, resolve as resolve16, sep as sep7, dirname as dirname17 } from "path";
6
6
  import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
7
7
 
8
8
  // src/types.ts
9
- var VERSION = "5.40.2";
9
+ var VERSION = "5.41.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -19922,7 +19922,7 @@ function opaqueLibrarySpecifiers(ast, elements) {
19922
19922
  }
19923
19923
 
19924
19924
  // src/glob.ts
19925
- import { existsSync as existsSync11, statSync as statSync6 } from "fs";
19925
+ import { existsSync as existsSync11, statSync as statSync10 } from "fs";
19926
19926
  import { join as join24, sep as sep3 } from "path";
19927
19927
 
19928
19928
  // src/util.ts
@@ -19958,13 +19958,18 @@ import { spawnSync } from "child_process";
19958
19958
  import { readdirSync, statSync, lstatSync, readFileSync as readFileSync2, realpathSync } from "fs";
19959
19959
  import { join, sep, extname as extname2 } from "path";
19960
19960
  import { createHash } from "crypto";
19961
- import { readFileSync as readFileSync22, existsSync } from "fs";
19961
+ import { readFileSync as readFileSync22, existsSync, statSync as statSync2 } from "fs";
19962
19962
  import { homedir } from "os";
19963
19963
  import { dirname, join as join2 } from "path";
19964
19964
  import { fileURLToPath } from "url";
19965
19965
  import { basename } from "path";
19966
19966
  import { readFileSync as readFileSync3 } from "fs";
19967
19967
  import { join as join3 } from "path";
19968
+ import { existsSync as existsSync2, statSync as statSync3 } from "fs";
19969
+ import * as os from "os";
19970
+ import { dirname as dirname2, join as join4 } from "path";
19971
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
19972
+ import { Worker } from "worker_threads";
19968
19973
  import { posix } from "path";
19969
19974
  import { join as join7 } from "path";
19970
19975
  import { posix as posix2 } from "path";
@@ -19972,11 +19977,11 @@ import { join as join8 } from "path";
19972
19977
  import { join as join9 } from "path";
19973
19978
  import { join as join10 } from "path";
19974
19979
  import { join as join11 } from "path";
19975
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
19976
- import { join as join12 } from "path";
19977
- import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
19978
- import { dirname as dirname4, join as join13 } from "path";
19979
- import { existsSync as existsSync5, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
19980
+ import { chmodSync, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
19981
+ import { basename as basename3, dirname as dirname4, join as join12 } from "path";
19982
+ import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync as rmSync3, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
19983
+ import { dirname as dirname5, join as join13 } from "path";
19984
+ import { existsSync as existsSync5, readdirSync as readdirSync3, statSync as statSync6 } from "fs";
19980
19985
  import { join as join14 } from "path";
19981
19986
  import { createHash as createHash3 } from "crypto";
19982
19987
  import { existsSync as existsSync6, readFileSync as readFileSync8 } from "fs";
@@ -19991,16 +19996,11 @@ import { spawn } from "child_process";
19991
19996
  import { existsSync as existsSync9 } from "fs";
19992
19997
  import { join as join20 } from "path";
19993
19998
  import { pathToFileURL as pathToFileURL2 } from "url";
19994
- import { statSync as statSync5 } from "fs";
19999
+ import { statSync as statSync7 } from "fs";
19995
20000
  import { join as join21 } from "path";
19996
- import { readFileSync as readFileSync12 } from "fs";
20001
+ import { readFileSync as readFileSync12, statSync as statSync8, watch as watchFs } from "fs";
19997
20002
  import { isAbsolute, join as join22 } from "path";
19998
20003
  import { createInterface } from "readline";
19999
- import { existsSync as existsSync2, statSync as statSync2 } from "fs";
20000
- import { availableParallelism } from "os";
20001
- import { dirname as dirname2, join as join4 } from "path";
20002
- import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
20003
- import { Worker } from "worker_threads";
20004
20004
  import { basename as basename2 } from "path";
20005
20005
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
20006
20006
  import { join as join5 } from "path";
@@ -20009,12 +20009,17 @@ import { existsSync as existsSync4, mkdirSync, mkdtempSync, readFileSync as read
20009
20009
  import { dirname as dirname3, join as join6, resolve, sep as sep2 } from "path";
20010
20010
  import { gunzipSync } from "zlib";
20011
20011
  import { join as join15 } from "path";
20012
- import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
20012
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync13, statSync as statSync9, writeFileSync as writeFileSync4 } from "fs";
20013
20013
  import { join as join23, resolve as resolve4 } from "path";
20014
20014
  var __defProp = Object.defineProperty;
20015
20015
  var __getOwnPropNames = Object.getOwnPropertyNames;
20016
- var __esm = (fn, res) => function __init() {
20017
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
20016
+ var __esm = (fn, res, err2) => function __init() {
20017
+ if (err2) throw err2[0];
20018
+ try {
20019
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
20020
+ } catch (e) {
20021
+ throw err2 = [e], e;
20022
+ }
20018
20023
  };
20019
20024
  var __export = (target, all) => {
20020
20025
  for (var name2 in all)
@@ -20026,9 +20031,9 @@ var EXTRACTOR_VERSION;
20026
20031
  var init_types = __esm({
20027
20032
  "src/types.ts"() {
20028
20033
  "use strict";
20029
- ENGINE_VERSION = "2.28.0";
20034
+ ENGINE_VERSION = "2.28.1";
20030
20035
  SCHEMA_VERSION2 = 5;
20031
- EXTRACTOR_VERSION = 13;
20036
+ EXTRACTOR_VERSION = 14;
20032
20037
  }
20033
20038
  });
20034
20039
  function sh(cmd, args2, opts = {}) {
@@ -20354,6 +20359,9 @@ var init_ignore = __esm({
20354
20359
  init_util();
20355
20360
  }
20356
20361
  });
20362
+ function isIgnoredDirectory(name2, ignoreDirs) {
20363
+ return ignoreDirs.has(name2) || name2.startsWith(".codeindex-edit-");
20364
+ }
20357
20365
  function walk(root, opts = {}) {
20358
20366
  const maxFileBytes = opts.maxFileBytes ?? 1024 * 1024;
20359
20367
  const maxFiles = opts.maxFiles ?? Infinity;
@@ -20402,7 +20410,7 @@ function walk(root, opts = {}) {
20402
20410
  const abs = join(frame.dir, name2);
20403
20411
  const rel2 = frame.rel ? `${frame.rel}/${name2}` : name2;
20404
20412
  const isLink = entry.isSymbolicLink();
20405
- if (entry.isDirectory() && ignoreDirs.has(name2)) continue;
20413
+ if (entry.isDirectory() && isIgnoredDirectory(name2, ignoreDirs)) continue;
20406
20414
  let st;
20407
20415
  try {
20408
20416
  st = isLink ? statSync(abs) : lstatSync(abs);
@@ -20410,7 +20418,7 @@ function walk(root, opts = {}) {
20410
20418
  continue;
20411
20419
  }
20412
20420
  if (st.isDirectory()) {
20413
- if (ignoreDirs.has(name2)) continue;
20421
+ if (isIgnoredDirectory(name2, ignoreDirs)) continue;
20414
20422
  if (isLink) continue;
20415
20423
  if (useGitignore && rules.length && isIgnored(rules, rel2, true)) continue;
20416
20424
  stack.push({ dir: abs, rel: rel2, rules });
@@ -25823,16 +25831,26 @@ async function ensureGrammars(keys) {
25823
25831
  parser = new Parser3();
25824
25832
  }
25825
25833
  for (const key2 of new Set(keys)) {
25826
- if (loaded.has(key2) || failed.has(key2)) continue;
25834
+ if (loaded.has(key2)) continue;
25827
25835
  const wasm = firstIn(`${key2}.wasm`);
25836
+ const fingerprint = wasm ? (() => {
25837
+ try {
25838
+ const st = statSync2(wasm);
25839
+ return `${wasm}:${st.size}:${st.mtimeMs}`;
25840
+ } catch {
25841
+ return `${wasm}:unreadable`;
25842
+ }
25843
+ })() : `missing:${dirs.join("|")}`;
25844
+ if (failed.get(key2) === fingerprint) continue;
25828
25845
  if (!wasm) {
25829
- failed.add(key2);
25846
+ failed.set(key2, fingerprint);
25830
25847
  continue;
25831
25848
  }
25832
25849
  try {
25833
25850
  loaded.set(key2, await Language.load(new Uint8Array(readFileSync22(wasm))));
25851
+ failed.delete(key2);
25834
25852
  } catch {
25835
- failed.add(key2);
25853
+ failed.set(key2, fingerprint);
25836
25854
  }
25837
25855
  }
25838
25856
  }
@@ -25935,7 +25953,7 @@ var init_loader = __esm({
25935
25953
  runtimeReady = false;
25936
25954
  parser = null;
25937
25955
  loaded = /* @__PURE__ */ new Map();
25938
- failed = /* @__PURE__ */ new Set();
25956
+ failed = /* @__PURE__ */ new Map();
25939
25957
  }
25940
25958
  });
25941
25959
  function findFirst(node, pred) {
@@ -28176,6 +28194,7 @@ function buildCodeRecord(rel2, ext2, size, content, hash, lang, opts = {}) {
28176
28194
  record.truncated = code2.truncated;
28177
28195
  record.relations = code2.relations;
28178
28196
  record.terms = code2.terms;
28197
+ record.literals = code2.literals;
28179
28198
  } else {
28180
28199
  record.title = basename(rel2);
28181
28200
  }
@@ -28254,7 +28273,7 @@ function scanRepo(root, opts = {}) {
28254
28273
  files.push(preUsable.record);
28255
28274
  continue;
28256
28275
  }
28257
- const record = {
28276
+ const record = kind === "code" ? buildCodeRecord(f.rel, f.ext, f.size, content, hash, lang, opts) : {
28258
28277
  rel: f.rel,
28259
28278
  ext: f.ext,
28260
28279
  size: f.size,
@@ -28266,37 +28285,21 @@ function scanRepo(root, opts = {}) {
28266
28285
  symbols: [],
28267
28286
  refs: []
28268
28287
  };
28269
- if (content) {
28270
- if (kind === "doc" && MARKDOWN_EXT.has(f.ext)) {
28288
+ if (kind !== "code") {
28289
+ if (content && kind === "doc" && MARKDOWN_EXT.has(f.ext)) {
28271
28290
  const md = extractMarkdown(content);
28272
28291
  record.title = md.title ?? basename(f.rel);
28273
28292
  record.summary = md.summary;
28274
28293
  record.headings = md.headings;
28275
28294
  record.refs = md.refs;
28276
- } else if (kind === "doc") {
28277
- record.title = basename(f.rel);
28278
- } else if (kind === "code") {
28279
- const code2 = extractCode(f.rel, f.ext, content, { maxCallsPerFile: opts.maxCallsPerFile });
28295
+ } else if (content && kind === "doc") {
28280
28296
  record.title = basename(f.rel);
28281
- record.summary = code2.summary;
28282
- record.symbols = code2.symbols;
28283
- record.refs = code2.refs;
28284
- record.pkg = code2.pkg;
28285
- record.idents = code2.idents;
28286
- record.calls = code2.calls;
28287
- record.importedNames = code2.importedNames;
28288
- record.truncated = code2.truncated;
28289
- record.relations = code2.relations;
28290
- record.terms = code2.terms;
28291
- record.literals = code2.literals;
28292
- } else if (kind === "config") {
28297
+ } else if (content && kind === "config") {
28293
28298
  record.title = basename(f.rel);
28294
28299
  record.literals = extractConfigLiterals(content);
28295
28300
  } else {
28296
28301
  record.title = basename(f.rel);
28297
28302
  }
28298
- } else {
28299
- record.title = basename(f.rel);
28300
28303
  }
28301
28304
  if (kind === "doc" && content) docText.set(f.rel, content);
28302
28305
  files.push(record);
@@ -28339,6 +28342,13 @@ function toCacheMap(scan2) {
28339
28342
  for (const f of scan2.files) m.set(f.rel, { hash: f.hash, record: f, size: f.size, mtimeMs: scan2.mtimes.get(f.rel) });
28340
28343
  return m;
28341
28344
  }
28345
+ function needsGrammarWarm(walked, cache, fullHash = false) {
28346
+ const codeFiles = walked.files.filter((file) => classify(file.rel, file.ext) === "code");
28347
+ return fullHash && codeFiles.length > 0 || codeFiles.some((file) => {
28348
+ const cached = cache.get(file.rel);
28349
+ return !cached || cached.size !== file.size || cached.mtimeMs !== file.mtimeMs;
28350
+ });
28351
+ }
28342
28352
  function readPersistedIndex(repo, indexDir = INDEX_DIR) {
28343
28353
  let parsed;
28344
28354
  try {
@@ -28390,6 +28400,34 @@ function preloadSession(repo, opts, indexDir = INDEX_DIR) {
28390
28400
  const scan2 = scanRepo(repo, { ...opts, cache: persisted.cacheMap });
28391
28401
  return { scan: scan2, cacheMap: toCacheMap(scan2), arts: preloadArtifacts(repo, scan2, persisted.meta, indexDir) };
28392
28402
  }
28403
+ async function preloadSessionLazy(repo, opts, warm, indexDir = INDEX_DIR) {
28404
+ const persisted = readPersistedIndex(repo, indexDir);
28405
+ if (!persisted) return void 0;
28406
+ const walked = opts.precomputedWalk ?? walk(repo, {
28407
+ maxFileBytes: opts.maxBytes,
28408
+ maxFiles: opts.maxFiles,
28409
+ gitignore: opts.gitignore,
28410
+ ignoreDirs: opts.ignoreDirs
28411
+ });
28412
+ const needsWarm = needsGrammarWarm(walked, persisted.cacheMap, opts.fullHash);
28413
+ if (needsWarm) {
28414
+ await warm();
28415
+ }
28416
+ const scan2 = scanRepo(repo, { ...opts, cache: persisted.cacheMap, precomputedWalk: walked });
28417
+ let artifactsTried = false;
28418
+ let artifacts;
28419
+ return {
28420
+ scan: scan2,
28421
+ cacheMap: toCacheMap(scan2),
28422
+ loadArtifacts: () => {
28423
+ if (!artifactsTried) {
28424
+ artifactsTried = true;
28425
+ artifacts = preloadArtifacts(repo, scan2, persisted.meta, indexDir);
28426
+ }
28427
+ return artifacts;
28428
+ }
28429
+ };
28430
+ }
28393
28431
  var INDEX_DIR;
28394
28432
  var init_preload = __esm({
28395
28433
  "src/preload.ts"() {
@@ -28397,9 +28435,144 @@ var init_preload = __esm({
28397
28435
  init_types();
28398
28436
  init_scan();
28399
28437
  init_hash();
28438
+ init_walk();
28439
+ init_classify();
28400
28440
  INDEX_DIR = ".codeindex";
28401
28441
  }
28402
28442
  });
28443
+ function resolveEngineUrl() {
28444
+ try {
28445
+ const here = fileURLToPath2(import.meta.url);
28446
+ if (here.endsWith("engine.mjs")) return pathToFileURL(here).href;
28447
+ const adjacent = join4(dirname2(here), "engine.mjs");
28448
+ if (existsSync2(adjacent)) return pathToFileURL(adjacent).href;
28449
+ return void 0;
28450
+ } catch {
28451
+ return void 0;
28452
+ }
28453
+ }
28454
+ function workerCount(requested) {
28455
+ const env = process.env["CODEINDEX_WORKERS"];
28456
+ const raw = requested ?? (env !== void 0 && env !== "" ? Number(env) : void 0);
28457
+ if (raw !== void 0) return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 0;
28458
+ let cores = 1;
28459
+ try {
28460
+ cores = typeof os.availableParallelism === "function" ? os.availableParallelism() : os.cpus().length;
28461
+ } catch {
28462
+ cores = 1;
28463
+ }
28464
+ return Math.max(0, Math.min(cores - 1, 8));
28465
+ }
28466
+ async function runExtractWorker(input, post) {
28467
+ await ensureGrammars(input.grammarKeys);
28468
+ const ready = input.grammarKeys.filter((k) => grammarReady(k));
28469
+ const records = [];
28470
+ for (const job of input.jobs) {
28471
+ let size;
28472
+ let mtimeMs;
28473
+ try {
28474
+ const st = statSync3(job.abs);
28475
+ size = st.size;
28476
+ mtimeMs = st.mtimeMs;
28477
+ } catch {
28478
+ continue;
28479
+ }
28480
+ const content = readText2(job.abs);
28481
+ const record = buildCodeRecord(job.rel, job.ext, size, content, sha1(content), extToLang(job.ext), {
28482
+ maxCallsPerFile: input.maxCallsPerFile
28483
+ });
28484
+ records.push({ rel: job.rel, size, mtimeMs, record });
28485
+ }
28486
+ post({ ready, records });
28487
+ }
28488
+ async function extractInParallel(jobs, grammarKeys, count, opts = {}) {
28489
+ if (count < 2 || jobs.length === 0) return void 0;
28490
+ const engineUrl = resolveEngineUrl();
28491
+ if (!engineUrl) return void 0;
28492
+ const wanted = grammarKeys.filter((k) => grammarReady(k)).sort();
28493
+ const shards = Array.from({ length: Math.min(count, jobs.length) }, () => []);
28494
+ jobs.forEach((j, i2) => shards[i2 % shards.length].push(j));
28495
+ const bootstrap = `import { runExtractWorker } from ${JSON.stringify(engineUrl)};
28496
+ import { parentPort, workerData } from "node:worker_threads";
28497
+ runExtractWorker(workerData.input, (o) => parentPort.postMessage(o)).catch((e) => parentPort.postMessage({ error: String(e) }));
28498
+ `;
28499
+ try {
28500
+ const outputs = await Promise.all(
28501
+ shards.map(
28502
+ (jobsForShard) => new Promise((resolve52, reject) => {
28503
+ const w = new Worker(bootstrap, {
28504
+ eval: true,
28505
+ workerData: { input: { jobs: jobsForShard, grammarKeys: wanted, maxCallsPerFile: opts.maxCallsPerFile } }
28506
+ });
28507
+ const timer = setTimeout(() => {
28508
+ reject(new Error("extraction worker timed out"));
28509
+ void w.terminate();
28510
+ }, WORKER_TIMEOUT_MS);
28511
+ const settle = (fn) => {
28512
+ clearTimeout(timer);
28513
+ fn();
28514
+ };
28515
+ w.once("message", (m) => {
28516
+ settle(() => resolve52(m));
28517
+ void w.terminate();
28518
+ });
28519
+ w.once("error", (e) => settle(() => reject(e)));
28520
+ w.once("exit", (code2) => {
28521
+ if (code2 !== 0) settle(() => reject(new Error(`extraction worker exited with ${code2}`)));
28522
+ });
28523
+ })
28524
+ )
28525
+ );
28526
+ const out2 = /* @__PURE__ */ new Map();
28527
+ for (const o of outputs) {
28528
+ if ("error" in o) return void 0;
28529
+ if (o.ready.slice().sort().join(",") !== wanted.join(",")) return void 0;
28530
+ for (const r of o.records) out2.set(r.rel, { size: r.size, mtimeMs: r.mtimeMs, record: r.record });
28531
+ }
28532
+ return out2;
28533
+ } catch {
28534
+ return void 0;
28535
+ }
28536
+ }
28537
+ async function scanRepoParallel(root, opts = {}) {
28538
+ const count = workerCount(opts.workers);
28539
+ if (count < 2) return scanRepo(root, opts);
28540
+ const walked = opts.precomputedWalk ?? walk(root, {
28541
+ maxFileBytes: opts.maxBytes,
28542
+ maxFiles: opts.maxFiles,
28543
+ gitignore: opts.gitignore,
28544
+ ignoreDirs: opts.ignoreDirs
28545
+ });
28546
+ const scanOpts = { ...opts, precomputedWalk: walked };
28547
+ const jobs = [];
28548
+ for (const { f } of keptCodeFiles(root, scanOpts)) {
28549
+ const cached = opts.cache?.get(f.rel);
28550
+ if (!opts.fullHash && cached && cached.size !== void 0 && cached.mtimeMs !== void 0 && cached.size === f.size && cached.mtimeMs === f.mtimeMs) {
28551
+ continue;
28552
+ }
28553
+ jobs.push({ abs: f.abs, rel: f.rel, ext: f.ext });
28554
+ }
28555
+ if (jobs.length === 0) return scanRepo(root, scanOpts);
28556
+ const workersForced = opts.workers !== void 0 || (process.env["CODEINDEX_WORKERS"] ?? "") !== "";
28557
+ if (!workersForced && jobs.length < DEFAULT_MIN_PARALLEL_JOBS) return scanRepo(root, scanOpts);
28558
+ const grammarKeys = grammarKeysForExts(walked.files.map((f) => f.ext));
28559
+ const extracted = await extractInParallel(jobs, grammarKeys, count, { maxCallsPerFile: opts.maxCallsPerFile });
28560
+ return scanRepo(root, extracted ? { ...scanOpts, extracted } : scanOpts);
28561
+ }
28562
+ var WORKER_TIMEOUT_MS;
28563
+ var DEFAULT_MIN_PARALLEL_JOBS;
28564
+ var init_pool = __esm({
28565
+ "src/pool.ts"() {
28566
+ "use strict";
28567
+ init_hash();
28568
+ init_walk();
28569
+ init_registry();
28570
+ init_loader();
28571
+ init_scan();
28572
+ WORKER_TIMEOUT_MS = 10 * 60 * 1e3;
28573
+ DEFAULT_MIN_PARALLEL_JOBS = 200;
28574
+ }
28575
+ });
28403
28576
  function distToSrcCandidates(target) {
28404
28577
  const segs = norm(target).split("/").filter((s) => s !== ".");
28405
28578
  const out2 = [];
@@ -29512,6 +29685,17 @@ function buildCallerIndex(scan2, importPairs, opts = {}) {
29512
29685
  arr.push(s);
29513
29686
  }
29514
29687
  }
29688
+ const defsByFamily = /* @__PURE__ */ new Map();
29689
+ for (const [name2, sites2] of defs) {
29690
+ const families = /* @__PURE__ */ new Map();
29691
+ for (const site of sites2) {
29692
+ const family = familyOf(site.lang);
29693
+ let grouped = families.get(family);
29694
+ if (!grouped) families.set(family, grouped = []);
29695
+ grouped.push(site);
29696
+ }
29697
+ defsByFamily.set(name2, families);
29698
+ }
29515
29699
  const localDefs = /* @__PURE__ */ new Map();
29516
29700
  for (const f of scan2.files) {
29517
29701
  const byName = /* @__PURE__ */ new Map();
@@ -29537,7 +29721,7 @@ function buildCallerIndex(scan2, importPairs, opts = {}) {
29537
29721
  record(local, recall ? { file: f.rel, line: c2.line, confidence: "corroborated" } : { file: f.rel, line: c2.line });
29538
29722
  continue;
29539
29723
  }
29540
- const cands = (defs.get(c2.name) ?? []).filter((d) => familyOf(d.lang) === family && d.file !== f.rel).map((d) => ({ file: d.file, lang: d.lang }));
29724
+ const cands = (defsByFamily.get(c2.name)?.get(family) ?? []).filter((d) => d.file !== f.rel);
29541
29725
  if (!cands.length) continue;
29542
29726
  const imported = cands.filter((d) => pairs.has(`${f.rel}|${d.file}`));
29543
29727
  const chosen = family === "js" ? imported.length ? pickCandidate(f.rel, imported) : (
@@ -29546,7 +29730,7 @@ function buildCallerIndex(scan2, importPairs, opts = {}) {
29546
29730
  recall && cands.length === 1 ? cands[0] : void 0
29547
29731
  ) : imported.length ? pickCandidate(f.rel, imported) : pickCandidate(f.rel, cands);
29548
29732
  if (!chosen) continue;
29549
- const def = defs.get(c2.name).find((d) => d.file === chosen.file);
29733
+ const def = chosen;
29550
29734
  record(
29551
29735
  def,
29552
29736
  recall ? { file: f.rel, line: c2.line, confidence: imported.length ? "corroborated" : "unique-name" } : { file: f.rel, line: c2.line }
@@ -30328,6 +30512,25 @@ function cacheFor(scan2) {
30328
30512
  if (!c2) caches.set(scan2, c2 = {});
30329
30513
  return c2;
30330
30514
  }
30515
+ function fileByRelFor(scan2) {
30516
+ const c2 = cacheFor(scan2);
30517
+ return c2.fileByRel ??= new Map(scan2.files.map((file) => [file.rel, file]));
30518
+ }
30519
+ function symbolsByNameFor(scan2) {
30520
+ const c2 = cacheFor(scan2);
30521
+ if (!c2.symbolsByName) {
30522
+ const byName = /* @__PURE__ */ new Map();
30523
+ for (const file of scan2.files) {
30524
+ for (const symbol of file.symbols) {
30525
+ const group = byName.get(symbol.name);
30526
+ if (group) group.push(symbol);
30527
+ else byName.set(symbol.name, [symbol]);
30528
+ }
30529
+ }
30530
+ c2.symbolsByName = byName;
30531
+ }
30532
+ return c2.symbolsByName;
30533
+ }
30331
30534
  function resolveContextFor(scan2) {
30332
30535
  const c2 = cacheFor(scan2);
30333
30536
  return c2.resolveCtx ??= buildResolveContext(scan2);
@@ -30630,8 +30833,11 @@ var init_graph = __esm({
30630
30833
  keyOf = (from, to, kind) => `${from}${SEP3}${to}${SEP3}${kind}`;
30631
30834
  }
30632
30835
  });
30836
+ function* allSymbols(scan2) {
30837
+ for (const file of scan2.files) yield* file.symbols;
30838
+ }
30633
30839
  function symbolsOverview(scan2, rel2) {
30634
- const f = scan2.files.find((x) => x.rel === rel2);
30840
+ const f = fileByRelFor(scan2).get(rel2);
30635
30841
  if (!f) return [];
30636
30842
  return [...f.symbols].filter((s) => !REFERENCE_KINDS5.has(s.kind)).sort((a, b) => a.line - b.line || byStr(a.name, b.name));
30637
30843
  }
@@ -30642,27 +30848,37 @@ function findSymbol(scan2, namePath, opts = {}) {
30642
30848
  const parents = segments.slice(0, -1);
30643
30849
  const matchName = (name2, wanted) => opts.substring ? name2.toLowerCase().includes(wanted.toLowerCase()) : name2 === wanted;
30644
30850
  const out2 = [];
30645
- for (const f of scan2.files) {
30646
- for (const s of f.symbols) {
30647
- if (REFERENCE_KINDS5.has(s.kind)) continue;
30648
- if (!matchName(s.name, leaf)) continue;
30649
- if (parents.length) {
30650
- const parent = parents[parents.length - 1];
30651
- if (!s.parent || s.parent !== parent) continue;
30652
- }
30653
- out2.push({ ...s });
30851
+ const candidates2 = opts.substring ? allSymbols(scan2) : symbolsByNameFor(scan2).get(leaf) ?? [];
30852
+ for (const s of candidates2) {
30853
+ if (REFERENCE_KINDS5.has(s.kind)) continue;
30854
+ if (!matchName(s.name, leaf)) continue;
30855
+ if (parents.length) {
30856
+ const parent = parents[parents.length - 1];
30857
+ if (!s.parent || s.parent !== parent) continue;
30654
30858
  }
30859
+ out2.push({ ...s });
30655
30860
  }
30656
30861
  out2.sort(
30657
30862
  (a, b) => Number(b.name === leaf) - Number(a.name === leaf) || byStr(a.file, b.file) || a.line - b.line
30658
30863
  );
30659
30864
  const capped = out2.slice(0, opts.maxResults ?? 50);
30660
30865
  if (opts.includeBody) {
30866
+ const linesByFile = /* @__PURE__ */ new Map();
30867
+ const unreadableFiles = /* @__PURE__ */ new Set();
30661
30868
  for (const m of capped) {
30662
30869
  const end = m.endLine ?? m.line;
30663
- const content = readText2(join11(scan2.root, m.file));
30664
- if (!content) continue;
30665
- m.body = content.split("\n").slice(m.line - 1, end).join("\n");
30870
+ if (unreadableFiles.has(m.file)) continue;
30871
+ let lines = linesByFile.get(m.file);
30872
+ if (!lines) {
30873
+ const content = readText2(join11(scan2.root, m.file));
30874
+ if (!content) {
30875
+ unreadableFiles.add(m.file);
30876
+ continue;
30877
+ }
30878
+ lines = content.split("\n");
30879
+ linesByFile.set(m.file, lines);
30880
+ }
30881
+ m.body = lines.slice(m.line - 1, end).join("\n");
30666
30882
  }
30667
30883
  }
30668
30884
  if (opts.concise) {
@@ -30727,6 +30943,34 @@ function resolveUniqueSymbol(scan2, namePath, file) {
30727
30943
  function readLines(abs) {
30728
30944
  return readFileSync6(abs, "utf8").split("\n");
30729
30945
  }
30946
+ function atomicWriteText(abs, content, cleanup = rmSync2) {
30947
+ const target = realpathSync2(abs);
30948
+ const mode = statSync4(target).mode;
30949
+ let tempDir;
30950
+ try {
30951
+ tempDir = mkdtempSync2(join12(dirname4(target), ".codeindex-edit-"));
30952
+ } catch {
30953
+ writeFileSync2(target, content);
30954
+ chmodSync(target, mode);
30955
+ return;
30956
+ }
30957
+ const tempFile = join12(tempDir, basename3(target));
30958
+ try {
30959
+ writeFileSync2(tempFile, content);
30960
+ chmodSync(tempFile, mode);
30961
+ try {
30962
+ renameSync2(tempFile, target);
30963
+ } catch {
30964
+ writeFileSync2(target, content);
30965
+ chmodSync(target, mode);
30966
+ }
30967
+ } finally {
30968
+ try {
30969
+ cleanup(tempDir, { recursive: true, force: true });
30970
+ } catch {
30971
+ }
30972
+ }
30973
+ }
30730
30974
  function replaceSymbolBody(scan2, namePath, body22, file) {
30731
30975
  const sym = resolveUniqueSymbol(scan2, namePath, file);
30732
30976
  const end = sym.endLine ?? sym.line;
@@ -30734,7 +30978,7 @@ function replaceSymbolBody(scan2, namePath, body22, file) {
30734
30978
  const lines = readLines(abs);
30735
30979
  const newLines = body22.replace(/^\n+|\n+$/g, "").split("\n");
30736
30980
  lines.splice(sym.line - 1, end - sym.line + 1, ...newLines);
30737
- writeFileSync2(abs, lines.join("\n"));
30981
+ atomicWriteText(abs, lines.join("\n"));
30738
30982
  return { file: sym.file, startLine: sym.line, endLine: sym.line + newLines.length - 1, lines: newLines.length };
30739
30983
  }
30740
30984
  function insertAt(scan2, sym, body22, index, blankBefore, blankAfter) {
@@ -30747,7 +30991,7 @@ function insertAt(scan2, sym, body22, index, blankBefore, blankAfter) {
30747
30991
  block.push(...newLines);
30748
30992
  if (blankAfter && minGap && lines[index]?.trim() !== "") block.push("");
30749
30993
  lines.splice(index, 0, ...block);
30750
- writeFileSync2(abs, lines.join("\n"));
30994
+ atomicWriteText(abs, lines.join("\n"));
30751
30995
  return { file: sym.file, startLine: index + 1, endLine: index + block.length, lines: block.length };
30752
30996
  }
30753
30997
  function insertAfterSymbol(scan2, namePath, body22, file) {
@@ -30784,7 +31028,7 @@ function memoryPath(repo, name2) {
30784
31028
  }
30785
31029
  function writeMemory(repo, name2, content) {
30786
31030
  const path = memoryPath(repo, name2);
30787
- mkdirSync2(dirname4(path), { recursive: true });
31031
+ mkdirSync2(dirname5(path), { recursive: true });
30788
31032
  writeFileSync3(path, content.endsWith("\n") ? content : content + "\n");
30789
31033
  return sanitize(name2);
30790
31034
  }
@@ -30798,11 +31042,11 @@ function readMemory(repo, name2) {
30798
31042
  function deleteMemory(repo, name2) {
30799
31043
  const path = memoryPath(repo, name2);
30800
31044
  try {
30801
- statSync3(path);
31045
+ statSync5(path);
30802
31046
  } catch {
30803
31047
  return false;
30804
31048
  }
30805
- rmSync2(path);
31049
+ rmSync3(path);
30806
31050
  return true;
30807
31051
  }
30808
31052
  function listMemories(repo) {
@@ -30997,7 +31241,7 @@ function addPackage(root, dir, found, kind, warnings) {
30997
31241
  }
30998
31242
  function isDirAt(root, rel2) {
30999
31243
  try {
31000
- return statSync4(join14(root, rel2)).isDirectory();
31244
+ return statSync6(join14(root, rel2)).isDirectory();
31001
31245
  } catch {
31002
31246
  return false;
31003
31247
  }
@@ -32155,31 +32399,31 @@ function serializeEmbeddings(index) {
32155
32399
  count: index.records.length,
32156
32400
  records: index.records.map((r) => ({ file: r.file, symbol: r.symbol ?? "", line: r.line ?? 0 }))
32157
32401
  });
32158
- const headerBuf = Buffer.from(header4, "utf8");
32159
- const body22 = Buffer.alloc(index.records.length * index.dim);
32160
- let off = 0;
32402
+ const headerBuf = new TextEncoder().encode(header4);
32403
+ const bodyLength = index.records.length * index.dim;
32404
+ const out2 = new Uint8Array(8 + headerBuf.length + bodyLength);
32405
+ out2.set([67, 73, 69, 49], 0);
32406
+ new DataView(out2.buffer, out2.byteOffset, out2.byteLength).setUint32(4, headerBuf.length, true);
32407
+ out2.set(headerBuf, 8);
32408
+ let off = 8 + headerBuf.length;
32161
32409
  for (const r of index.records) {
32162
- for (let d = 0; d < index.dim; d++) body22.writeInt8(r.vec[d] ?? 0, off++);
32410
+ for (let d = 0; d < index.dim; d++) out2[off++] = r.vec[d] ?? 0;
32163
32411
  }
32164
- const out2 = Buffer.alloc(8 + headerBuf.length + body22.length);
32165
- out2.write(MAGIC, 0, "ascii");
32166
- out2.writeUInt32LE(headerBuf.length, 4);
32167
- headerBuf.copy(out2, 8);
32168
- body22.copy(out2, 8 + headerBuf.length);
32169
32412
  return out2;
32170
32413
  }
32171
32414
  function deserializeEmbeddings(bytes) {
32172
- const buf = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
32173
- if (buf.length < 8 || buf.toString("ascii", 0, 4) !== MAGIC) {
32415
+ if (bytes.byteLength < 8 || String.fromCharCode(...bytes.subarray(0, 4)) !== MAGIC) {
32174
32416
  throw new Error("embeddings.bin: bad magic (not a codeindex embeddings artifact)");
32175
32417
  }
32176
- const headerLen = buf.readUInt32LE(4);
32177
- const header4 = JSON.parse(buf.toString("utf8", 8, 8 + headerLen));
32418
+ const data2 = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
32419
+ const headerLen = data2.getUint32(4, true);
32420
+ if (8 + headerLen > bytes.byteLength) throw new Error("embeddings.bin: truncated header");
32421
+ const header4 = JSON.parse(new TextDecoder().decode(bytes.subarray(8, 8 + headerLen)));
32178
32422
  const bodyOff = 8 + headerLen;
32179
32423
  const { dim } = header4;
32424
+ if (bodyOff + header4.records.length * dim > bytes.byteLength) throw new Error("embeddings.bin: truncated body");
32180
32425
  const records = header4.records.map((m, i2) => {
32181
- const vec = new Int8Array(dim);
32182
- for (let d = 0; d < dim; d++) vec[d] = buf.readInt8(bodyOff + i2 * dim + d);
32426
+ const vec = new Int8Array(bytes.buffer.slice(bytes.byteOffset + bodyOff + i2 * dim, bytes.byteOffset + bodyOff + (i2 + 1) * dim));
32183
32427
  const rec = { file: m.file, vec };
32184
32428
  if (m.symbol) rec.symbol = m.symbol;
32185
32429
  if (m.line) rec.line = m.line;
@@ -32546,18 +32790,33 @@ function createFramer() {
32546
32790
  };
32547
32791
  }
32548
32792
  function fileUri(root, rel2) {
32549
- const abs = `${root.replace(/\/+$/, "")}/${rel2.replace(/^\/+/, "")}`;
32793
+ const rootPath = root.replace(/\\/g, "/").replace(/\/+$/, "");
32794
+ const relPath = rel2.replace(/\\/g, "/").replace(/^\/+/, "");
32795
+ const abs = `${rootPath}/${relPath}`;
32796
+ if (abs.startsWith("//")) {
32797
+ const [host = "", ...segments] = abs.slice(2).split("/");
32798
+ return `file://${encodeURIComponent(host)}/${segments.map(encodeURIComponent).join("/")}`;
32799
+ }
32550
32800
  const drive = /^([A-Za-z]):/.exec(abs);
32551
32801
  const path = drive ? `/${abs}` : abs;
32552
- return "file://" + path.split("/").map((segment, i2) => i2 === 0 ? segment : encodeURIComponent(segment)).join("/");
32802
+ return "file://" + path.split("/").map((segment, i2) => i2 === 0 || i2 === 1 && /^[A-Za-z]:$/.test(segment) ? segment : encodeURIComponent(segment)).join("/");
32553
32803
  }
32554
32804
  function relFromUri(root, uri) {
32555
32805
  if (!uri.startsWith("file://")) return void 0;
32556
- let path = decodeURIComponent(uri.slice("file://".length));
32806
+ let path;
32807
+ try {
32808
+ const encoded = uri.slice("file://".length);
32809
+ path = decodeURIComponent(encoded.startsWith("/") ? encoded : `//${encoded}`).replace(/\\/g, "/");
32810
+ } catch {
32811
+ return void 0;
32812
+ }
32557
32813
  if (/^\/[A-Za-z]:/.test(path)) path = path.slice(1);
32558
- const base = root.replace(/\/+$/, "");
32559
- if (path === base) return "";
32560
- if (!path.startsWith(`${base}/`)) return void 0;
32814
+ const base = root.replace(/\\/g, "/").replace(/\/+$/, "");
32815
+ const windows = /^[A-Za-z]:/.test(base) || base.startsWith("//");
32816
+ const comparablePath = windows ? path.toLowerCase() : path;
32817
+ const comparableBase = windows ? base.toLowerCase() : base;
32818
+ if (comparablePath === comparableBase) return "";
32819
+ if (!comparablePath.startsWith(`${comparableBase}/`)) return void 0;
32561
32820
  return path.slice(base.length + 1);
32562
32821
  }
32563
32822
  function locationsToRefs(root, raw) {
@@ -33350,9 +33609,13 @@ function validateArgs(schema, args2) {
33350
33609
  if (!spec?.type) continue;
33351
33610
  const actual = Array.isArray(value) ? "array" : typeof value;
33352
33611
  if (spec.type === "number") {
33353
- if (actual === "number") continue;
33354
- if (actual === "string" && Number.isFinite(Number(value)) && value.trim() !== "") continue;
33355
- return `\`${key2}\` must be a number, got ${actual === "string" ? JSON.stringify(value) : actual}`;
33612
+ const numeric = actual === "number" ? value : actual === "string" && value.trim() !== "" ? Number(value) : NaN;
33613
+ if (!Number.isFinite(numeric)) {
33614
+ return `\`${key2}\` must be a number, got ${actual === "string" ? JSON.stringify(value) : actual}`;
33615
+ }
33616
+ if (spec.minimum !== void 0 && numeric < spec.minimum) return `\`${key2}\` must be at least ${spec.minimum}`;
33617
+ if (spec.maximum !== void 0 && numeric > spec.maximum) return `\`${key2}\` must be at most ${spec.maximum}`;
33618
+ continue;
33356
33619
  }
33357
33620
  if (spec.type === "array") {
33358
33621
  if (actual !== "array") return `\`${key2}\` must be an array of strings, got ${actual}`;
@@ -33580,7 +33843,7 @@ var init_tools = __esm({
33580
33843
  type: "boolean",
33581
33844
  description: "Return only name/kind/file/line \u2014 drop the signature, line span, visibility and language. Roughly 2.5x smaller; use it when you are resolving a path and nothing more (default false)."
33582
33845
  },
33583
- maxResults: { type: "number", description: "Cap matches (default 50)" }
33846
+ maxResults: { type: "number", minimum: 1, description: "Cap matches (default 50)" }
33584
33847
  },
33585
33848
  required: ["repo", "namePath"]
33586
33849
  }
@@ -33620,7 +33883,7 @@ var init_tools = __esm({
33620
33883
  type: "object",
33621
33884
  properties: {
33622
33885
  ...repoProp,
33623
- budgetTokens: { type: "number", description: "Token budget for the key-files section (default 900)" },
33886
+ budgetTokens: { type: "number", minimum: 1, description: "Token budget for the key-files section (default 900)" },
33624
33887
  remember: { type: "boolean", description: "Persist the brief as the `onboarding` memory (default true)" }
33625
33888
  },
33626
33889
  required: ["repo"]
@@ -33631,7 +33894,7 @@ var init_tools = __esm({
33631
33894
  description: "Token-budgeted map of the repository: the highest-PageRank files with their key exported signatures, deterministically rendered to fit `budgetTokens` (default 1024). The densest single read to understand an unfamiliar codebase.",
33632
33895
  inputSchema: {
33633
33896
  type: "object",
33634
- properties: { ...repoProp, budgetTokens: { type: "number", description: "Approximate token budget (default 1024)" } },
33897
+ properties: { ...repoProp, budgetTokens: { type: "number", minimum: 1, description: "Approximate token budget (default 1024)" } },
33635
33898
  required: ["repo"]
33636
33899
  }
33637
33900
  },
@@ -33725,7 +33988,7 @@ var init_tools = __esm({
33725
33988
  properties: {
33726
33989
  ...repoProp,
33727
33990
  ...scopeProps,
33728
- limit: { type: "number", description: "Cap entries (default: all)" }
33991
+ limit: { type: "number", minimum: 0, description: "Cap entries (default: all)" }
33729
33992
  },
33730
33993
  required: ["repo"]
33731
33994
  }
@@ -33738,10 +34001,10 @@ var init_tools = __esm({
33738
34001
  properties: {
33739
34002
  ...repoProp,
33740
34003
  ...scopeProps,
33741
- minFiles: { type: "number", description: "Distinct files a value must span (default 2)" },
33742
- minCount: { type: "number", description: "Total occurrences required (default 3)" },
34004
+ minFiles: { type: "number", minimum: 1, description: "Distinct files a value must span (default 2)" },
34005
+ minCount: { type: "number", minimum: 1, description: "Total occurrences required (default 3)" },
33743
34006
  includeTests: { type: "boolean", description: "Count test files too (default false)" },
33744
- limit: { type: "number", description: "Cap duplications (default: all)" }
34007
+ limit: { type: "number", minimum: 0, description: "Cap duplications (default: all)" }
33745
34008
  },
33746
34009
  required: ["repo"]
33747
34010
  }
@@ -33751,7 +34014,13 @@ var init_tools = __esm({
33751
34014
  description: "Cyclomatic-complexity estimates (branch-token counting over AST line spans), most-complex first. Pass `file` for one file's symbols, omit for the repo-wide top. Combine with hotspots: the `risk` field of this tool's sibling ranks complexity \xD7 churn.",
33752
34015
  inputSchema: {
33753
34016
  type: "object",
33754
- properties: { ...repoProp, file: { type: "string" }, risk: { type: "boolean", description: "Return complexity \xD7 git-churn risk ranking instead" } },
34017
+ properties: {
34018
+ ...repoProp,
34019
+ file: { type: "string" },
34020
+ risk: { type: "boolean", description: "Return complexity \xD7 git-churn risk ranking instead" },
34021
+ since: { type: "string", description: "Only count risk churn after this ref" },
34022
+ top: { type: "number", minimum: 1, description: "Cap ranked symbols" }
34023
+ },
33755
34024
  required: ["repo"]
33756
34025
  }
33757
34026
  },
@@ -33760,7 +34029,11 @@ var init_tools = __esm({
33760
34029
  description: "Mermaid diagram of the module graph (renders inline in Claude/GitHub \u2014 no graph database). Optionally scoped to one module's neighborhood.",
33761
34030
  inputSchema: {
33762
34031
  type: "object",
33763
- properties: { ...repoProp, module: { type: "string", description: "Module slug to focus on" } },
34032
+ properties: {
34033
+ ...repoProp,
34034
+ module: { type: "string", description: "Module slug to focus on" },
34035
+ maxEdges: { type: "number", minimum: 1, description: "Cap rendered edges" }
34036
+ },
33764
34037
  required: ["repo"]
33765
34038
  }
33766
34039
  },
@@ -33775,7 +34048,7 @@ var init_tools = __esm({
33775
34048
  scope: { type: "string", description: "Restrict to one directory (repo-relative)" },
33776
34049
  globs: { type: "array", items: { type: "string" }, description: "Restrict to matching paths" },
33777
34050
  ignoreCase: { type: "boolean" },
33778
- maxHits: { type: "number" }
34051
+ maxHits: { type: "number", minimum: 1 }
33779
34052
  },
33780
34053
  required: ["repo", "pattern"]
33781
34054
  }
@@ -33789,7 +34062,7 @@ var init_tools = __esm({
33789
34062
  ...repoProp,
33790
34063
  ...scopeProps,
33791
34064
  query: { type: "string", description: "Natural-language or identifier query" },
33792
- limit: { type: "number", description: "Max results (default 20)" },
34065
+ limit: { type: "number", minimum: 0, description: "Max results (default 20)" },
33793
34066
  fuzzy: {
33794
34067
  type: "boolean",
33795
34068
  description: 'Fallback for query terms with zero document frequency: a morphological stem match first ("caching" finds "cache"), then trigram similarity for typos (default true)'
@@ -33823,7 +34096,7 @@ var init_tools = __esm({
33823
34096
  ...repoProp,
33824
34097
  ...scopeProps,
33825
34098
  query: { type: "string", description: "Natural-language or identifier query" },
33826
- limit: { type: "number", description: "Max results (default 20)" },
34099
+ limit: { type: "number", minimum: 0, description: "Max results (default 20)" },
33827
34100
  fuzzy: { type: "boolean", description: "Stem/trigram fallback for zero-document-frequency terms (default true)" },
33828
34101
  exact: { type: "boolean", description: "Drop results carrying no verbatim term match (default false)" }
33829
34102
  },
@@ -33861,7 +34134,7 @@ var init_tools = __esm({
33861
34134
  properties: {
33862
34135
  ...repoProp,
33863
34136
  symbol: { type: "string", description: "Symbol name to centre on" },
33864
- depth: { type: "number", description: "Hops to follow (default 2, max 5)" },
34137
+ depth: { type: "number", minimum: 1, maximum: 5, description: "Hops to follow (default 2, max 5)" },
33865
34138
  direction: { type: "string", description: "out | in | both (default both)" }
33866
34139
  },
33867
34140
  required: ["repo", "symbol"]
@@ -34125,7 +34398,7 @@ async function memoizedEmbeddingIndex(key2, build) {
34125
34398
  function memoizedEmbedModel(modelDir) {
34126
34399
  let stat;
34127
34400
  try {
34128
- stat = statSync5(join21(modelDir, "model.json"));
34401
+ stat = statSync7(join21(modelDir, "model.json"));
34129
34402
  } catch {
34130
34403
  return void 0;
34131
34404
  }
@@ -34152,6 +34425,14 @@ function sessionPut(entry) {
34152
34425
  function sessionClear() {
34153
34426
  sessionCaches.length = 0;
34154
34427
  }
34428
+ function sessionInvalidate(repo, rel2) {
34429
+ const prefix2 = repo + "\0";
34430
+ for (const entry of sessionCaches) {
34431
+ if (!entry.key.startsWith(prefix2)) continue;
34432
+ if (rel2) entry.cacheMap.delete(rel2);
34433
+ else entry.cacheMap.clear();
34434
+ }
34435
+ }
34155
34436
  function sessionKey(repo, opts) {
34156
34437
  return repo + "\0" + JSON.stringify({
34157
34438
  scope: opts.scope,
@@ -34173,7 +34454,11 @@ function getScan(repo, opts = {}, walked) {
34173
34454
  const fresh = scanRepo(repo, { ...opts, cache: hit.cacheMap, precomputedWalk: walked });
34174
34455
  if (fresh.contentUnchanged) {
34175
34456
  if (fresh.cacheDirty) hit.cacheMap = toCacheMap(fresh);
34176
- if (hit.scan.commit !== fresh.commit) hit.scan.commit = fresh.commit;
34457
+ if (hit.scan.commit !== fresh.commit) {
34458
+ hit.scan.commit = fresh.commit;
34459
+ hit.arts = void 0;
34460
+ hit.loadArtifacts = void 0;
34461
+ }
34177
34462
  return hit.scan;
34178
34463
  }
34179
34464
  sessionPut({ key: key2, scan: fresh, cacheMap: toCacheMap(fresh) });
@@ -34181,31 +34466,77 @@ function getScan(repo, opts = {}, walked) {
34181
34466
  }
34182
34467
  const preloaded = preloadSession(repo, { ...opts, precomputedWalk: walked });
34183
34468
  if (preloaded) {
34184
- sessionPut({ key: key2, scan: preloaded.scan, cacheMap: preloaded.cacheMap, arts: preloaded.arts });
34469
+ sessionPut({
34470
+ key: key2,
34471
+ scan: preloaded.scan,
34472
+ cacheMap: preloaded.cacheMap,
34473
+ arts: preloaded.arts
34474
+ });
34185
34475
  return preloaded.scan;
34186
34476
  }
34187
34477
  const scan2 = scanRepo(repo, { ...opts, precomputedWalk: walked });
34188
34478
  sessionPut({ key: key2, scan: scan2, cacheMap: toCacheMap(scan2) });
34189
34479
  return scan2;
34190
34480
  }
34191
- function getScanSummary(repo, opts = {}, walked) {
34192
- if (sessionCaches.some((e) => e.key === sessionKey(repo, opts))) {
34193
- const scan2 = getScan(repo, opts, walked);
34194
- return {
34195
- root: scan2.root,
34196
- commit: scan2.commit,
34197
- fileCount: scan2.files.length,
34198
- languages: scan2.languages,
34199
- capped: scan2.capped,
34200
- excluded: scan2.excluded
34481
+ async function getScanParallel(repo, opts = {}, walked, warm = async () => {
34482
+ }) {
34483
+ const key2 = sessionKey(repo, opts);
34484
+ const existing = sessionCaches.find((entry) => entry.key === key2);
34485
+ if (existing) {
34486
+ const originalCache = existing.cacheMap;
34487
+ const reuseUnchanged = (fresh) => {
34488
+ if (fresh.cacheDirty) existing.cacheMap = toCacheMap(fresh);
34489
+ if (existing.scan.commit !== fresh.commit) {
34490
+ existing.scan.commit = fresh.commit;
34491
+ existing.arts = void 0;
34492
+ existing.loadArtifacts = void 0;
34493
+ }
34494
+ sessionGet(key2);
34495
+ return existing.scan;
34201
34496
  };
34497
+ if (walked && needsGrammarWarm(walked, originalCache, opts.fullHash)) {
34498
+ await warm();
34499
+ const fresh = await scanRepoParallel(repo, { ...opts, cache: originalCache, precomputedWalk: walked });
34500
+ if (fresh.contentUnchanged) return reuseUnchanged(fresh);
34501
+ sessionPut({ key: key2, scan: fresh, cacheMap: toCacheMap(fresh) });
34502
+ return fresh;
34503
+ }
34504
+ const provisional = scanRepo(repo, { ...opts, cache: originalCache, precomputedWalk: walked });
34505
+ if (provisional.contentUnchanged) {
34506
+ return reuseUnchanged(provisional);
34507
+ }
34508
+ if (walked) {
34509
+ sessionPut({ key: key2, scan: provisional, cacheMap: toCacheMap(provisional) });
34510
+ return provisional;
34511
+ }
34512
+ await warm();
34513
+ const scan3 = await scanRepoParallel(repo, { ...opts, cache: originalCache, precomputedWalk: walked });
34514
+ sessionPut({ key: key2, scan: scan3, cacheMap: toCacheMap(scan3) });
34515
+ return scan3;
34516
+ }
34517
+ const preloaded = await preloadSessionLazy(repo, { ...opts, precomputedWalk: walked }, warm);
34518
+ if (preloaded) {
34519
+ sessionPut({
34520
+ key: key2,
34521
+ scan: preloaded.scan,
34522
+ cacheMap: preloaded.cacheMap,
34523
+ arts: preloaded.arts,
34524
+ loadArtifacts: preloaded.loadArtifacts
34525
+ });
34526
+ return preloaded.scan;
34202
34527
  }
34528
+ await warm();
34529
+ const scan2 = await scanRepoParallel(repo, { ...opts, precomputedWalk: walked });
34530
+ sessionPut({ key: key2, scan: scan2, cacheMap: toCacheMap(scan2) });
34531
+ return scan2;
34532
+ }
34533
+ function getScanSummary(repo, opts = {}, walked) {
34203
34534
  return scanSummary(repo, { ...opts, precomputedWalk: walked });
34204
34535
  }
34205
- function getArtifacts(repo, opts = {}, walked) {
34206
- const scan2 = getScan(repo, opts, walked);
34536
+ function getArtifacts(repo, opts = {}, walked, prepared) {
34537
+ const scan2 = prepared ?? getScan(repo, opts, walked);
34207
34538
  const entry = sessionCaches.find((e) => e.scan === scan2);
34208
- if (entry) return entry.arts ??= buildArtifactsFromScan(scan2, opts);
34539
+ if (entry) return entry.arts ??= entry.loadArtifacts?.() ?? buildArtifactsFromScan(scan2, opts);
34209
34540
  return buildArtifactsFromScan(scan2, opts);
34210
34541
  }
34211
34542
  async function warmGrammarsForRepo(repo) {
@@ -34223,6 +34554,7 @@ var init_session = __esm({
34223
34554
  "use strict";
34224
34555
  init_pipeline();
34225
34556
  init_scan();
34557
+ init_pool();
34226
34558
  init_preload();
34227
34559
  init_walk();
34228
34560
  init_loader();
@@ -34245,6 +34577,7 @@ __export(mcp_exports, {
34245
34577
  capResponse: () => capResponse,
34246
34578
  getArtifacts: () => getArtifacts,
34247
34579
  getScan: () => getScan,
34580
+ getScanParallel: () => getScanParallel,
34248
34581
  getScanSummary: () => getScanSummary,
34249
34582
  memoizedEmbedModel: () => memoizedEmbedModel,
34250
34583
  memoizedEmbeddingIndex: () => memoizedEmbeddingIndex,
@@ -34261,6 +34594,17 @@ __export(mcp_exports, {
34261
34594
  warmGrammarsForRepo: () => warmGrammarsForRepo,
34262
34595
  warmGrammarsForWalk: () => warmGrammarsForWalk
34263
34596
  });
34597
+ function isRpcRequest(value) {
34598
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
34599
+ const req = value;
34600
+ if (req.jsonrpc !== "2.0" || typeof req.method !== "string") return false;
34601
+ return req.id === void 0 || req.id === null || typeof req.id === "number" || typeof req.id === "string";
34602
+ }
34603
+ function isRpcResponse(value) {
34604
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
34605
+ const response = value;
34606
+ return response.jsonrpc === "2.0" && typeof response.method !== "string" && ("result" in response || "error" in response);
34607
+ }
34264
34608
  function str(v) {
34265
34609
  return typeof v === "string" && v ? v : void 0;
34266
34610
  }
@@ -34269,7 +34613,11 @@ function strArray(v) {
34269
34613
  }
34270
34614
  function num(v) {
34271
34615
  const n = typeof v === "number" ? v : typeof v === "string" && v.trim() !== "" ? Number(v) : NaN;
34272
- return Number.isFinite(n) && n > 0 ? n : void 0;
34616
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
34617
+ }
34618
+ function positiveNum(v) {
34619
+ const n = num(v);
34620
+ return n !== void 0 && n > 0 ? n : void 0;
34273
34621
  }
34274
34622
  function errMessage(e) {
34275
34623
  return e instanceof Error ? e.message : String(e);
@@ -34277,14 +34625,27 @@ function errMessage(e) {
34277
34625
  async function callTool(name2, args2, defaultRepo) {
34278
34626
  const repo = str(args2.repo) ?? defaultRepo;
34279
34627
  if (!repo) throw new Error("`repo` is required (absolute path to the repository root)");
34628
+ try {
34629
+ if (!statSync8(repo).isDirectory()) throw new Error("not a directory");
34630
+ } catch {
34631
+ throw new Error(`repository root is not a readable directory: ${repo}`);
34632
+ }
34280
34633
  const scanOpts = { scope: str(args2.scope), include: strArray(args2.include), exclude: strArray(args2.exclude) };
34281
34634
  const rankArg = str(args2.rank);
34282
34635
  const rankOpt = rankArg === "graph" || rankArg === "lexical" ? { rank: rankArg } : {};
34283
34636
  let walked;
34637
+ let preparedScan;
34284
34638
  if (!SCANLESS_TOOLS.has(name2)) {
34285
34639
  walked = walk(repo, {});
34286
- await warmGrammarsForWalk(walked);
34640
+ preparedScan = await getScanParallel(
34641
+ repo,
34642
+ scanOpts,
34643
+ walked,
34644
+ () => walked ? warmGrammarsForWalk(walked) : Promise.resolve()
34645
+ );
34287
34646
  }
34647
+ const readScan = () => preparedScan ?? getScan(repo, scanOpts, walked);
34648
+ const readArtifacts = () => getArtifacts(repo, scanOpts, walked, preparedScan);
34288
34649
  if (name2 === "scan_summary") {
34289
34650
  const s = getScanSummary(repo, scanOpts, walked);
34290
34651
  return JSON.stringify(
@@ -34294,10 +34655,10 @@ async function callTool(name2, args2, defaultRepo) {
34294
34655
  );
34295
34656
  }
34296
34657
  if (name2 === "graph") {
34297
- return renderGraphJson(getArtifacts(repo, scanOpts, walked).graph);
34658
+ return renderGraphJson(readArtifacts().graph);
34298
34659
  }
34299
34660
  if (name2 === "symbols") {
34300
- const { symbols } = getArtifacts(repo, scanOpts, walked);
34661
+ const { symbols } = readArtifacts();
34301
34662
  const lookup2 = str(args2.name);
34302
34663
  if (lookup2) {
34303
34664
  return JSON.stringify({ name: lookup2, defs: symbols.defs[lookup2] ?? [], refs: symbols.refs[lookup2] ?? [] }, null, 2);
@@ -34305,7 +34666,7 @@ async function callTool(name2, args2, defaultRepo) {
34305
34666
  return JSON.stringify(symbols, null, 2);
34306
34667
  }
34307
34668
  if (name2 === "callers") {
34308
- const scan2 = getScan(repo, scanOpts, walked);
34669
+ const scan2 = readScan();
34309
34670
  const index = args2.recall === true ? buildCallerIndex(scan2, void 0, { recall: true }) : callerIndexFor(scan2);
34310
34671
  const lookup2 = str(args2.name);
34311
34672
  if (lookup2) {
@@ -34329,35 +34690,35 @@ async function callTool(name2, args2, defaultRepo) {
34329
34690
  if (name2 === "symbols_overview") {
34330
34691
  const file = str(args2.file);
34331
34692
  if (!file) throw new Error("`file` is required");
34332
- return JSON.stringify(symbolsOverview(getScan(repo, scanOpts, walked), file), null, 2);
34693
+ return JSON.stringify(symbolsOverview(readScan(), file), null, 2);
34333
34694
  }
34334
34695
  if (name2 === "find_symbol") {
34335
34696
  const namePath = str(args2.namePath);
34336
34697
  if (!namePath) throw new Error("`namePath` is required");
34337
- const matches = findSymbol(getScan(repo, scanOpts, walked), namePath, {
34698
+ const matches = findSymbol(readScan(), namePath, {
34338
34699
  substring: args2.substring === true,
34339
34700
  includeBody: args2.includeBody === true,
34340
34701
  concise: args2.concise === true,
34341
- maxResults: num(args2.maxResults)
34702
+ maxResults: positiveNum(args2.maxResults)
34342
34703
  });
34343
34704
  return JSON.stringify(matches, null, 2);
34344
34705
  }
34345
34706
  if (name2 === "find_references") {
34346
34707
  const symName = str(args2.name);
34347
34708
  if (!symName) throw new Error("`name` is required");
34348
- const scan2 = getScan(repo, scanOpts, walked);
34709
+ const scan2 = readScan();
34349
34710
  const statik = findReferences(scan2, symName);
34350
34711
  if (args2.lsp === true) return JSON.stringify(await referencesWithLsp(scan2, repo, symName, statik), null, 2);
34351
34712
  return JSON.stringify(statik, null, 2);
34352
34713
  }
34353
34714
  if (name2 === "lsp_status") {
34354
- return JSON.stringify(await lspStatus(getScan(repo, scanOpts, walked), repo, args2.probe === true), null, 2);
34715
+ return JSON.stringify(await lspStatus(readScan(), repo, args2.probe === true), null, 2);
34355
34716
  }
34356
34717
  if (name2 === "replace_symbol_body" || name2 === "insert_after_symbol" || name2 === "insert_before_symbol") {
34357
34718
  const namePath = str(args2.namePath);
34358
34719
  const body22 = typeof args2.body === "string" ? args2.body : void 0;
34359
34720
  if (!namePath || body22 === void 0) throw new Error("`namePath` and `body` are required");
34360
- const scan2 = getScan(repo, scanOpts, walked);
34721
+ const scan2 = readScan();
34361
34722
  const fn = name2 === "replace_symbol_body" ? replaceSymbolBody : name2 === "insert_after_symbol" ? insertAfterSymbol : insertBeforeSymbol;
34362
34723
  const result = fn(scan2, namePath, body22, str(args2.file));
34363
34724
  sessionClear();
@@ -34385,15 +34746,15 @@ async function callTool(name2, args2, defaultRepo) {
34385
34746
  return JSON.stringify({ deleted: deleteMemory(repo, memName) }, null, 2);
34386
34747
  }
34387
34748
  if (name2 === "dead_code") {
34388
- const all = findDeadCode(getScan(repo, scanOpts, walked));
34749
+ const all = findDeadCode(readScan());
34389
34750
  const limit = num(args2.limit);
34390
34751
  if (limit === void 0 || all.length <= limit) return JSON.stringify(all, null, 2);
34391
34752
  return JSON.stringify({ total: all.length, shown: limit, truncated: true, candidates: all.slice(0, limit) }, null, 2);
34392
34753
  }
34393
34754
  if (name2 === "duplicated_literals") {
34394
- const report = findLiteralDuplications(getScan(repo, scanOpts, walked), {
34395
- minFiles: num(args2.minFiles),
34396
- minCount: num(args2.minCount),
34755
+ const report = findLiteralDuplications(readScan(), {
34756
+ minFiles: positiveNum(args2.minFiles),
34757
+ minCount: positiveNum(args2.minCount),
34397
34758
  includeTests: args2.includeTests === true
34398
34759
  });
34399
34760
  const limit = num(args2.limit);
@@ -34411,23 +34772,23 @@ async function callTool(name2, args2, defaultRepo) {
34411
34772
  );
34412
34773
  }
34413
34774
  if (name2 === "complexity") {
34414
- const scan2 = getScan(repo, scanOpts, walked);
34775
+ const scan2 = readScan();
34415
34776
  if (args2.risk === true) {
34416
34777
  const { churn, ok } = gitChurn(repo, { since: str(args2.since) });
34417
- return JSON.stringify({ churnOk: ok, risks: riskHotspots(scan2, churn, num(args2.top)) }, null, 2);
34778
+ return JSON.stringify({ churnOk: ok, risks: riskHotspots(scan2, churn, positiveNum(args2.top)) }, null, 2);
34418
34779
  }
34419
- return JSON.stringify(symbolComplexity(scan2, str(args2.file), num(args2.top)), null, 2);
34780
+ return JSON.stringify(symbolComplexity(scan2, str(args2.file), positiveNum(args2.top)), null, 2);
34420
34781
  }
34421
34782
  if (name2 === "mermaid") {
34422
- const { graph } = getArtifacts(repo, scanOpts, walked);
34423
- return renderMermaid(graph, { module: str(args2.module), maxEdges: num(args2.maxEdges) });
34783
+ const { graph } = readArtifacts();
34784
+ return renderMermaid(graph, { module: str(args2.module), maxEdges: positiveNum(args2.maxEdges) });
34424
34785
  }
34425
34786
  if (name2 === "onboard") {
34426
- const scan2 = getScan(repo, scanOpts, walked);
34427
- const { graph } = getArtifacts(repo, scanOpts, walked);
34787
+ const scan2 = readScan();
34788
+ const { graph } = readArtifacts();
34428
34789
  return JSON.stringify(
34429
34790
  onboardBrief(scan2, graph, {
34430
- ...typeof args2.budgetTokens === "number" ? { budgetTokens: args2.budgetTokens } : {},
34791
+ ...positiveNum(args2.budgetTokens) !== void 0 ? { budgetTokens: positiveNum(args2.budgetTokens) } : {},
34431
34792
  ...args2.remember === false ? { remember: false } : {}
34432
34793
  }),
34433
34794
  null,
@@ -34435,11 +34796,11 @@ async function callTool(name2, args2, defaultRepo) {
34435
34796
  );
34436
34797
  }
34437
34798
  if (name2 === "repo_map") {
34438
- const { scan: scan2, graph } = getArtifacts(repo, scanOpts, walked);
34439
- return renderRepoMap(scan2, graph, { budgetTokens: typeof args2.budgetTokens === "number" ? args2.budgetTokens : void 0 });
34799
+ const { scan: scan2, graph } = readArtifacts();
34800
+ return renderRepoMap(scan2, graph, { budgetTokens: positiveNum(args2.budgetTokens) });
34440
34801
  }
34441
34802
  if (name2 === "hotspots") {
34442
- const scan2 = getScan(repo, scanOpts, walked);
34803
+ const scan2 = readScan();
34443
34804
  const { churn, ok } = gitChurn(repo, { since: str(args2.since) });
34444
34805
  return JSON.stringify({ churnOk: ok, hotspots: rankHotspots(scan2, churn) }, null, 2);
34445
34806
  }
@@ -34455,15 +34816,15 @@ async function callTool(name2, args2, defaultRepo) {
34455
34816
  const hits = grepRepo(repo, pattern, {
34456
34817
  globs: scope ? [...globs ?? [], `${scope.replace(/\/+$/, "")}/**`] : globs,
34457
34818
  ignoreCase: args2.ignoreCase === true,
34458
- maxHits: typeof args2.maxHits === "number" ? args2.maxHits : void 0
34819
+ maxHits: positiveNum(args2.maxHits)
34459
34820
  });
34460
34821
  return JSON.stringify(hits, null, 2);
34461
34822
  }
34462
34823
  if (name2 === "search") {
34463
34824
  const query = str(args2.query);
34464
34825
  if (!query) throw new Error("`query` is required");
34465
- const scan2 = getScan(repo, scanOpts, walked);
34466
- const limit = typeof args2.limit === "number" ? args2.limit : void 0;
34826
+ const scan2 = readScan();
34827
+ const limit = num(args2.limit);
34467
34828
  const fuzzy = typeof args2.fuzzy === "boolean" ? args2.fuzzy : void 0;
34468
34829
  const exactOpt = args2.exact === true ? { exact: true } : {};
34469
34830
  if (args2.semantic === true) {
@@ -34506,8 +34867,8 @@ async function callTool(name2, args2, defaultRepo) {
34506
34867
  if (name2 === "explain_search") {
34507
34868
  const query = str(args2.query);
34508
34869
  if (!query) throw new Error("`query` is required");
34509
- const scan2 = getScan(repo, scanOpts, walked);
34510
- const limit = typeof args2.limit === "number" ? args2.limit : void 0;
34870
+ const scan2 = readScan();
34871
+ const limit = num(args2.limit);
34511
34872
  const fuzzy = typeof args2.fuzzy === "boolean" ? args2.fuzzy : void 0;
34512
34873
  const { results, explain } = explainQuery(scan2, query, {
34513
34874
  limit,
@@ -34532,7 +34893,7 @@ async function callTool(name2, args2, defaultRepo) {
34532
34893
  return JSON.stringify(status, null, 2);
34533
34894
  }
34534
34895
  if (name2 === "type_hierarchy") {
34535
- const hierarchy = hierarchyFor(getScan(repo, scanOpts, walked));
34896
+ const hierarchy = hierarchyFor(readScan());
34536
34897
  const wanted = str(args2.name);
34537
34898
  if (!wanted) {
34538
34899
  const obj = {};
@@ -34546,7 +34907,7 @@ async function callTool(name2, args2, defaultRepo) {
34546
34907
  if (name2 === "implementations") {
34547
34908
  const wanted = str(args2.name);
34548
34909
  if (!wanted) throw new Error("`name` is required");
34549
- const hierarchy = hierarchyFor(getScan(repo, scanOpts, walked));
34910
+ const hierarchy = hierarchyFor(readScan());
34550
34911
  if (!hierarchy.has(wanted)) return JSON.stringify({ error: `no type named ${wanted}` }, null, 2);
34551
34912
  return JSON.stringify({ name: wanted, implementations: implementationsOf(hierarchy, wanted) }, null, 2);
34552
34913
  }
@@ -34555,8 +34916,8 @@ async function callTool(name2, args2, defaultRepo) {
34555
34916
  if (!symbol) throw new Error("`symbol` is required");
34556
34917
  const direction = str(args2.direction);
34557
34918
  const dir = direction === "out" || direction === "in" ? direction : "both";
34558
- const result = neighborhood(symbolGraphFor(getScan(repo, scanOpts, walked)), symbol, {
34559
- ...typeof args2.depth === "number" ? { depth: args2.depth } : {},
34919
+ const result = neighborhood(symbolGraphFor(readScan()), symbol, {
34920
+ ...positiveNum(args2.depth) !== void 0 ? { depth: positiveNum(args2.depth) } : {},
34560
34921
  direction: dir
34561
34922
  });
34562
34923
  if (!result.root.length) return JSON.stringify({ error: `no symbol named ${symbol}` }, null, 2);
@@ -34575,7 +34936,7 @@ async function callTool(name2, args2, defaultRepo) {
34575
34936
  }
34576
34937
  if (payload === void 0) throw new Error("`rules` (or `configPath`) is required");
34577
34938
  const rules = parseRules(payload);
34578
- const { graph } = getArtifacts(repo, scanOpts, walked);
34939
+ const { graph } = readArtifacts();
34579
34940
  return JSON.stringify(checkRules(graph, rules), null, 2);
34580
34941
  }
34581
34942
  throw new Error(`unknown tool: ${name2}`);
@@ -34587,31 +34948,81 @@ async function runMcpServer(opts = {}) {
34587
34948
  };
34588
34949
  let protocolVersion = PROTOCOL_VERSIONS[0];
34589
34950
  let tools = toolsFor(opts.defaultRepo, protocolVersion, opts.profile);
34951
+ let watcher;
34952
+ if (opts.watch && opts.defaultRepo) {
34953
+ try {
34954
+ watcher = watchFs(opts.defaultRepo, { recursive: true }, (_event, filename) => {
34955
+ const rel2 = filename?.toString().replaceAll("\\", "/") ?? "";
34956
+ const ignored = rel2.split("/").some(
34957
+ (segment) => IGNORE_DIRS.has(segment) || segment.startsWith(".codeindex-edit-")
34958
+ );
34959
+ if (ignored) return;
34960
+ sessionInvalidate(opts.defaultRepo, rel2 || void 0);
34961
+ });
34962
+ watcher.on("error", (error) => {
34963
+ process.stderr.write(`codeindex: MCP watcher disabled (${error.message}); using freshness scans
34964
+ `);
34965
+ watcher?.close();
34966
+ watcher = void 0;
34967
+ sessionInvalidate(opts.defaultRepo);
34968
+ });
34969
+ } catch (error) {
34970
+ process.stderr.write(
34971
+ `codeindex: MCP watcher unavailable (${error instanceof Error ? error.message : String(error)}); using freshness scans
34972
+ `
34973
+ );
34974
+ }
34975
+ }
34590
34976
  const send = (msg) => {
34591
- process.stdout.write(JSON.stringify({ jsonrpc: "2.0", ...msg }) + "\n");
34977
+ const wire = Array.isArray(msg) ? msg.map((entry) => ({ jsonrpc: "2.0", ...entry })) : { jsonrpc: "2.0", ...msg };
34978
+ process.stdout.write(JSON.stringify(wire) + "\n");
34592
34979
  };
34593
34980
  const rl = createInterface({ input: process.stdin, terminal: false });
34594
- for await (const line of rl) {
34595
- const trimmed = line.trim();
34596
- if (!trimmed) continue;
34597
- let parsed;
34598
- try {
34599
- parsed = JSON.parse(trimmed);
34600
- } catch {
34601
- send({ id: null, error: { code: -32700, message: "parse error" } });
34602
- continue;
34981
+ try {
34982
+ for await (const line of rl) {
34983
+ const trimmed = line.trim();
34984
+ if (!trimmed) continue;
34985
+ let parsed;
34986
+ try {
34987
+ parsed = JSON.parse(trimmed);
34988
+ } catch {
34989
+ send({ id: null, error: { code: -32700, message: "parse error" } });
34990
+ continue;
34991
+ }
34992
+ if (Array.isArray(parsed) && parsed.length === 0) {
34993
+ send({ id: null, error: { code: -32600, message: "invalid request" } });
34994
+ continue;
34995
+ }
34996
+ const dispatch2 = async (req) => {
34997
+ if (isRpcResponse(req)) return void 0;
34998
+ if (!isRpcRequest(req)) {
34999
+ return { id: null, error: { code: -32600, message: "invalid request" } };
35000
+ }
35001
+ return handle2(req);
35002
+ };
35003
+ if (Array.isArray(parsed)) {
35004
+ const replies = [];
35005
+ for (const req of parsed) {
35006
+ const reply = await dispatch2(req);
35007
+ if (reply) replies.push(reply);
35008
+ }
35009
+ if (replies.length > 0) send(replies);
35010
+ } else {
35011
+ const reply = await dispatch2(parsed);
35012
+ if (reply) send(reply);
35013
+ }
34603
35014
  }
34604
- const requests = Array.isArray(parsed) ? parsed : [parsed];
34605
- for (const req of requests) await handle2(req);
35015
+ } finally {
35016
+ watcher?.close();
34606
35017
  }
34607
35018
  async function handle2(req) {
34608
- if (req.id === void 0 || req.id === null) return;
35019
+ const notification = !("id" in req);
35020
+ const respond = (body22) => notification ? void 0 : { id: req.id ?? null, ...body22 };
34609
35021
  try {
34610
35022
  if (req.method === "initialize") {
34611
35023
  protocolVersion = negotiateProtocol(req.params?.protocolVersion);
34612
35024
  tools = toolsFor(opts.defaultRepo, protocolVersion, opts.profile);
34613
- send({
34614
- id: req.id,
35025
+ return respond({
34615
35026
  result: {
34616
35027
  protocolVersion,
34617
35028
  capabilities: { tools: {} },
@@ -34619,9 +35030,9 @@ async function runMcpServer(opts = {}) {
34619
35030
  }
34620
35031
  });
34621
35032
  } else if (req.method === "ping") {
34622
- send({ id: req.id, result: {} });
35033
+ return respond({ result: {} });
34623
35034
  } else if (req.method === "tools/list") {
34624
- send({ id: req.id, result: { tools } });
35035
+ return respond({ result: { tools } });
34625
35036
  } else if (req.method === "tools/call") {
34626
35037
  const params = req.params ?? {};
34627
35038
  const name2 = str(params.name) ?? "";
@@ -34638,24 +35049,22 @@ async function runMcpServer(opts = {}) {
34638
35049
  const capped = text !== raw;
34639
35050
  const link = capped && protocolVersion >= RICH_TOOLS_SINCE ? resourceLinkFor(text, name2) : void 0;
34640
35051
  const structured = protocolVersion >= RICH_TOOLS_SINCE ? structuredContentFor(text, capped, OUTPUT_SCHEMAS[name2] !== void 0) : void 0;
34641
- send({
34642
- id: req.id,
35052
+ return respond({
34643
35053
  result: {
34644
35054
  content: link ? [{ type: "text", text }, link] : [{ type: "text", text }],
34645
35055
  ...structured ? { structuredContent: structured } : {}
34646
35056
  }
34647
35057
  });
34648
35058
  } catch (e) {
34649
- send({
34650
- id: req.id,
35059
+ return respond({
34651
35060
  result: { content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }], isError: true }
34652
35061
  });
34653
35062
  }
34654
35063
  } else {
34655
- send({ id: req.id, error: { code: -32601, message: `method not found: ${req.method}` } });
35064
+ return respond({ error: { code: -32601, message: `method not found: ${req.method}` } });
34656
35065
  }
34657
35066
  } catch (e) {
34658
- send({ id: req.id, error: { code: -32603, message: e instanceof Error ? e.message : String(e) } });
35067
+ return respond({ error: { code: -32603, message: e instanceof Error ? e.message : String(e) } });
34659
35068
  }
34660
35069
  }
34661
35070
  }
@@ -34707,8 +35116,7 @@ var init_mcp = __esm({
34707
35116
  "delete_memory",
34708
35117
  "embed_status",
34709
35118
  // scan_summary counts and classifies by path only — it never parses, so the
34710
- // grammar warm (a whole extra walk) would be pure overhead. When a scan is
34711
- // already cached getScanSummary reuses it, warm grammars included.
35119
+ // grammar warm (a whole extra walk) would be pure overhead.
34712
35120
  "scan_summary"
34713
35121
  ]);
34714
35122
  }
@@ -34832,129 +35240,7 @@ init_walk();
34832
35240
  init_scan();
34833
35241
  init_scan();
34834
35242
  init_preload();
34835
- init_hash();
34836
- init_walk();
34837
- init_registry();
34838
- init_loader();
34839
- init_scan();
34840
- function resolveEngineUrl() {
34841
- try {
34842
- const here = fileURLToPath2(import.meta.url);
34843
- if (here.endsWith("engine.mjs")) return pathToFileURL(here).href;
34844
- const adjacent = join4(dirname2(here), "engine.mjs");
34845
- if (existsSync2(adjacent)) return pathToFileURL(adjacent).href;
34846
- return void 0;
34847
- } catch {
34848
- return void 0;
34849
- }
34850
- }
34851
- var WORKER_TIMEOUT_MS = 10 * 60 * 1e3;
34852
- function workerCount(requested) {
34853
- const env = process.env["CODEINDEX_WORKERS"];
34854
- const raw = requested ?? (env !== void 0 && env !== "" ? Number(env) : void 0);
34855
- if (raw !== void 0) return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 0;
34856
- let cores = 1;
34857
- try {
34858
- cores = availableParallelism();
34859
- } catch {
34860
- cores = 1;
34861
- }
34862
- return Math.max(0, Math.min(cores - 1, 8));
34863
- }
34864
- async function runExtractWorker(input, post) {
34865
- await ensureGrammars(input.grammarKeys);
34866
- const ready = input.grammarKeys.filter((k) => grammarReady(k));
34867
- const records = [];
34868
- for (const job of input.jobs) {
34869
- let size;
34870
- let mtimeMs;
34871
- try {
34872
- const st = statSync2(job.abs);
34873
- size = st.size;
34874
- mtimeMs = st.mtimeMs;
34875
- } catch {
34876
- continue;
34877
- }
34878
- const content = readText2(job.abs);
34879
- const record = buildCodeRecord(job.rel, job.ext, size, content, sha1(content), extToLang(job.ext), {
34880
- maxCallsPerFile: input.maxCallsPerFile
34881
- });
34882
- records.push({ rel: job.rel, size, mtimeMs, record });
34883
- }
34884
- post({ ready, records });
34885
- }
34886
- async function extractInParallel(jobs, grammarKeys, count, opts = {}) {
34887
- if (count < 2 || jobs.length === 0) return void 0;
34888
- const engineUrl = resolveEngineUrl();
34889
- if (!engineUrl) return void 0;
34890
- const wanted = grammarKeys.filter((k) => grammarReady(k)).sort();
34891
- const shards = Array.from({ length: Math.min(count, jobs.length) }, () => []);
34892
- jobs.forEach((j, i2) => shards[i2 % shards.length].push(j));
34893
- const bootstrap = `import { runExtractWorker } from ${JSON.stringify(engineUrl)};
34894
- import { parentPort, workerData } from "node:worker_threads";
34895
- runExtractWorker(workerData.input, (o) => parentPort.postMessage(o)).catch((e) => parentPort.postMessage({ error: String(e) }));
34896
- `;
34897
- try {
34898
- const outputs = await Promise.all(
34899
- shards.map(
34900
- (jobsForShard) => new Promise((resolve52, reject) => {
34901
- const w = new Worker(bootstrap, {
34902
- eval: true,
34903
- workerData: { input: { jobs: jobsForShard, grammarKeys: wanted, maxCallsPerFile: opts.maxCallsPerFile } }
34904
- });
34905
- const timer = setTimeout(() => {
34906
- reject(new Error("extraction worker timed out"));
34907
- void w.terminate();
34908
- }, WORKER_TIMEOUT_MS);
34909
- const settle = (fn) => {
34910
- clearTimeout(timer);
34911
- fn();
34912
- };
34913
- w.once("message", (m) => {
34914
- settle(() => resolve52(m));
34915
- void w.terminate();
34916
- });
34917
- w.once("error", (e) => settle(() => reject(e)));
34918
- w.once("exit", (code2) => {
34919
- if (code2 !== 0) settle(() => reject(new Error(`extraction worker exited with ${code2}`)));
34920
- });
34921
- })
34922
- )
34923
- );
34924
- const out2 = /* @__PURE__ */ new Map();
34925
- for (const o of outputs) {
34926
- if ("error" in o) return void 0;
34927
- if (o.ready.slice().sort().join(",") !== wanted.join(",")) return void 0;
34928
- for (const r of o.records) out2.set(r.rel, { size: r.size, mtimeMs: r.mtimeMs, record: r.record });
34929
- }
34930
- return out2;
34931
- } catch {
34932
- return void 0;
34933
- }
34934
- }
34935
- async function scanRepoParallel(root, opts = {}) {
34936
- const count = workerCount(opts.workers);
34937
- if (count < 2) return scanRepo(root, opts);
34938
- const walked = opts.precomputedWalk ?? walk(root, {
34939
- maxFileBytes: opts.maxBytes,
34940
- maxFiles: opts.maxFiles,
34941
- gitignore: opts.gitignore,
34942
- ignoreDirs: opts.ignoreDirs
34943
- });
34944
- const scanOpts = { ...opts, precomputedWalk: walked };
34945
- const jobs = [];
34946
- for (const { f } of keptCodeFiles(root, scanOpts)) {
34947
- const cached = opts.cache?.get(f.rel);
34948
- if (!opts.fullHash && cached && cached.size !== void 0 && cached.mtimeMs !== void 0 && cached.size === f.size && cached.mtimeMs === f.mtimeMs) {
34949
- continue;
34950
- }
34951
- jobs.push({ abs: f.abs, rel: f.rel, ext: f.ext });
34952
- }
34953
- if (jobs.length === 0) return scanRepo(root, scanOpts);
34954
- const grammarKeys = grammarKeysForExts(walked.files.map((f) => f.ext));
34955
- const extracted = await extractInParallel(jobs, grammarKeys, count, { maxCallsPerFile: opts.maxCallsPerFile });
34956
- return scanRepo(root, extracted ? { ...scanOpts, extracted } : scanOpts);
34957
- }
35243
+ init_pool();
34958
35244
  init_glob();
34959
35245
  init_ignore();
34960
35246
  init_classify();
@@ -35251,6 +35537,64 @@ function extractGrammarsTarball(bytes, destDir) {
35251
35537
  const raw = b.length >= 2 && b[0] === 31 && b[1] === 139 ? gunzipSync(b) : b;
35252
35538
  return extractTarInto(raw, destDir);
35253
35539
  }
35540
+ function installGrammarCacheAtomically(tempDir, cacheDir, markerPath, expectedSha256, rename = renameSync, cleanup = rmSync) {
35541
+ const parent = dirname3(cacheDir);
35542
+ const swapDir = mkdtempSync(join6(parent, ".grammars-swap-"));
35543
+ const previousCache = join6(swapDir, "previous-cache");
35544
+ const previousMarker = join6(swapDir, "previous-marker");
35545
+ const nextMarker = join6(swapDir, "next-marker");
35546
+ let cacheBackedUp = false;
35547
+ let markerBackedUp = false;
35548
+ let cacheInstalled = false;
35549
+ let markerInstalled = false;
35550
+ try {
35551
+ if (expectedSha256) writeFileSync(nextMarker, expectedSha256 + "\n");
35552
+ if (existsSync4(cacheDir)) {
35553
+ rename(cacheDir, previousCache);
35554
+ cacheBackedUp = true;
35555
+ }
35556
+ if (existsSync4(markerPath)) {
35557
+ rename(markerPath, previousMarker);
35558
+ markerBackedUp = true;
35559
+ }
35560
+ rename(tempDir, cacheDir);
35561
+ cacheInstalled = true;
35562
+ if (expectedSha256) {
35563
+ rename(nextMarker, markerPath);
35564
+ markerInstalled = true;
35565
+ }
35566
+ } catch (error) {
35567
+ const rollbackErrors = [];
35568
+ const attempt = (operation) => {
35569
+ try {
35570
+ operation();
35571
+ } catch (rollback) {
35572
+ rollbackErrors.push(rollback);
35573
+ }
35574
+ };
35575
+ if (markerInstalled && existsSync4(markerPath)) attempt(() => rmSync(markerPath, { force: true }));
35576
+ if (cacheInstalled && existsSync4(cacheDir)) attempt(() => rmSync(cacheDir, { recursive: true, force: true }));
35577
+ if (markerBackedUp && existsSync4(previousMarker)) attempt(() => rename(previousMarker, markerPath));
35578
+ if (cacheBackedUp && existsSync4(previousCache)) attempt(() => rename(previousCache, cacheDir));
35579
+ if (rollbackErrors.length === 0) {
35580
+ try {
35581
+ rmSync(swapDir, { recursive: true, force: true });
35582
+ } catch {
35583
+ }
35584
+ }
35585
+ if (rollbackErrors.length > 0) {
35586
+ const rollbackError = rollbackErrors[0];
35587
+ throw new Error(
35588
+ `${error instanceof Error ? error.message : String(error)}; rollback failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)} (backup preserved at ${swapDir})`
35589
+ );
35590
+ }
35591
+ throw error;
35592
+ }
35593
+ try {
35594
+ cleanup(swapDir, { recursive: true, force: true });
35595
+ } catch {
35596
+ }
35597
+ }
35254
35598
  async function pullGrammars(cacheDir, opts = {}) {
35255
35599
  const note = opts.onNote ?? (() => {
35256
35600
  });
@@ -35299,10 +35643,8 @@ async function pullGrammars(cacheDir, opts = {}) {
35299
35643
  if (!existsSync4(join6(tmp, "web-tree-sitter.wasm"))) {
35300
35644
  throw new Error("archive is missing web-tree-sitter.wasm");
35301
35645
  }
35302
- if (existsSync4(cacheDir)) rmSync(cacheDir, { recursive: true, force: true });
35303
- renameSync(tmp, cacheDir);
35646
+ installGrammarCacheAtomically(tmp, cacheDir, markerPath, expected);
35304
35647
  tmp = void 0;
35305
- if (expected) writeFileSync(markerPath, expected + "\n");
35306
35648
  } catch (e) {
35307
35649
  if (tmp) {
35308
35650
  try {
@@ -36066,6 +36408,7 @@ init_hash();
36066
36408
  init_graph_json();
36067
36409
  init_symbols_json();
36068
36410
  init_scan();
36411
+ init_pool();
36069
36412
  init_preload();
36070
36413
  init_walk();
36071
36414
  init_relations();
@@ -36192,7 +36535,8 @@ Commands:
36192
36535
  advertises a named subset (all | orient | find | impact | edit |
36193
36536
  risk, default all) \u2014 every advertised tool's schema costs an agent
36194
36537
  context on EVERY turn, and a tool left out is still answerable
36195
- when called by name
36538
+ when called by name; --watch enables proactive invalidation for a
36539
+ pinned repo while retaining per-request freshness verification
36196
36540
  version Print the engine version
36197
36541
 
36198
36542
  Flags (accepted before OR after the subcommand: '--repo X scan' and
@@ -36343,6 +36687,7 @@ function parseMcpFlags(argv) {
36343
36687
  let name2;
36344
36688
  let maxResponseBytes;
36345
36689
  let profile;
36690
+ let watch = false;
36346
36691
  for (let i2 = 0; i2 < argv.length; i2++) {
36347
36692
  const a = argv[i2];
36348
36693
  if (a === "--repo") {
@@ -36363,12 +36708,15 @@ function parseMcpFlags(argv) {
36363
36708
  if (!v) throw new Error(`--tools requires a profile: ${profileNames().join(", ")}`);
36364
36709
  toolsInProfiles(v);
36365
36710
  profile = v === "all" ? void 0 : v;
36711
+ } else if (a === "--watch") {
36712
+ watch = true;
36366
36713
  } else {
36367
36714
  throw new Error(`unknown flag for \`mcp\`: ${a}`);
36368
36715
  }
36369
36716
  }
36370
36717
  if (defaultRepo && !existsSync10(defaultRepo)) throw new Error(`--repo path does not exist: ${defaultRepo}`);
36371
- return { defaultRepo, serverInfo: name2 ? { name: name2 } : void 0, maxResponseBytes, profile };
36718
+ if (watch && !defaultRepo) throw new Error("--watch requires --repo <dir>");
36719
+ return { defaultRepo, serverInfo: name2 ? { name: name2 } : void 0, maxResponseBytes, profile, watch };
36372
36720
  }
36373
36721
  var VALUE_FLAGS = /* @__PURE__ */ new Set([
36374
36722
  "--repo",
@@ -36392,7 +36740,12 @@ var VALUE_FLAGS = /* @__PURE__ */ new Set([
36392
36740
  "--tools",
36393
36741
  "--workers",
36394
36742
  "--index",
36395
- "--max-response-bytes"
36743
+ "--max-response-bytes",
36744
+ "--base",
36745
+ "--depth",
36746
+ "--kind",
36747
+ "--rank",
36748
+ "--direction"
36396
36749
  ]);
36397
36750
  function hoistLeadingFlags(argv) {
36398
36751
  const lead = [];
@@ -36438,6 +36791,7 @@ async function runCli(rawArgv) {
36438
36791
  }
36439
36792
  const flags2 = parseFlags(rest);
36440
36793
  if (!existsSync10(flags2.repo)) throw new Error(`--repo path does not exist: ${flags2.repo}`);
36794
+ if (!statSync9(flags2.repo).isDirectory()) throw new Error(`--repo path is not a directory: ${flags2.repo}`);
36441
36795
  const scans = !SCANLESS_COMMANDS.has(cmd) && !(cmd === "embed" && flags2.positional !== "build");
36442
36796
  let precomputedWalk;
36443
36797
  if (scans && !flags2.noAst) {
@@ -36447,25 +36801,45 @@ async function runCli(rawArgv) {
36447
36801
  gitignore: flags2.gitignore,
36448
36802
  ignoreDirs: flags2.ignoreDirs.length ? flags2.ignoreDirs : void 0
36449
36803
  });
36450
- await ensureGrammars(grammarKeysForExts(precomputedWalk.files.map((f) => f.ext)));
36451
36804
  }
36805
+ let grammarsWarmed = false;
36806
+ const warmPresentGrammars = async () => {
36807
+ if (grammarsWarmed || flags2.noAst || !precomputedWalk) return;
36808
+ await ensureGrammars(grammarKeysForExts(precomputedWalk.files.map((f) => f.ext)));
36809
+ grammarsWarmed = true;
36810
+ };
36452
36811
  const indexDir = flags2.indexDir ?? INDEX_DIR;
36453
36812
  let preloadTried = false;
36813
+ let preloadPromise;
36454
36814
  let preloaded;
36455
- const tryPreload = () => {
36815
+ const tryPreload = async () => {
36816
+ if (preloadPromise) return preloadPromise;
36456
36817
  if (preloadTried) return preloaded;
36457
36818
  preloadTried = true;
36458
36819
  if (flags2.noIndexCache) return void 0;
36459
- const p = preloadSession(flags2.repo, scanOptions(flags2, precomputedWalk), indexDir);
36460
- if (p) preloaded = { scan: p.scan, arts: p.arts };
36461
- return preloaded;
36820
+ preloadPromise = preloadSessionLazy(flags2.repo, scanOptions(flags2, precomputedWalk), warmPresentGrammars, indexDir).then((p) => {
36821
+ if (p) preloaded = { scan: p.scan, arts: p.arts, loadArtifacts: p.loadArtifacts };
36822
+ return preloaded;
36823
+ });
36824
+ return preloadPromise;
36462
36825
  };
36463
- const readScan = () => tryPreload()?.scan ?? scanRepo(flags2.repo, scanOptions(flags2, precomputedWalk));
36464
- const readArtifacts = () => {
36465
- const p = tryPreload();
36826
+ let readScanPromise;
36827
+ const readScan = async () => {
36828
+ const preloadedScan = (await tryPreload())?.scan;
36829
+ if (preloadedScan) return preloadedScan;
36830
+ return readScanPromise ??= warmPresentGrammars().then(
36831
+ () => scanRepoParallel(flags2.repo, {
36832
+ ...scanOptions(flags2, precomputedWalk),
36833
+ workers: flags2.workers
36834
+ })
36835
+ );
36836
+ };
36837
+ let readArtifactsPromise;
36838
+ const readArtifacts = async () => {
36839
+ const p = await tryPreload();
36466
36840
  if (p?.arts) return p.arts;
36467
- if (p) return buildArtifactsFromScan(p.scan, scanOptions(flags2, precomputedWalk));
36468
- return buildIndexArtifacts(flags2.repo, scanOptions(flags2, precomputedWalk));
36841
+ if (p) return p.arts ??= p.loadArtifacts?.() ?? buildArtifactsFromScan(p.scan, scanOptions(flags2, precomputedWalk));
36842
+ return readArtifactsPromise ??= readScan().then((scan2) => buildArtifactsFromScan(scan2, scanOptions(flags2, precomputedWalk)));
36469
36843
  };
36470
36844
  if (cmd === "index") {
36471
36845
  if (!flags2.out) throw new Error("index needs --out <dir>");
@@ -36488,6 +36862,7 @@ async function runCli(rawArgv) {
36488
36862
  }
36489
36863
  } catch {
36490
36864
  }
36865
+ await warmPresentGrammars();
36491
36866
  const scan2 = await scanRepoParallel(flags2.repo, {
36492
36867
  ...scanOptions(flags2, precomputedWalk),
36493
36868
  cache,
@@ -36566,13 +36941,13 @@ async function runCli(rawArgv) {
36566
36941
  };
36567
36942
  emit(JSON.stringify(summary, null, 2) + "\n", flags2.out);
36568
36943
  } else if (cmd === "graph") {
36569
- const { graph } = readArtifacts();
36944
+ const { graph } = await readArtifacts();
36570
36945
  emit(renderGraphJson(graph), flags2.out);
36571
36946
  } else if (cmd === "symbols") {
36572
- const { symbols } = readArtifacts();
36947
+ const { symbols } = await readArtifacts();
36573
36948
  emit(renderSymbolsJson(symbols), flags2.out);
36574
36949
  } else if (cmd === "scip") {
36575
- const scan2 = readScan();
36950
+ const scan2 = await readScan();
36576
36951
  const bytes = renderScip(scan2, { projectRoot: flags2.projectRoot });
36577
36952
  const out2 = flags2.out ?? resolve4("index.scip");
36578
36953
  if (out2 === "-") process.stdout.write(Buffer.from(bytes));
@@ -36582,13 +36957,13 @@ async function runCli(rawArgv) {
36582
36957
  `);
36583
36958
  }
36584
36959
  } else if (cmd === "callers") {
36585
- const scan2 = readScan();
36960
+ const scan2 = await readScan();
36586
36961
  const index = buildCallerIndex(scan2, void 0, { recall: flags2.recall });
36587
36962
  const obj = {};
36588
36963
  for (const [name2, entry] of index) obj[name2] = entry;
36589
36964
  emit(JSON.stringify(obj, null, 2) + "\n", flags2.out);
36590
36965
  } else if (cmd === "hierarchy") {
36591
- const scan2 = readScan();
36966
+ const scan2 = await readScan();
36592
36967
  const hierarchy = buildTypeHierarchy(scan2, computeImportPairs(scan2));
36593
36968
  if (flags2.positional) {
36594
36969
  const entry = hierarchy.get(flags2.positional);
@@ -36601,7 +36976,7 @@ async function runCli(rawArgv) {
36601
36976
  }
36602
36977
  } else if (cmd === "implementations") {
36603
36978
  if (!flags2.positional) throw new Error("implementations needs a type name: cli.mjs implementations <Name> --repo <dir>");
36604
- const scan2 = readScan();
36979
+ const scan2 = await readScan();
36605
36980
  const hierarchy = buildTypeHierarchy(scan2, computeImportPairs(scan2));
36606
36981
  if (!hierarchy.has(flags2.positional)) throw new Error(`no type named ${flags2.positional}`);
36607
36982
  emit(
@@ -36610,7 +36985,7 @@ async function runCli(rawArgv) {
36610
36985
  );
36611
36986
  } else if (cmd === "callgraph") {
36612
36987
  if (!flags2.positional) throw new Error("callgraph needs a symbol: cli.mjs callgraph <Symbol> --repo <dir>");
36613
- const scan2 = readScan();
36988
+ const scan2 = await readScan();
36614
36989
  const graph = buildSymbolGraph(scan2, computeImportPairs(scan2));
36615
36990
  const result = neighborhood(graph, flags2.positional, {
36616
36991
  ...flags2.depth !== void 0 ? { depth: flags2.depth } : {},
@@ -36620,7 +36995,7 @@ async function runCli(rawArgv) {
36620
36995
  emit(JSON.stringify(result, null, 2) + "\n", flags2.out);
36621
36996
  } else if (cmd === "search") {
36622
36997
  if (!flags2.positional) throw new Error('search needs a query: cli.mjs search "<query>" --repo <dir>');
36623
- const scan2 = readScan();
36998
+ const scan2 = await readScan();
36624
36999
  const searchOpts = {
36625
37000
  limit: flags2.limit,
36626
37001
  fuzzy: flags2.fuzzy,
@@ -36725,7 +37100,7 @@ async function runCli(rawArgv) {
36725
37100
  }
36726
37101
  const model = loadEmbedModel(modelDir);
36727
37102
  mkdirSync3(flags2.out, { recursive: true });
36728
- const scan2 = readScan();
37103
+ const scan2 = await readScan();
36729
37104
  const index = buildEmbeddingIndex(scan2, model);
36730
37105
  writeFileSync4(join23(flags2.out, "embeddings.bin"), serializeEmbeddings(index));
36731
37106
  process.stderr.write(`codeindex: ${index.records.length} embedding records \u2192 ${flags2.out}/embeddings.bin (model ${model.modelId})
@@ -36764,7 +37139,7 @@ async function runCli(rawArgv) {
36764
37139
  } else if (cmd === "lsp") {
36765
37140
  const sub = flags2.positional;
36766
37141
  if (sub !== "status") throw new Error("lsp needs a subcommand: status");
36767
- emit(JSON.stringify(await lspStatus(readScan(), flags2.repo, flags2.probe === true), null, 2) + "\n", flags2.out);
37142
+ emit(JSON.stringify(await lspStatus(await readScan(), flags2.repo, flags2.probe === true), null, 2) + "\n", flags2.out);
36768
37143
  } else if (cmd === "grammars") {
36769
37144
  const sub = flags2.positional;
36770
37145
  const cacheDir = sharedGrammarsCacheDir();
@@ -36803,7 +37178,7 @@ async function runCli(rawArgv) {
36803
37178
  } else if (cmd === "rules") {
36804
37179
  if (!flags2.config) throw new Error("rules needs --config <codeindex.rules.json>");
36805
37180
  const rules = parseRules(JSON.parse(readFileSync13(flags2.config, "utf8")));
36806
- const { graph } = readArtifacts();
37181
+ const { graph } = await readArtifacts();
36807
37182
  const violations = checkRules(graph, rules);
36808
37183
  const errors = violations.filter((v) => v.severity === "error").length;
36809
37184
  emit(JSON.stringify({ errors, warnings: violations.length - errors, violations }, null, 2) + "\n", flags2.out);
@@ -36824,33 +37199,33 @@ async function runCli(rawArgv) {
36824
37199
  for (const k of [...churn.keys()].sort()) sorted[k] = churn.get(k);
36825
37200
  emit(JSON.stringify({ ok, churn: sorted }, null, 2) + "\n", flags2.out);
36826
37201
  } else if (cmd === "repomap") {
36827
- const { scan: scan2, graph } = readArtifacts();
37202
+ const { scan: scan2, graph } = await readArtifacts();
36828
37203
  emit(renderRepoMap(scan2, graph, { budgetTokens: flags2.budgetTokens }), flags2.out);
36829
37204
  } else if (cmd === "hotspots") {
36830
- const scan2 = readScan();
37205
+ const scan2 = await readScan();
36831
37206
  const { churn, ok } = gitChurn(flags2.repo, { since: flags2.since });
36832
37207
  emit(JSON.stringify({ churnOk: ok, hotspots: rankHotspots(scan2, churn) }, null, 2) + "\n", flags2.out);
36833
37208
  } else if (cmd === "coupling") {
36834
37209
  const { ok, couplings } = changeCoupling(flags2.repo, { since: flags2.since });
36835
37210
  emit(JSON.stringify({ ok, couplings }, null, 2) + "\n", flags2.out);
36836
37211
  } else if (cmd === "deadcode") {
36837
- emit(JSON.stringify(findDeadCode(readScan()), null, 2) + "\n", flags2.out);
37212
+ emit(JSON.stringify(findDeadCode(await readScan()), null, 2) + "\n", flags2.out);
36838
37213
  } else if (cmd === "literals") {
36839
- const report = findLiteralDuplications(readScan(), {
37214
+ const report = findLiteralDuplications(await readScan(), {
36840
37215
  minFiles: flags2.minFiles,
36841
37216
  minCount: flags2.minCount,
36842
37217
  includeTests: flags2.includeTests
36843
37218
  });
36844
37219
  emit(JSON.stringify(report, null, 2) + "\n", flags2.out);
36845
37220
  } else if (cmd === "complexity") {
36846
- const scan2 = readScan();
37221
+ const scan2 = await readScan();
36847
37222
  emit(JSON.stringify(symbolComplexity(scan2, flags2.positional), null, 2) + "\n", flags2.out);
36848
37223
  } else if (cmd === "risk") {
36849
- const scan2 = readScan();
37224
+ const scan2 = await readScan();
36850
37225
  const { churn, ok } = gitChurn(flags2.repo, { since: flags2.since });
36851
37226
  emit(JSON.stringify({ churnOk: ok, risks: riskHotspots(scan2, churn) }, null, 2) + "\n", flags2.out);
36852
37227
  } else if (cmd === "delta") {
36853
- const { graph, symbols } = readArtifacts();
37228
+ const { graph, symbols } = await readArtifacts();
36854
37229
  const res = deltaFor(flags2.repo, graph, symbols, {
36855
37230
  base: flags2.base,
36856
37231
  staged: flags2.staged,
@@ -36860,19 +37235,19 @@ async function runCli(rawArgv) {
36860
37235
  emit(flags2.json ? JSON.stringify(res, null, 2) + "\n" : formatDeltaPanel(res), flags2.out);
36861
37236
  } else if (cmd === "impact") {
36862
37237
  if (!flags2.positional) throw new Error("impact needs a target: cli.mjs impact <file|module> --repo <dir>");
36863
- const { graph } = readArtifacts();
37238
+ const { graph } = await readArtifacts();
36864
37239
  const res = impactOf(graph, flags2.positional, flags2.depth ?? Infinity);
36865
37240
  if (!res) throw new Error(`no such file or module in the index: ${flags2.positional}`);
36866
37241
  emit(JSON.stringify(res, null, 2) + "\n", flags2.out);
36867
37242
  } else if (cmd === "neighbors") {
36868
37243
  if (!flags2.positional) throw new Error("neighbors needs a target: cli.mjs neighbors <file|module> --repo <dir>");
36869
- const { graph } = readArtifacts();
37244
+ const { graph } = await readArtifacts();
36870
37245
  const kinds = flags2.kind ? new Set(flags2.kind.split(",").map((k) => k.trim()).filter(Boolean)) : void 0;
36871
37246
  const res = neighborsOf(graph, flags2.positional, flags2.depth ?? 1, kinds);
36872
37247
  if (!res) throw new Error(`no such file or module in the index: ${flags2.positional}`);
36873
37248
  emit(JSON.stringify(res, null, 2) + "\n", flags2.out);
36874
37249
  } else if (cmd === "mermaid") {
36875
- const { graph } = readArtifacts();
37250
+ const { graph } = await readArtifacts();
36876
37251
  emit(renderMermaid(graph, { module: flags2.positional }), flags2.out);
36877
37252
  } else if (cmd === "grep") {
36878
37253
  if (!flags2.positional) throw new Error("grep needs a pattern: cli.mjs grep <pattern> --repo <dir>");
@@ -36976,7 +37351,7 @@ function expandInputs(inputs, opts = {}) {
36976
37351
  const acc = walkCached(staticBase(input), opts);
36977
37352
  for (const f of acc) if (match(toPosix(f)) && exts.has(ext(f))) files.add(f);
36978
37353
  } else if (existsSync11(input)) {
36979
- if (statSync6(input).isDirectory()) {
37354
+ if (statSync10(input).isDirectory()) {
36980
37355
  const acc = walkCached(input, opts);
36981
37356
  for (const f of acc) if (exts.has(ext(f))) files.add(f);
36982
37357
  } else if (exts.has(ext(input))) {
@@ -37151,7 +37526,7 @@ function parseSourceWithAst(source, file, opts = {}) {
37151
37526
 
37152
37527
  // src/snapshot.ts
37153
37528
  import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync14, readdirSync as readdirSync4, writeFileSync as writeFileSync5 } from "fs";
37154
- import { dirname as dirname5, join as join25 } from "path";
37529
+ import { dirname as dirname6, join as join25 } from "path";
37155
37530
 
37156
37531
  // src/collector.ts
37157
37532
  var COLLECTED_CSS = [
@@ -37476,7 +37851,7 @@ function align(doc, entries) {
37476
37851
  }
37477
37852
  function attachSignals(doc) {
37478
37853
  if (!isSnapshotDom(doc.file)) return;
37479
- const dir = dirname5(doc.file);
37854
+ const dir = dirname6(doc.file);
37480
37855
  const styles = readJson2(join25(dir, "styles.json"));
37481
37856
  const boxes = readJson2(join25(dir, "boxes.json"));
37482
37857
  const axtree = readJson2(join25(dir, "axtree.json"));
@@ -50827,7 +51202,7 @@ function crossToFinding(doc, ruleId, def, cf) {
50827
51202
  import { resolve as absPath } from "path";
50828
51203
 
50829
51204
  // src/graph/resolve.ts
50830
- import { dirname as dirname6, join as join26 } from "path";
51205
+ import { dirname as dirname7, join as join26 } from "path";
50831
51206
  var EXT_ORDER = [".tsx", ".jsx", ".ts", ".js"];
50832
51207
  function candidates(base) {
50833
51208
  const out2 = [base];
@@ -50849,7 +51224,7 @@ function matchKnown(base, known) {
50849
51224
  }
50850
51225
  function resolveSpecifier(fromFile, spec, known, aliases) {
50851
51226
  if (spec.startsWith(".")) {
50852
- return matchKnown(join26(dirname6(toPosix(fromFile)), spec), known);
51227
+ return matchKnown(join26(dirname7(toPosix(fromFile)), spec), known);
50853
51228
  }
50854
51229
  if (aliases?.length) {
50855
51230
  for (const rule of aliases) {
@@ -50873,7 +51248,7 @@ function resolveSpecifier(fromFile, spec, known, aliases) {
50873
51248
 
50874
51249
  // src/graph/tsconfig.ts
50875
51250
  import { existsSync as existsSync13, readFileSync as readFileSync16 } from "fs";
50876
- import { dirname as dirname7, join as join27, resolve as resolve5, relative } from "path";
51251
+ import { dirname as dirname8, join as join27, resolve as resolve5, relative } from "path";
50877
51252
  function readJsonish(path) {
50878
51253
  try {
50879
51254
  const raw = readFileSync16(path, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/,(\s*[}\]])/g, "$1");
@@ -50887,7 +51262,7 @@ function findTsconfig(startDir) {
50887
51262
  for (let i2 = 0; i2 < 30; i2++) {
50888
51263
  const p = join27(dir, "tsconfig.json");
50889
51264
  if (existsSync13(p)) return p;
50890
- const parent = dirname7(dir);
51265
+ const parent = dirname8(dir);
50891
51266
  if (parent === dir) break;
50892
51267
  dir = parent;
50893
51268
  }
@@ -50907,7 +51282,7 @@ function tsconfigChain(startDir) {
50907
51282
  out2.push(p);
50908
51283
  const cfg = readJsonish(p);
50909
51284
  const exts = Array.isArray(cfg?.extends) ? cfg.extends : typeof cfg?.extends === "string" ? [cfg.extends] : [];
50910
- const dir = dirname7(p);
51285
+ const dir = dirname8(p);
50911
51286
  for (const e of exts) {
50912
51287
  if (typeof e !== "string") continue;
50913
51288
  const cands = e.endsWith(".json") ? [resolve5(dir, e)] : [resolve5(dir, `${e}.json`), resolve5(dir, e, "tsconfig.json")];
@@ -50920,7 +51295,7 @@ function tsconfigChain(startDir) {
50920
51295
  function readTsAliases(startDir, cwd = process.cwd()) {
50921
51296
  const tsconfigPath = findTsconfig(startDir);
50922
51297
  if (!tsconfigPath) return [];
50923
- const root = dirname7(tsconfigPath);
51298
+ const root = dirname8(tsconfigPath);
50924
51299
  const cfg = readJsonish(tsconfigPath);
50925
51300
  if (!cfg) return [];
50926
51301
  let co = cfg.compilerOptions ?? {};
@@ -51378,7 +51753,7 @@ function runPackRules(doc, pack) {
51378
51753
  }
51379
51754
 
51380
51755
  // src/graph/build.ts
51381
- import { dirname as dirname8 } from "path";
51756
+ import { dirname as dirname9 } from "path";
51382
51757
 
51383
51758
  // src/graph/imports.ts
51384
51759
  var NAME_PROPS2 = /* @__PURE__ */ new Set(["aria-label", "aria-labelledby", "title", "label", "alt"]);
@@ -51676,7 +52051,7 @@ function buildGraphAndDocs(files, opts = {}) {
51676
52051
  }
51677
52052
  nodes.push(extractGraphNode(ast, doc, file, { sfc }));
51678
52053
  }
51679
- const startDir = files[0] ? dirname8(files[0]) : process.cwd();
52054
+ const startDir = files[0] ? dirname9(files[0]) : process.cwd();
51680
52055
  return { graph: buildGraph2(nodes, readTsAliases(startDir), startDir), docs };
51681
52056
  }
51682
52057
 
@@ -52498,7 +52873,7 @@ function baselineSummary(diff, lang = "fr") {
52498
52873
  }
52499
52874
 
52500
52875
  // src/config.ts
52501
- import { existsSync as existsSync16, statSync as statSync7 } from "fs";
52876
+ import { existsSync as existsSync16, statSync as statSync11 } from "fs";
52502
52877
  import { join as join29, isAbsolute as isAbsolute2 } from "path";
52503
52878
 
52504
52879
  // src/pack.ts
@@ -56645,7 +57020,7 @@ function loadConfig(cwd) {
56645
57020
  }
56646
57021
  function packPaths(path) {
56647
57022
  if (!existsSync16(path)) return null;
56648
- if (statSync7(path).isDirectory()) {
57023
+ if (statSync11(path).isDirectory()) {
56649
57024
  const pack = join29(path, "pack.json");
56650
57025
  if (!existsSync16(pack)) return null;
56651
57026
  const glossary = join29(path, "glossary.json");
@@ -60310,7 +60685,7 @@ function renderCriteriaReference() {
60310
60685
 
60311
60686
  // src/check.ts
60312
60687
  import { existsSync as existsSync21, readFileSync as readFileSync19, readdirSync as readdirSync5 } from "fs";
60313
- import { dirname as dirname9, join as join34 } from "path";
60688
+ import { dirname as dirname10, join as join34 } from "path";
60314
60689
 
60315
60690
  // src/verify.ts
60316
60691
  import { existsSync as existsSync19, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
@@ -60874,7 +61249,7 @@ function checkSemantic(md, opts) {
60874
61249
  const standard = opts.standard ?? "wcag";
60875
61250
  const s = M[lang];
60876
61251
  const empty = { total: 0, grounded: 0, moved: 0, failed: 0 };
60877
- const artifact = opts.verdictsPath ?? join34(dirname9(opts.reportPath), "VERIFY.todo.json");
61252
+ const artifact = opts.verdictsPath ?? join34(dirname10(opts.reportPath), "VERIFY.todo.json");
60878
61253
  if (!existsSync21(artifact)) return { ok: false, issues: [s.semanticMissing(artifact)], ...empty };
60879
61254
  let items;
60880
61255
  try {
@@ -61087,7 +61462,7 @@ function openPerPage(audit2, standard, lang) {
61087
61462
  }
61088
61463
 
61089
61464
  // src/adjudicate.ts
61090
- import { mkdirSync as mkdirSync9, statSync as statSync8, writeFileSync as writeFileSync10 } from "fs";
61465
+ import { mkdirSync as mkdirSync9, statSync as statSync12, writeFileSync as writeFileSync10 } from "fs";
61091
61466
  import { isAbsolute as isAbsolute3, join as join35, relative as relative4, resolve as resolve10 } from "path";
61092
61467
 
61093
61468
  // src/data/adjudication.json
@@ -62124,7 +62499,7 @@ function withinAuditInput(file, audit2, cwd) {
62124
62499
  if (input === "-" || input === "<stdin>") continue;
62125
62500
  const root = resolve10(cwd ?? process.cwd(), input);
62126
62501
  try {
62127
- if (statSync8(root).isDirectory()) {
62502
+ if (statSync12(root).isDirectory()) {
62128
62503
  const rel2 = relative4(root, target);
62129
62504
  if (rel2 === "" || rel2 !== ".." && !rel2.startsWith("../") && !isAbsolute3(rel2)) return true;
62130
62505
  } else if (root === target) return true;
@@ -63082,7 +63457,7 @@ function pruneRefuted(audit2, standard, items, lang = "en") {
63082
63457
  // src/ledger.ts
63083
63458
  import { createHash as createHash6 } from "crypto";
63084
63459
  import { existsSync as existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
63085
- import { dirname as dirname10, join as join36 } from "path";
63460
+ import { dirname as dirname11, join as join36 } from "path";
63086
63461
  var LEDGER_DIR = ".ultra11y/verdicts";
63087
63462
  function ledgerPath(standard, root = ".") {
63088
63463
  return join36(root, LEDGER_DIR, `${standard}.json`);
@@ -63144,7 +63519,7 @@ function unreadableCaptures(audit2, cwd = ".") {
63144
63519
  return (audit2.scope.pagesAudited ?? []).filter((id) => !existsSync22(join36(cwd, PAGES_DIR, id, "dom.html")));
63145
63520
  }
63146
63521
  function writeLedger(path, ledger) {
63147
- mkdirSync10(dirname10(path), { recursive: true });
63522
+ mkdirSync10(dirname11(path), { recursive: true });
63148
63523
  const sorted = { ...ledger, entries: [...ledger.entries].sort((a, b) => a.criteriaId.localeCompare(b.criteriaId, "en", { numeric: true })) };
63149
63524
  writeFileSync11(path, `${JSON.stringify(sorted, null, 2)}
63150
63525
  `);
@@ -63740,9 +64115,9 @@ async function runCli2(argv, prompt, opts, extract) {
63740
64115
 
63741
64116
  // src/agent-codex.ts
63742
64117
  import { spawn as spawn3 } from "child_process";
63743
- import { existsSync as existsSync24, mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "fs";
64118
+ import { existsSync as existsSync24, mkdtempSync as mkdtempSync3, rmSync as rmSync4, writeFileSync as writeFileSync12 } from "fs";
63744
64119
  import { tmpdir as tmpdir2 } from "os";
63745
- import { delimiter as delimiter2, dirname as dirname11, join as join38 } from "path";
64120
+ import { delimiter as delimiter2, dirname as dirname12, join as join38 } from "path";
63746
64121
  var MAX_ATTEMPTS3 = 4;
63747
64122
  var CODEX_EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
63748
64123
  var DEFAULT_CODEX_TIMEOUT_MS = 10 * 6e4;
@@ -63806,7 +64181,7 @@ function codexArgv(opts, schemaPath) {
63806
64181
  "multi_agent",
63807
64182
  "--strict-config",
63808
64183
  "--cd",
63809
- dirname11(schemaPath),
64184
+ dirname12(schemaPath),
63810
64185
  "--skip-git-repo-check",
63811
64186
  "--sandbox",
63812
64187
  "read-only",
@@ -63893,7 +64268,7 @@ function transient(message) {
63893
64268
  }
63894
64269
  async function runCodex(schema, prompt, opts, extract) {
63895
64270
  const run2 = opts.spawnImpl ?? realSpawn2;
63896
- const dir = mkdtempSync2(join38(tmpdir2(), "ultra11y-codex-"));
64271
+ const dir = mkdtempSync3(join38(tmpdir2(), "ultra11y-codex-"));
63897
64272
  const schemaPath = join38(dir, "schema.json");
63898
64273
  writeFileSync12(schemaPath, `${JSON.stringify(schema)}
63899
64274
  `, { mode: 384 });
@@ -63927,7 +64302,7 @@ async function runCodex(schema, prompt, opts, extract) {
63927
64302
  return extract(env.result);
63928
64303
  }
63929
64304
  } finally {
63930
- rmSync3(dir, { recursive: true, force: true });
64305
+ rmSync4(dir, { recursive: true, force: true });
63931
64306
  }
63932
64307
  throw new Error(`ultra11y judge: ${lastError || "Codex failed after every attempt."}`);
63933
64308
  }
@@ -63948,7 +64323,7 @@ async function refuteBatchCodex(items, prompt, opts, lang = "en") {
63948
64323
 
63949
64324
  // src/scan.ts
63950
64325
  import { execFileSync as execFileSync6 } from "child_process";
63951
- import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync13, existsSync as existsSync26, statSync as statSync9, readdirSync as readdirSync6, rmSync as rmSync4, readFileSync as readFileSync21 } from "fs";
64326
+ import { mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync13, existsSync as existsSync26, statSync as statSync13, readdirSync as readdirSync6, rmSync as rmSync5, readFileSync as readFileSync21 } from "fs";
63952
64327
  import { tmpdir as tmpdir3 } from "os";
63953
64328
  import { join as join39, resolve as resolve11 } from "path";
63954
64329
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -64291,14 +64666,14 @@ function imageExists(tag) {
64291
64666
  }
64292
64667
  var CTX_PREFIX = "ultra11y-dyn-";
64293
64668
  function buildImage(tag = IMAGE_TAG) {
64294
- const ctx = mkdtempSync3(join39(tmpdir3(), CTX_PREFIX));
64669
+ const ctx = mkdtempSync4(join39(tmpdir3(), CTX_PREFIX));
64295
64670
  try {
64296
64671
  writeFileSync13(join39(ctx, "runner.mjs"), RUNNER);
64297
64672
  writeFileSync13(join39(ctx, "package.json"), PKG);
64298
64673
  writeFileSync13(join39(ctx, "Dockerfile"), DOCKERFILE);
64299
64674
  execFileSync6("docker", ["build", "-t", tag, ctx], { stdio: "inherit", timeout: 9e5 });
64300
64675
  } finally {
64301
- rmSync4(ctx, { recursive: true, force: true });
64676
+ rmSync5(ctx, { recursive: true, force: true });
64302
64677
  }
64303
64678
  }
64304
64679
  function cleanTempContexts() {
@@ -64306,7 +64681,7 @@ function cleanTempContexts() {
64306
64681
  const dir = tmpdir3();
64307
64682
  for (const name2 of readdirSync6(dir)) {
64308
64683
  if (!name2.startsWith(CTX_PREFIX)) continue;
64309
- rmSync4(join39(dir, name2), { recursive: true, force: true });
64684
+ rmSync5(join39(dir, name2), { recursive: true, force: true });
64310
64685
  removed++;
64311
64686
  }
64312
64687
  return removed;
@@ -64518,7 +64893,7 @@ function runScan(opts) {
64518
64893
  }
64519
64894
  const tag = opts.tag ?? IMAGE_TAG;
64520
64895
  if (!imageExists(tag)) buildImage(tag);
64521
- const isFile = !isUrl3 && existsSync26(opts.target) && statSync9(opts.target).isFile();
64896
+ const isFile = !isUrl3 && existsSync26(opts.target) && statSync13(opts.target).isFile();
64522
64897
  const out2 = runRunner(opts.target, isFile, tag, Boolean(opts.snapshotRoot));
64523
64898
  const id = opts.snapshotRoot ? writeRunnerSnapshot(opts.snapshotRoot, out2, opts.target) : void 0;
64524
64899
  return { ...toDynamicResult(out2, opts.target), testedScs: [...DOCKER_TESTED_SCS], ...id ? { snapshots: [id] } : {} };
@@ -64797,7 +65172,7 @@ function mergeSnapshotAudit(base, snap) {
64797
65172
  }
64798
65173
 
64799
65174
  // src/scan-local.ts
64800
- import { existsSync as existsSync27, statSync as statSync10 } from "fs";
65175
+ import { existsSync as existsSync27, statSync as statSync14 } from "fs";
64801
65176
  import { createRequire } from "module";
64802
65177
  import { resolve as resolve12 } from "path";
64803
65178
 
@@ -64901,7 +65276,8 @@ function focusSetupExpr(scope = "", maxFocusables = PROBE_DEFAULTS.maxFocusables
64901
65276
  const rootExpr = scope ? `document.querySelectorAll(${JSON.stringify(scope)})` : `[document.documentElement]`;
64902
65277
  return `(() => { ${PRELUDE}
64903
65278
  const sel = 'a[href],button:not([disabled]),input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"]),[role=button]:not([disabled])';
64904
- const snap = (e) => { const s = getComputedStyle(e); return [s.outlineStyle, s.outlineWidth, s.outlineColor, s.boxShadow, s.borderColor, s.borderTopWidth, s.borderBottomWidth, s.backgroundColor, s.color, s.textDecorationLine].join('|'); };
65279
+ const __style = (e, pseudo) => { const s = getComputedStyle(e, pseudo); return [s.outlineStyle, s.outlineWidth, s.outlineColor, s.boxShadow, s.borderColor, s.borderTopWidth, s.borderBottomWidth, s.backgroundColor, s.color, s.textDecorationLine].join('|'); };
65280
+ const snap = (e) => [__style(e, null), __style(e, '::before'), __style(e, '::after')].join('#');
64905
65281
  // Visually-hidden radio/checkbox \u2192 measure its visible label/proxy, not the input.
64906
65282
  const proxyFor = (e) => {
64907
65283
  const type = (e.getAttribute('type') || '').toLowerCase();
@@ -64943,8 +65319,12 @@ var FOCUS_CHECK_PROBE = `(() => {
64943
65319
  if (!key || !window.__u11yF || !window.__u11yF[key]) return null;
64944
65320
  const rec = window.__u11yF[key];
64945
65321
  const proxy = document.querySelector('[data-u11y-fp="' + key + '"]') || e;
64946
- const s = getComputedStyle(proxy);
64947
- const now = [s.outlineStyle, s.outlineWidth, s.outlineColor, s.boxShadow, s.borderColor, s.borderTopWidth, s.borderBottomWidth, s.backgroundColor, s.color, s.textDecorationLine].join('|');
65322
+ // THE SAME THREE BOXES pass 1 snapshotted, in the same order. A design system that paints
65323
+ // its control in label::before -- DSFR, GOV.UK, USWDS, Bootstrap -- puts the focus ring
65324
+ // there too, and reading only the element would report every one of them as unfocusable.
65325
+ // (No backticks in this comment: it lives inside a template literal.)
65326
+ const st = (pseudo) => { const s = getComputedStyle(proxy, pseudo); return [s.outlineStyle, s.outlineWidth, s.outlineColor, s.boxShadow, s.borderColor, s.borderTopWidth, s.borderBottomWidth, s.backgroundColor, s.color, s.textDecorationLine].join('|'); };
65327
+ const now = [st(null), st('::before'), st('::after')].join('#');
64948
65328
  return { key: key, changed: now !== rec.rest, selector: rec.sel, html: rec.html };
64949
65329
  })()`;
64950
65330
  var FOCUS_OBSCURED_PROBE = `(() => { ${PRELUDE}
@@ -65605,7 +65985,7 @@ async function runScanLocal(opts) {
65605
65985
  if (!isUrl3 && !existsSync27(opts.target)) {
65606
65986
  throw new Error(`File not found: ${opts.target}. Pass an http(s):// URL or an existing HTML file.`);
65607
65987
  }
65608
- const isFile = !isUrl3 && statSync10(opts.target).isFile();
65988
+ const isFile = !isUrl3 && statSync14(opts.target).isFile();
65609
65989
  const lang = opts.lang ?? "en";
65610
65990
  const interact = opts.interact !== false;
65611
65991
  const { chromium, AxeBuilder } = resolveLocalDeps(opts.cwd);
@@ -66252,7 +66632,7 @@ function fixSummary(r, lang = "fr", write = false, standard = CORE2) {
66252
66632
  }
66253
66633
 
66254
66634
  // src/init.ts
66255
- import { writeFileSync as writeFileSync15, mkdirSync as mkdirSync11, chmodSync, realpathSync as realpathSync2 } from "fs";
66635
+ import { writeFileSync as writeFileSync15, mkdirSync as mkdirSync11, chmodSync as chmodSync2, realpathSync as realpathSync3 } from "fs";
66256
66636
  import { execFileSync as execFileSync7 } from "child_process";
66257
66637
  import { join as join40, relative as relative5, sep as sep4 } from "path";
66258
66638
  var EN_SEV = { bloquant: "blocking", majeur: "major", mineur: "minor" };
@@ -66266,7 +66646,7 @@ function repoRoot() {
66266
66646
  function resolveEnginePath(root) {
66267
66647
  const argv1 = process.argv[1] ?? "scripts/ultra11y.mjs";
66268
66648
  try {
66269
- const abs = realpathSync2(argv1);
66649
+ const abs = realpathSync3(argv1);
66270
66650
  return abs.startsWith(root + sep4) ? relative5(root, abs) : abs;
66271
66651
  } catch {
66272
66652
  return argv1;
@@ -66376,7 +66756,7 @@ function writeHook(root, enginePath, failOn, mode = "staged") {
66376
66756
  mkdirSync11(dir, { recursive: true });
66377
66757
  const path = join40(dir, "pre-commit");
66378
66758
  writeFileSync15(path, mode === "baseline" ? hookScript(enginePath, failOn) : stagedHookScript(enginePath, failOn));
66379
- chmodSync(path, 493);
66759
+ chmodSync2(path, 493);
66380
66760
  return path;
66381
66761
  }
66382
66762
  function writeCi(root, enginePath, failOn) {
@@ -66388,8 +66768,8 @@ function writeCi(root, enginePath, failOn) {
66388
66768
  }
66389
66769
 
66390
66770
  // src/install/json-edit.ts
66391
- import { copyFileSync as copyFileSync2, existsSync as existsSync28, mkdirSync as mkdirSync12, readFileSync as readFileSync23, renameSync as renameSync2, rmSync as rmSync5, writeFileSync as writeFileSync16 } from "fs";
66392
- import { dirname as dirname12 } from "path";
66771
+ import { copyFileSync as copyFileSync2, existsSync as existsSync28, mkdirSync as mkdirSync12, readFileSync as readFileSync23, renameSync as renameSync3, rmSync as rmSync6, writeFileSync as writeFileSync16 } from "fs";
66772
+ import { dirname as dirname13 } from "path";
66393
66773
  var SettingsParseError = class extends Error {
66394
66774
  constructor(path, cause) {
66395
66775
  super(`${path} is not valid JSON (${cause}) \u2014 fix or move it, then run install again. It has NOT been modified.`);
@@ -66403,7 +66783,7 @@ function stamp() {
66403
66783
  }
66404
66784
  function writeTextWithBackup(path, content, marker = "ultra11y") {
66405
66785
  if (existsSync28(path) && readFileSync23(path, "utf8") === content) return { path, changed: false };
66406
- mkdirSync12(dirname12(path), { recursive: true });
66786
+ mkdirSync12(dirname13(path), { recursive: true });
66407
66787
  let backup;
66408
66788
  if (existsSync28(path)) {
66409
66789
  backup = `${path}.${marker}-backup-${stamp()}`;
@@ -66412,9 +66792,9 @@ function writeTextWithBackup(path, content, marker = "ultra11y") {
66412
66792
  const tmp = `${path}.${process.pid}.tmp`;
66413
66793
  try {
66414
66794
  writeFileSync16(tmp, content, { mode: 420 });
66415
- renameSync2(tmp, path);
66795
+ renameSync3(tmp, path);
66416
66796
  } catch (e) {
66417
- rmSync5(tmp, { force: true });
66797
+ rmSync6(tmp, { force: true });
66418
66798
  throw e;
66419
66799
  }
66420
66800
  return { path, changed: true, backup };
@@ -66485,7 +66865,7 @@ function claudeCodeWired(settingsPath) {
66485
66865
  }
66486
66866
 
66487
66867
  // src/install/text-edit.ts
66488
- import { existsSync as existsSync29, readFileSync as readFileSync24, rmSync as rmSync6 } from "fs";
66868
+ import { existsSync as existsSync29, readFileSync as readFileSync24, rmSync as rmSync7 } from "fs";
66489
66869
  var BLOCK_BEGIN = "<!-- BEGIN ultra11y (managed by `ultra11y install --agents-md`; edit outside this block) -->";
66490
66870
  var BLOCK_END = "<!-- END ultra11y -->";
66491
66871
  var blockRe = () => new RegExp(`${escapeRe2(BLOCK_BEGIN)}[\\s\\S]*?${escapeRe2(BLOCK_END)}\\n?`);
@@ -66509,7 +66889,7 @@ function removeManagedBlock(path) {
66509
66889
  if (!blockRe().test(current)) return { path, changed: false };
66510
66890
  const rest = current.replace(blockRe(), "");
66511
66891
  if (rest.trim() === "") {
66512
- rmSync6(path, { force: true });
66892
+ rmSync7(path, { force: true });
66513
66893
  return { path, changed: true };
66514
66894
  }
66515
66895
  return writeTextWithBackup(path, rest.replace(/\n+$/, "\n"));
@@ -66580,9 +66960,9 @@ import { existsSync as existsSync31, readFileSync as readFileSync26 } from "fs";
66580
66960
  import { join as join43 } from "path";
66581
66961
 
66582
66962
  // src/install/paths.ts
66583
- import { copyFileSync as copyFileSync3, cpSync, existsSync as existsSync30, mkdirSync as mkdirSync13, readFileSync as readFileSync25, realpathSync as realpathSync3, statSync as statSync11 } from "fs";
66963
+ import { copyFileSync as copyFileSync3, cpSync, existsSync as existsSync30, mkdirSync as mkdirSync13, readFileSync as readFileSync25, realpathSync as realpathSync4, statSync as statSync15 } from "fs";
66584
66964
  import { homedir as homedir2 } from "os";
66585
- import { dirname as dirname13, join as join42 } from "path";
66965
+ import { dirname as dirname14, join as join42 } from "path";
66586
66966
  function codexHome() {
66587
66967
  return process.env.CODEX_HOME || join42(homedir2(), ".codex");
66588
66968
  }
@@ -66602,7 +66982,7 @@ function installedCliCommand() {
66602
66982
  const argv1 = process.argv[1];
66603
66983
  let source = null;
66604
66984
  try {
66605
- if (argv1) source = realpathSync3(argv1);
66985
+ if (argv1) source = realpathSync4(argv1);
66606
66986
  } catch {
66607
66987
  }
66608
66988
  const ephemeral = !source || /[/\\](?:_npx|\.npm[/\\]_npx|npm-cache|Temp|tmp)[/\\]/.test(source);
@@ -66617,13 +66997,13 @@ function installedCliCommand() {
66617
66997
  function packageRoot() {
66618
66998
  let dir;
66619
66999
  try {
66620
- dir = dirname13(realpathSync3(process.argv[1] ?? ""));
67000
+ dir = dirname14(realpathSync4(process.argv[1] ?? ""));
66621
67001
  } catch {
66622
67002
  return null;
66623
67003
  }
66624
67004
  for (let i2 = 0; i2 < 6 && dir && dir !== "/"; i2++) {
66625
67005
  if (existsSync30(join42(dir, "skills", "review-a11y", "SKILL.md"))) return dir;
66626
- dir = dirname13(dir);
67006
+ dir = dirname14(dir);
66627
67007
  }
66628
67008
  return null;
66629
67009
  }
@@ -66647,7 +67027,7 @@ function copySkillsInto(source, dest) {
66647
67027
  const a = join42(from, f);
66648
67028
  const b = join42(to, f);
66649
67029
  try {
66650
- return existsSync30(b) && statSync11(a).size === statSync11(b).size && readFileSync25(a).equals(readFileSync25(b));
67030
+ return existsSync30(b) && statSync15(a).size === statSync15(b).size && readFileSync25(a).equals(readFileSync25(b));
66651
67031
  } catch {
66652
67032
  return false;
66653
67033
  }
@@ -66751,7 +67131,7 @@ function codexHooksEnabled(codexDir) {
66751
67131
  }
66752
67132
 
66753
67133
  // src/install/opencode.ts
66754
- import { existsSync as existsSync32, readFileSync as readFileSync27, rmSync as rmSync7 } from "fs";
67134
+ import { existsSync as existsSync32, readFileSync as readFileSync27, rmSync as rmSync8 } from "fs";
66755
67135
  import { join as join44 } from "path";
66756
67136
  var OPENCODE_MARKER = "ULTRA11Y_OPENCODE_PLUGIN";
66757
67137
  function pluginTarget(configDir) {
@@ -66780,8 +67160,8 @@ function uninstallOpencode({ configDir }) {
66780
67160
  const reports = [];
66781
67161
  const target = pluginTarget(configDir);
66782
67162
  if (existsSync32(target) && readFileSync27(target, "utf8").includes(OPENCODE_MARKER)) {
66783
- rmSync7(target, { force: true });
66784
- rmSync7(join44(configDir, "plugin", "ultra11y.mjs"), { force: true });
67163
+ rmSync8(target, { force: true });
67164
+ rmSync8(join44(configDir, "plugin", "ultra11y.mjs"), { force: true });
66785
67165
  reports.push({ path: target, changed: true });
66786
67166
  }
66787
67167
  const configPath = join44(configDir, "opencode.json");
@@ -68126,7 +68506,7 @@ function writeEvidence(result, opts) {
68126
68506
  }
68127
68507
 
68128
68508
  // src/html-emit.ts
68129
- import { mkdirSync as mkdirSync15, readFileSync as readFileSync29, statSync as statSync12, writeFileSync as writeFileSync18 } from "fs";
68509
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync29, statSync as statSync16, writeFileSync as writeFileSync18 } from "fs";
68130
68510
  import { join as join47 } from "path";
68131
68511
 
68132
68512
  // src/html.ts
@@ -68767,7 +69147,7 @@ var T5 = {
68767
69147
  var mb = (n) => (n / (1024 * 1024)).toFixed(1);
68768
69148
  function inlineSize(path) {
68769
69149
  try {
68770
- return Math.ceil(statSync12(path).size / 3) * 4;
69150
+ return Math.ceil(statSync16(path).size / 3) * 4;
68771
69151
  } catch {
68772
69152
  return 0;
68773
69153
  }
@@ -68928,7 +69308,7 @@ function noticeRuns(notices) {
68928
69308
  // src/dev.ts
68929
69309
  import { createServer } from "http";
68930
69310
  import { mkdirSync as mkdirSync16, readFileSync as readFileSync30, writeFileSync as writeFileSync19 } from "fs";
68931
- import { dirname as dirname14, join as join48 } from "path";
69311
+ import { dirname as dirname15, join as join48 } from "path";
68932
69312
  var DEV_DEFAULT_PORT = 4111;
68933
69313
  function criterionLabel3(f, standard) {
68934
69314
  if (isCore(standard)) return `WCAG ${f.criteriaId}`;
@@ -69286,7 +69666,7 @@ function startDevServer(opts) {
69286
69666
  let auditPath;
69287
69667
  if (applied.ok) {
69288
69668
  auditPath = join48(opts.root, "audits", "audit-latest.json");
69289
- mkdirSync16(dirname14(auditPath), { recursive: true });
69669
+ mkdirSync16(dirname15(auditPath), { recursive: true });
69290
69670
  writeFileSync19(auditPath, `${JSON.stringify(applied.audit, null, 2)}
69291
69671
  `);
69292
69672
  }
@@ -69605,7 +69985,7 @@ function e2eSetupPlan(runners, paths, lang = "en") {
69605
69985
  }
69606
69986
 
69607
69987
  // src/orchestrate.ts
69608
- import { existsSync as existsSync35, mkdirSync as mkdirSync17, readFileSync as readFileSync31, rmSync as rmSync8, writeFileSync as writeFileSync20 } from "fs";
69988
+ import { existsSync as existsSync35, mkdirSync as mkdirSync17, readFileSync as readFileSync31, rmSync as rmSync9, writeFileSync as writeFileSync20 } from "fs";
69609
69989
  import { join as join50, resolve as resolve13 } from "path";
69610
69990
 
69611
69991
  // src/orchestrate-templates.ts
@@ -69990,7 +70370,7 @@ function orchestrateRun(runDir, engineAbs, opts = {}) {
69990
70370
  if (emitted.has(ph.name)) continue;
69991
70371
  const stale = join50(orchDir, `${ph.name}.workflow.mjs`);
69992
70372
  if (existsSync35(stale)) {
69993
- rmSync8(stale, { force: true });
70373
+ rmSync9(stale, { force: true });
69994
70374
  notices.push(`phase "${ph.name}": stale workflow removed \u2014 its worklist ${ph.ready ? "is now empty" : "no longer exists"}.`);
69995
70375
  }
69996
70376
  }
@@ -70018,7 +70398,7 @@ function orchestrateRun(runDir, engineAbs, opts = {}) {
70018
70398
  import { createInterface as createInterface2 } from "readline";
70019
70399
 
70020
70400
  // src/mcp/handlers.ts
70021
- import { existsSync as existsSync36, readFileSync as readFileSync32, realpathSync as realpathSync4, statSync as statSync13 } from "fs";
70401
+ import { existsSync as existsSync36, readFileSync as readFileSync32, realpathSync as realpathSync5, statSync as statSync17 } from "fs";
70022
70402
  import { isAbsolute as isAbsolute4, join as join51, resolve as resolve14, sep as sep5 } from "path";
70023
70403
 
70024
70404
  // src/criteria-view.ts
@@ -70504,7 +70884,7 @@ function requiredCwd(args2, defaults) {
70504
70884
  if (!cwd) throw new ToolError("`cwd` is required: an absolute path to the project root.");
70505
70885
  const abs = resolve14(cwd);
70506
70886
  if (!existsSync36(abs)) throw new ToolError(`project root not found: ${abs}`);
70507
- if (!statSync13(abs).isDirectory()) throw new ToolError(`\`cwd\` is not a directory: ${abs}`);
70887
+ if (!statSync17(abs).isDirectory()) throw new ToolError(`\`cwd\` is not a directory: ${abs}`);
70508
70888
  return abs;
70509
70889
  }
70510
70890
  function optionalCwd(args2, defaults) {
@@ -70924,15 +71304,15 @@ function handleRead(args2, cwd) {
70924
71304
  const target = isAbsolute4(raw) ? raw : join51(cwd, raw);
70925
71305
  let real;
70926
71306
  try {
70927
- real = realpathSync4(target);
71307
+ real = realpathSync5(target);
70928
71308
  } catch {
70929
71309
  throw new ToolError(`no such file: ${raw}`);
70930
71310
  }
70931
- const root = realpathSync4(cwd);
71311
+ const root = realpathSync5(cwd);
70932
71312
  if (real !== root && !real.startsWith(root + sep5)) {
70933
71313
  throw new ToolError(`path is outside the project: ${raw}. Use your own file tool for anything else.`);
70934
71314
  }
70935
- const st = statSync13(real);
71315
+ const st = statSync17(real);
70936
71316
  if (!st.isFile()) throw new ToolError(`not a file: ${raw}`);
70937
71317
  if (st.size > MAX_READ_BYTES) throw new ToolError(`file is too large to read (${st.size} bytes): ${raw}`);
70938
71318
  const lines = readFileSync32(real, "utf8").split("\n");
@@ -71590,13 +71970,13 @@ function str3(v) {
71590
71970
  var DECLARED = new Set([...TOOLS2, ...WRITE_TOOLS].map((t3) => t3.name));
71591
71971
 
71592
71972
  // src/mcp/resources.ts
71593
- import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync33, realpathSync as realpathSync5, statSync as statSync14 } from "fs";
71594
- import { basename as basename3, dirname as dirname15, join as join52, resolve as resolve15, sep as sep6 } from "path";
71973
+ import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync33, realpathSync as realpathSync6, statSync as statSync18 } from "fs";
71974
+ import { basename as basename4, dirname as dirname16, join as join52, resolve as resolve15, sep as sep6 } from "path";
71595
71975
  import { fileURLToPath as fileURLToPath4 } from "url";
71596
71976
  var SKILL_NAME = "ultra11y";
71597
71977
  var URI_SCHEME = "skill://";
71598
71978
  function resolveSkillRoot(moduleDir) {
71599
- const here = moduleDir ?? dirname15(fileURLToPath4(import.meta.url));
71979
+ const here = moduleDir ?? dirname16(fileURLToPath4(import.meta.url));
71600
71980
  const candidates2 = [resolve15(here, ".."), resolve15(here, "..", "skills", SKILL_NAME), resolve15(here, "..", "..", "skills", SKILL_NAME)];
71601
71981
  return candidates2.find((dir) => existsSync37(join52(dir, "SKILL.md")));
71602
71982
  }
@@ -71608,7 +71988,7 @@ function listResources(moduleDir) {
71608
71988
  if (!existsSync37(refDir)) return out2;
71609
71989
  for (const file of readdirSync7(refDir).sort()) {
71610
71990
  if (!file.endsWith(".md")) continue;
71611
- out2.push(describe(root, join52("references", file), `${SKILL_NAME} reference: ${basename3(file, ".md")}`));
71991
+ out2.push(describe(root, join52("references", file), `${SKILL_NAME} reference: ${basename4(file, ".md")}`));
71612
71992
  }
71613
71993
  return out2;
71614
71994
  }
@@ -71621,17 +72001,17 @@ function readResource(uri, moduleDir) {
71621
72001
  const rel2 = uri.slice(URI_SCHEME.length);
71622
72002
  if (!rel2) throw new ResourceError("empty resource path");
71623
72003
  const target = resolve15(root, rel2);
71624
- const rootReal = realpathSync5(root);
72004
+ const rootReal = realpathSync6(root);
71625
72005
  let targetReal;
71626
72006
  try {
71627
- targetReal = realpathSync5(target);
72007
+ targetReal = realpathSync6(target);
71628
72008
  } catch {
71629
72009
  throw new ResourceError(`no such resource: ${uri}`);
71630
72010
  }
71631
72011
  if (targetReal !== rootReal && !targetReal.startsWith(rootReal + sep6)) {
71632
72012
  throw new ResourceError(`resource path escapes the skill root: ${uri}`);
71633
72013
  }
71634
- if (!statSync14(targetReal).isFile()) throw new ResourceError(`not a file: ${uri}`);
72014
+ if (!statSync18(targetReal).isFile()) throw new ResourceError(`not a file: ${uri}`);
71635
72015
  return { uri, mimeType: "text/markdown", text: readFileSync33(targetReal, "utf8") };
71636
72016
  }
71637
72017
  var ResourceError = class extends Error {
@@ -73077,7 +73457,7 @@ async function cmdAudit(p) {
73077
73457
  const asFile = out2.toLowerCase().endsWith(".json");
73078
73458
  const target = asFile ? out2 : join53(out2, "audit-latest.json");
73079
73459
  try {
73080
- mkdirSync18(asFile ? dirname16(out2) : out2, { recursive: true });
73460
+ mkdirSync18(asFile ? dirname17(out2) : out2, { recursive: true });
73081
73461
  writeFileSync21(target, JSON.stringify(document, null, 2) + "\n");
73082
73462
  console.error(lang === "fr" ? `\u2192 audit \xE9crit dans ${target}` : `\u2192 audit written to ${target}`);
73083
73463
  } catch {
@@ -74001,7 +74381,7 @@ function depsAt(root) {
74001
74381
  function engineRefFor(root) {
74002
74382
  let ref = process.argv[1] ?? "scripts/ultra11y.mjs";
74003
74383
  try {
74004
- const abs = realpathSync6(ref);
74384
+ const abs = realpathSync7(ref);
74005
74385
  ref = abs.startsWith(root + sep7) ? relative6(root, abs) : abs;
74006
74386
  } catch {
74007
74387
  }
@@ -74064,7 +74444,7 @@ Fill in COMPONENTS, run it (e.g. npx tsx ${out2}), then: node scripts/ultra11y.m
74064
74444
  const rel2 = ".ultra11y/capture-setup.mjs";
74065
74445
  const out2 = join53(root, rel2);
74066
74446
  try {
74067
- mkdirSync18(dirname16(out2), { recursive: true });
74447
+ mkdirSync18(dirname17(out2), { recursive: true });
74068
74448
  writeFileSync21(out2, captureSetup());
74069
74449
  } catch (e) {
74070
74450
  console.error(`ultra11y render: could not write ${out2}: ${e instanceof Error ? e.message : String(e)}`);
@@ -75627,7 +76007,7 @@ function cmdOrchestrate(p) {
75627
76007
  );
75628
76008
  return 2;
75629
76009
  }
75630
- const engineAbs = realpathSync6(fileURLToPath5(import.meta.url));
76010
+ const engineAbs = realpathSync7(fileURLToPath5(import.meta.url));
75631
76011
  if (p.flags.list === true) {
75632
76012
  if (!existsSync38(runFlag)) {
75633
76013
  console.error(`ultra11y orchestrate: run dir not found: ${runFlag}.`);
@@ -75778,7 +76158,7 @@ function isInvokedDirectly() {
75778
76158
  if (argv1 === void 0) return false;
75779
76159
  const modulePath = fileURLToPath5(import.meta.url);
75780
76160
  try {
75781
- if (realpathSync6(argv1) === realpathSync6(modulePath)) return true;
76161
+ if (realpathSync7(argv1) === realpathSync7(modulePath)) return true;
75782
76162
  } catch {
75783
76163
  }
75784
76164
  return import.meta.url === pathToFileURL3(argv1).href;