@neat.is/core 0.10.1 → 0.10.3-dev.20260930

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.cjs CHANGED
@@ -59,8 +59,8 @@ function mountBearerAuth(app, opts) {
59
59
  ]);
60
60
  const publicRead = opts.publicRead === true;
61
61
  app.addHook("preHandler", (req, reply, done) => {
62
- const path77 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
- if (exactUnauthPaths.has(path77) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path77)) {
62
+ const path78 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
+ if (exactUnauthPaths.has(path78) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path78)) {
64
64
  done();
65
65
  return;
66
66
  }
@@ -192,8 +192,8 @@ function reshapeGrpcRequest(req) {
192
192
  };
193
193
  }
194
194
  function resolveProtoRoot() {
195
- const here = import_node_path55.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
- return import_node_path55.default.resolve(here, "..", "proto");
195
+ const here = import_node_path56.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
+ return import_node_path56.default.resolve(here, "..", "proto");
197
197
  }
198
198
  function loadTraceService() {
199
199
  const protoRoot = resolveProtoRoot();
@@ -261,13 +261,13 @@ async function startOtelGrpcReceiver(opts) {
261
261
  })
262
262
  };
263
263
  }
264
- var import_node_url, import_node_path55, import_node_crypto2, grpc, protoLoader;
264
+ var import_node_url, import_node_path56, import_node_crypto2, grpc, protoLoader;
265
265
  var init_otel_grpc = __esm({
266
266
  "src/otel-grpc.ts"() {
267
267
  "use strict";
268
268
  init_cjs_shims();
269
269
  import_node_url = require("url");
270
- import_node_path55 = __toESM(require("path"), 1);
270
+ import_node_path56 = __toESM(require("path"), 1);
271
271
  import_node_crypto2 = require("crypto");
272
272
  grpc = __toESM(require("@grpc/grpc-js"), 1);
273
273
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -413,8 +413,8 @@ function websocketChannelPathOf(attrs) {
413
413
  const v = attrs[key];
414
414
  if (typeof v === "string" && v.length > 0) {
415
415
  const q = v.indexOf("?");
416
- const path77 = q === -1 ? v : v.slice(0, q);
417
- if (path77.length > 0) return path77;
416
+ const path78 = q === -1 ? v : v.slice(0, q);
417
+ if (path78.length > 0) return path78;
418
418
  }
419
419
  }
420
420
  return void 0;
@@ -476,10 +476,10 @@ function parseOtlpRequest(body) {
476
476
  return out;
477
477
  }
478
478
  function loadProtoRoot() {
479
- const here = import_node_path56.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
480
- const protoRoot = import_node_path56.default.resolve(here, "..", "proto");
479
+ const here = import_node_path57.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
480
+ const protoRoot = import_node_path57.default.resolve(here, "..", "proto");
481
481
  const root = new import_protobufjs.default.Root();
482
- root.resolvePath = (_origin, target) => import_node_path56.default.resolve(protoRoot, target);
482
+ root.resolvePath = (_origin, target) => import_node_path57.default.resolve(protoRoot, target);
483
483
  root.loadSync(
484
484
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
485
485
  { keepCase: true }
@@ -741,12 +741,12 @@ async function buildOtelReceiver(opts) {
741
741
  };
742
742
  return decorated;
743
743
  }
744
- var import_node_path56, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
744
+ var import_node_path57, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
745
745
  var init_otel = __esm({
746
746
  "src/otel.ts"() {
747
747
  "use strict";
748
748
  init_cjs_shims();
749
- import_node_path56 = __toESM(require("path"), 1);
749
+ import_node_path57 = __toESM(require("path"), 1);
750
750
  import_node_url2 = require("url");
751
751
  import_node_zlib = __toESM(require("zlib"), 1);
752
752
  import_fastify = __toESM(require("fastify"), 1);
@@ -763,7 +763,7 @@ var init_otel = __esm({
763
763
 
764
764
  // src/server.ts
765
765
  init_cjs_shims();
766
- var import_node_path76 = __toESM(require("path"), 1);
766
+ var import_node_path77 = __toESM(require("path"), 1);
767
767
 
768
768
  // src/graph.ts
769
769
  init_cjs_shims();
@@ -1505,8 +1505,8 @@ init_cjs_shims();
1505
1505
 
1506
1506
  // src/ingest.ts
1507
1507
  init_cjs_shims();
1508
- var import_node_fs9 = require("fs");
1509
- var import_node_path10 = __toESM(require("path"), 1);
1508
+ var import_node_fs10 = require("fs");
1509
+ var import_node_path11 = __toESM(require("path"), 1);
1510
1510
  var sourceMapJs = __toESM(require("source-map-js"), 1);
1511
1511
 
1512
1512
  // src/policy.ts
@@ -2032,7 +2032,7 @@ var import_types7 = require("@neat.is/types");
2032
2032
 
2033
2033
  // src/extract/routes.ts
2034
2034
  init_cjs_shims();
2035
- var import_node_path9 = __toESM(require("path"), 1);
2035
+ var import_node_path10 = __toESM(require("path"), 1);
2036
2036
  var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
2037
2037
  var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
2038
2038
  var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
@@ -2058,6 +2058,17 @@ var IGNORED_DIRS = /* @__PURE__ */ new Set([
2058
2058
  "dist",
2059
2059
  "build",
2060
2060
  ".next",
2061
+ // `_next` is the *emitted* half of the pair above — `next build`'s output as
2062
+ // it is served or exported. `.next` was listed and `_next` wasn't, so an
2063
+ // exported bundle walked in as first-party source: minified chunks, one file
2064
+ // per line, hundreds of KB each (#1254).
2065
+ "_next",
2066
+ // Agent scratch space. `.claude/worktrees/` holds a full checkout per agent
2067
+ // session, so walking it re-extracts the whole repo once per worktree — and
2068
+ // pulls in whatever build output those checkouts happen to carry. It is
2069
+ // gitignored in practice, but the file walk doesn't read .gitignore, so the
2070
+ // name has to be listed here.
2071
+ ".claude",
2061
2072
  // Python virtualenv shapes (issue #344). Walking into a venv pulls in the
2062
2073
  // entire CPython stdlib + every installed package as if it were first-party
2063
2074
  // service code — 20k+ files, none of which the user wrote. The shape names
@@ -2289,6 +2300,15 @@ function noteExtractedDropped(edge) {
2289
2300
  function drainDroppedExtracted() {
2290
2301
  return droppedSink.splice(0, droppedSink.length);
2291
2302
  }
2303
+ var skippedSink = /* @__PURE__ */ new Map();
2304
+ function noteSkippedFile(file) {
2305
+ if (!skippedSink.has(file.path)) skippedSink.set(file.path, file);
2306
+ }
2307
+ function drainSkippedFiles() {
2308
+ const out = [...skippedSink.values()];
2309
+ skippedSink.clear();
2310
+ return out;
2311
+ }
2292
2312
  function isRejectedLogEnabled() {
2293
2313
  const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG;
2294
2314
  return raw === "1" || raw === "true";
@@ -2302,14 +2322,91 @@ async function writeRejectedExtracted(drops, rejectedPath) {
2302
2322
 
2303
2323
  // src/extract/calls/shared.ts
2304
2324
  init_cjs_shims();
2325
+ var import_node_fs8 = require("fs");
2326
+ var import_node_path8 = __toESM(require("path"), 1);
2327
+ var import_types4 = require("@neat.is/types");
2328
+
2329
+ // src/extract/gitignore.ts
2330
+ init_cjs_shims();
2305
2331
  var import_node_fs7 = require("fs");
2306
2332
  var import_node_path7 = __toESM(require("path"), 1);
2307
- var import_types4 = require("@neat.is/types");
2333
+ var import_ignore = __toESM(require("ignore"), 1);
2334
+ var LAYER_CACHE = /* @__PURE__ */ new Map();
2335
+ async function layerFor(dir) {
2336
+ const cached = LAYER_CACHE.get(dir);
2337
+ if (cached !== void 0) return cached;
2338
+ let layer = null;
2339
+ try {
2340
+ const raw = await import_node_fs7.promises.readFile(import_node_path7.default.join(dir, ".gitignore"), "utf8");
2341
+ layer = { dir, ig: (0, import_ignore.default)().add(raw) };
2342
+ } catch {
2343
+ layer = null;
2344
+ }
2345
+ LAYER_CACHE.set(dir, layer);
2346
+ return layer;
2347
+ }
2348
+ async function isRepoRoot(dir) {
2349
+ try {
2350
+ await import_node_fs7.promises.stat(import_node_path7.default.join(dir, ".git"));
2351
+ return true;
2352
+ } catch {
2353
+ return false;
2354
+ }
2355
+ }
2356
+ async function loadIgnoreChain(startDir) {
2357
+ const dirs = [];
2358
+ let current = import_node_path7.default.resolve(startDir);
2359
+ for (; ; ) {
2360
+ dirs.push(current);
2361
+ if (await isRepoRoot(current)) break;
2362
+ const parent = import_node_path7.default.dirname(current);
2363
+ if (parent === current) break;
2364
+ current = parent;
2365
+ }
2366
+ dirs.reverse();
2367
+ const layers = [];
2368
+ for (const dir of dirs) {
2369
+ const layer = await layerFor(dir);
2370
+ if (layer) layers.push(layer);
2371
+ }
2372
+ return layers;
2373
+ }
2374
+ async function extendIgnoreChain(chain, dir) {
2375
+ const layer = await layerFor(import_node_path7.default.resolve(dir));
2376
+ return layer ? [...chain, layer] : chain;
2377
+ }
2378
+ function isIgnored(chain, fullPath, isDir) {
2379
+ return decide(chain, fullPath, isDir).ignored;
2380
+ }
2381
+ function decide(chain, fullPath, isDir) {
2382
+ if (chain.length === 0) return { ignored: false, subtree: chain };
2383
+ const abs = import_node_path7.default.resolve(fullPath);
2384
+ let ignored = false;
2385
+ let unignoredAt = -1;
2386
+ for (let i = 0; i < chain.length; i++) {
2387
+ const layer = chain[i];
2388
+ const rel = import_node_path7.default.relative(layer.dir, abs);
2389
+ if (!rel || rel.startsWith("..") || import_node_path7.default.isAbsolute(rel)) continue;
2390
+ const candidate = rel.split(import_node_path7.default.sep).join("/") + (isDir ? "/" : "");
2391
+ const result = layer.ig.test(candidate);
2392
+ if (result.ignored) ignored = true;
2393
+ else if (result.unignored) {
2394
+ ignored = false;
2395
+ unignoredAt = i;
2396
+ }
2397
+ }
2398
+ return {
2399
+ ignored,
2400
+ subtree: unignoredAt >= 0 ? chain.slice(unignoredAt) : chain
2401
+ };
2402
+ }
2403
+
2404
+ // src/extract/calls/shared.ts
2308
2405
  function buildServiceHostIndex(services) {
2309
2406
  const knownHosts = /* @__PURE__ */ new Set();
2310
2407
  const hostToNodeId = /* @__PURE__ */ new Map();
2311
2408
  for (const service of services) {
2312
- const base = import_node_path7.default.basename(service.dir);
2409
+ const base = import_node_path8.default.basename(service.dir);
2313
2410
  knownHosts.add(base);
2314
2411
  knownHosts.add(service.pkg.name);
2315
2412
  hostToNodeId.set(base, service.node.id);
@@ -2318,33 +2415,62 @@ function buildServiceHostIndex(services) {
2318
2415
  return { knownHosts, hostToNodeId };
2319
2416
  }
2320
2417
  async function walkSourceFiles(dir, excludeDirs = []) {
2321
- const excluded = new Set(excludeDirs.map((d) => import_node_path7.default.resolve(d)));
2418
+ const excluded = new Set(excludeDirs.map((d) => import_node_path8.default.resolve(d)));
2322
2419
  const out = [];
2323
- async function walk11(current) {
2324
- const entries = await import_node_fs7.promises.readdir(current, { withFileTypes: true }).catch(() => []);
2420
+ const rootChain = await loadIgnoreChain(dir);
2421
+ async function walk11(current, inherited) {
2422
+ const entries = await import_node_fs8.promises.readdir(current, { withFileTypes: true }).catch(() => []);
2423
+ const chain = entries.some((e) => e.isFile() && e.name === ".gitignore") ? await extendIgnoreChain(inherited, current) : inherited;
2325
2424
  for (const entry of entries) {
2326
- const full = import_node_path7.default.join(current, entry.name);
2425
+ const full = import_node_path8.default.join(current, entry.name);
2327
2426
  if (entry.isDirectory()) {
2328
2427
  if (IGNORED_DIRS.has(entry.name)) continue;
2329
- if (excluded.has(import_node_path7.default.resolve(full))) continue;
2428
+ if (excluded.has(import_node_path8.default.resolve(full))) continue;
2429
+ const verdict = decide(chain, full, true);
2430
+ if (verdict.ignored) continue;
2330
2431
  if (await isPythonVenvDir(full)) continue;
2331
- await walk11(full);
2332
- } else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path7.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
2432
+ await walk11(full, verdict.subtree);
2433
+ } else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path8.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
2333
2434
  // would attribute our instrumentation imports to the user's service.
2334
- !isNeatAuthoredSourceFile(entry.name)) {
2435
+ !isNeatAuthoredSourceFile(entry.name) && !isIgnored(chain, full, false)) {
2335
2436
  out.push(full);
2336
2437
  }
2337
2438
  }
2338
2439
  }
2339
- await walk11(dir);
2440
+ await walk11(dir, rootChain.filter((l) => import_node_path8.default.resolve(l.dir) !== import_node_path8.default.resolve(dir)));
2340
2441
  return out;
2341
2442
  }
2443
+ var MINIFIED_LINE_CHARS = 5e3;
2444
+ function hasMinifiedName(filePath) {
2445
+ return /\.min\.(js|mjs|cjs|jsx|ts|tsx)$/i.test(filePath);
2446
+ }
2447
+ function isMinifiedSource(filePath, content) {
2448
+ if (hasMinifiedName(filePath)) return { minified: true, detail: "named *.min.js" };
2449
+ let longest = 0;
2450
+ let start = 0;
2451
+ for (; ; ) {
2452
+ const nl = content.indexOf("\n", start);
2453
+ const len = (nl === -1 ? content.length : nl) - start;
2454
+ if (len > longest) longest = len;
2455
+ if (nl === -1) break;
2456
+ start = nl + 1;
2457
+ }
2458
+ if (longest > MINIFIED_LINE_CHARS) {
2459
+ return { minified: true, detail: `longest line ${longest} chars` };
2460
+ }
2461
+ return { minified: false, detail: "" };
2462
+ }
2342
2463
  async function loadSourceFiles(dir, excludeDirs = []) {
2343
2464
  const paths = await walkSourceFiles(dir, excludeDirs);
2344
2465
  const out = [];
2345
2466
  for (const p of paths) {
2346
2467
  try {
2347
- const content = await import_node_fs7.promises.readFile(p, "utf8");
2468
+ const content = await import_node_fs8.promises.readFile(p, "utf8");
2469
+ const verdict = isMinifiedSource(p, content);
2470
+ if (verdict.minified) {
2471
+ noteSkippedFile({ path: p, reason: "minified", detail: verdict.detail });
2472
+ continue;
2473
+ }
2348
2474
  out.push({ path: p, content });
2349
2475
  } catch {
2350
2476
  }
@@ -2356,15 +2482,18 @@ function lineOf(text, needle) {
2356
2482
  if (idx < 0) return 1;
2357
2483
  return text.slice(0, idx).split("\n").length;
2358
2484
  }
2485
+ var SNIPPET_MAX_CHARS = 120;
2359
2486
  function snippet(text, line) {
2360
2487
  const lines = text.split("\n");
2361
- return (lines[line - 1] ?? "").trim();
2488
+ const raw = (lines[line - 1] ?? "").trim();
2489
+ if (raw.length <= SNIPPET_MAX_CHARS) return raw;
2490
+ return `${raw.slice(0, SNIPPET_MAX_CHARS)}\u2026 (+${raw.length - SNIPPET_MAX_CHARS} chars)`;
2362
2491
  }
2363
2492
  function toPosix(p) {
2364
2493
  return p.split("\\").join("/");
2365
2494
  }
2366
2495
  function languageForPath(relPath) {
2367
- switch (import_node_path7.default.extname(relPath).toLowerCase()) {
2496
+ switch (import_node_path8.default.extname(relPath).toLowerCase()) {
2368
2497
  case ".py":
2369
2498
  return "python";
2370
2499
  case ".go":
@@ -2438,8 +2567,8 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
2438
2567
 
2439
2568
  // src/extract/imports.ts
2440
2569
  init_cjs_shims();
2441
- var import_node_path8 = __toESM(require("path"), 1);
2442
- var import_node_fs8 = require("fs");
2570
+ var import_node_path9 = __toESM(require("path"), 1);
2571
+ var import_node_fs9 = require("fs");
2443
2572
  var import_tree_sitter = __toESM(require("tree-sitter"), 1);
2444
2573
  var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
2445
2574
  var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
@@ -2584,15 +2713,15 @@ function collectPyImports(node, out) {
2584
2713
  }
2585
2714
  async function fileExists2(p) {
2586
2715
  try {
2587
- await import_node_fs8.promises.access(p);
2716
+ await import_node_fs9.promises.access(p);
2588
2717
  return true;
2589
2718
  } catch {
2590
2719
  return false;
2591
2720
  }
2592
2721
  }
2593
2722
  function isWithinServiceDir(candidate, serviceDir) {
2594
- const rel = import_node_path8.default.relative(serviceDir, candidate);
2595
- return rel !== "" && !rel.startsWith("..") && !import_node_path8.default.isAbsolute(rel);
2723
+ const rel = import_node_path9.default.relative(serviceDir, candidate);
2724
+ return rel !== "" && !rel.startsWith("..") && !import_node_path9.default.isAbsolute(rel);
2596
2725
  }
2597
2726
  var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
2598
2727
  var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
@@ -2600,22 +2729,22 @@ async function firstExistingCandidate(base, serviceDir) {
2600
2729
  for (const ext of JS_EXTENSIONS) {
2601
2730
  const candidate = base + ext;
2602
2731
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2603
- return toPosix(import_node_path8.default.relative(serviceDir, candidate));
2732
+ return toPosix(import_node_path9.default.relative(serviceDir, candidate));
2604
2733
  }
2605
2734
  }
2606
2735
  for (const indexFile of JS_INDEX_FILES) {
2607
- const candidate = import_node_path8.default.join(base, indexFile);
2736
+ const candidate = import_node_path9.default.join(base, indexFile);
2608
2737
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2609
- return toPosix(import_node_path8.default.relative(serviceDir, candidate));
2738
+ return toPosix(import_node_path9.default.relative(serviceDir, candidate));
2610
2739
  }
2611
2740
  }
2612
2741
  return null;
2613
2742
  }
2614
2743
  async function loadTsPathConfig(serviceDir) {
2615
- const tsconfigPath = import_node_path8.default.join(serviceDir, "tsconfig.json");
2744
+ const tsconfigPath = import_node_path9.default.join(serviceDir, "tsconfig.json");
2616
2745
  let raw;
2617
2746
  try {
2618
- raw = await import_node_fs8.promises.readFile(tsconfigPath, "utf8");
2747
+ raw = await import_node_fs9.promises.readFile(tsconfigPath, "utf8");
2619
2748
  } catch {
2620
2749
  return null;
2621
2750
  }
@@ -2624,7 +2753,7 @@ async function loadTsPathConfig(serviceDir) {
2624
2753
  const paths = parsed.compilerOptions?.paths;
2625
2754
  if (!paths || Object.keys(paths).length === 0) return null;
2626
2755
  const baseUrl = parsed.compilerOptions?.baseUrl;
2627
- return { paths, baseDir: baseUrl ? import_node_path8.default.resolve(serviceDir, baseUrl) : serviceDir };
2756
+ return { paths, baseDir: baseUrl ? import_node_path9.default.resolve(serviceDir, baseUrl) : serviceDir };
2628
2757
  } catch (err) {
2629
2758
  recordExtractionError("import alias resolution", tsconfigPath, err);
2630
2759
  return null;
@@ -2642,11 +2771,11 @@ async function resolveTsAlias(specifier, config, serviceDir) {
2642
2771
  if (suffix === null) continue;
2643
2772
  for (const target of targets) {
2644
2773
  const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
2645
- const resolvedBase = import_node_path8.default.resolve(config.baseDir, targetBase, suffix);
2774
+ const resolvedBase = import_node_path9.default.resolve(config.baseDir, targetBase, suffix);
2646
2775
  const hit = await firstExistingCandidate(resolvedBase, serviceDir);
2647
2776
  if (hit) return hit;
2648
2777
  if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists2(resolvedBase)) {
2649
- return toPosix(import_node_path8.default.relative(serviceDir, resolvedBase));
2778
+ return toPosix(import_node_path9.default.relative(serviceDir, resolvedBase));
2650
2779
  }
2651
2780
  }
2652
2781
  }
@@ -2655,18 +2784,18 @@ async function resolveTsAlias(specifier, config, serviceDir) {
2655
2784
  async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
2656
2785
  if (!specifier) return null;
2657
2786
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
2658
- const base = import_node_path8.default.resolve(importerDir, specifier);
2659
- const ext = import_node_path8.default.extname(specifier);
2787
+ const base = import_node_path9.default.resolve(importerDir, specifier);
2788
+ const ext = import_node_path9.default.extname(specifier);
2660
2789
  if (ext) {
2661
2790
  if (ext === ".js" || ext === ".jsx") {
2662
2791
  const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
2663
2792
  const tsSibling = base.slice(0, -ext.length) + tsExt;
2664
2793
  if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists2(tsSibling)) {
2665
- return toPosix(import_node_path8.default.relative(serviceDir, tsSibling));
2794
+ return toPosix(import_node_path9.default.relative(serviceDir, tsSibling));
2666
2795
  }
2667
2796
  }
2668
2797
  if (isWithinServiceDir(base, serviceDir) && await fileExists2(base)) {
2669
- return toPosix(import_node_path8.default.relative(serviceDir, base));
2798
+ return toPosix(import_node_path9.default.relative(serviceDir, base));
2670
2799
  }
2671
2800
  if (!JS_EXTENSIONS.includes(ext)) {
2672
2801
  return firstExistingCandidate(base, serviceDir);
@@ -2681,30 +2810,30 @@ async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
2681
2810
  async function resolvePyImport(imp, importerPath, serviceDir) {
2682
2811
  let baseDir;
2683
2812
  if (imp.level > 0) {
2684
- baseDir = import_node_path8.default.dirname(importerPath);
2685
- for (let i = 1; i < imp.level; i++) baseDir = import_node_path8.default.dirname(baseDir);
2813
+ baseDir = import_node_path9.default.dirname(importerPath);
2814
+ for (let i = 1; i < imp.level; i++) baseDir = import_node_path9.default.dirname(baseDir);
2686
2815
  } else {
2687
2816
  baseDir = serviceDir;
2688
2817
  }
2689
- const moduleBase = imp.modulePath ? import_node_path8.default.join(baseDir, imp.modulePath.split(".").join("/")) : baseDir;
2818
+ const moduleBase = imp.modulePath ? import_node_path9.default.join(baseDir, imp.modulePath.split(".").join("/")) : baseDir;
2690
2819
  const resolved = /* @__PURE__ */ new Set();
2691
2820
  let needModuleFile = imp.names.length === 0;
2692
2821
  for (const name of imp.names) {
2693
- const submoduleFile = import_node_path8.default.join(moduleBase, `${name}.py`);
2694
- const subpackageInit = import_node_path8.default.join(moduleBase, name, "__init__.py");
2822
+ const submoduleFile = import_node_path9.default.join(moduleBase, `${name}.py`);
2823
+ const subpackageInit = import_node_path9.default.join(moduleBase, name, "__init__.py");
2695
2824
  if (isWithinServiceDir(submoduleFile, serviceDir) && await fileExists2(submoduleFile)) {
2696
- resolved.add(toPosix(import_node_path8.default.relative(serviceDir, submoduleFile)));
2825
+ resolved.add(toPosix(import_node_path9.default.relative(serviceDir, submoduleFile)));
2697
2826
  } else if (isWithinServiceDir(subpackageInit, serviceDir) && await fileExists2(subpackageInit)) {
2698
- resolved.add(toPosix(import_node_path8.default.relative(serviceDir, subpackageInit)));
2827
+ resolved.add(toPosix(import_node_path9.default.relative(serviceDir, subpackageInit)));
2699
2828
  } else {
2700
2829
  needModuleFile = true;
2701
2830
  }
2702
2831
  }
2703
2832
  if (needModuleFile) {
2704
- const moduleFileCandidates = imp.modulePath ? [`${moduleBase}.py`, import_node_path8.default.join(moduleBase, "__init__.py")] : [import_node_path8.default.join(moduleBase, "__init__.py")];
2833
+ const moduleFileCandidates = imp.modulePath ? [`${moduleBase}.py`, import_node_path9.default.join(moduleBase, "__init__.py")] : [import_node_path9.default.join(moduleBase, "__init__.py")];
2705
2834
  for (const candidate of moduleFileCandidates) {
2706
2835
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2707
- resolved.add(toPosix(import_node_path8.default.relative(serviceDir, candidate)));
2836
+ resolved.add(toPosix(import_node_path9.default.relative(serviceDir, candidate)));
2708
2837
  break;
2709
2838
  }
2710
2839
  }
@@ -2714,11 +2843,11 @@ async function resolvePyImport(imp, importerPath, serviceDir) {
2714
2843
  async function resolveGoImport(specifier, modulePath, serviceDir) {
2715
2844
  if (specifier !== modulePath && !specifier.startsWith(`${modulePath}/`)) return null;
2716
2845
  const suffix = specifier === modulePath ? "" : specifier.slice(modulePath.length + 1);
2717
- const dir = import_node_path8.default.join(serviceDir, suffix);
2718
- const entries = await import_node_fs8.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
2719
- const candidates = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".go") && !entry.name.endsWith("_test.go")).map((entry) => import_node_path8.default.join(dir, entry.name));
2846
+ const dir = import_node_path9.default.join(serviceDir, suffix);
2847
+ const entries = await import_node_fs9.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
2848
+ const candidates = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".go") && !entry.name.endsWith("_test.go")).map((entry) => import_node_path9.default.join(dir, entry.name));
2720
2849
  if (candidates.length !== 1) return null;
2721
- return toPosix(import_node_path8.default.relative(serviceDir, candidates[0]));
2850
+ return toPosix(import_node_path9.default.relative(serviceDir, candidates[0]));
2722
2851
  }
2723
2852
  function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
2724
2853
  const importeeFileId = (0, import_types5.fileId)(serviceName, importeeRelPath);
@@ -2748,12 +2877,12 @@ async function addImports(graph, services) {
2748
2877
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
2749
2878
  for (const file of files) {
2750
2879
  if (isTestPath(file.path)) continue;
2751
- const relFile = toPosix(import_node_path8.default.relative(service.dir, file.path));
2880
+ const relFile = toPosix(import_node_path9.default.relative(service.dir, file.path));
2752
2881
  const importerFileId = (0, import_types5.fileId)(service.pkg.name, relFile);
2753
- const isPython = import_node_path8.default.extname(file.path) === ".py";
2754
- const isGo = import_node_path8.default.extname(file.path) === ".go";
2755
- if (import_node_path8.default.extname(file.path) === ".rb") continue;
2756
- if (import_node_path8.default.extname(file.path) === ".php") continue;
2882
+ const isPython = import_node_path9.default.extname(file.path) === ".py";
2883
+ const isGo = import_node_path9.default.extname(file.path) === ".go";
2884
+ if (import_node_path9.default.extname(file.path) === ".rb") continue;
2885
+ if (import_node_path9.default.extname(file.path) === ".php") continue;
2757
2886
  if (isGo) {
2758
2887
  let goImports = [];
2759
2888
  try {
@@ -2763,7 +2892,7 @@ async function addImports(graph, services) {
2763
2892
  recordExtractionError("import extraction", file.path, err);
2764
2893
  continue;
2765
2894
  }
2766
- const goMod = await import_node_fs8.promises.readFile(import_node_path8.default.join(service.dir, "go.mod"), "utf8").catch(() => "");
2895
+ const goMod = await import_node_fs9.promises.readFile(import_node_path9.default.join(service.dir, "go.mod"), "utf8").catch(() => "");
2767
2896
  const modulePath = goMod.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
2768
2897
  if (!modulePath) continue;
2769
2898
  for (const imp of goImports) {
@@ -2807,7 +2936,7 @@ async function addImports(graph, services) {
2807
2936
  continue;
2808
2937
  }
2809
2938
  for (const imp of jsImports) {
2810
- const resolved = await resolveJsImport(imp.specifier, import_node_path8.default.dirname(file.path), service.dir, tsPaths);
2939
+ const resolved = await resolveJsImport(imp.specifier, import_node_path9.default.dirname(file.path), service.dir, tsPaths);
2811
2940
  if (!resolved) continue;
2812
2941
  edgesAdded += emitImportEdge(
2813
2942
  graph,
@@ -2932,8 +3061,8 @@ function chiRoutesFromSource(source, parser) {
2932
3061
  chiWalk(tree.rootNode, "", out);
2933
3062
  return out;
2934
3063
  }
2935
- function stripChiRegex(path77) {
2936
- return path77.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
3064
+ function stripChiRegex(path78) {
3065
+ return path78.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
2937
3066
  }
2938
3067
  function chiWalk(node, prefix, out) {
2939
3068
  for (let i = 0; i < node.namedChildCount; i++) {
@@ -3273,7 +3402,7 @@ function isNextPagesApiFile(relFile) {
3273
3402
  if (pagesIdx === -1 || segs[pagesIdx + 1] !== "api") return false;
3274
3403
  const base = segs[segs.length - 1] ?? "";
3275
3404
  if (/^_(app|document|middleware)\./.test(base)) return false;
3276
- return JS_ROUTE_EXTENSIONS.has(import_node_path9.default.extname(base));
3405
+ return JS_ROUTE_EXTENSIONS.has(import_node_path10.default.extname(base));
3277
3406
  }
3278
3407
  function nextSegment(seg) {
3279
3408
  if (seg.startsWith("(") && seg.endsWith(")")) return null;
@@ -3605,9 +3734,9 @@ function rubyRocketRoute(args) {
3605
3734
  if (!pair || pair.type !== "pair") continue;
3606
3735
  const k = pair.childForFieldName("key");
3607
3736
  if (k?.type !== "string") continue;
3608
- const path77 = rubyLiteral(k);
3609
- if (path77 === null) continue;
3610
- return { path: path77, target: rubyLiteral(pair.childForFieldName("value")) };
3737
+ const path78 = rubyLiteral(k);
3738
+ if (path78 === null) continue;
3739
+ return { path: path78, target: rubyLiteral(pair.childForFieldName("value")) };
3611
3740
  }
3612
3741
  return null;
3613
3742
  }
@@ -4455,12 +4584,12 @@ async function expressMountPrefixes(files, serviceDir, tsPaths) {
4455
4584
  const jsParser = makeJsParser2();
4456
4585
  const fileInfo = /* @__PURE__ */ new Map();
4457
4586
  for (const f of files) {
4458
- if (!JS_ROUTE_EXTENSIONS.has(import_node_path9.default.extname(f.path))) continue;
4587
+ if (!JS_ROUTE_EXTENSIONS.has(import_node_path10.default.extname(f.path))) continue;
4459
4588
  if (isTestPath(f.path)) continue;
4460
- const rel = toPosix(import_node_path9.default.relative(serviceDir, f.path));
4589
+ const rel = toPosix(import_node_path10.default.relative(serviceDir, f.path));
4461
4590
  try {
4462
4591
  const tree = parseSource2(jsParser, f.content);
4463
- fileInfo.set(rel, analyzeExpressFile(tree.rootNode, import_node_path9.default.dirname(f.path)));
4592
+ fileInfo.set(rel, analyzeExpressFile(tree.rootNode, import_node_path10.default.dirname(f.path)));
4464
4593
  } catch {
4465
4594
  }
4466
4595
  }
@@ -4559,14 +4688,14 @@ async function addRoutes(graph, services) {
4559
4688
  const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
4560
4689
  for (const file of files) {
4561
4690
  if (isTestPath(file.path)) continue;
4562
- const ext = import_node_path9.default.extname(file.path);
4691
+ const ext = import_node_path10.default.extname(file.path);
4563
4692
  const isPy = ext === ".py";
4564
4693
  const isGo = ext === ".go";
4565
4694
  const isRb = ext === ".rb";
4566
4695
  const isPhp = ext === ".php";
4567
4696
  const isRs = ext === ".rs";
4568
4697
  if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue;
4569
- const relFile = toPosix(import_node_path9.default.relative(service.dir, file.path));
4698
+ const relFile = toPosix(import_node_path10.default.relative(service.dir, file.path));
4570
4699
  let routes;
4571
4700
  try {
4572
4701
  if (isPhp) {
@@ -5023,7 +5152,7 @@ function languageForExt(relPath) {
5023
5152
  function relPathForRuntimeFile(filepath, serviceNode, scanPath) {
5024
5153
  let p = toPosix2(filepath).replace(/^file:\/\//, "");
5025
5154
  if (scanPath && scanPath.length > 0) {
5026
- const absRoot = toPosix2(import_node_path10.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
5155
+ const absRoot = toPosix2(import_node_path11.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
5027
5156
  const anchor = absRoot.endsWith("/") ? absRoot : `${absRoot}/`;
5028
5157
  if (p.startsWith(anchor)) return p.slice(anchor.length);
5029
5158
  }
@@ -5051,10 +5180,10 @@ function resolveDistToSrc(absFilepath, line) {
5051
5180
  entry = null;
5052
5181
  const mapPath = `${absFilepath}.map`;
5053
5182
  try {
5054
- if ((0, import_node_fs9.existsSync)(mapPath)) {
5055
- const raw = JSON.parse((0, import_node_fs9.readFileSync)(mapPath, "utf8"));
5183
+ if ((0, import_node_fs10.existsSync)(mapPath)) {
5184
+ const raw = JSON.parse((0, import_node_fs10.readFileSync)(mapPath, "utf8"));
5056
5185
  const consumer = new sourceMapJs.SourceMapConsumer(raw);
5057
- entry = { consumer, dir: import_node_path10.default.dirname(mapPath) };
5186
+ entry = { consumer, dir: import_node_path11.default.dirname(mapPath) };
5058
5187
  }
5059
5188
  } catch {
5060
5189
  entry = null;
@@ -5074,7 +5203,7 @@ function resolveDistToSrc(absFilepath, line) {
5074
5203
  }
5075
5204
  if (!pos || !pos.source) return null;
5076
5205
  const root = entry.consumer.sourceRoot ?? "";
5077
- const resolved = import_node_path10.default.resolve(entry.dir, root, pos.source);
5206
+ const resolved = import_node_path11.default.resolve(entry.dir, root, pos.source);
5078
5207
  return { filepath: resolved, ...pos.line ? { line: pos.line } : {} };
5079
5208
  } catch {
5080
5209
  return null;
@@ -5618,8 +5747,8 @@ function emitIncidentEvent(project, ev) {
5618
5747
  });
5619
5748
  }
5620
5749
  async function appendErrorEvent(ctx, ev) {
5621
- await import_node_fs9.promises.mkdir(import_node_path10.default.dirname(ctx.errorsPath), { recursive: true });
5622
- await import_node_fs9.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
5750
+ await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(ctx.errorsPath), { recursive: true });
5751
+ await import_node_fs10.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
5623
5752
  emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
5624
5753
  }
5625
5754
  async function appendConnectorIncident(errorsPath, input, project) {
@@ -5634,8 +5763,8 @@ async function appendConnectorIncident(errorsPath, input, project) {
5634
5763
  ...input.attributes && Object.keys(input.attributes).length > 0 ? { attributes: input.attributes } : {},
5635
5764
  affectedNode: input.affectedNode
5636
5765
  };
5637
- await import_node_fs9.promises.mkdir(import_node_path10.default.dirname(errorsPath), { recursive: true });
5638
- await import_node_fs9.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
5766
+ await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(errorsPath), { recursive: true });
5767
+ await import_node_fs10.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
5639
5768
  if (project) emitIncidentEvent(project, ev);
5640
5769
  }
5641
5770
  function landIncidentCallSite(span, callSite, trusted, graph) {
@@ -6226,13 +6355,13 @@ async function markStaleEdges(graph, options = {}) {
6226
6355
  return { count: events.length, events };
6227
6356
  }
6228
6357
  async function appendStaleEvents(staleEventsPath, events) {
6229
- await import_node_fs9.promises.mkdir(import_node_path10.default.dirname(staleEventsPath), { recursive: true });
6358
+ await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(staleEventsPath), { recursive: true });
6230
6359
  const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
6231
- await import_node_fs9.promises.appendFile(staleEventsPath, lines, "utf8");
6360
+ await import_node_fs10.promises.appendFile(staleEventsPath, lines, "utf8");
6232
6361
  }
6233
6362
  async function readStaleEvents(staleEventsPath) {
6234
6363
  try {
6235
- const raw = await import_node_fs9.promises.readFile(staleEventsPath, "utf8");
6364
+ const raw = await import_node_fs10.promises.readFile(staleEventsPath, "utf8");
6236
6365
  return raw.split("\n").filter((line) => line.length > 0).map((line) => JSON.parse(line));
6237
6366
  } catch (err) {
6238
6367
  if (err.code === "ENOENT") return [];
@@ -6268,7 +6397,7 @@ function startStalenessLoop(graph, options = {}) {
6268
6397
  var INCIDENT_READ_MAX_BYTES = 32 * 1024 * 1024;
6269
6398
  var INCIDENT_READ_MAX_EVENTS = 5e3;
6270
6399
  async function readErrorFileTail(errorsPath, maxBytes) {
6271
- const handle = await import_node_fs9.promises.open(errorsPath, "r");
6400
+ const handle = await import_node_fs10.promises.open(errorsPath, "r");
6272
6401
  try {
6273
6402
  const { size } = await handle.stat();
6274
6403
  if (size <= maxBytes) {
@@ -6511,19 +6640,19 @@ function confidenceFromMix(edges, now = Date.now()) {
6511
6640
  function longestIncomingWalk(graph, start, maxDepth) {
6512
6641
  let best = { path: [start], edges: [] };
6513
6642
  const visited = /* @__PURE__ */ new Set([start]);
6514
- function step(node, path77, edges) {
6515
- if (path77.length > best.path.length) {
6516
- best = { path: [...path77], edges: [...edges] };
6643
+ function step(node, path78, edges) {
6644
+ if (path78.length > best.path.length) {
6645
+ best = { path: [...path78], edges: [...edges] };
6517
6646
  }
6518
- if (path77.length - 1 >= maxDepth) return;
6647
+ if (path78.length - 1 >= maxDepth) return;
6519
6648
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
6520
6649
  for (const [srcId, edge] of incoming) {
6521
6650
  if (visited.has(srcId)) continue;
6522
6651
  visited.add(srcId);
6523
- path77.push(srcId);
6652
+ path78.push(srcId);
6524
6653
  edges.push(edge);
6525
- step(srcId, path77, edges);
6526
- path77.pop();
6654
+ step(srcId, path78, edges);
6655
+ path78.pop();
6527
6656
  edges.pop();
6528
6657
  visited.delete(srcId);
6529
6658
  }
@@ -6738,20 +6867,20 @@ function dominantFailingCall(graph, serviceId17, visited) {
6738
6867
  return best;
6739
6868
  }
6740
6869
  function followFailingCallChain(graph, originServiceId, maxDepth) {
6741
- const path77 = [originServiceId];
6870
+ const path78 = [originServiceId];
6742
6871
  const edges = [];
6743
6872
  const visited = /* @__PURE__ */ new Set([originServiceId]);
6744
6873
  let current = originServiceId;
6745
6874
  for (let depth = 0; depth < maxDepth; depth++) {
6746
6875
  const hop = dominantFailingCall(graph, current, visited);
6747
6876
  if (!hop) break;
6748
- path77.push(hop.nextService);
6877
+ path78.push(hop.nextService);
6749
6878
  edges.push(hop.edge);
6750
6879
  visited.add(hop.nextService);
6751
6880
  current = hop.nextService;
6752
6881
  }
6753
6882
  if (edges.length === 0) return null;
6754
- return { path: path77, edges, culprit: current };
6883
+ return { path: path78, edges, culprit: current };
6755
6884
  }
6756
6885
  function isStaleCallEdge(e) {
6757
6886
  return e.type === import_types8.EdgeType.CALLS && e.provenance === import_types8.Provenance.STALE;
@@ -6787,26 +6916,26 @@ function dominantStaleCall(graph, serviceId17, visited) {
6787
6916
  return best;
6788
6917
  }
6789
6918
  function followStaleCallChain(graph, originServiceId, maxDepth) {
6790
- const path77 = [originServiceId];
6919
+ const path78 = [originServiceId];
6791
6920
  const edges = [];
6792
6921
  const visited = /* @__PURE__ */ new Set([originServiceId]);
6793
6922
  let current = originServiceId;
6794
6923
  for (let depth = 0; depth < maxDepth; depth++) {
6795
6924
  const hop = dominantStaleCall(graph, current, visited);
6796
6925
  if (!hop) break;
6797
- path77.push(hop.nextService);
6926
+ path78.push(hop.nextService);
6798
6927
  edges.push(hop.edge);
6799
6928
  visited.add(hop.nextService);
6800
6929
  current = hop.nextService;
6801
6930
  }
6802
6931
  if (edges.length === 0) return null;
6803
- return { path: path77, edges, culprit: current };
6932
+ return { path: path78, edges, culprit: current };
6804
6933
  }
6805
6934
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6806
6935
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
6807
6936
  if (!chain) return null;
6808
6937
  const culprit = chain.culprit;
6809
- const path77 = [...chain.path];
6938
+ const path78 = [...chain.path];
6810
6939
  const edgeProvenances = chain.edges.map((e) => e.provenance);
6811
6940
  const baseConfidence = confidenceFromMix(chain.edges);
6812
6941
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -6814,14 +6943,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6814
6943
  if (loc) {
6815
6944
  let rootCauseNode = culprit;
6816
6945
  if (loc.fileNode) {
6817
- path77.push(loc.fileNode);
6946
+ path78.push(loc.fileNode);
6818
6947
  edgeProvenances.push(import_types8.Provenance.OBSERVED);
6819
6948
  rootCauseNode = loc.fileNode;
6820
6949
  }
6821
6950
  return import_types8.RootCauseResultSchema.parse({
6822
6951
  rootCauseNode,
6823
6952
  rootCauseReason: loc.rootCauseReason,
6824
- traversalPath: path77,
6953
+ traversalPath: path78,
6825
6954
  edgeProvenances,
6826
6955
  confidence,
6827
6956
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -6833,7 +6962,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6833
6962
  return import_types8.RootCauseResultSchema.parse({
6834
6963
  rootCauseNode: culprit,
6835
6964
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
6836
- traversalPath: path77,
6965
+ traversalPath: path78,
6837
6966
  edgeProvenances,
6838
6967
  confidence,
6839
6968
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -7486,10 +7615,10 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
7486
7615
  traversalPath = staleChain.path;
7487
7616
  edgeProvenances = staleChain.edges.map((e) => e.provenance);
7488
7617
  } else if (top.node !== seedNode) {
7489
- const path77 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
7490
- if (path77) {
7491
- traversalPath = path77.nodes;
7492
- edgeProvenances = path77.edges.map((e) => e.provenance);
7618
+ const path78 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
7619
+ if (path78) {
7620
+ traversalPath = path78.nodes;
7621
+ edgeProvenances = path78.edges.map((e) => e.provenance);
7493
7622
  } else {
7494
7623
  traversalPath = [errorNodeId, top.node];
7495
7624
  edgeProvenances = [top.provenance ?? import_types8.Provenance.OBSERVED];
@@ -8251,16 +8380,16 @@ init_cjs_shims();
8251
8380
 
8252
8381
  // src/extract/services.ts
8253
8382
  init_cjs_shims();
8254
- var import_node_fs20 = require("fs");
8255
- var import_node_path22 = __toESM(require("path"), 1);
8256
- var import_ignore = __toESM(require("ignore"), 1);
8383
+ var import_node_fs21 = require("fs");
8384
+ var import_node_path23 = __toESM(require("path"), 1);
8385
+ var import_ignore2 = __toESM(require("ignore"), 1);
8257
8386
  var import_minimatch2 = require("minimatch");
8258
8387
  var import_types19 = require("@neat.is/types");
8259
8388
 
8260
8389
  // src/extract/python.ts
8261
8390
  init_cjs_shims();
8262
- var import_node_fs10 = require("fs");
8263
- var import_node_path11 = __toESM(require("path"), 1);
8391
+ var import_node_fs11 = require("fs");
8392
+ var import_node_path12 = __toESM(require("path"), 1);
8264
8393
  var import_smol_toml = require("smol-toml");
8265
8394
  var REQUIREMENT_LINE = /^\s*([A-Za-z0-9_.-]+)(?:\[[^\]]*\])?\s*(?:(==)\s*([A-Za-z0-9_.+-]+))?/;
8266
8395
  function parseRequirementsTxt(content) {
@@ -8293,25 +8422,25 @@ function depsFromPyProject(pyproject) {
8293
8422
  return out;
8294
8423
  }
8295
8424
  async function discoverPythonService(serviceDir) {
8296
- const pyprojectPath = import_node_path11.default.join(serviceDir, "pyproject.toml");
8297
- const requirementsPath = import_node_path11.default.join(serviceDir, "requirements.txt");
8298
- const setupPath = import_node_path11.default.join(serviceDir, "setup.py");
8425
+ const pyprojectPath = import_node_path12.default.join(serviceDir, "pyproject.toml");
8426
+ const requirementsPath = import_node_path12.default.join(serviceDir, "requirements.txt");
8427
+ const setupPath = import_node_path12.default.join(serviceDir, "setup.py");
8299
8428
  const hasPyproject = await exists2(pyprojectPath);
8300
8429
  const hasRequirements = await exists2(requirementsPath);
8301
8430
  const hasSetup = await exists2(setupPath);
8302
8431
  if (!hasPyproject && !hasRequirements && !hasSetup) return null;
8303
- let name = import_node_path11.default.basename(serviceDir);
8432
+ let name = import_node_path12.default.basename(serviceDir);
8304
8433
  let version;
8305
8434
  const dependencies = {};
8306
8435
  if (hasPyproject) {
8307
- const raw = await import_node_fs10.promises.readFile(pyprojectPath, "utf8");
8436
+ const raw = await import_node_fs11.promises.readFile(pyprojectPath, "utf8");
8308
8437
  const pyproject = (0, import_smol_toml.parse)(raw);
8309
8438
  name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name;
8310
8439
  version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? void 0;
8311
8440
  Object.assign(dependencies, depsFromPyProject(pyproject));
8312
8441
  }
8313
8442
  if (hasRequirements) {
8314
- const raw = await import_node_fs10.promises.readFile(requirementsPath, "utf8");
8443
+ const raw = await import_node_fs11.promises.readFile(requirementsPath, "utf8");
8315
8444
  Object.assign(dependencies, parseRequirementsTxt(raw));
8316
8445
  }
8317
8446
  return { name, version, dependencies };
@@ -8326,8 +8455,8 @@ function pythonToPackage(service) {
8326
8455
 
8327
8456
  // src/extract/go.ts
8328
8457
  init_cjs_shims();
8329
- var import_node_fs11 = require("fs");
8330
- var import_node_path12 = __toESM(require("path"), 1);
8458
+ var import_node_fs12 = require("fs");
8459
+ var import_node_path13 = __toESM(require("path"), 1);
8331
8460
  var import_types10 = require("@neat.is/types");
8332
8461
  function parseGoMod(source) {
8333
8462
  const module2 = source.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
@@ -8354,7 +8483,7 @@ function goFramework(deps) {
8354
8483
  async function discoverGoService(scanPath, dir) {
8355
8484
  let raw;
8356
8485
  try {
8357
- raw = await import_node_fs11.promises.readFile(import_node_path12.default.join(dir, "go.mod"), "utf8");
8486
+ raw = await import_node_fs12.promises.readFile(import_node_path13.default.join(dir, "go.mod"), "utf8");
8358
8487
  } catch {
8359
8488
  return null;
8360
8489
  }
@@ -8369,7 +8498,7 @@ async function discoverGoService(scanPath, dir) {
8369
8498
  name,
8370
8499
  language: "go",
8371
8500
  dependencies: mod.dependencies,
8372
- repoPath: import_node_path12.default.relative(scanPath, dir),
8501
+ repoPath: import_node_path13.default.relative(scanPath, dir),
8373
8502
  ...framework ? { framework } : {}
8374
8503
  };
8375
8504
  return { pkg, dir, node };
@@ -8377,8 +8506,8 @@ async function discoverGoService(scanPath, dir) {
8377
8506
 
8378
8507
  // src/extract/ruby.ts
8379
8508
  init_cjs_shims();
8380
- var import_node_fs12 = require("fs");
8381
- var import_node_path13 = __toESM(require("path"), 1);
8509
+ var import_node_fs13 = require("fs");
8510
+ var import_node_path14 = __toESM(require("path"), 1);
8382
8511
  var import_types11 = require("@neat.is/types");
8383
8512
  function parseGemfile(source) {
8384
8513
  const dependencies = {};
@@ -8395,12 +8524,12 @@ function parseGemfile(source) {
8395
8524
  async function discoverRubyService(scanPath, dir) {
8396
8525
  let raw;
8397
8526
  try {
8398
- raw = await import_node_fs12.promises.readFile(import_node_path13.default.join(dir, "Gemfile"), "utf8");
8527
+ raw = await import_node_fs13.promises.readFile(import_node_path14.default.join(dir, "Gemfile"), "utf8");
8399
8528
  } catch {
8400
8529
  return null;
8401
8530
  }
8402
8531
  const gemfile = parseGemfile(raw);
8403
- const name = import_node_path13.default.basename(dir);
8532
+ const name = import_node_path14.default.basename(dir);
8404
8533
  const pkg = { name, dependencies: gemfile.dependencies };
8405
8534
  const node = {
8406
8535
  id: (0, import_types11.serviceId)(name),
@@ -8408,7 +8537,7 @@ async function discoverRubyService(scanPath, dir) {
8408
8537
  name,
8409
8538
  language: "ruby",
8410
8539
  dependencies: gemfile.dependencies,
8411
- repoPath: import_node_path13.default.relative(scanPath, dir),
8540
+ repoPath: import_node_path14.default.relative(scanPath, dir),
8412
8541
  ...gemfile.dependencies["rails"] !== void 0 ? { framework: "rails" } : {}
8413
8542
  };
8414
8543
  return { pkg, dir, node };
@@ -8416,7 +8545,7 @@ async function discoverRubyService(scanPath, dir) {
8416
8545
 
8417
8546
  // src/extract/php.ts
8418
8547
  init_cjs_shims();
8419
- var import_node_path14 = __toESM(require("path"), 1);
8548
+ var import_node_path15 = __toESM(require("path"), 1);
8420
8549
  var import_types12 = require("@neat.is/types");
8421
8550
  function parseComposerJson(composer) {
8422
8551
  return {
@@ -8429,12 +8558,12 @@ function parseComposerJson(composer) {
8429
8558
  async function discoverPhpService(scanPath, dir) {
8430
8559
  let composer;
8431
8560
  try {
8432
- composer = await readJson(import_node_path14.default.join(dir, "composer.json"));
8561
+ composer = await readJson(import_node_path15.default.join(dir, "composer.json"));
8433
8562
  } catch {
8434
8563
  return null;
8435
8564
  }
8436
8565
  const { dependencies } = parseComposerJson(composer);
8437
- const name = import_node_path14.default.basename(dir);
8566
+ const name = import_node_path15.default.basename(dir);
8438
8567
  const pkg = { name, dependencies };
8439
8568
  const node = {
8440
8569
  id: (0, import_types12.serviceId)(name),
@@ -8442,7 +8571,7 @@ async function discoverPhpService(scanPath, dir) {
8442
8571
  name,
8443
8572
  language: "php",
8444
8573
  dependencies,
8445
- repoPath: import_node_path14.default.relative(scanPath, dir),
8574
+ repoPath: import_node_path15.default.relative(scanPath, dir),
8446
8575
  ...dependencies["laravel/framework"] !== void 0 ? { framework: "laravel" } : {}
8447
8576
  };
8448
8577
  return { pkg, dir, node };
@@ -8450,23 +8579,23 @@ async function discoverPhpService(scanPath, dir) {
8450
8579
 
8451
8580
  // src/extract/csharp.ts
8452
8581
  init_cjs_shims();
8453
- var import_node_fs13 = require("fs");
8454
- var import_node_path15 = __toESM(require("path"), 1);
8582
+ var import_node_fs14 = require("fs");
8583
+ var import_node_path16 = __toESM(require("path"), 1);
8455
8584
  var import_types13 = require("@neat.is/types");
8456
8585
  var CSHARP_PROJECT_EXTS = /* @__PURE__ */ new Set([".csproj", ".sln"]);
8457
8586
  async function projectFiles(dir) {
8458
- const entries = await import_node_fs13.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8587
+ const entries = await import_node_fs14.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8459
8588
  const out = [];
8460
8589
  for (const entry of entries) {
8461
8590
  if (!entry.isFile()) continue;
8462
- if (CSHARP_PROJECT_EXTS.has(import_node_path15.default.extname(entry.name).toLowerCase())) out.push(entry.name);
8591
+ if (CSHARP_PROJECT_EXTS.has(import_node_path16.default.extname(entry.name).toLowerCase())) out.push(entry.name);
8463
8592
  }
8464
8593
  return out.sort();
8465
8594
  }
8466
8595
  var NESTED_PROJECT_DIR = "src";
8467
8596
  async function resolveProjectDir(dir) {
8468
8597
  if ((await projectFiles(dir)).length > 0) return dir;
8469
- const nested = import_node_path15.default.join(dir, NESTED_PROJECT_DIR);
8598
+ const nested = import_node_path16.default.join(dir, NESTED_PROJECT_DIR);
8470
8599
  if ((await projectFiles(nested)).length > 0) return nested;
8471
8600
  return null;
8472
8601
  }
@@ -8491,10 +8620,10 @@ async function discoverCsharpService(scanPath, dir) {
8491
8620
  if (projectDir === null) return null;
8492
8621
  const projects = await projectFiles(projectDir);
8493
8622
  const csproj = projects.find((p) => p.toLowerCase().endsWith(".csproj"));
8494
- const name = csproj ? import_node_path15.default.basename(csproj, import_node_path15.default.extname(csproj)) : import_node_path15.default.basename(dir);
8623
+ const name = csproj ? import_node_path16.default.basename(csproj, import_node_path16.default.extname(csproj)) : import_node_path16.default.basename(dir);
8495
8624
  let dependencies = {};
8496
8625
  if (csproj) {
8497
- const raw = await import_node_fs13.promises.readFile(import_node_path15.default.join(projectDir, csproj), "utf8").catch(() => "");
8626
+ const raw = await import_node_fs14.promises.readFile(import_node_path16.default.join(projectDir, csproj), "utf8").catch(() => "");
8498
8627
  dependencies = parseCsproj(raw).dependencies;
8499
8628
  }
8500
8629
  const pkg = { name, dependencies };
@@ -8506,20 +8635,20 @@ async function discoverCsharpService(scanPath, dir) {
8506
8635
  dependencies,
8507
8636
  // Anchor on the directory that holds the project and its `.cs` files, so file
8508
8637
  // attribution reaches the source whether it sits at the root or under `src/`.
8509
- repoPath: import_node_path15.default.relative(scanPath, projectDir)
8638
+ repoPath: import_node_path16.default.relative(scanPath, projectDir)
8510
8639
  };
8511
8640
  return { pkg, dir: projectDir, node };
8512
8641
  }
8513
8642
 
8514
8643
  // src/extract/java.ts
8515
8644
  init_cjs_shims();
8516
- var import_node_fs14 = require("fs");
8517
- var import_node_path16 = __toESM(require("path"), 1);
8645
+ var import_node_fs15 = require("fs");
8646
+ var import_node_path17 = __toESM(require("path"), 1);
8518
8647
  var import_types14 = require("@neat.is/types");
8519
8648
  var JAVA_MANIFESTS = ["pom.xml", "build.gradle", "build.gradle.kts"];
8520
8649
  async function hasJavaManifest(dir) {
8521
8650
  for (const manifest of JAVA_MANIFESTS) {
8522
- if (await exists2(import_node_path16.default.join(dir, manifest))) return true;
8651
+ if (await exists2(import_node_path17.default.join(dir, manifest))) return true;
8523
8652
  }
8524
8653
  return false;
8525
8654
  }
@@ -8554,19 +8683,19 @@ function parseGradle(source) {
8554
8683
  return { dependencies };
8555
8684
  }
8556
8685
  async function discoverJavaService(scanPath, dir) {
8557
- const pomPath = import_node_path16.default.join(dir, "pom.xml");
8558
- const gradlePath = import_node_path16.default.join(dir, "build.gradle");
8559
- const gradleKtsPath = import_node_path16.default.join(dir, "build.gradle.kts");
8686
+ const pomPath = import_node_path17.default.join(dir, "pom.xml");
8687
+ const gradlePath = import_node_path17.default.join(dir, "build.gradle");
8688
+ const gradleKtsPath = import_node_path17.default.join(dir, "build.gradle.kts");
8560
8689
  let manifest = null;
8561
8690
  if (await exists2(pomPath)) {
8562
- manifest = parsePomXml(await import_node_fs14.promises.readFile(pomPath, "utf8").catch(() => ""));
8691
+ manifest = parsePomXml(await import_node_fs15.promises.readFile(pomPath, "utf8").catch(() => ""));
8563
8692
  } else if (await exists2(gradlePath)) {
8564
- manifest = parseGradle(await import_node_fs14.promises.readFile(gradlePath, "utf8").catch(() => ""));
8693
+ manifest = parseGradle(await import_node_fs15.promises.readFile(gradlePath, "utf8").catch(() => ""));
8565
8694
  } else if (await exists2(gradleKtsPath)) {
8566
- manifest = parseGradle(await import_node_fs14.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8695
+ manifest = parseGradle(await import_node_fs15.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8567
8696
  }
8568
8697
  if (!manifest) return null;
8569
- const name = manifest.name?.trim() || import_node_path16.default.basename(dir);
8698
+ const name = manifest.name?.trim() || import_node_path17.default.basename(dir);
8570
8699
  const dependencies = manifest.dependencies;
8571
8700
  const pkg = { name, dependencies };
8572
8701
  const node = {
@@ -8575,15 +8704,15 @@ async function discoverJavaService(scanPath, dir) {
8575
8704
  name,
8576
8705
  language: "java",
8577
8706
  dependencies,
8578
- repoPath: import_node_path16.default.relative(scanPath, dir)
8707
+ repoPath: import_node_path17.default.relative(scanPath, dir)
8579
8708
  };
8580
8709
  return { pkg, dir, node };
8581
8710
  }
8582
8711
 
8583
8712
  // src/extract/kotlin.ts
8584
8713
  init_cjs_shims();
8585
- var import_node_fs15 = require("fs");
8586
- var import_node_path17 = __toESM(require("path"), 1);
8714
+ var import_node_fs16 = require("fs");
8715
+ var import_node_path18 = __toESM(require("path"), 1);
8587
8716
  var import_types15 = require("@neat.is/types");
8588
8717
  var KOTLIN_SOURCE_EXT = ".kt";
8589
8718
  var JAVA_SOURCE_EXT = ".java";
@@ -8593,15 +8722,15 @@ async function dominantJvmSourceLanguage(dir) {
8593
8722
  let java = 0;
8594
8723
  async function recurse(current, depth) {
8595
8724
  if (depth > SOURCE_PROBE_MAX_DEPTH) return;
8596
- const entries = await import_node_fs15.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8725
+ const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8597
8726
  for (const entry of entries) {
8598
8727
  if (entry.isDirectory()) {
8599
8728
  if (IGNORED_DIRS.has(entry.name)) continue;
8600
- await recurse(import_node_path17.default.join(current, entry.name), depth + 1);
8729
+ await recurse(import_node_path18.default.join(current, entry.name), depth + 1);
8601
8730
  continue;
8602
8731
  }
8603
8732
  if (!entry.isFile()) continue;
8604
- const ext = import_node_path17.default.extname(entry.name).toLowerCase();
8733
+ const ext = import_node_path18.default.extname(entry.name).toLowerCase();
8605
8734
  if (ext === KOTLIN_SOURCE_EXT) kt++;
8606
8735
  else if (ext === JAVA_SOURCE_EXT) java++;
8607
8736
  }
@@ -8612,17 +8741,17 @@ async function dominantJvmSourceLanguage(dir) {
8612
8741
  return void 0;
8613
8742
  }
8614
8743
  async function readJvmManifest(dir) {
8615
- const pomPath = import_node_path17.default.join(dir, JAVA_MANIFESTS[0]);
8616
- const gradlePath = import_node_path17.default.join(dir, JAVA_MANIFESTS[1]);
8617
- const gradleKtsPath = import_node_path17.default.join(dir, JAVA_MANIFESTS[2]);
8744
+ const pomPath = import_node_path18.default.join(dir, JAVA_MANIFESTS[0]);
8745
+ const gradlePath = import_node_path18.default.join(dir, JAVA_MANIFESTS[1]);
8746
+ const gradleKtsPath = import_node_path18.default.join(dir, JAVA_MANIFESTS[2]);
8618
8747
  if (await exists2(pomPath)) {
8619
- return parsePomXml(await import_node_fs15.promises.readFile(pomPath, "utf8").catch(() => ""));
8748
+ return parsePomXml(await import_node_fs16.promises.readFile(pomPath, "utf8").catch(() => ""));
8620
8749
  }
8621
8750
  if (await exists2(gradlePath)) {
8622
- return parseGradle(await import_node_fs15.promises.readFile(gradlePath, "utf8").catch(() => ""));
8751
+ return parseGradle(await import_node_fs16.promises.readFile(gradlePath, "utf8").catch(() => ""));
8623
8752
  }
8624
8753
  if (await exists2(gradleKtsPath)) {
8625
- return parseGradle(await import_node_fs15.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8754
+ return parseGradle(await import_node_fs16.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8626
8755
  }
8627
8756
  return null;
8628
8757
  }
@@ -8631,7 +8760,7 @@ async function discoverKotlinService(scanPath, dir) {
8631
8760
  if (await dominantJvmSourceLanguage(dir) !== "kotlin") return null;
8632
8761
  const manifest = await readJvmManifest(dir);
8633
8762
  if (!manifest) return null;
8634
- const name = manifest.name?.trim() || import_node_path17.default.basename(dir);
8763
+ const name = manifest.name?.trim() || import_node_path18.default.basename(dir);
8635
8764
  const dependencies = manifest.dependencies;
8636
8765
  const pkg = { name, dependencies };
8637
8766
  const node = {
@@ -8640,20 +8769,20 @@ async function discoverKotlinService(scanPath, dir) {
8640
8769
  name,
8641
8770
  language: "kotlin",
8642
8771
  dependencies,
8643
- repoPath: import_node_path17.default.relative(scanPath, dir)
8772
+ repoPath: import_node_path18.default.relative(scanPath, dir)
8644
8773
  };
8645
8774
  return { pkg, dir, node };
8646
8775
  }
8647
8776
 
8648
8777
  // src/extract/rust.ts
8649
8778
  init_cjs_shims();
8650
- var import_node_fs16 = require("fs");
8651
- var import_node_path18 = __toESM(require("path"), 1);
8779
+ var import_node_fs17 = require("fs");
8780
+ var import_node_path19 = __toESM(require("path"), 1);
8652
8781
  var import_smol_toml2 = require("smol-toml");
8653
8782
  var import_types16 = require("@neat.is/types");
8654
8783
  var CARGO_MANIFEST = "Cargo.toml";
8655
8784
  async function hasRustManifest(dir) {
8656
- return exists2(import_node_path18.default.join(dir, CARGO_MANIFEST));
8785
+ return exists2(import_node_path19.default.join(dir, CARGO_MANIFEST));
8657
8786
  }
8658
8787
  function parseCargoToml(source) {
8659
8788
  const dependencies = {};
@@ -8678,10 +8807,10 @@ function parseCargoToml(source) {
8678
8807
  return { name, dependencies };
8679
8808
  }
8680
8809
  async function discoverRustService(scanPath, dir) {
8681
- const cargoPath = import_node_path18.default.join(dir, CARGO_MANIFEST);
8810
+ const cargoPath = import_node_path19.default.join(dir, CARGO_MANIFEST);
8682
8811
  if (!await exists2(cargoPath)) return null;
8683
- const manifest = parseCargoToml(await import_node_fs16.promises.readFile(cargoPath, "utf8").catch(() => ""));
8684
- const name = manifest.name?.trim() || import_node_path18.default.basename(dir);
8812
+ const manifest = parseCargoToml(await import_node_fs17.promises.readFile(cargoPath, "utf8").catch(() => ""));
8813
+ const name = manifest.name?.trim() || import_node_path19.default.basename(dir);
8685
8814
  const dependencies = manifest.dependencies;
8686
8815
  const pkg = { name, dependencies };
8687
8816
  const node = {
@@ -8690,19 +8819,19 @@ async function discoverRustService(scanPath, dir) {
8690
8819
  name,
8691
8820
  language: "rust",
8692
8821
  dependencies,
8693
- repoPath: import_node_path18.default.relative(scanPath, dir)
8822
+ repoPath: import_node_path19.default.relative(scanPath, dir)
8694
8823
  };
8695
8824
  return { pkg, dir, node };
8696
8825
  }
8697
8826
 
8698
8827
  // src/extract/cpp.ts
8699
8828
  init_cjs_shims();
8700
- var import_node_fs17 = require("fs");
8701
- var import_node_path19 = __toESM(require("path"), 1);
8829
+ var import_node_fs18 = require("fs");
8830
+ var import_node_path20 = __toESM(require("path"), 1);
8702
8831
  var import_types17 = require("@neat.is/types");
8703
8832
  var CMAKE_MANIFEST = "CMakeLists.txt";
8704
8833
  async function hasCppManifest(dir) {
8705
- return exists2(import_node_path19.default.join(dir, CMAKE_MANIFEST));
8834
+ return exists2(import_node_path20.default.join(dir, CMAKE_MANIFEST));
8706
8835
  }
8707
8836
  function parseCMakeProjectName(source) {
8708
8837
  const withoutComments = source.replace(/#.*$/gm, "");
@@ -8710,10 +8839,10 @@ function parseCMakeProjectName(source) {
8710
8839
  return m?.[1];
8711
8840
  }
8712
8841
  async function discoverCppService(scanPath, dir) {
8713
- const cmakePath = import_node_path19.default.join(dir, CMAKE_MANIFEST);
8842
+ const cmakePath = import_node_path20.default.join(dir, CMAKE_MANIFEST);
8714
8843
  if (!await exists2(cmakePath)) return null;
8715
- const source = await import_node_fs17.promises.readFile(cmakePath, "utf8").catch(() => "");
8716
- const name = parseCMakeProjectName(source)?.trim() || import_node_path19.default.basename(dir);
8844
+ const source = await import_node_fs18.promises.readFile(cmakePath, "utf8").catch(() => "");
8845
+ const name = parseCMakeProjectName(source)?.trim() || import_node_path20.default.basename(dir);
8717
8846
  const dependencies = {};
8718
8847
  const pkg = { name, dependencies };
8719
8848
  const node = {
@@ -8722,15 +8851,15 @@ async function discoverCppService(scanPath, dir) {
8722
8851
  name,
8723
8852
  language: "cpp",
8724
8853
  dependencies,
8725
- repoPath: import_node_path19.default.relative(scanPath, dir)
8854
+ repoPath: import_node_path20.default.relative(scanPath, dir)
8726
8855
  };
8727
8856
  return { pkg, dir, node };
8728
8857
  }
8729
8858
 
8730
8859
  // src/extract/dockerfile-service.ts
8731
8860
  init_cjs_shims();
8732
- var import_node_fs18 = require("fs");
8733
- var import_node_path20 = __toESM(require("path"), 1);
8861
+ var import_node_fs19 = require("fs");
8862
+ var import_node_path21 = __toESM(require("path"), 1);
8734
8863
  var import_types18 = require("@neat.is/types");
8735
8864
  function languageForSourceExt(ext) {
8736
8865
  switch (ext) {
@@ -8772,12 +8901,12 @@ function languageForSourceExt(ext) {
8772
8901
  }
8773
8902
  var LANGUAGE_PRECEDENCE = ["typescript", "javascript", "python", "go", "ruby", "php", "csharp", "java", "kotlin", "rust", "cpp"];
8774
8903
  async function inferServiceLanguage(dir) {
8775
- const entries = await import_node_fs18.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8904
+ const entries = await import_node_fs19.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8776
8905
  const counts = /* @__PURE__ */ new Map();
8777
8906
  for (const entry of entries) {
8778
8907
  if (!entry.isFile()) continue;
8779
8908
  if (isNeatAuthoredSourceFile(entry.name)) continue;
8780
- const ext = import_node_path20.default.extname(entry.name).toLowerCase();
8909
+ const ext = import_node_path21.default.extname(entry.name).toLowerCase();
8781
8910
  if (!SERVICE_FILE_EXTENSIONS.has(ext)) continue;
8782
8911
  const lang = languageForSourceExt(ext);
8783
8912
  if (!lang) continue;
@@ -8796,7 +8925,7 @@ async function inferServiceLanguage(dir) {
8796
8925
  return best;
8797
8926
  }
8798
8927
  async function hasLanguageManifest(dir) {
8799
- return await exists2(import_node_path20.default.join(dir, "package.json")) || await exists2(import_node_path20.default.join(dir, "pyproject.toml")) || await exists2(import_node_path20.default.join(dir, "requirements.txt")) || await exists2(import_node_path20.default.join(dir, "setup.py")) || await exists2(import_node_path20.default.join(dir, "go.mod")) || await exists2(import_node_path20.default.join(dir, "Gemfile")) || await exists2(import_node_path20.default.join(dir, "composer.json")) || // C#'s marker is a glob (`*.csproj` / `*.sln`), so it reads the directory
8928
+ return await exists2(import_node_path21.default.join(dir, "package.json")) || await exists2(import_node_path21.default.join(dir, "pyproject.toml")) || await exists2(import_node_path21.default.join(dir, "requirements.txt")) || await exists2(import_node_path21.default.join(dir, "setup.py")) || await exists2(import_node_path21.default.join(dir, "go.mod")) || await exists2(import_node_path21.default.join(dir, "Gemfile")) || await exists2(import_node_path21.default.join(dir, "composer.json")) || // C#'s marker is a glob (`*.csproj` / `*.sln`), so it reads the directory
8800
8929
  // rather than probing a fixed filename (ADR-196).
8801
8930
  await hasCsharpProject(dir) || // Java (and its JVM sibling Kotlin, ADR-199) key on the same Maven / Gradle
8802
8931
  // build manifest (ADR-197), so this one check stands the Dockerfile fallback
@@ -8806,15 +8935,15 @@ async function hasLanguageManifest(dir) {
8806
8935
  await hasCppManifest(dir);
8807
8936
  }
8808
8937
  async function hasDockerfileDeclaredService(dir) {
8809
- if (!await exists2(import_node_path20.default.join(dir, "Dockerfile"))) return false;
8938
+ if (!await exists2(import_node_path21.default.join(dir, "Dockerfile"))) return false;
8810
8939
  return await inferServiceLanguage(dir) !== null;
8811
8940
  }
8812
8941
  async function discoverDockerfileService(scanPath, dir) {
8813
- if (!await exists2(import_node_path20.default.join(dir, "Dockerfile"))) return null;
8942
+ if (!await exists2(import_node_path21.default.join(dir, "Dockerfile"))) return null;
8814
8943
  if (await hasLanguageManifest(dir)) return null;
8815
8944
  const language = await inferServiceLanguage(dir);
8816
8945
  if (!language) return null;
8817
- const name = import_node_path20.default.basename(dir);
8946
+ const name = import_node_path21.default.basename(dir);
8818
8947
  const pkg = { name, dependencies: {} };
8819
8948
  const node = {
8820
8949
  id: (0, import_types18.serviceId)(name),
@@ -8822,24 +8951,24 @@ async function discoverDockerfileService(scanPath, dir) {
8822
8951
  name,
8823
8952
  language,
8824
8953
  dependencies: {},
8825
- repoPath: import_node_path20.default.relative(scanPath, dir)
8954
+ repoPath: import_node_path21.default.relative(scanPath, dir)
8826
8955
  };
8827
8956
  return { pkg, dir, node };
8828
8957
  }
8829
8958
 
8830
8959
  // src/extract/owners.ts
8831
8960
  init_cjs_shims();
8832
- var import_node_fs19 = require("fs");
8833
- var import_node_path21 = __toESM(require("path"), 1);
8961
+ var import_node_fs20 = require("fs");
8962
+ var import_node_path22 = __toESM(require("path"), 1);
8834
8963
  var import_minimatch = require("minimatch");
8835
8964
  async function loadCodeowners(scanPath) {
8836
8965
  const candidates = [
8837
- import_node_path21.default.join(scanPath, "CODEOWNERS"),
8838
- import_node_path21.default.join(scanPath, ".github", "CODEOWNERS")
8966
+ import_node_path22.default.join(scanPath, "CODEOWNERS"),
8967
+ import_node_path22.default.join(scanPath, ".github", "CODEOWNERS")
8839
8968
  ];
8840
8969
  for (const file of candidates) {
8841
8970
  if (await exists2(file)) {
8842
- const raw = await import_node_fs19.promises.readFile(file, "utf8");
8971
+ const raw = await import_node_fs20.promises.readFile(file, "utf8");
8843
8972
  return parseCodeowners(raw);
8844
8973
  }
8845
8974
  }
@@ -8857,7 +8986,7 @@ function parseCodeowners(raw) {
8857
8986
  return { rules };
8858
8987
  }
8859
8988
  function matchOwner(file, repoPath) {
8860
- const normalized = repoPath.split(import_node_path21.default.sep).join("/");
8989
+ const normalized = repoPath.split(import_node_path22.default.sep).join("/");
8861
8990
  for (const rule of file.rules) {
8862
8991
  if (matchesPattern(rule.pattern, normalized)) return rule.owners;
8863
8992
  }
@@ -8873,7 +9002,7 @@ function matchesPattern(rawPattern, repoPath) {
8873
9002
  return false;
8874
9003
  }
8875
9004
  async function readPackageJsonAuthor(serviceDir) {
8876
- const pkgPath = import_node_path21.default.join(serviceDir, "package.json");
9005
+ const pkgPath = import_node_path22.default.join(serviceDir, "package.json");
8877
9006
  if (!await exists2(pkgPath)) return null;
8878
9007
  try {
8879
9008
  const pkg = await readJson(pkgPath);
@@ -8910,36 +9039,36 @@ function workspaceGlobs(pkg) {
8910
9039
  return null;
8911
9040
  }
8912
9041
  async function hasPythonManifest(dir) {
8913
- return await exists2(import_node_path22.default.join(dir, "pyproject.toml")) || await exists2(import_node_path22.default.join(dir, "requirements.txt")) || await exists2(import_node_path22.default.join(dir, "setup.py"));
9042
+ return await exists2(import_node_path23.default.join(dir, "pyproject.toml")) || await exists2(import_node_path23.default.join(dir, "requirements.txt")) || await exists2(import_node_path23.default.join(dir, "setup.py"));
8914
9043
  }
8915
9044
  async function hasGoManifest(dir) {
8916
- return exists2(import_node_path22.default.join(dir, "go.mod"));
9045
+ return exists2(import_node_path23.default.join(dir, "go.mod"));
8917
9046
  }
8918
9047
  async function hasRubyManifest(dir) {
8919
- return exists2(import_node_path22.default.join(dir, "Gemfile"));
9048
+ return exists2(import_node_path23.default.join(dir, "Gemfile"));
8920
9049
  }
8921
9050
  async function hasPhpManifest(dir) {
8922
- return exists2(import_node_path22.default.join(dir, "composer.json"));
9051
+ return exists2(import_node_path23.default.join(dir, "composer.json"));
8923
9052
  }
8924
9053
  async function hasCsharpManifest(dir) {
8925
9054
  return hasCsharpProject(dir);
8926
9055
  }
8927
9056
  async function loadGitignore(scanPath) {
8928
- const gitignorePath = import_node_path22.default.join(scanPath, ".gitignore");
9057
+ const gitignorePath = import_node_path23.default.join(scanPath, ".gitignore");
8929
9058
  if (!await exists2(gitignorePath)) return null;
8930
- const raw = await import_node_fs20.promises.readFile(gitignorePath, "utf8");
8931
- return (0, import_ignore.default)().add(raw);
9059
+ const raw = await import_node_fs21.promises.readFile(gitignorePath, "utf8");
9060
+ return (0, import_ignore2.default)().add(raw);
8932
9061
  }
8933
9062
  async function walkDirs(start, scanPath, options, visit) {
8934
9063
  async function recurse(current, depth) {
8935
9064
  if (depth > options.maxDepth) return;
8936
- const entries = await import_node_fs20.promises.readdir(current, { withFileTypes: true }).catch(() => []);
9065
+ const entries = await import_node_fs21.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8937
9066
  for (const entry of entries) {
8938
9067
  if (!entry.isDirectory()) continue;
8939
9068
  if (IGNORED_DIRS.has(entry.name)) continue;
8940
- const child = import_node_path22.default.join(current, entry.name);
9069
+ const child = import_node_path23.default.join(current, entry.name);
8941
9070
  if (options.ig) {
8942
- const rel = import_node_path22.default.relative(scanPath, child).split(import_node_path22.default.sep).join("/");
9071
+ const rel = import_node_path23.default.relative(scanPath, child).split(import_node_path23.default.sep).join("/");
8943
9072
  if (rel && options.ig.ignores(rel + "/")) continue;
8944
9073
  }
8945
9074
  if (await isPythonVenvDir(child)) continue;
@@ -8955,8 +9084,8 @@ async function expandWorkspaceGlobs(scanPath, globs) {
8955
9084
  for (const raw of globs) {
8956
9085
  const pattern = raw.replace(/^\.\//, "");
8957
9086
  if (!pattern.includes("*")) {
8958
- const candidate = import_node_path22.default.join(scanPath, pattern);
8959
- if (await exists2(import_node_path22.default.join(candidate, "package.json"))) found.add(candidate);
9087
+ const candidate = import_node_path23.default.join(scanPath, pattern);
9088
+ if (await exists2(import_node_path23.default.join(candidate, "package.json"))) found.add(candidate);
8960
9089
  continue;
8961
9090
  }
8962
9091
  const segments = pattern.split("/");
@@ -8965,13 +9094,13 @@ async function expandWorkspaceGlobs(scanPath, globs) {
8965
9094
  if (seg.includes("*")) break;
8966
9095
  staticSegments.push(seg);
8967
9096
  }
8968
- const start = import_node_path22.default.join(scanPath, ...staticSegments);
9097
+ const start = import_node_path23.default.join(scanPath, ...staticSegments);
8969
9098
  if (!await exists2(start)) continue;
8970
9099
  const hasDoubleStar = pattern.includes("**");
8971
9100
  const walkDepth = hasDoubleStar ? scanDepth : Math.max(0, segments.length - staticSegments.length - 1);
8972
9101
  await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {
8973
- const rel = import_node_path22.default.relative(scanPath, dir).split(import_node_path22.default.sep).join("/");
8974
- if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path22.default.join(dir, "package.json"))) {
9102
+ const rel = import_node_path23.default.relative(scanPath, dir).split(import_node_path23.default.sep).join("/");
9103
+ if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path23.default.join(dir, "package.json"))) {
8975
9104
  found.add(dir);
8976
9105
  }
8977
9106
  });
@@ -8994,18 +9123,18 @@ function detectJsFramework(pkg) {
8994
9123
  async function detectJsServiceLanguage(dir, pkg) {
8995
9124
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
8996
9125
  if (deps["typescript"] !== void 0) return "typescript";
8997
- const entries = await import_node_fs20.promises.readdir(dir).catch(() => []);
9126
+ const entries = await import_node_fs21.promises.readdir(dir).catch(() => []);
8998
9127
  if (entries.some((name) => /^tsconfig(\..+)?\.json$/.test(name))) return "typescript";
8999
9128
  return "javascript";
9000
9129
  }
9001
9130
  async function discoverNodeService(scanPath, dir) {
9002
- const pkgPath = import_node_path22.default.join(dir, "package.json");
9131
+ const pkgPath = import_node_path23.default.join(dir, "package.json");
9003
9132
  if (!await exists2(pkgPath)) return null;
9004
9133
  let pkg;
9005
9134
  try {
9006
9135
  pkg = await readJson(pkgPath);
9007
9136
  } catch (err) {
9008
- recordExtractionError("services", import_node_path22.default.relative(scanPath, pkgPath), err);
9137
+ recordExtractionError("services", import_node_path23.default.relative(scanPath, pkgPath), err);
9009
9138
  return null;
9010
9139
  }
9011
9140
  if (!pkg.name) return null;
@@ -9018,7 +9147,7 @@ async function discoverNodeService(scanPath, dir) {
9018
9147
  language,
9019
9148
  version: pkg.version,
9020
9149
  dependencies: pkg.dependencies ?? {},
9021
- repoPath: import_node_path22.default.relative(scanPath, dir),
9150
+ repoPath: import_node_path23.default.relative(scanPath, dir),
9022
9151
  ...pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {},
9023
9152
  ...framework ? { framework } : {}
9024
9153
  };
@@ -9035,12 +9164,12 @@ async function discoverPyService(scanPath, dir) {
9035
9164
  language: "python",
9036
9165
  version: py.version,
9037
9166
  dependencies: py.dependencies,
9038
- repoPath: import_node_path22.default.relative(scanPath, dir)
9167
+ repoPath: import_node_path23.default.relative(scanPath, dir)
9039
9168
  };
9040
9169
  return { pkg, dir, node };
9041
9170
  }
9042
9171
  async function discoverServices(scanPath) {
9043
- const rootPkgPath = import_node_path22.default.join(scanPath, "package.json");
9172
+ const rootPkgPath = import_node_path23.default.join(scanPath, "package.json");
9044
9173
  let rootPkg = null;
9045
9174
  if (await exists2(rootPkgPath)) {
9046
9175
  try {
@@ -9048,7 +9177,7 @@ async function discoverServices(scanPath) {
9048
9177
  } catch (err) {
9049
9178
  recordExtractionError(
9050
9179
  "services workspaces",
9051
- import_node_path22.default.relative(scanPath, rootPkgPath),
9180
+ import_node_path23.default.relative(scanPath, rootPkgPath),
9052
9181
  err
9053
9182
  );
9054
9183
  }
@@ -9069,7 +9198,7 @@ async function discoverServices(scanPath) {
9069
9198
  scanPath,
9070
9199
  { maxDepth: parseScanDepth(), ig },
9071
9200
  async (dir) => {
9072
- if (await exists2(import_node_path22.default.join(dir, "package.json"))) {
9201
+ if (await exists2(import_node_path23.default.join(dir, "package.json"))) {
9073
9202
  candidateDirs.push(dir);
9074
9203
  } else if (await hasPythonManifest(dir) || await hasGoManifest(dir) || await hasRubyManifest(dir) || await hasPhpManifest(dir) || await hasCsharpManifest(dir) || await hasJavaManifest(dir) || await hasRustManifest(dir) || await hasCppManifest(dir)) {
9075
9204
  candidateDirs.push(dir);
@@ -9097,8 +9226,8 @@ async function discoverServices(scanPath) {
9097
9226
  seenDirs.add(service.dir);
9098
9227
  const existingDir = seen.get(service.node.name);
9099
9228
  if (existingDir !== void 0) {
9100
- const a = import_node_path22.default.relative(scanPath, existingDir) || ".";
9101
- const b = import_node_path22.default.relative(scanPath, dir) || ".";
9229
+ const a = import_node_path23.default.relative(scanPath, existingDir) || ".";
9230
+ const b = import_node_path23.default.relative(scanPath, dir) || ".";
9102
9231
  console.warn(
9103
9232
  `[neat] duplicate package name "${service.node.name}" \u2014 keeping ${a}, ignoring ${b}`
9104
9233
  );
@@ -9112,14 +9241,14 @@ async function discoverServices(scanPath) {
9112
9241
  const owner = await computeServiceOwner(codeowners, service.node.repoPath, service.dir);
9113
9242
  if (owner !== void 0) service.node.owner = owner;
9114
9243
  }
9115
- const resolvedDirs = out.map((s) => import_node_path22.default.resolve(s.dir));
9244
+ const resolvedDirs = out.map((s) => import_node_path23.default.resolve(s.dir));
9116
9245
  for (let i = 0; i < out.length; i++) {
9117
9246
  const self = resolvedDirs[i];
9118
9247
  const nested = [];
9119
9248
  for (let j = 0; j < out.length; j++) {
9120
9249
  if (i === j) continue;
9121
9250
  const other = resolvedDirs[j];
9122
- if (other.startsWith(self + import_node_path22.default.sep)) nested.push(other);
9251
+ if (other.startsWith(self + import_node_path23.default.sep)) nested.push(other);
9123
9252
  }
9124
9253
  out[i].excludeDirs = nested;
9125
9254
  }
@@ -9146,8 +9275,8 @@ function addServiceNodes(graph, services) {
9146
9275
 
9147
9276
  // src/extract/aliases.ts
9148
9277
  init_cjs_shims();
9149
- var import_node_path23 = __toESM(require("path"), 1);
9150
- var import_node_fs21 = require("fs");
9278
+ var import_node_path24 = __toESM(require("path"), 1);
9279
+ var import_node_fs22 = require("fs");
9151
9280
  var import_yaml2 = require("yaml");
9152
9281
  var import_types20 = require("@neat.is/types");
9153
9282
  var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
@@ -9174,14 +9303,14 @@ function indexServicesByName(services) {
9174
9303
  const map = /* @__PURE__ */ new Map();
9175
9304
  for (const s of services) {
9176
9305
  map.set(s.node.name, s.node.id);
9177
- map.set(import_node_path23.default.basename(s.dir), s.node.id);
9306
+ map.set(import_node_path24.default.basename(s.dir), s.node.id);
9178
9307
  }
9179
9308
  return map;
9180
9309
  }
9181
9310
  async function collectComposeAliases(graph, scanPath, serviceIndex) {
9182
9311
  let composePath = null;
9183
9312
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
9184
- const abs = import_node_path23.default.join(scanPath, name);
9313
+ const abs = import_node_path24.default.join(scanPath, name);
9185
9314
  if (await exists2(abs)) {
9186
9315
  composePath = abs;
9187
9316
  break;
@@ -9194,7 +9323,7 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
9194
9323
  } catch (err) {
9195
9324
  recordExtractionError(
9196
9325
  "aliases compose",
9197
- import_node_path23.default.relative(scanPath, composePath),
9326
+ import_node_path24.default.relative(scanPath, composePath),
9198
9327
  err
9199
9328
  );
9200
9329
  return;
@@ -9237,11 +9366,11 @@ function parseDockerfileLabels(content) {
9237
9366
  }
9238
9367
  async function collectDockerfileAliases(graph, services) {
9239
9368
  for (const service of services) {
9240
- const dockerfilePath = import_node_path23.default.join(service.dir, "Dockerfile");
9369
+ const dockerfilePath = import_node_path24.default.join(service.dir, "Dockerfile");
9241
9370
  if (!await exists2(dockerfilePath)) continue;
9242
9371
  let content;
9243
9372
  try {
9244
- content = await import_node_fs21.promises.readFile(dockerfilePath, "utf8");
9373
+ content = await import_node_fs22.promises.readFile(dockerfilePath, "utf8");
9245
9374
  } catch (err) {
9246
9375
  recordExtractionError("aliases dockerfile", dockerfilePath, err);
9247
9376
  continue;
@@ -9253,15 +9382,15 @@ async function collectDockerfileAliases(graph, services) {
9253
9382
  async function walkYamlFiles(start, depth = 0, max = 5) {
9254
9383
  if (depth > max) return [];
9255
9384
  const out = [];
9256
- const entries = await import_node_fs21.promises.readdir(start, { withFileTypes: true }).catch(() => []);
9385
+ const entries = await import_node_fs22.promises.readdir(start, { withFileTypes: true }).catch(() => []);
9257
9386
  for (const entry of entries) {
9258
9387
  if (entry.isDirectory()) {
9259
9388
  if (IGNORED_DIRS.has(entry.name)) continue;
9260
- const child = import_node_path23.default.join(start, entry.name);
9389
+ const child = import_node_path24.default.join(start, entry.name);
9261
9390
  if (await isPythonVenvDir(child)) continue;
9262
9391
  out.push(...await walkYamlFiles(child, depth + 1, max));
9263
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path23.default.extname(entry.name))) {
9264
- out.push(import_node_path23.default.join(start, entry.name));
9392
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path24.default.extname(entry.name))) {
9393
+ out.push(import_node_path24.default.join(start, entry.name));
9265
9394
  }
9266
9395
  }
9267
9396
  return out;
@@ -9288,7 +9417,7 @@ function k8sServiceTarget(doc, byName) {
9288
9417
  async function collectK8sAliases(graph, scanPath, serviceIndex) {
9289
9418
  const files = await walkYamlFiles(scanPath);
9290
9419
  for (const file of files) {
9291
- const content = await import_node_fs21.promises.readFile(file, "utf8");
9420
+ const content = await import_node_fs22.promises.readFile(file, "utf8");
9292
9421
  let docs;
9293
9422
  try {
9294
9423
  docs = (0, import_yaml2.parseAllDocuments)(content).map((d) => d.toJSON());
@@ -9313,14 +9442,14 @@ async function addServiceAliases(graph, scanPath, services) {
9313
9442
 
9314
9443
  // src/extract/files.ts
9315
9444
  init_cjs_shims();
9316
- var import_node_path24 = __toESM(require("path"), 1);
9445
+ var import_node_path25 = __toESM(require("path"), 1);
9317
9446
  async function addFiles(graph, services) {
9318
9447
  let nodesAdded = 0;
9319
9448
  let edgesAdded = 0;
9320
9449
  for (const service of services) {
9321
9450
  const filePaths = await walkSourceFiles(service.dir, service.excludeDirs);
9322
9451
  for (const filePath of filePaths) {
9323
- const relPath = toPosix(import_node_path24.default.relative(service.dir, filePath));
9452
+ const relPath = toPosix(import_node_path25.default.relative(service.dir, filePath));
9324
9453
  const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
9325
9454
  graph,
9326
9455
  service.pkg.name,
@@ -9336,7 +9465,7 @@ async function addFiles(graph, services) {
9336
9465
 
9337
9466
  // src/extract/symbols.ts
9338
9467
  init_cjs_shims();
9339
- var import_node_path25 = __toESM(require("path"), 1);
9468
+ var import_node_path26 = __toESM(require("path"), 1);
9340
9469
  var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
9341
9470
  var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
9342
9471
  var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript"), 1);
@@ -10088,10 +10217,10 @@ async function addSymbols(graph, services) {
10088
10217
  for (const service of services) {
10089
10218
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10090
10219
  for (const file of files) {
10091
- const ext = import_node_path25.default.extname(file.path);
10220
+ const ext = import_node_path26.default.extname(file.path);
10092
10221
  const parser = parserForExt5(ext);
10093
10222
  if (!parser) continue;
10094
- const relPath = toPosix(import_node_path25.default.relative(service.dir, file.path));
10223
+ const relPath = toPosix(import_node_path26.default.relative(service.dir, file.path));
10095
10224
  let defs;
10096
10225
  try {
10097
10226
  const tree = parseSource3(parser, file.content);
@@ -10151,7 +10280,7 @@ async function addSymbols(graph, services) {
10151
10280
 
10152
10281
  // src/extract/symbol-edges.ts
10153
10282
  init_cjs_shims();
10154
- var import_node_path26 = __toESM(require("path"), 1);
10283
+ var import_node_path27 = __toESM(require("path"), 1);
10155
10284
  var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
10156
10285
  var import_types22 = require("@neat.is/types");
10157
10286
  function extendsInfo(classHeritage) {
@@ -10258,10 +10387,10 @@ async function addSymbolEdges(graph, services) {
10258
10387
  const tsPaths = await loadTsPathConfig(service.dir);
10259
10388
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10260
10389
  for (const file of files) {
10261
- const parser = parserForExt5(import_node_path26.default.extname(file.path));
10390
+ const parser = parserForExt5(import_node_path27.default.extname(file.path));
10262
10391
  if (!parser) continue;
10263
- const relPath = toPosix(import_node_path26.default.relative(service.dir, file.path));
10264
- const fileDir = import_node_path26.default.dirname(file.path);
10392
+ const relPath = toPosix(import_node_path27.default.relative(service.dir, file.path));
10393
+ const fileDir = import_node_path27.default.dirname(file.path);
10265
10394
  let root;
10266
10395
  try {
10267
10396
  root = parseSource3(parser, file.content).rootNode;
@@ -10396,7 +10525,7 @@ async function addSymbolEdges(graph, services) {
10396
10525
 
10397
10526
  // src/extract/actions.ts
10398
10527
  init_cjs_shims();
10399
- var import_node_path27 = __toESM(require("path"), 1);
10528
+ var import_node_path28 = __toESM(require("path"), 1);
10400
10529
  var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
10401
10530
  var import_types23 = require("@neat.is/types");
10402
10531
  function stringLiteralText2(node) {
@@ -10543,9 +10672,9 @@ async function addServerActions(graph, services) {
10543
10672
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10544
10673
  for (const file of files) {
10545
10674
  if (isTestPath(file.path)) continue;
10546
- const parser = parserForExt5(import_node_path27.default.extname(file.path));
10675
+ const parser = parserForExt5(import_node_path28.default.extname(file.path));
10547
10676
  if (!parser) continue;
10548
- const relPath = toPosix(import_node_path27.default.relative(service.dir, file.path));
10677
+ const relPath = toPosix(import_node_path28.default.relative(service.dir, file.path));
10549
10678
  let root;
10550
10679
  try {
10551
10680
  root = parseSource3(parser, file.content).rootNode;
@@ -10606,10 +10735,10 @@ async function addServerActions(graph, services) {
10606
10735
  }
10607
10736
  for (const file of files) {
10608
10737
  if (isTestPath(file.path)) continue;
10609
- const parser = parserForExt5(import_node_path27.default.extname(file.path));
10738
+ const parser = parserForExt5(import_node_path28.default.extname(file.path));
10610
10739
  if (!parser) continue;
10611
- const relPath = toPosix(import_node_path27.default.relative(service.dir, file.path));
10612
- const fileDir = import_node_path27.default.dirname(file.path);
10740
+ const relPath = toPosix(import_node_path28.default.relative(service.dir, file.path));
10741
+ const fileDir = import_node_path28.default.dirname(file.path);
10613
10742
  let root;
10614
10743
  try {
10615
10744
  root = parseSource3(parser, file.content).rootNode;
@@ -10662,14 +10791,14 @@ async function addServerActions(graph, services) {
10662
10791
 
10663
10792
  // src/extract/databases/index.ts
10664
10793
  init_cjs_shims();
10665
- var import_node_path36 = __toESM(require("path"), 1);
10794
+ var import_node_path37 = __toESM(require("path"), 1);
10666
10795
  var import_types24 = require("@neat.is/types");
10667
10796
 
10668
10797
  // src/extract/databases/db-config-yaml.ts
10669
10798
  init_cjs_shims();
10670
- var import_node_path28 = __toESM(require("path"), 1);
10799
+ var import_node_path29 = __toESM(require("path"), 1);
10671
10800
  async function parse(serviceDir) {
10672
- const yamlPath = import_node_path28.default.join(serviceDir, "db-config.yaml");
10801
+ const yamlPath = import_node_path29.default.join(serviceDir, "db-config.yaml");
10673
10802
  if (!await exists2(yamlPath)) return [];
10674
10803
  const raw = await readYaml(yamlPath);
10675
10804
  return [
@@ -10687,13 +10816,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
10687
10816
 
10688
10817
  // src/extract/databases/dotenv.ts
10689
10818
  init_cjs_shims();
10690
- var import_node_fs23 = require("fs");
10691
- var import_node_path30 = __toESM(require("path"), 1);
10819
+ var import_node_fs24 = require("fs");
10820
+ var import_node_path31 = __toESM(require("path"), 1);
10692
10821
 
10693
10822
  // src/extract/databases/shared.ts
10694
10823
  init_cjs_shims();
10695
- var import_node_fs22 = require("fs");
10696
- var import_node_path29 = __toESM(require("path"), 1);
10824
+ var import_node_fs23 = require("fs");
10825
+ var import_node_path30 = __toESM(require("path"), 1);
10697
10826
  function schemeToEngine(scheme) {
10698
10827
  const s = scheme.toLowerCase().split("+")[0];
10699
10828
  switch (s) {
@@ -10732,18 +10861,18 @@ function parseConnectionString(url) {
10732
10861
  }
10733
10862
  async function readIfExists(filePath) {
10734
10863
  try {
10735
- return await import_node_fs22.promises.readFile(filePath, "utf8");
10864
+ return await import_node_fs23.promises.readFile(filePath, "utf8");
10736
10865
  } catch {
10737
10866
  return null;
10738
10867
  }
10739
10868
  }
10740
10869
  async function resolveEnvVar(serviceDir, name) {
10741
- const entries = await import_node_fs22.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10870
+ const entries = await import_node_fs23.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10742
10871
  const envNames = entries.filter((e) => e.isFile() && (e.name === ".env" || e.name.startsWith(".env."))).map((e) => e.name);
10743
10872
  const rank = (n) => n === ".env.local" ? 0 : n === ".env" ? 1 : 2;
10744
10873
  envNames.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
10745
10874
  for (const fileName of envNames) {
10746
- const content = await readIfExists(import_node_path29.default.join(serviceDir, fileName));
10875
+ const content = await readIfExists(import_node_path30.default.join(serviceDir, fileName));
10747
10876
  if (!content) continue;
10748
10877
  for (const line of content.split("\n")) {
10749
10878
  const trimmed = line.trim();
@@ -10762,7 +10891,7 @@ async function resolveEnvVar(serviceDir, name) {
10762
10891
  }
10763
10892
  async function findFirst(serviceDir, candidates) {
10764
10893
  for (const rel of candidates) {
10765
- const abs = import_node_path29.default.join(serviceDir, rel);
10894
+ const abs = import_node_path30.default.join(serviceDir, rel);
10766
10895
  const content = await readIfExists(abs);
10767
10896
  if (content !== null) return abs;
10768
10897
  }
@@ -10820,15 +10949,15 @@ function parseDotenvLine(line) {
10820
10949
  return { key, value };
10821
10950
  }
10822
10951
  async function parse2(serviceDir) {
10823
- const entries = await import_node_fs23.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10952
+ const entries = await import_node_fs24.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10824
10953
  const configs = [];
10825
10954
  const seen = /* @__PURE__ */ new Set();
10826
10955
  for (const entry of entries) {
10827
10956
  if (!entry.isFile()) continue;
10828
10957
  const match = isConfigFile(entry.name);
10829
10958
  if (!match.match || match.fileType !== "env") continue;
10830
- const filePath = import_node_path30.default.join(serviceDir, entry.name);
10831
- const content = await import_node_fs23.promises.readFile(filePath, "utf8");
10959
+ const filePath = import_node_path31.default.join(serviceDir, entry.name);
10960
+ const content = await import_node_fs24.promises.readFile(filePath, "utf8");
10832
10961
  for (const line of content.split("\n")) {
10833
10962
  const parsed = parseDotenvLine(line);
10834
10963
  if (!parsed) continue;
@@ -10847,9 +10976,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
10847
10976
 
10848
10977
  // src/extract/databases/prisma.ts
10849
10978
  init_cjs_shims();
10850
- var import_node_path31 = __toESM(require("path"), 1);
10979
+ var import_node_path32 = __toESM(require("path"), 1);
10851
10980
  async function parse3(serviceDir) {
10852
- const schemaPath = import_node_path31.default.join(serviceDir, "prisma", "schema.prisma");
10981
+ const schemaPath = import_node_path32.default.join(serviceDir, "prisma", "schema.prisma");
10853
10982
  const content = await readIfExists(schemaPath);
10854
10983
  if (!content) return [];
10855
10984
  const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
@@ -11007,10 +11136,10 @@ var knexParser = { name: "knex", parse: parse5 };
11007
11136
 
11008
11137
  // src/extract/databases/ormconfig.ts
11009
11138
  init_cjs_shims();
11010
- var import_node_path32 = __toESM(require("path"), 1);
11139
+ var import_node_path33 = __toESM(require("path"), 1);
11011
11140
  async function parse6(serviceDir) {
11012
11141
  for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
11013
- const abs = import_node_path32.default.join(serviceDir, candidate);
11142
+ const abs = import_node_path33.default.join(serviceDir, candidate);
11014
11143
  if (!await exists2(abs)) continue;
11015
11144
  const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
11016
11145
  const entries = Array.isArray(raw) ? raw : [raw];
@@ -11070,9 +11199,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
11070
11199
 
11071
11200
  // src/extract/databases/sequelize.ts
11072
11201
  init_cjs_shims();
11073
- var import_node_path33 = __toESM(require("path"), 1);
11202
+ var import_node_path34 = __toESM(require("path"), 1);
11074
11203
  async function parse8(serviceDir) {
11075
- const configPath = import_node_path33.default.join(serviceDir, "config", "config.json");
11204
+ const configPath = import_node_path34.default.join(serviceDir, "config", "config.json");
11076
11205
  if (!await exists2(configPath)) return [];
11077
11206
  const raw = await readJson(configPath);
11078
11207
  const out = [];
@@ -11099,8 +11228,8 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
11099
11228
 
11100
11229
  // src/extract/databases/csharp.ts
11101
11230
  init_cjs_shims();
11102
- var import_node_fs24 = require("fs");
11103
- var import_node_path34 = __toESM(require("path"), 1);
11231
+ var import_node_fs25 = require("fs");
11232
+ var import_node_path35 = __toESM(require("path"), 1);
11104
11233
  var CS_EXT = ".cs";
11105
11234
  var NPGSQL_GATE = /\bUseNpgsql\b|\bNpgsql\b/;
11106
11235
  var REDIS_GATE = /\bConnectionMultiplexer\b|\bStackExchange\.Redis\b|\bConfigurationOptions\.Parse\b|\bAddStackExchangeRedisCache\b/;
@@ -11147,12 +11276,12 @@ function parseRedisEndpoint(raw) {
11147
11276
  return { host, port, database: "", engine: "redis", engineVersion: "unknown" };
11148
11277
  }
11149
11278
  async function resolveEnvUpTree(startDir, name) {
11150
- let dir = import_node_path34.default.resolve(startDir);
11279
+ let dir = import_node_path35.default.resolve(startDir);
11151
11280
  for (let depth = 0; depth < 12; depth++) {
11152
11281
  const value = await resolveEnvVar(dir, name);
11153
11282
  if (value !== null) return value;
11154
- const atRepoRoot = await import_node_fs24.promises.access(import_node_path34.default.join(dir, ".git")).then(() => true).catch(() => false);
11155
- const parent = import_node_path34.default.dirname(dir);
11283
+ const atRepoRoot = await import_node_fs25.promises.access(import_node_path35.default.join(dir, ".git")).then(() => true).catch(() => false);
11284
+ const parent = import_node_path35.default.dirname(dir);
11156
11285
  if (atRepoRoot || parent === dir) break;
11157
11286
  dir = parent;
11158
11287
  }
@@ -11207,12 +11336,12 @@ async function resolveConfigs(literals, keys, serviceDir, looksLike, parse11) {
11207
11336
  }
11208
11337
  async function parse9(serviceDir) {
11209
11338
  const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(
11210
- (f) => import_node_path34.default.extname(f) === CS_EXT
11339
+ (f) => import_node_path35.default.extname(f) === CS_EXT
11211
11340
  );
11212
11341
  if (files.length === 0) return [];
11213
11342
  const sources = [];
11214
11343
  for (const file of files) {
11215
- const content = await import_node_fs24.promises.readFile(file, "utf8").catch(() => null);
11344
+ const content = await import_node_fs25.promises.readFile(file, "utf8").catch(() => null);
11216
11345
  if (content !== null) sources.push({ file, content });
11217
11346
  }
11218
11347
  let pgGateFile = null;
@@ -11253,7 +11382,7 @@ var csharpParser = { name: "csharp", parse: parse9 };
11253
11382
 
11254
11383
  // src/extract/databases/docker-compose.ts
11255
11384
  init_cjs_shims();
11256
- var import_node_path35 = __toESM(require("path"), 1);
11385
+ var import_node_path36 = __toESM(require("path"), 1);
11257
11386
  function portFromService(svc) {
11258
11387
  for (const raw of svc.ports ?? []) {
11259
11388
  const str = String(raw);
@@ -11280,7 +11409,7 @@ function databaseFromEnv(svc) {
11280
11409
  }
11281
11410
  async function parse10(serviceDir) {
11282
11411
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
11283
- const abs = import_node_path35.default.join(serviceDir, name);
11412
+ const abs = import_node_path36.default.join(serviceDir, name);
11284
11413
  if (!await exists2(abs)) continue;
11285
11414
  const raw = await readYaml(abs);
11286
11415
  if (!raw?.services) return [];
@@ -11453,7 +11582,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11453
11582
  discoveredVia: mergedDiscoveredVia
11454
11583
  });
11455
11584
  }
11456
- const relConfigFile = toPosix(import_node_path36.default.relative(service.dir, config.sourceFile));
11585
+ const relConfigFile = toPosix(import_node_path37.default.relative(service.dir, config.sourceFile));
11457
11586
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11458
11587
  graph,
11459
11588
  service.pkg.name,
@@ -11462,7 +11591,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11462
11591
  );
11463
11592
  nodesAdded += fn;
11464
11593
  edgesAdded += fe;
11465
- const evidenceFile = toPosix(import_node_path36.default.relative(scanPath, config.sourceFile));
11594
+ const evidenceFile = toPosix(import_node_path37.default.relative(scanPath, config.sourceFile));
11466
11595
  const edge = {
11467
11596
  id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types24.EdgeType.CONNECTS_TO),
11468
11597
  source: fileNodeId,
@@ -11483,15 +11612,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11483
11612
  if (allConfigs.length === 1) {
11484
11613
  const primary = allConfigs[0];
11485
11614
  service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
11486
- const relPath = import_node_path36.default.relative(scanPath, primary.sourceFile);
11615
+ const relPath = import_node_path37.default.relative(scanPath, primary.sourceFile);
11487
11616
  const cfgId = (0, import_types24.configId)(relPath);
11488
11617
  if (!graph.hasNode(cfgId)) {
11489
11618
  const cfgNode = {
11490
11619
  id: cfgId,
11491
11620
  type: import_types24.NodeType.ConfigNode,
11492
- name: import_node_path36.default.basename(primary.sourceFile),
11621
+ name: import_node_path37.default.basename(primary.sourceFile),
11493
11622
  path: relPath,
11494
- fileType: isConfigFile(import_node_path36.default.basename(primary.sourceFile)).fileType || "config"
11623
+ fileType: isConfigFile(import_node_path37.default.basename(primary.sourceFile)).fileType || "config"
11495
11624
  };
11496
11625
  graph.addNode(cfgId, cfgNode);
11497
11626
  nodesAdded++;
@@ -11532,19 +11661,19 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11532
11661
 
11533
11662
  // src/extract/configs.ts
11534
11663
  init_cjs_shims();
11535
- var import_node_fs25 = require("fs");
11536
- var import_node_path37 = __toESM(require("path"), 1);
11664
+ var import_node_fs26 = require("fs");
11665
+ var import_node_path38 = __toESM(require("path"), 1);
11537
11666
  var import_types25 = require("@neat.is/types");
11538
11667
  async function walkConfigFiles(dir, excludeDirs = []) {
11539
- const excluded = new Set(excludeDirs.map((d) => import_node_path37.default.resolve(d)));
11668
+ const excluded = new Set(excludeDirs.map((d) => import_node_path38.default.resolve(d)));
11540
11669
  const out = [];
11541
11670
  async function walk11(current) {
11542
- const entries = await import_node_fs25.promises.readdir(current, { withFileTypes: true });
11671
+ const entries = await import_node_fs26.promises.readdir(current, { withFileTypes: true });
11543
11672
  for (const entry of entries) {
11544
- const full = import_node_path37.default.join(current, entry.name);
11673
+ const full = import_node_path38.default.join(current, entry.name);
11545
11674
  if (entry.isDirectory()) {
11546
11675
  if (IGNORED_DIRS.has(entry.name)) continue;
11547
- if (excluded.has(import_node_path37.default.resolve(full))) continue;
11676
+ if (excluded.has(import_node_path38.default.resolve(full))) continue;
11548
11677
  if (await isPythonVenvDir(full)) continue;
11549
11678
  await walk11(full);
11550
11679
  } else if (entry.isFile() && isConfigFile(entry.name).match) {
@@ -11561,19 +11690,19 @@ async function addConfigNodes(graph, services, scanPath) {
11561
11690
  for (const service of services) {
11562
11691
  const configFiles = await walkConfigFiles(service.dir, service.excludeDirs);
11563
11692
  for (const file of configFiles) {
11564
- const relPath = import_node_path37.default.relative(scanPath, file);
11693
+ const relPath = import_node_path38.default.relative(scanPath, file);
11565
11694
  const node = {
11566
11695
  id: (0, import_types25.configId)(relPath),
11567
11696
  type: import_types25.NodeType.ConfigNode,
11568
- name: import_node_path37.default.basename(file),
11697
+ name: import_node_path38.default.basename(file),
11569
11698
  path: relPath,
11570
- fileType: isConfigFile(import_node_path37.default.basename(file)).fileType
11699
+ fileType: isConfigFile(import_node_path38.default.basename(file)).fileType
11571
11700
  };
11572
11701
  if (!graph.hasNode(node.id)) {
11573
11702
  graph.addNode(node.id, node);
11574
11703
  nodesAdded++;
11575
11704
  }
11576
- const relToService = toPosix(import_node_path37.default.relative(service.dir, file));
11705
+ const relToService = toPosix(import_node_path38.default.relative(service.dir, file));
11577
11706
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11578
11707
  graph,
11579
11708
  service.pkg.name,
@@ -11589,7 +11718,7 @@ async function addConfigNodes(graph, services, scanPath) {
11589
11718
  type: import_types25.EdgeType.CONFIGURED_BY,
11590
11719
  provenance: import_types25.Provenance.EXTRACTED,
11591
11720
  confidence: (0, import_types25.confidenceForExtracted)("structural"),
11592
- evidence: { file: relPath.split(import_node_path37.default.sep).join("/") }
11721
+ evidence: { file: relPath.split(import_node_path38.default.sep).join("/") }
11593
11722
  };
11594
11723
  if (!graph.hasEdge(edge.id)) {
11595
11724
  graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
@@ -11602,8 +11731,8 @@ async function addConfigNodes(graph, services, scanPath) {
11602
11731
 
11603
11732
  // src/extract/proto.ts
11604
11733
  init_cjs_shims();
11605
- var import_node_fs26 = require("fs");
11606
- var import_node_path38 = __toESM(require("path"), 1);
11734
+ var import_node_fs27 = require("fs");
11735
+ var import_node_path39 = __toESM(require("path"), 1);
11607
11736
  var import_types26 = require("@neat.is/types");
11608
11737
  var PROTO_EXTENSION = ".proto";
11609
11738
  function packageOf(content) {
@@ -11641,18 +11770,18 @@ function grpcMethodsFromProto(content, fqPackage) {
11641
11770
  return out;
11642
11771
  }
11643
11772
  async function walkProtoFiles(dir, excludeDirs = []) {
11644
- const excluded = new Set(excludeDirs.map((d) => import_node_path38.default.resolve(d)));
11773
+ const excluded = new Set(excludeDirs.map((d) => import_node_path39.default.resolve(d)));
11645
11774
  const out = [];
11646
11775
  async function walk11(current) {
11647
- const entries = await import_node_fs26.promises.readdir(current, { withFileTypes: true }).catch(() => []);
11776
+ const entries = await import_node_fs27.promises.readdir(current, { withFileTypes: true }).catch(() => []);
11648
11777
  for (const entry of entries) {
11649
- const full = import_node_path38.default.join(current, entry.name);
11778
+ const full = import_node_path39.default.join(current, entry.name);
11650
11779
  if (entry.isDirectory()) {
11651
11780
  if (IGNORED_DIRS.has(entry.name)) continue;
11652
- if (excluded.has(import_node_path38.default.resolve(full))) continue;
11781
+ if (excluded.has(import_node_path39.default.resolve(full))) continue;
11653
11782
  if (await isPythonVenvDir(full)) continue;
11654
11783
  await walk11(full);
11655
- } else if (entry.isFile() && import_node_path38.default.extname(entry.name) === PROTO_EXTENSION) {
11784
+ } else if (entry.isFile() && import_node_path39.default.extname(entry.name) === PROTO_EXTENSION) {
11656
11785
  out.push(full);
11657
11786
  }
11658
11787
  }
@@ -11667,10 +11796,10 @@ async function addGrpcMethods(graph, services) {
11667
11796
  const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs);
11668
11797
  for (const protoPath of protoPaths) {
11669
11798
  if (isTestPath(protoPath)) continue;
11670
- const relFile = toPosix(import_node_path38.default.relative(service.dir, protoPath));
11799
+ const relFile = toPosix(import_node_path39.default.relative(service.dir, protoPath));
11671
11800
  let content;
11672
11801
  try {
11673
- content = await import_node_fs26.promises.readFile(protoPath, "utf8");
11802
+ content = await import_node_fs27.promises.readFile(protoPath, "utf8");
11674
11803
  } catch (err) {
11675
11804
  recordExtractionError("proto extraction", protoPath, err);
11676
11805
  continue;
@@ -11729,7 +11858,7 @@ var import_types46 = require("@neat.is/types");
11729
11858
 
11730
11859
  // src/extract/calls/http.ts
11731
11860
  init_cjs_shims();
11732
- var import_node_path39 = __toESM(require("path"), 1);
11861
+ var import_node_path40 = __toESM(require("path"), 1);
11733
11862
  var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
11734
11863
  var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
11735
11864
  var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
@@ -11812,7 +11941,7 @@ async function addHttpCallEdges(graph, services) {
11812
11941
  const seen = /* @__PURE__ */ new Set();
11813
11942
  for (const file of files) {
11814
11943
  if (isTestPath(file.path)) continue;
11815
- const parser = parserForExt(import_node_path39.default.extname(file.path), parserCache);
11944
+ const parser = parserForExt(import_node_path40.default.extname(file.path), parserCache);
11816
11945
  let sites;
11817
11946
  try {
11818
11947
  sites = callsFromSource(file.content, parser, knownHosts);
@@ -11821,7 +11950,7 @@ async function addHttpCallEdges(graph, services) {
11821
11950
  continue;
11822
11951
  }
11823
11952
  if (sites.length === 0) continue;
11824
- const relFile = toPosix(import_node_path39.default.relative(service.dir, file.path));
11953
+ const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
11825
11954
  for (const site of sites) {
11826
11955
  const targetId = hostToNodeId.get(site.host);
11827
11956
  if (!targetId || targetId === service.node.id) continue;
@@ -11875,7 +12004,7 @@ async function addHttpCallEdges(graph, services) {
11875
12004
 
11876
12005
  // src/extract/calls/route-match.ts
11877
12006
  init_cjs_shims();
11878
- var import_node_path40 = __toESM(require("path"), 1);
12007
+ var import_node_path41 = __toESM(require("path"), 1);
11879
12008
  var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
11880
12009
  var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
11881
12010
  var import_types28 = require("@neat.is/types");
@@ -12153,7 +12282,7 @@ async function addRouteCallEdges(graph, services) {
12153
12282
  const seen = /* @__PURE__ */ new Set();
12154
12283
  for (const file of files) {
12155
12284
  if (isTestPath(file.path)) continue;
12156
- if (!JS_CLIENT_EXTENSIONS.has(import_node_path40.default.extname(file.path))) continue;
12285
+ if (!JS_CLIENT_EXTENSIONS.has(import_node_path41.default.extname(file.path))) continue;
12157
12286
  let sites;
12158
12287
  try {
12159
12288
  sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
@@ -12162,7 +12291,7 @@ async function addRouteCallEdges(graph, services) {
12162
12291
  continue;
12163
12292
  }
12164
12293
  if (sites.length === 0) continue;
12165
- const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
12294
+ const relFile = toPosix(import_node_path41.default.relative(service.dir, file.path));
12166
12295
  for (const site of sites) {
12167
12296
  if (site.host === null) {
12168
12297
  const dedupKey2 = `${relFile}|unresolved-host`;
@@ -12255,7 +12384,7 @@ async function addRouteCallEdges(graph, services) {
12255
12384
 
12256
12385
  // src/extract/calls/kafka.ts
12257
12386
  init_cjs_shims();
12258
- var import_node_path41 = __toESM(require("path"), 1);
12387
+ var import_node_path42 = __toESM(require("path"), 1);
12259
12388
  var import_types29 = require("@neat.is/types");
12260
12389
  var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
12261
12390
  var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
@@ -12343,13 +12472,13 @@ function kafkaEndpointsFromFile(file, serviceDir) {
12343
12472
  // call sites — verified-call-site tier (ADR-066).
12344
12473
  confidenceKind: "verified-call-site",
12345
12474
  evidence: {
12346
- file: import_node_path41.default.relative(serviceDir, file.path),
12475
+ file: import_node_path42.default.relative(serviceDir, file.path),
12347
12476
  line,
12348
12477
  snippet: snippet(file.content, line)
12349
12478
  }
12350
12479
  });
12351
12480
  };
12352
- if (import_node_path41.default.extname(file.path) === ".go") {
12481
+ if (import_node_path42.default.extname(file.path) === ".go") {
12353
12482
  goSaramaEndpoints(file.content, make);
12354
12483
  } else {
12355
12484
  for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
@@ -12360,7 +12489,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
12360
12489
 
12361
12490
  // src/extract/calls/redis.ts
12362
12491
  init_cjs_shims();
12363
- var import_node_path42 = __toESM(require("path"), 1);
12492
+ var import_node_path43 = __toESM(require("path"), 1);
12364
12493
  var import_types30 = require("@neat.is/types");
12365
12494
  var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
12366
12495
  function redisEndpointsFromFile(file, serviceDir) {
@@ -12383,7 +12512,7 @@ function redisEndpointsFromFile(file, serviceDir) {
12383
12512
  // support tier (ADR-066).
12384
12513
  confidenceKind: "url-with-structural-support",
12385
12514
  evidence: {
12386
- file: import_node_path42.default.relative(serviceDir, file.path),
12515
+ file: import_node_path43.default.relative(serviceDir, file.path),
12387
12516
  line,
12388
12517
  snippet: snippet(file.content, line)
12389
12518
  }
@@ -12394,7 +12523,7 @@ function redisEndpointsFromFile(file, serviceDir) {
12394
12523
 
12395
12524
  // src/extract/calls/aws.ts
12396
12525
  init_cjs_shims();
12397
- var import_node_path43 = __toESM(require("path"), 1);
12526
+ var import_node_path44 = __toESM(require("path"), 1);
12398
12527
  var import_types31 = require("@neat.is/types");
12399
12528
  var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
12400
12529
  var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
@@ -12428,7 +12557,7 @@ function awsEndpointsFromFile(file, serviceDir) {
12428
12557
  // (ADR-066).
12429
12558
  confidenceKind: "verified-call-site",
12430
12559
  evidence: {
12431
- file: import_node_path43.default.relative(serviceDir, file.path),
12560
+ file: import_node_path44.default.relative(serviceDir, file.path),
12432
12561
  line,
12433
12562
  snippet: snippet(file.content, line)
12434
12563
  }
@@ -12453,7 +12582,7 @@ function awsEndpointsFromFile(file, serviceDir) {
12453
12582
 
12454
12583
  // src/extract/calls/grpc.ts
12455
12584
  init_cjs_shims();
12456
- var import_node_path44 = __toESM(require("path"), 1);
12585
+ var import_node_path45 = __toESM(require("path"), 1);
12457
12586
  var import_types32 = require("@neat.is/types");
12458
12587
  var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
12459
12588
  var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
@@ -12512,7 +12641,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
12512
12641
  // tier (ADR-066).
12513
12642
  confidenceKind: "verified-call-site",
12514
12643
  evidence: {
12515
- file: import_node_path44.default.relative(serviceDir, file.path),
12644
+ file: import_node_path45.default.relative(serviceDir, file.path),
12516
12645
  line,
12517
12646
  snippet: snippet(file.content, line)
12518
12647
  }
@@ -12523,7 +12652,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
12523
12652
 
12524
12653
  // src/extract/calls/supabase.ts
12525
12654
  init_cjs_shims();
12526
- var import_node_path45 = __toESM(require("path"), 1);
12655
+ var import_node_path46 = __toESM(require("path"), 1);
12527
12656
  var import_types33 = require("@neat.is/types");
12528
12657
  var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
12529
12658
  var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
@@ -12582,7 +12711,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12582
12711
  // tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
12583
12712
  confidenceKind: "verified-call-site",
12584
12713
  evidence: {
12585
- file: import_node_path45.default.relative(serviceDir, file.path),
12714
+ file: import_node_path46.default.relative(serviceDir, file.path),
12586
12715
  line,
12587
12716
  snippet: snippet(file.content, line)
12588
12717
  }
@@ -12609,7 +12738,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12609
12738
  edgeType: "CALLS",
12610
12739
  confidenceKind: "verified-call-site",
12611
12740
  evidence: {
12612
- file: import_node_path45.default.relative(serviceDir, file.path),
12741
+ file: import_node_path46.default.relative(serviceDir, file.path),
12613
12742
  line,
12614
12743
  snippet: snippet(file.content, line)
12615
12744
  }
@@ -12621,7 +12750,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12621
12750
 
12622
12751
  // src/extract/calls/firestore.ts
12623
12752
  init_cjs_shims();
12624
- var import_node_path46 = __toESM(require("path"), 1);
12753
+ var import_node_path47 = __toESM(require("path"), 1);
12625
12754
  var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
12626
12755
  var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
12627
12756
  var import_types34 = require("@neat.is/types");
@@ -12794,7 +12923,7 @@ function firestoreEndpointsFromFile(file, serviceDir, imported) {
12794
12923
  if (!hasClient && !hasAdmin && importedNames.size === 0) return [];
12795
12924
  const ownSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12796
12925
  const fileSdk = !hasClient && !hasAdmin ? imported?.sdk ?? null : ownSdk;
12797
- const tree = parseSource3(parserForExt2(import_node_path46.default.extname(file.path)), file.content);
12926
+ const tree = parseSource3(parserForExt2(import_node_path47.default.extname(file.path)), file.content);
12798
12927
  const clientVars = firestoreClientVars(tree.rootNode);
12799
12928
  for (const n of importedNames) clientVars.add(n);
12800
12929
  const collLine = /* @__PURE__ */ new Map();
@@ -12899,7 +13028,7 @@ function firestoreEndpointsFromFile(file, serviceDir, imported) {
12899
13028
  ...columnSet.size > 0 ? { columns: [...columnSet] } : {},
12900
13029
  ...sdkWrites ? { sdkWrites } : {},
12901
13030
  evidence: {
12902
- file: import_node_path46.default.relative(serviceDir, file.path),
13031
+ file: import_node_path47.default.relative(serviceDir, file.path),
12903
13032
  line,
12904
13033
  snippet: snippet(file.content, line)
12905
13034
  }
@@ -12959,7 +13088,7 @@ function sdkOf(content) {
12959
13088
  return hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12960
13089
  }
12961
13090
  function parseOrNull(file) {
12962
- const ext = import_node_path46.default.extname(file.path);
13091
+ const ext = import_node_path47.default.extname(file.path);
12963
13092
  if (!(ext in GRAMMAR_BY_EXT)) return null;
12964
13093
  try {
12965
13094
  return parseSource3(parserForExt2(ext), file.content).rootNode;
@@ -12975,7 +13104,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
12975
13104
  if (!root) continue;
12976
13105
  const names = exportedFirestoreClients(root);
12977
13106
  if (names.size === 0) continue;
12978
- registry.set(toPosix(import_node_path46.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
13107
+ registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
12979
13108
  }
12980
13109
  if (registry.size === 0) return [];
12981
13110
  const out = [];
@@ -12988,7 +13117,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
12988
13117
  const names = /* @__PURE__ */ new Set();
12989
13118
  let sdk = null;
12990
13119
  for (const b of bindings) {
12991
- const rel = await resolveJsImport(b.specifier, import_node_path46.default.dirname(f.path), serviceDir, null);
13120
+ const rel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
12992
13121
  if (!rel) continue;
12993
13122
  const entry = registry.get(rel);
12994
13123
  if (!entry || !entry.names.has(b.imported)) continue;
@@ -13003,7 +13132,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
13003
13132
 
13004
13133
  // src/extract/calls/mongoose.ts
13005
13134
  init_cjs_shims();
13006
- var import_node_path47 = __toESM(require("path"), 1);
13135
+ var import_node_path48 = __toESM(require("path"), 1);
13007
13136
  var import_types35 = require("@neat.is/types");
13008
13137
  var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
13009
13138
  var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
@@ -13154,7 +13283,7 @@ function endpoint(r, file, serviceDir, matchText) {
13154
13283
  kind: r.kind,
13155
13284
  edgeType: "CALLS",
13156
13285
  confidenceKind: "verified-call-site",
13157
- evidence: { file: import_node_path47.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13286
+ evidence: { file: import_node_path48.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13158
13287
  };
13159
13288
  }
13160
13289
  function mongooseEndpointsFromFile(file, serviceDir) {
@@ -13244,7 +13373,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13244
13373
  const registry = /* @__PURE__ */ new Map();
13245
13374
  for (const f of mongooseFiles) {
13246
13375
  const fx = fileExportsOf(f.content, pluralizeOn);
13247
- if (fx) registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), fx);
13376
+ if (fx) registry.set(toPosix(import_node_path48.default.relative(serviceDir, f.path)), fx);
13248
13377
  }
13249
13378
  if (registry.size === 0) return [];
13250
13379
  const out = [];
@@ -13255,7 +13384,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13255
13384
  const directColl = /* @__PURE__ */ new Map();
13256
13385
  const nsExports = /* @__PURE__ */ new Map();
13257
13386
  for (const b of bindings) {
13258
- const resolvedRel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
13387
+ const resolvedRel = await resolveJsImport(b.specifier, import_node_path48.default.dirname(f.path), serviceDir, null);
13259
13388
  if (!resolvedRel) continue;
13260
13389
  const fx = registry.get(resolvedRel);
13261
13390
  if (!fx) continue;
@@ -13299,7 +13428,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13299
13428
 
13300
13429
  // src/extract/calls/sqlalchemy.ts
13301
13430
  init_cjs_shims();
13302
- var import_node_path48 = __toESM(require("path"), 1);
13431
+ var import_node_path49 = __toESM(require("path"), 1);
13303
13432
  var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
13304
13433
  var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
13305
13434
  var import_types36 = require("@neat.is/types");
@@ -13438,7 +13567,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
13438
13567
  childTable,
13439
13568
  parentTable,
13440
13569
  evidence: {
13441
- file: import_node_path48.default.relative(serviceDir, file.path),
13570
+ file: import_node_path49.default.relative(serviceDir, file.path),
13442
13571
  line,
13443
13572
  snippet: snippet(file.content, line)
13444
13573
  }
@@ -13463,7 +13592,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
13463
13592
  confidenceKind: "verified-call-site",
13464
13593
  ...columns && columns.length > 0 ? { columns } : {},
13465
13594
  evidence: {
13466
- file: import_node_path48.default.relative(serviceDir, file.path),
13595
+ file: import_node_path49.default.relative(serviceDir, file.path),
13467
13596
  line,
13468
13597
  snippet: snippet(file.content, line)
13469
13598
  }
@@ -13570,7 +13699,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
13570
13699
  edgeType: "CALLS",
13571
13700
  confidenceKind: "verified-call-site",
13572
13701
  evidence: {
13573
- file: import_node_path48.default.relative(serviceDir, file.path),
13702
+ file: import_node_path49.default.relative(serviceDir, file.path),
13574
13703
  line,
13575
13704
  snippet: snippet(file.content, line)
13576
13705
  }
@@ -13582,7 +13711,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
13582
13711
 
13583
13712
  // src/extract/calls/socket.ts
13584
13713
  init_cjs_shims();
13585
- var import_node_path49 = __toESM(require("path"), 1);
13714
+ var import_node_path50 = __toESM(require("path"), 1);
13586
13715
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
13587
13716
  var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
13588
13717
  var import_types37 = require("@neat.is/types");
@@ -13658,7 +13787,7 @@ function socketEndpointsFromFile(file, serviceDir) {
13658
13787
  // A verified `socket.socket(...)` + `.connect((host, port))` call site.
13659
13788
  confidenceKind: "verified-call-site",
13660
13789
  evidence: {
13661
- file: import_node_path49.default.relative(serviceDir, file.path),
13790
+ file: import_node_path50.default.relative(serviceDir, file.path),
13662
13791
  line,
13663
13792
  snippet: snippet(file.content, line)
13664
13793
  }
@@ -13669,7 +13798,7 @@ function socketEndpointsFromFile(file, serviceDir) {
13669
13798
 
13670
13799
  // src/extract/calls/django-orm.ts
13671
13800
  init_cjs_shims();
13672
- var import_node_path50 = __toESM(require("path"), 1);
13801
+ var import_node_path51 = __toESM(require("path"), 1);
13673
13802
  var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
13674
13803
  var import_tree_sitter_python7 = __toESM(require("tree-sitter-python"), 1);
13675
13804
  var import_types38 = require("@neat.is/types");
@@ -13739,7 +13868,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13739
13868
  const tree = parseSource8(makePyParser5(), file.content);
13740
13869
  const out = [];
13741
13870
  const seen = /* @__PURE__ */ new Set();
13742
- const defaultAppLabel = import_node_path50.default.basename(import_node_path50.default.dirname(file.path));
13871
+ const defaultAppLabel = import_node_path51.default.basename(import_node_path51.default.dirname(file.path));
13743
13872
  walk5(tree.rootNode, (node) => {
13744
13873
  if (node.type !== "class_definition") return;
13745
13874
  if (!extendsDjangoModel(node)) return;
@@ -13757,7 +13886,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13757
13886
  kind: "sql-table",
13758
13887
  edgeType: "CALLS",
13759
13888
  confidenceKind: "verified-call-site",
13760
- evidence: { file: import_node_path50.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13889
+ evidence: { file: import_node_path51.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13761
13890
  });
13762
13891
  });
13763
13892
  return out;
@@ -13765,7 +13894,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13765
13894
 
13766
13895
  // src/extract/calls/drizzle.ts
13767
13896
  init_cjs_shims();
13768
- var import_node_path51 = __toESM(require("path"), 1);
13897
+ var import_node_path52 = __toESM(require("path"), 1);
13769
13898
  var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
13770
13899
  var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
13771
13900
  var import_types39 = require("@neat.is/types");
@@ -13843,7 +13972,7 @@ function columnsFromObject(obj) {
13843
13972
  }
13844
13973
  function drizzleEndpointsFromFile(file, serviceDir) {
13845
13974
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
13846
- const tree = parseSource3(parserForExt3(import_node_path51.default.extname(file.path)), file.content);
13975
+ const tree = parseSource3(parserForExt3(import_node_path52.default.extname(file.path)), file.content);
13847
13976
  const out = [];
13848
13977
  const seen = /* @__PURE__ */ new Set();
13849
13978
  const walk11 = (node) => {
@@ -13866,7 +13995,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
13866
13995
  confidenceKind: "structural",
13867
13996
  columns,
13868
13997
  evidence: {
13869
- file: import_node_path51.default.relative(serviceDir, file.path),
13998
+ file: import_node_path52.default.relative(serviceDir, file.path),
13870
13999
  line,
13871
14000
  snippet: snippet(file.content, line)
13872
14001
  }
@@ -13932,7 +14061,7 @@ function referencesTargetVar(call) {
13932
14061
  }
13933
14062
  function drizzleForeignKeys(file, serviceDir) {
13934
14063
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
13935
- const tree = parseSource3(parserForExt3(import_node_path51.default.extname(file.path)), file.content);
14064
+ const tree = parseSource3(parserForExt3(import_node_path52.default.extname(file.path)), file.content);
13936
14065
  const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
13937
14066
  const out = [];
13938
14067
  const seen = /* @__PURE__ */ new Set();
@@ -13951,7 +14080,7 @@ function drizzleForeignKeys(file, serviceDir) {
13951
14080
  childTable: table.tableName,
13952
14081
  parentTable,
13953
14082
  evidence: {
13954
- file: import_node_path51.default.relative(serviceDir, file.path),
14083
+ file: import_node_path52.default.relative(serviceDir, file.path),
13955
14084
  line,
13956
14085
  snippet: snippet(file.content, line)
13957
14086
  }
@@ -13968,7 +14097,7 @@ function drizzleForeignKeys(file, serviceDir) {
13968
14097
 
13969
14098
  // src/extract/calls/prisma.ts
13970
14099
  init_cjs_shims();
13971
- var import_node_path52 = __toESM(require("path"), 1);
14100
+ var import_node_path53 = __toESM(require("path"), 1);
13972
14101
  var import_types40 = require("@neat.is/types");
13973
14102
  var SCALAR_TYPES = /* @__PURE__ */ new Set([
13974
14103
  "Int",
@@ -14024,7 +14153,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
14024
14153
  confidenceKind: "structural",
14025
14154
  columns: b.columns,
14026
14155
  evidence: {
14027
- file: import_node_path52.default.relative(serviceDir, file.path),
14156
+ file: import_node_path53.default.relative(serviceDir, file.path),
14028
14157
  line: b.startLine,
14029
14158
  snippet: snippet(content, b.startLine)
14030
14159
  }
@@ -14085,7 +14214,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
14085
14214
  }
14086
14215
  async function prismaColumnEndpoints(serviceDir) {
14087
14216
  const schemaPath = await findFirst(serviceDir, [
14088
- import_node_path52.default.join("prisma", "schema.prisma"),
14217
+ import_node_path53.default.join("prisma", "schema.prisma"),
14089
14218
  "schema.prisma"
14090
14219
  ]);
14091
14220
  if (!schemaPath) return [];
@@ -14160,7 +14289,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
14160
14289
  childTable: current.table,
14161
14290
  parentTable,
14162
14291
  evidence: {
14163
- file: import_node_path52.default.relative(serviceDir, file.path),
14292
+ file: import_node_path53.default.relative(serviceDir, file.path),
14164
14293
  line: lineNo,
14165
14294
  snippet: snippet(content, lineNo)
14166
14295
  }
@@ -14175,7 +14304,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
14175
14304
  }
14176
14305
  async function prismaForeignKeys(serviceDir) {
14177
14306
  const schemaPath = await findFirst(serviceDir, [
14178
- import_node_path52.default.join("prisma", "schema.prisma"),
14307
+ import_node_path53.default.join("prisma", "schema.prisma"),
14179
14308
  "schema.prisma"
14180
14309
  ]);
14181
14310
  if (!schemaPath) return [];
@@ -14186,7 +14315,7 @@ async function prismaForeignKeys(serviceDir) {
14186
14315
 
14187
14316
  // src/extract/calls/activerecord.ts
14188
14317
  init_cjs_shims();
14189
- var import_node_path53 = __toESM(require("path"), 1);
14318
+ var import_node_path54 = __toESM(require("path"), 1);
14190
14319
  var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
14191
14320
  var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
14192
14321
  var import_types41 = require("@neat.is/types");
@@ -14394,7 +14523,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
14394
14523
  confidenceKind: "structural",
14395
14524
  ...table.columns.length > 0 ? { columns: table.columns } : {},
14396
14525
  evidence: {
14397
- file: import_node_path53.default.relative(serviceDir, file.path),
14526
+ file: import_node_path54.default.relative(serviceDir, file.path),
14398
14527
  line: table.line,
14399
14528
  snippet: snippet(file.content, table.line)
14400
14529
  }
@@ -14416,7 +14545,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
14416
14545
  childTable,
14417
14546
  parentTable,
14418
14547
  evidence: {
14419
- file: import_node_path53.default.relative(serviceDir, file.path),
14548
+ file: import_node_path54.default.relative(serviceDir, file.path),
14420
14549
  line,
14421
14550
  snippet: snippet(file.content, line)
14422
14551
  }
@@ -14499,7 +14628,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
14499
14628
  edgeType: "CALLS",
14500
14629
  confidenceKind: "verified-call-site",
14501
14630
  evidence: {
14502
- file: import_node_path53.default.relative(serviceDir, file.path),
14631
+ file: import_node_path54.default.relative(serviceDir, file.path),
14503
14632
  line,
14504
14633
  snippet: snippet(file.content, line)
14505
14634
  }
@@ -14536,7 +14665,7 @@ function railsModelForeignKeys(file, serviceDir) {
14536
14665
  childTable,
14537
14666
  parentTable,
14538
14667
  evidence: {
14539
- file: import_node_path53.default.relative(serviceDir, file.path),
14668
+ file: import_node_path54.default.relative(serviceDir, file.path),
14540
14669
  line,
14541
14670
  snippet: snippet(file.content, line)
14542
14671
  }
@@ -14548,7 +14677,7 @@ function railsModelForeignKeys(file, serviceDir) {
14548
14677
 
14549
14678
  // src/extract/calls/eloquent.ts
14550
14679
  init_cjs_shims();
14551
- var import_node_path54 = __toESM(require("path"), 1);
14680
+ var import_node_path55 = __toESM(require("path"), 1);
14552
14681
  var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
14553
14682
  var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
14554
14683
  var import_types42 = require("@neat.is/types");
@@ -14805,7 +14934,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
14805
14934
  confidenceKind: "structural",
14806
14935
  ...columns.length > 0 ? { columns } : {},
14807
14936
  evidence: {
14808
- file: import_node_path54.default.relative(serviceDir, file.path),
14937
+ file: import_node_path55.default.relative(serviceDir, file.path),
14809
14938
  line: bp.line,
14810
14939
  snippet: snippet(file.content, bp.line)
14811
14940
  }
@@ -14827,7 +14956,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
14827
14956
  childTable,
14828
14957
  parentTable,
14829
14958
  evidence: {
14830
- file: import_node_path54.default.relative(serviceDir, file.path),
14959
+ file: import_node_path55.default.relative(serviceDir, file.path),
14831
14960
  line,
14832
14961
  snippet: snippet(file.content, line)
14833
14962
  }
@@ -14947,7 +15076,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
14947
15076
  edgeType: "CALLS",
14948
15077
  confidenceKind: "verified-call-site",
14949
15078
  evidence: {
14950
- file: import_node_path54.default.relative(serviceDir, file.path),
15079
+ file: import_node_path55.default.relative(serviceDir, file.path),
14951
15080
  line,
14952
15081
  snippet: snippet(file.content, line)
14953
15082
  }
@@ -14983,7 +15112,7 @@ function laravelModelForeignKeys(file, serviceDir) {
14983
15112
  childTable,
14984
15113
  parentTable,
14985
15114
  evidence: {
14986
- file: import_node_path54.default.relative(serviceDir, file.path),
15115
+ file: import_node_path55.default.relative(serviceDir, file.path),
14987
15116
  line,
14988
15117
  snippet: snippet(file.content, line)
14989
15118
  }
@@ -14995,7 +15124,7 @@ function laravelModelForeignKeys(file, serviceDir) {
14995
15124
 
14996
15125
  // src/extract/calls/go.ts
14997
15126
  init_cjs_shims();
14998
- var import_node_path57 = __toESM(require("path"), 1);
15127
+ var import_node_path58 = __toESM(require("path"), 1);
14999
15128
  var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
15000
15129
  var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
15001
15130
  var import_types43 = require("@neat.is/types");
@@ -15070,7 +15199,7 @@ function firstStringLiteralArg(argsNode) {
15070
15199
  return null;
15071
15200
  }
15072
15201
  function goSqlEndpointsFromFile(file, serviceDir) {
15073
- if (import_node_path57.default.extname(file.path) !== ".go") return [];
15202
+ if (import_node_path58.default.extname(file.path) !== ".go") return [];
15074
15203
  if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
15075
15204
  const tree = parseSource11(makeGoParser3(), file.content);
15076
15205
  const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
@@ -15099,7 +15228,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
15099
15228
  confidenceKind: "verified-call-site",
15100
15229
  ...columns.length > 0 ? { columns } : {},
15101
15230
  evidence: {
15102
- file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
15231
+ file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
15103
15232
  line,
15104
15233
  snippet: snippet(file.content, line)
15105
15234
  }
@@ -15110,7 +15239,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
15110
15239
 
15111
15240
  // src/extract/calls/gorm.ts
15112
15241
  init_cjs_shims();
15113
- var import_node_path58 = __toESM(require("path"), 1);
15242
+ var import_node_path59 = __toESM(require("path"), 1);
15114
15243
  var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
15115
15244
  var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
15116
15245
  var import_types44 = require("@neat.is/types");
@@ -15543,7 +15672,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
15543
15672
  seen.delete(struct.name);
15544
15673
  }
15545
15674
  function gormEndpointsFromFile(file, serviceDir) {
15546
- if (import_node_path58.default.extname(file.path) !== ".go") return [];
15675
+ if (import_node_path59.default.extname(file.path) !== ".go") return [];
15547
15676
  if (!GORM_IMPORT_RE.test(file.content)) return [];
15548
15677
  const tree = parseSource12(makeGoParser4(), file.content);
15549
15678
  const { structs, models, tableFor } = analyze(tree);
@@ -15565,7 +15694,7 @@ function gormEndpointsFromFile(file, serviceDir) {
15565
15694
  confidenceKind: "structural",
15566
15695
  ...columns.length > 0 ? { columns } : {},
15567
15696
  evidence: {
15568
- file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
15697
+ file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15569
15698
  line: struct.line,
15570
15699
  snippet: snippet(file.content, struct.line)
15571
15700
  }
@@ -15574,7 +15703,7 @@ function gormEndpointsFromFile(file, serviceDir) {
15574
15703
  return out;
15575
15704
  }
15576
15705
  function gormForeignKeys(file, serviceDir) {
15577
- if (import_node_path58.default.extname(file.path) !== ".go") return [];
15706
+ if (import_node_path59.default.extname(file.path) !== ".go") return [];
15578
15707
  if (!GORM_IMPORT_RE.test(file.content)) return [];
15579
15708
  const tree = parseSource12(makeGoParser4(), file.content);
15580
15709
  const { structs, models, tableFor } = analyze(tree);
@@ -15589,7 +15718,7 @@ function gormForeignKeys(file, serviceDir) {
15589
15718
  childTable,
15590
15719
  parentTable,
15591
15720
  evidence: {
15592
- file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
15721
+ file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15593
15722
  line,
15594
15723
  snippet: snippet(file.content, line)
15595
15724
  }
@@ -15626,7 +15755,7 @@ function gormForeignKeys(file, serviceDir) {
15626
15755
 
15627
15756
  // src/extract/calls/efcore.ts
15628
15757
  init_cjs_shims();
15629
- var import_node_path59 = __toESM(require("path"), 1);
15758
+ var import_node_path60 = __toESM(require("path"), 1);
15630
15759
  var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
15631
15760
  var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
15632
15761
  var import_types45 = require("@neat.is/types");
@@ -15705,7 +15834,7 @@ function tableFromToTable(call) {
15705
15834
  return value ? csStringLiteral(value) : null;
15706
15835
  }
15707
15836
  function efcoreEndpointsFromFile(file, serviceDir) {
15708
- if (import_node_path59.default.extname(file.path) !== ".cs") return [];
15837
+ if (import_node_path60.default.extname(file.path) !== ".cs") return [];
15709
15838
  if (!EFCORE_GATE.test(file.content)) return [];
15710
15839
  const tree = parseSource13(makeCsParser(), file.content);
15711
15840
  const out = [];
@@ -15720,7 +15849,7 @@ function efcoreEndpointsFromFile(file, serviceDir) {
15720
15849
  edgeType: "CALLS",
15721
15850
  confidenceKind: "structural",
15722
15851
  evidence: {
15723
- file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15852
+ file: toPosix(import_node_path60.default.relative(serviceDir, file.path)),
15724
15853
  line,
15725
15854
  snippet: snippet(file.content, line)
15726
15855
  }
@@ -15975,7 +16104,7 @@ init_cjs_shims();
15975
16104
 
15976
16105
  // src/extract/infra/docker-compose.ts
15977
16106
  init_cjs_shims();
15978
- var import_node_path60 = __toESM(require("path"), 1);
16107
+ var import_node_path61 = __toESM(require("path"), 1);
15979
16108
  var import_types49 = require("@neat.is/types");
15980
16109
 
15981
16110
  // src/extract/infra/shared.ts
@@ -16046,7 +16175,7 @@ function dependsOnList(value) {
16046
16175
  }
16047
16176
  function serviceNameToServiceNode(name, services) {
16048
16177
  for (const s of services) {
16049
- if (s.node.name === name || import_node_path60.default.basename(s.dir) === name) return s.node.id;
16178
+ if (s.node.name === name || import_node_path61.default.basename(s.dir) === name) return s.node.id;
16050
16179
  }
16051
16180
  return null;
16052
16181
  }
@@ -16055,7 +16184,7 @@ async function addComposeInfra(graph, scanPath, services) {
16055
16184
  let edgesAdded = 0;
16056
16185
  let composePath = null;
16057
16186
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
16058
- const abs = import_node_path60.default.join(scanPath, name);
16187
+ const abs = import_node_path61.default.join(scanPath, name);
16059
16188
  if (await exists2(abs)) {
16060
16189
  composePath = abs;
16061
16190
  break;
@@ -16068,13 +16197,13 @@ async function addComposeInfra(graph, scanPath, services) {
16068
16197
  } catch (err) {
16069
16198
  recordExtractionError(
16070
16199
  "infra docker-compose",
16071
- import_node_path60.default.relative(scanPath, composePath),
16200
+ import_node_path61.default.relative(scanPath, composePath),
16072
16201
  err
16073
16202
  );
16074
16203
  return { nodesAdded, edgesAdded };
16075
16204
  }
16076
16205
  if (!compose?.services) return { nodesAdded, edgesAdded };
16077
- const evidenceFile = import_node_path60.default.relative(scanPath, composePath).split(import_node_path60.default.sep).join("/");
16206
+ const evidenceFile = import_node_path61.default.relative(scanPath, composePath).split(import_node_path61.default.sep).join("/");
16078
16207
  const composeNameToNodeId = /* @__PURE__ */ new Map();
16079
16208
  for (const [composeName, svc] of Object.entries(compose.services)) {
16080
16209
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -16116,8 +16245,8 @@ async function addComposeInfra(graph, scanPath, services) {
16116
16245
 
16117
16246
  // src/extract/infra/dockerfile.ts
16118
16247
  init_cjs_shims();
16119
- var import_node_path61 = __toESM(require("path"), 1);
16120
- var import_node_fs27 = require("fs");
16248
+ var import_node_path62 = __toESM(require("path"), 1);
16249
+ var import_node_fs28 = require("fs");
16121
16250
  var import_types50 = require("@neat.is/types");
16122
16251
  function readDockerfile(content) {
16123
16252
  let image = null;
@@ -16147,15 +16276,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16147
16276
  let nodesAdded = 0;
16148
16277
  let edgesAdded = 0;
16149
16278
  for (const service of services) {
16150
- const dockerfilePath = import_node_path61.default.join(service.dir, "Dockerfile");
16279
+ const dockerfilePath = import_node_path62.default.join(service.dir, "Dockerfile");
16151
16280
  if (!await exists2(dockerfilePath)) continue;
16152
16281
  let content;
16153
16282
  try {
16154
- content = await import_node_fs27.promises.readFile(dockerfilePath, "utf8");
16283
+ content = await import_node_fs28.promises.readFile(dockerfilePath, "utf8");
16155
16284
  } catch (err) {
16156
16285
  recordExtractionError(
16157
16286
  "infra dockerfile",
16158
- import_node_path61.default.relative(scanPath, dockerfilePath),
16287
+ import_node_path62.default.relative(scanPath, dockerfilePath),
16159
16288
  err
16160
16289
  );
16161
16290
  continue;
@@ -16167,8 +16296,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16167
16296
  graph.addNode(node.id, node);
16168
16297
  nodesAdded++;
16169
16298
  }
16170
- const relDockerfile = toPosix(import_node_path61.default.relative(service.dir, dockerfilePath));
16171
- const evidenceFile = toPosix(import_node_path61.default.relative(scanPath, dockerfilePath));
16299
+ const relDockerfile = toPosix(import_node_path62.default.relative(service.dir, dockerfilePath));
16300
+ const evidenceFile = toPosix(import_node_path62.default.relative(scanPath, dockerfilePath));
16172
16301
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
16173
16302
  graph,
16174
16303
  service.pkg.name,
@@ -16220,23 +16349,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16220
16349
 
16221
16350
  // src/extract/infra/terraform.ts
16222
16351
  init_cjs_shims();
16223
- var import_node_fs28 = require("fs");
16224
- var import_node_path62 = __toESM(require("path"), 1);
16352
+ var import_node_fs29 = require("fs");
16353
+ var import_node_path63 = __toESM(require("path"), 1);
16225
16354
  var import_types51 = require("@neat.is/types");
16226
16355
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
16227
16356
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
16228
16357
  async function walkTfFiles(start, depth = 0, max = 5) {
16229
16358
  if (depth > max) return [];
16230
16359
  const out = [];
16231
- const entries = await import_node_fs28.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16360
+ const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16232
16361
  for (const entry of entries) {
16233
16362
  if (entry.isDirectory()) {
16234
16363
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
16235
- const child = import_node_path62.default.join(start, entry.name);
16364
+ const child = import_node_path63.default.join(start, entry.name);
16236
16365
  if (await isPythonVenvDir(child)) continue;
16237
16366
  out.push(...await walkTfFiles(child, depth + 1, max));
16238
16367
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
16239
- out.push(import_node_path62.default.join(start, entry.name));
16368
+ out.push(import_node_path63.default.join(start, entry.name));
16240
16369
  }
16241
16370
  }
16242
16371
  return out;
@@ -16267,8 +16396,8 @@ async function addTerraformResources(graph, scanPath) {
16267
16396
  let edgesAdded = 0;
16268
16397
  const files = await walkTfFiles(scanPath);
16269
16398
  for (const file of files) {
16270
- const content = await import_node_fs28.promises.readFile(file, "utf8");
16271
- const evidenceFile = toPosix(import_node_path62.default.relative(scanPath, file));
16399
+ const content = await import_node_fs29.promises.readFile(file, "utf8");
16400
+ const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, file));
16272
16401
  const resources = [];
16273
16402
  const byKey = /* @__PURE__ */ new Map();
16274
16403
  RESOURCE_RE.lastIndex = 0;
@@ -16325,8 +16454,8 @@ async function addTerraformResources(graph, scanPath) {
16325
16454
 
16326
16455
  // src/extract/infra/k8s.ts
16327
16456
  init_cjs_shims();
16328
- var import_node_fs29 = require("fs");
16329
- var import_node_path63 = __toESM(require("path"), 1);
16457
+ var import_node_fs30 = require("fs");
16458
+ var import_node_path64 = __toESM(require("path"), 1);
16330
16459
  var import_yaml3 = require("yaml");
16331
16460
  var import_types52 = require("@neat.is/types");
16332
16461
  var K8S_KIND_TO_INFRA_KIND = {
@@ -16342,15 +16471,15 @@ var WORKLOAD_KINDS = /* @__PURE__ */ new Set(["Deployment", "StatefulSet", "Daem
16342
16471
  async function walkYamlFiles2(start, depth = 0, max = 5) {
16343
16472
  if (depth > max) return [];
16344
16473
  const out = [];
16345
- const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16474
+ const entries = await import_node_fs30.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16346
16475
  for (const entry of entries) {
16347
16476
  if (entry.isDirectory()) {
16348
16477
  if (IGNORED_DIRS.has(entry.name)) continue;
16349
- const child = import_node_path63.default.join(start, entry.name);
16478
+ const child = import_node_path64.default.join(start, entry.name);
16350
16479
  if (await isPythonVenvDir(child)) continue;
16351
16480
  out.push(...await walkYamlFiles2(child, depth + 1, max));
16352
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path63.default.extname(entry.name))) {
16353
- out.push(import_node_path63.default.join(start, entry.name));
16481
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path64.default.extname(entry.name))) {
16482
+ out.push(import_node_path64.default.join(start, entry.name));
16354
16483
  }
16355
16484
  }
16356
16485
  return out;
@@ -16360,14 +16489,14 @@ async function addK8sResources(graph, scanPath) {
16360
16489
  let edgesAdded = 0;
16361
16490
  const files = await walkYamlFiles2(scanPath);
16362
16491
  for (const file of files) {
16363
- const content = await import_node_fs29.promises.readFile(file, "utf8");
16492
+ const content = await import_node_fs30.promises.readFile(file, "utf8");
16364
16493
  let docs;
16365
16494
  try {
16366
16495
  docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
16367
16496
  } catch {
16368
16497
  continue;
16369
16498
  }
16370
- const relFile = toPosix(import_node_path63.default.relative(scanPath, file));
16499
+ const relFile = toPosix(import_node_path64.default.relative(scanPath, file));
16371
16500
  for (const doc of docs) {
16372
16501
  if (!doc?.kind || !doc.metadata?.name) continue;
16373
16502
  const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind];
@@ -16416,16 +16545,16 @@ async function addK8sResources(graph, scanPath) {
16416
16545
 
16417
16546
  // src/extract/infra/cloudflare.ts
16418
16547
  init_cjs_shims();
16419
- var import_node_fs30 = require("fs");
16420
- var import_node_path64 = __toESM(require("path"), 1);
16548
+ var import_node_fs31 = require("fs");
16549
+ var import_node_path65 = __toESM(require("path"), 1);
16421
16550
  var import_smol_toml3 = require("smol-toml");
16422
16551
  var import_types53 = require("@neat.is/types");
16423
16552
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
16424
16553
  async function readWranglerConfig(dir) {
16425
16554
  for (const filename of WRANGLER_FILENAMES) {
16426
- const abs = import_node_path64.default.join(dir, filename);
16555
+ const abs = import_node_path65.default.join(dir, filename);
16427
16556
  if (!await exists2(abs)) continue;
16428
- const raw = await import_node_fs30.promises.readFile(abs, "utf8");
16557
+ const raw = await import_node_fs31.promises.readFile(abs, "utf8");
16429
16558
  const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
16430
16559
  return { config, relFile: filename, raw };
16431
16560
  }
@@ -16486,11 +16615,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16486
16615
  try {
16487
16616
  read = await readWranglerConfig(service.dir);
16488
16617
  } catch (err) {
16489
- recordExtractionError("infra cloudflare", import_node_path64.default.relative(scanPath, service.dir), err);
16618
+ recordExtractionError("infra cloudflare", import_node_path65.default.relative(scanPath, service.dir), err);
16490
16619
  continue;
16491
16620
  }
16492
16621
  if (!read || !read.config.name) continue;
16493
- const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, read.relFile)));
16622
+ const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, read.relFile)));
16494
16623
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
16495
16624
  }
16496
16625
  for (const worker of discovered) {
@@ -16502,7 +16631,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16502
16631
  }
16503
16632
  let anchorId = service.node.id;
16504
16633
  if (config.main) {
16505
- const entryRelPath = toPosix(import_node_path64.default.normalize(config.main));
16634
+ const entryRelPath = toPosix(import_node_path65.default.normalize(config.main));
16506
16635
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
16507
16636
  graph,
16508
16637
  service.pkg.name,
@@ -16649,24 +16778,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16649
16778
 
16650
16779
  // src/extract/infra/vercel.ts
16651
16780
  init_cjs_shims();
16652
- var import_node_fs31 = require("fs");
16653
- var import_node_path65 = __toESM(require("path"), 1);
16781
+ var import_node_fs32 = require("fs");
16782
+ var import_node_path66 = __toESM(require("path"), 1);
16654
16783
  var import_types54 = require("@neat.is/types");
16655
16784
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
16656
16785
  async function readVercelConfig(dir) {
16657
16786
  for (const filename of VERCEL_CONFIG_FILENAMES) {
16658
- const abs = import_node_path65.default.join(dir, filename);
16787
+ const abs = import_node_path66.default.join(dir, filename);
16659
16788
  if (!await exists2(abs)) continue;
16660
- const raw = await import_node_fs31.promises.readFile(abs, "utf8");
16789
+ const raw = await import_node_fs32.promises.readFile(abs, "utf8");
16661
16790
  const config = JSON.parse(maskCommentsInSource(raw));
16662
16791
  return { config, relFile: filename, raw };
16663
16792
  }
16664
16793
  return null;
16665
16794
  }
16666
16795
  async function readLinkedProjectName(dir) {
16667
- const abs = import_node_path65.default.join(dir, ".vercel", "project.json");
16796
+ const abs = import_node_path66.default.join(dir, ".vercel", "project.json");
16668
16797
  if (!await exists2(abs)) return void 0;
16669
- const parsed = JSON.parse(await import_node_fs31.promises.readFile(abs, "utf8"));
16798
+ const parsed = JSON.parse(await import_node_fs32.promises.readFile(abs, "utf8"));
16670
16799
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
16671
16800
  }
16672
16801
  function routeSource(route) {
@@ -16682,7 +16811,7 @@ async function addVercelServices(graph, services, scanPath) {
16682
16811
  read = await readVercelConfig(service.dir);
16683
16812
  projectName = await readLinkedProjectName(service.dir);
16684
16813
  } catch (err) {
16685
- recordExtractionError("infra vercel", import_node_path65.default.relative(scanPath, service.dir), err);
16814
+ recordExtractionError("infra vercel", import_node_path66.default.relative(scanPath, service.dir), err);
16686
16815
  continue;
16687
16816
  }
16688
16817
  if (!read && !projectName) continue;
@@ -16698,7 +16827,7 @@ async function addVercelServices(graph, services, scanPath) {
16698
16827
  const anchorId = service.node.id;
16699
16828
  if (!read) continue;
16700
16829
  const { config, relFile, raw } = read;
16701
- const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, relFile)));
16830
+ const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
16702
16831
  const add = (edgeType, kind, name) => {
16703
16832
  if (!name) return;
16704
16833
  const result = emitPlatformResourceEdge(
@@ -16727,16 +16856,16 @@ async function addVercelServices(graph, services, scanPath) {
16727
16856
 
16728
16857
  // src/extract/infra/railway.ts
16729
16858
  init_cjs_shims();
16730
- var import_node_fs32 = require("fs");
16731
- var import_node_path66 = __toESM(require("path"), 1);
16859
+ var import_node_fs33 = require("fs");
16860
+ var import_node_path67 = __toESM(require("path"), 1);
16732
16861
  var import_smol_toml4 = require("smol-toml");
16733
16862
  var import_types55 = require("@neat.is/types");
16734
16863
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
16735
16864
  async function readRailwayConfig(dir) {
16736
16865
  for (const filename of RAILWAY_FILENAMES) {
16737
- const abs = import_node_path66.default.join(dir, filename);
16866
+ const abs = import_node_path67.default.join(dir, filename);
16738
16867
  if (!await exists2(abs)) continue;
16739
- const raw = await import_node_fs32.promises.readFile(abs, "utf8");
16868
+ const raw = await import_node_fs33.promises.readFile(abs, "utf8");
16740
16869
  const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
16741
16870
  return { config, relFile: filename, raw };
16742
16871
  }
@@ -16750,7 +16879,7 @@ async function addRailwayServices(graph, services, scanPath) {
16750
16879
  try {
16751
16880
  read = await readRailwayConfig(service.dir);
16752
16881
  } catch (err) {
16753
- recordExtractionError("infra railway", import_node_path66.default.relative(scanPath, service.dir), err);
16882
+ recordExtractionError("infra railway", import_node_path67.default.relative(scanPath, service.dir), err);
16754
16883
  continue;
16755
16884
  }
16756
16885
  if (!read) continue;
@@ -16760,7 +16889,7 @@ async function addRailwayServices(graph, services, scanPath) {
16760
16889
  }
16761
16890
  const anchorId = service.node.id;
16762
16891
  const { config, relFile, raw } = read;
16763
- const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
16892
+ const evidenceFile = toPosix(import_node_path67.default.relative(scanPath, import_node_path67.default.join(service.dir, relFile)));
16764
16893
  const add = (edgeType, kind, name) => {
16765
16894
  if (!name) return;
16766
16895
  const result = emitPlatformResourceEdge(
@@ -16785,15 +16914,15 @@ async function addRailwayServices(graph, services, scanPath) {
16785
16914
 
16786
16915
  // src/extract/infra/supabase.ts
16787
16916
  init_cjs_shims();
16788
- var import_node_fs33 = require("fs");
16789
- var import_node_path67 = __toESM(require("path"), 1);
16917
+ var import_node_fs34 = require("fs");
16918
+ var import_node_path68 = __toESM(require("path"), 1);
16790
16919
  var import_smol_toml5 = require("smol-toml");
16791
16920
  var import_types56 = require("@neat.is/types");
16792
16921
  async function readSupabaseConfig(dir) {
16793
- const relFile = import_node_path67.default.join("supabase", "config.toml");
16794
- const abs = import_node_path67.default.join(dir, relFile);
16922
+ const relFile = import_node_path68.default.join("supabase", "config.toml");
16923
+ const abs = import_node_path68.default.join(dir, relFile);
16795
16924
  if (!await exists2(abs)) return null;
16796
- const raw = await import_node_fs33.promises.readFile(abs, "utf8");
16925
+ const raw = await import_node_fs34.promises.readFile(abs, "utf8");
16797
16926
  const config = (0, import_smol_toml5.parse)(raw);
16798
16927
  return { config, relFile, raw };
16799
16928
  }
@@ -16805,7 +16934,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
16805
16934
  try {
16806
16935
  read = await readSupabaseConfig(service.dir);
16807
16936
  } catch (err) {
16808
- recordExtractionError("infra supabase", import_node_path67.default.relative(scanPath, service.dir), err);
16937
+ recordExtractionError("infra supabase", import_node_path68.default.relative(scanPath, service.dir), err);
16809
16938
  continue;
16810
16939
  }
16811
16940
  if (!read) continue;
@@ -16820,7 +16949,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
16820
16949
  });
16821
16950
  }
16822
16951
  const anchorId = service.node.id;
16823
- const evidenceFile = toPosix(import_node_path67.default.relative(scanPath, import_node_path67.default.join(service.dir, relFile)));
16952
+ const evidenceFile = toPosix(import_node_path68.default.relative(scanPath, import_node_path68.default.join(service.dir, relFile)));
16824
16953
  const add = (edgeType, kind, name) => {
16825
16954
  if (!name) return;
16826
16955
  const result = emitPlatformResourceEdge(
@@ -16862,7 +16991,7 @@ async function addInfra(graph, scanPath, services) {
16862
16991
 
16863
16992
  // src/extract/zod-shapes.ts
16864
16993
  init_cjs_shims();
16865
- var import_node_path68 = __toESM(require("path"), 1);
16994
+ var import_node_path69 = __toESM(require("path"), 1);
16866
16995
  var import_tree_sitter18 = __toESM(require("tree-sitter"), 1);
16867
16996
  var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
16868
16997
  var import_types57 = require("@neat.is/types");
@@ -16957,7 +17086,7 @@ function topLevelSchemas(root) {
16957
17086
  }
16958
17087
  function zodShapesFromFile(file, serviceDir) {
16959
17088
  if (!ZOD_IMPORT_RE.test(file.content)) return [];
16960
- const tree = parseSource3(parserForExt4(import_node_path68.default.extname(file.path)), file.content);
17089
+ const tree = parseSource3(parserForExt4(import_node_path69.default.extname(file.path)), file.content);
16961
17090
  const out = [];
16962
17091
  const seen = /* @__PURE__ */ new Set();
16963
17092
  for (const { name, call } of topLevelSchemas(tree.rootNode)) {
@@ -16975,7 +17104,7 @@ function zodShapesFromFile(file, serviceDir) {
16975
17104
  name,
16976
17105
  fields,
16977
17106
  evidence: {
16978
- file: import_node_path68.default.relative(serviceDir, file.path),
17107
+ file: import_node_path69.default.relative(serviceDir, file.path),
16979
17108
  line,
16980
17109
  snippet: snippet(file.content, line)
16981
17110
  }
@@ -17243,12 +17372,12 @@ async function addFirestoreRules(graph, services) {
17243
17372
  }
17244
17373
 
17245
17374
  // src/extract/index.ts
17246
- var import_node_path70 = __toESM(require("path"), 1);
17375
+ var import_node_path71 = __toESM(require("path"), 1);
17247
17376
 
17248
17377
  // src/extract/retire.ts
17249
17378
  init_cjs_shims();
17250
- var import_node_fs34 = require("fs");
17251
- var import_node_path69 = __toESM(require("path"), 1);
17379
+ var import_node_fs35 = require("fs");
17380
+ var import_node_path70 = __toESM(require("path"), 1);
17252
17381
  var import_types59 = require("@neat.is/types");
17253
17382
  function dropOrphanedFileNodes(graph) {
17254
17383
  const orphans = [];
@@ -17269,11 +17398,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
17269
17398
  if (edge.provenance !== import_types59.Provenance.EXTRACTED) return;
17270
17399
  const evidenceFile = edge.evidence?.file;
17271
17400
  if (!evidenceFile) return;
17272
- if (import_node_path69.default.isAbsolute(evidenceFile)) {
17273
- if (!(0, import_node_fs34.existsSync)(evidenceFile)) toDrop.push(id);
17401
+ if (import_node_path70.default.isAbsolute(evidenceFile)) {
17402
+ if (!(0, import_node_fs35.existsSync)(evidenceFile)) toDrop.push(id);
17274
17403
  return;
17275
17404
  }
17276
- const found = bases.some((base) => (0, import_node_fs34.existsSync)(import_node_path69.default.join(base, evidenceFile)));
17405
+ const found = bases.some((base) => (0, import_node_fs35.existsSync)(import_node_path70.default.join(base, evidenceFile)));
17277
17406
  if (!found) toDrop.push(id);
17278
17407
  });
17279
17408
  for (const id of toDrop) graph.dropEdge(id);
@@ -17285,6 +17414,7 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
17285
17414
  async function extractFromDirectory(graph, scanPath, opts = {}) {
17286
17415
  await ensureCompatLoaded();
17287
17416
  drainExtractionErrors();
17417
+ drainSkippedFiles();
17288
17418
  const services = await discoverServices(scanPath);
17289
17419
  const phase1Nodes = addServiceNodes(graph, services);
17290
17420
  await addServiceAliases(graph, scanPath, services);
@@ -17329,8 +17459,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
17329
17459
  }
17330
17460
  }
17331
17461
  const droppedEntries = drainDroppedExtracted();
17462
+ const skippedEntries = drainSkippedFiles();
17332
17463
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
17333
- const rejectedPath = import_node_path70.default.join(import_node_path70.default.dirname(opts.errorsPath), "rejected.ndjson");
17464
+ const rejectedPath = import_node_path71.default.join(import_node_path71.default.dirname(opts.errorsPath), "rejected.ndjson");
17334
17465
  try {
17335
17466
  await writeRejectedExtracted(droppedEntries, rejectedPath);
17336
17467
  } catch (err) {
@@ -17347,7 +17478,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
17347
17478
  errorEntries,
17348
17479
  ghostsRetired,
17349
17480
  extractedDropped: droppedEntries.length,
17350
- droppedEntries
17481
+ droppedEntries,
17482
+ skippedFiles: skippedEntries.length,
17483
+ skippedEntries
17351
17484
  };
17352
17485
  emitNeatEvent({
17353
17486
  type: "extraction-complete",
@@ -18267,7 +18400,7 @@ async function askGraph(graph, question, opts = {}) {
18267
18400
 
18268
18401
  // src/diff.ts
18269
18402
  init_cjs_shims();
18270
- var import_node_fs35 = require("fs");
18403
+ var import_node_fs36 = require("fs");
18271
18404
  async function loadSnapshotForDiff(target) {
18272
18405
  if (/^https?:\/\//i.test(target)) {
18273
18406
  const res = await fetch(target);
@@ -18276,7 +18409,7 @@ async function loadSnapshotForDiff(target) {
18276
18409
  }
18277
18410
  return await res.json();
18278
18411
  }
18279
- const raw = await import_node_fs35.promises.readFile(target, "utf8");
18412
+ const raw = await import_node_fs36.promises.readFile(target, "utf8");
18280
18413
  return JSON.parse(raw);
18281
18414
  }
18282
18415
  function indexEntries(entries) {
@@ -18344,8 +18477,8 @@ function canonicalJson(value) {
18344
18477
 
18345
18478
  // src/persist.ts
18346
18479
  init_cjs_shims();
18347
- var import_node_fs36 = require("fs");
18348
- var import_node_path71 = __toESM(require("path"), 1);
18480
+ var import_node_fs37 = require("fs");
18481
+ var import_node_path72 = __toESM(require("path"), 1);
18349
18482
  var import_types62 = require("@neat.is/types");
18350
18483
  var SCHEMA_VERSION = 7;
18351
18484
  function migrateV1ToV2(payload) {
@@ -18400,7 +18533,43 @@ function migrateV2ToV3(payload) {
18400
18533
  return { ...payload, schemaVersion: 3 };
18401
18534
  }
18402
18535
  async function ensureDir(filePath) {
18403
- await import_node_fs36.promises.mkdir(import_node_path71.default.dirname(filePath), { recursive: true });
18536
+ await import_node_fs37.promises.mkdir(import_node_path72.default.dirname(filePath), { recursive: true });
18537
+ }
18538
+ var WRITE_FLUSH_CHARS = 4 * 1024 * 1024;
18539
+ function jsonOrUndefined(value) {
18540
+ return JSON.stringify(value);
18541
+ }
18542
+ function* serializeArray(items) {
18543
+ yield "[";
18544
+ for (let i = 0; i < items.length; i++) {
18545
+ if (i > 0) yield ",";
18546
+ yield jsonOrUndefined(items[i]) ?? "null";
18547
+ }
18548
+ yield "]";
18549
+ }
18550
+ function isPlainObject(value) {
18551
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
18552
+ const proto = Object.getPrototypeOf(value);
18553
+ return proto === Object.prototype || proto === null;
18554
+ }
18555
+ function* serializeObject(obj) {
18556
+ yield "{";
18557
+ let first = true;
18558
+ for (const key of Object.keys(obj)) {
18559
+ const value = obj[key];
18560
+ const descend = Array.isArray(value) || isPlainObject(value);
18561
+ if (!descend && jsonOrUndefined(value) === void 0) continue;
18562
+ if (!first) yield ",";
18563
+ first = false;
18564
+ yield `${JSON.stringify(key)}:`;
18565
+ if (Array.isArray(value)) yield* serializeArray(value);
18566
+ else if (isPlainObject(value)) yield* serializeObject(value);
18567
+ else yield jsonOrUndefined(value);
18568
+ }
18569
+ yield "}";
18570
+ }
18571
+ function* serializeGraphChunks(payload) {
18572
+ yield* serializeObject(payload);
18404
18573
  }
18405
18574
  async function saveGraphToDisk(graph, outPath) {
18406
18575
  await ensureDir(outPath);
@@ -18410,13 +18579,26 @@ async function saveGraphToDisk(graph, outPath) {
18410
18579
  graph: graph.export()
18411
18580
  };
18412
18581
  const tmp = `${outPath}.tmp`;
18413
- await import_node_fs36.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
18414
- await import_node_fs36.promises.rename(tmp, outPath);
18582
+ const handle = await import_node_fs37.promises.open(tmp, "w");
18583
+ try {
18584
+ let buffered = "";
18585
+ for (const chunk of serializeGraphChunks(payload)) {
18586
+ buffered += chunk;
18587
+ if (buffered.length >= WRITE_FLUSH_CHARS) {
18588
+ await handle.write(buffered, null, "utf8");
18589
+ buffered = "";
18590
+ }
18591
+ }
18592
+ if (buffered.length > 0) await handle.write(buffered, null, "utf8");
18593
+ } finally {
18594
+ await handle.close();
18595
+ }
18596
+ await import_node_fs37.promises.rename(tmp, outPath);
18415
18597
  }
18416
18598
  async function loadGraphFromDisk(graph, outPath) {
18417
18599
  let raw;
18418
18600
  try {
18419
- raw = await import_node_fs36.promises.readFile(outPath, "utf8");
18601
+ raw = await import_node_fs37.promises.readFile(outPath, "utf8");
18420
18602
  } catch (err) {
18421
18603
  if (err.code === "ENOENT") return;
18422
18604
  throw err;
@@ -18490,23 +18672,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
18490
18672
 
18491
18673
  // src/projects.ts
18492
18674
  init_cjs_shims();
18493
- var import_node_path72 = __toESM(require("path"), 1);
18675
+ var import_node_path73 = __toESM(require("path"), 1);
18494
18676
  function pathsForProject(project, baseDir) {
18495
18677
  if (project === DEFAULT_PROJECT) {
18496
18678
  return {
18497
- snapshotPath: import_node_path72.default.join(baseDir, "graph.json"),
18498
- errorsPath: import_node_path72.default.join(baseDir, "errors.ndjson"),
18499
- staleEventsPath: import_node_path72.default.join(baseDir, "stale-events.ndjson"),
18500
- embeddingsCachePath: import_node_path72.default.join(baseDir, "embeddings.json"),
18501
- policyViolationsPath: import_node_path72.default.join(baseDir, "policy-violations.ndjson")
18679
+ snapshotPath: import_node_path73.default.join(baseDir, "graph.json"),
18680
+ errorsPath: import_node_path73.default.join(baseDir, "errors.ndjson"),
18681
+ staleEventsPath: import_node_path73.default.join(baseDir, "stale-events.ndjson"),
18682
+ embeddingsCachePath: import_node_path73.default.join(baseDir, "embeddings.json"),
18683
+ policyViolationsPath: import_node_path73.default.join(baseDir, "policy-violations.ndjson")
18502
18684
  };
18503
18685
  }
18504
18686
  return {
18505
- snapshotPath: import_node_path72.default.join(baseDir, `${project}.json`),
18506
- errorsPath: import_node_path72.default.join(baseDir, `errors.${project}.ndjson`),
18507
- staleEventsPath: import_node_path72.default.join(baseDir, `stale-events.${project}.ndjson`),
18508
- embeddingsCachePath: import_node_path72.default.join(baseDir, `embeddings.${project}.json`),
18509
- policyViolationsPath: import_node_path72.default.join(baseDir, `policy-violations.${project}.ndjson`)
18687
+ snapshotPath: import_node_path73.default.join(baseDir, `${project}.json`),
18688
+ errorsPath: import_node_path73.default.join(baseDir, `errors.${project}.ndjson`),
18689
+ staleEventsPath: import_node_path73.default.join(baseDir, `stale-events.${project}.ndjson`),
18690
+ embeddingsCachePath: import_node_path73.default.join(baseDir, `embeddings.${project}.json`),
18691
+ policyViolationsPath: import_node_path73.default.join(baseDir, `policy-violations.${project}.ndjson`)
18510
18692
  };
18511
18693
  }
18512
18694
  var Projects = class {
@@ -18546,20 +18728,20 @@ function parseExtraProjects(raw) {
18546
18728
 
18547
18729
  // src/registry.ts
18548
18730
  init_cjs_shims();
18549
- var import_node_fs37 = require("fs");
18731
+ var import_node_fs38 = require("fs");
18550
18732
  var import_node_os3 = __toESM(require("os"), 1);
18551
- var import_node_path73 = __toESM(require("path"), 1);
18733
+ var import_node_path74 = __toESM(require("path"), 1);
18552
18734
  var import_types63 = require("@neat.is/types");
18553
18735
  function neatHome() {
18554
18736
  const override = process.env.NEAT_HOME;
18555
- if (override && override.length > 0) return import_node_path73.default.resolve(override);
18556
- return import_node_path73.default.join(import_node_os3.default.homedir(), ".neat");
18737
+ if (override && override.length > 0) return import_node_path74.default.resolve(override);
18738
+ return import_node_path74.default.join(import_node_os3.default.homedir(), ".neat");
18557
18739
  }
18558
18740
  function registryPath() {
18559
- return import_node_path73.default.join(neatHome(), "projects.json");
18741
+ return import_node_path74.default.join(neatHome(), "projects.json");
18560
18742
  }
18561
18743
  function daemonsDir() {
18562
- return import_node_path73.default.join(neatHome(), "daemons");
18744
+ return import_node_path74.default.join(neatHome(), "daemons");
18563
18745
  }
18564
18746
  function isFiniteInt(v) {
18565
18747
  return typeof v === "number" && Number.isFinite(v);
@@ -18592,7 +18774,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
18592
18774
  const dir = daemonsDir();
18593
18775
  let names;
18594
18776
  try {
18595
- names = await import_node_fs37.promises.readdir(dir);
18777
+ names = await import_node_fs38.promises.readdir(dir);
18596
18778
  } catch (err) {
18597
18779
  if (err.code === "ENOENT") return [];
18598
18780
  throw err;
@@ -18600,10 +18782,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
18600
18782
  const out = [];
18601
18783
  for (const name of names) {
18602
18784
  if (!name.endsWith(".json")) continue;
18603
- const file = import_node_path73.default.join(dir, name);
18785
+ const file = import_node_path74.default.join(dir, name);
18604
18786
  let raw;
18605
18787
  try {
18606
- raw = await import_node_fs37.promises.readFile(file, "utf8");
18788
+ raw = await import_node_fs38.promises.readFile(file, "utf8");
18607
18789
  } catch {
18608
18790
  continue;
18609
18791
  }
@@ -18631,7 +18813,7 @@ async function readRegistry() {
18631
18813
  const file = registryPath();
18632
18814
  let raw;
18633
18815
  try {
18634
- raw = await import_node_fs37.promises.readFile(file, "utf8");
18816
+ raw = await import_node_fs38.promises.readFile(file, "utf8");
18635
18817
  } catch (err) {
18636
18818
  if (err.code === "ENOENT") {
18637
18819
  return { version: 1, projects: [] };
@@ -18714,8 +18896,8 @@ init_auth();
18714
18896
  // src/connectors-config.ts
18715
18897
  init_cjs_shims();
18716
18898
  var import_node_os4 = __toESM(require("os"), 1);
18717
- var import_node_path74 = __toESM(require("path"), 1);
18718
- var import_node_fs38 = require("fs");
18899
+ var import_node_path75 = __toESM(require("path"), 1);
18900
+ var import_node_fs39 = require("fs");
18719
18901
  var CONNECTORS_CONFIG_VERSION = 1;
18720
18902
  var EnvRefUnsetError = class extends Error {
18721
18903
  ref;
@@ -18729,17 +18911,17 @@ var EnvRefUnsetError = class extends Error {
18729
18911
  };
18730
18912
  function neatHome2() {
18731
18913
  const override = process.env.NEAT_HOME;
18732
- if (override && override.length > 0) return import_node_path74.default.resolve(override);
18733
- return import_node_path74.default.join(import_node_os4.default.homedir(), ".neat");
18914
+ if (override && override.length > 0) return import_node_path75.default.resolve(override);
18915
+ return import_node_path75.default.join(import_node_os4.default.homedir(), ".neat");
18734
18916
  }
18735
18917
  function connectorsConfigPath(home = neatHome2()) {
18736
- return import_node_path74.default.join(home, "connectors.json");
18918
+ return import_node_path75.default.join(home, "connectors.json");
18737
18919
  }
18738
18920
  var MODE_MASK_LOOSER_THAN_0600 = 63;
18739
18921
  async function warnIfModeLooserThan0600(file) {
18740
18922
  if (process.platform === "win32") return;
18741
18923
  try {
18742
- const stat = await import_node_fs38.promises.stat(file);
18924
+ const stat = await import_node_fs39.promises.stat(file);
18743
18925
  if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
18744
18926
  const mode = (stat.mode & 511).toString(8).padStart(3, "0");
18745
18927
  console.warn(
@@ -18753,7 +18935,7 @@ async function readConnectorsConfig(home = neatHome2()) {
18753
18935
  const file = connectorsConfigPath(home);
18754
18936
  let raw;
18755
18937
  try {
18756
- raw = await import_node_fs38.promises.readFile(file, "utf8");
18938
+ raw = await import_node_fs39.promises.readFile(file, "utf8");
18757
18939
  } catch (err) {
18758
18940
  if (err.code === "ENOENT") {
18759
18941
  return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
@@ -19507,10 +19689,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
19507
19689
  // src/connectors/supabase/map.ts
19508
19690
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
19509
19691
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
19510
- function targetFromRestPath(path77) {
19511
- const rpcMatch = REST_RPC_PATH_RE.exec(path77);
19692
+ function targetFromRestPath(path78) {
19693
+ const rpcMatch = REST_RPC_PATH_RE.exec(path78);
19512
19694
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
19513
- const tableMatch = REST_TABLE_PATH_RE.exec(path77);
19695
+ const tableMatch = REST_TABLE_PATH_RE.exec(path78);
19514
19696
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
19515
19697
  return null;
19516
19698
  }
@@ -20114,9 +20296,9 @@ function parseFirebaseTargetName(targetName) {
20114
20296
  const secondSep = rest.indexOf(FIELD_SEP);
20115
20297
  if (secondSep === -1) return null;
20116
20298
  const method = rest.slice(0, secondSep);
20117
- const path77 = rest.slice(secondSep + 1);
20118
- if (!resourceName || !method || !path77) return null;
20119
- return { resourceName, method, path: path77 };
20299
+ const path78 = rest.slice(secondSep + 1);
20300
+ if (!resourceName || !method || !path78) return null;
20301
+ return { resourceName, method, path: path78 };
20120
20302
  }
20121
20303
  function resourceNameFor(type, labels) {
20122
20304
  if (!labels) return null;
@@ -20154,14 +20336,14 @@ function mapLogEntryToSignal(entry) {
20154
20336
  if (!req) return null;
20155
20337
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
20156
20338
  const method = req.requestMethod.toUpperCase();
20157
- const path77 = pathFromRequestUrl(req.requestUrl);
20158
- if (path77 === null) return null;
20339
+ const path78 = pathFromRequestUrl(req.requestUrl);
20340
+ if (path78 === null) return null;
20159
20341
  const timestamp = entry.timestamp;
20160
20342
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
20161
20343
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
20162
20344
  return {
20163
20345
  targetKind: resourceType,
20164
- targetName: packFirebaseTargetName({ resourceName, method, path: path77 }),
20346
+ targetName: packFirebaseTargetName({ resourceName, method, path: path78 }),
20165
20347
  callCount: 1,
20166
20348
  errorCount: isError ? 1 : 0,
20167
20349
  lastObservedIso: timestamp
@@ -20186,9 +20368,9 @@ var import_types71 = require("@neat.is/types");
20186
20368
  function normalizeName(name) {
20187
20369
  return name.toLowerCase().replace(/[^a-z0-9]/g, "");
20188
20370
  }
20189
- function inferServiceName(graph, resourceName, method, path77) {
20371
+ function inferServiceName(graph, resourceName, method, path78) {
20190
20372
  const wantedMethod = method.toUpperCase();
20191
- const wantedPath = normalizePathTemplate(path77);
20373
+ const wantedPath = normalizePathTemplate(path78);
20192
20374
  const services = [];
20193
20375
  const owners = /* @__PURE__ */ new Set();
20194
20376
  graph.forEachNode((_id, attrs) => {
@@ -20405,7 +20587,7 @@ function mapEventToSignal(event) {
20405
20587
  if (Number.isNaN(observedAt.getTime())) return null;
20406
20588
  const statusCode = metadata?.statusCode;
20407
20589
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
20408
- const path77 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
20590
+ const path78 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
20409
20591
  return {
20410
20592
  targetKind: CLOUDFLARE_TARGET_KIND,
20411
20593
  targetName: scriptName,
@@ -20413,7 +20595,7 @@ function mapEventToSignal(event) {
20413
20595
  errorCount: isError ? 1 : 0,
20414
20596
  lastObservedIso: observedAt.toISOString(),
20415
20597
  method,
20416
- ...path77 ? { path: path77 } : {},
20598
+ ...path78 ? { path: path78 } : {},
20417
20599
  ...typeof statusCode === "number" ? { statusCode } : {},
20418
20600
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
20419
20601
  };
@@ -20459,8 +20641,8 @@ function findTaggedWorkerFileNode(graph, workerName) {
20459
20641
  });
20460
20642
  return found;
20461
20643
  }
20462
- function findMatchingRouteNode(graph, serviceName, method, path77) {
20463
- const normalizedPath = normalizePathTemplate(path77);
20644
+ function findMatchingRouteNode(graph, serviceName, method, path78) {
20645
+ const normalizedPath = normalizePathTemplate(path78);
20464
20646
  let found = null;
20465
20647
  graph.forEachNode((id, attrs) => {
20466
20648
  if (found) return;
@@ -20477,10 +20659,10 @@ function createCloudflareResolveTarget(config, graph) {
20477
20659
  return (signal) => {
20478
20660
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
20479
20661
  const scriptName = signal.targetName;
20480
- const { method, path: path77 } = signal;
20662
+ const { method, path: path78 } = signal;
20481
20663
  const resolveRouteGrain = (serviceName, wholeFileId) => {
20482
- if (!method || !path77) return wholeFileId;
20483
- return findMatchingRouteNode(graph, serviceName, method, path77) ?? wholeFileId;
20664
+ if (!method || !path78) return wholeFileId;
20665
+ return findMatchingRouteNode(graph, serviceName, method, path78) ?? wholeFileId;
20484
20666
  };
20485
20667
  const mapping = config.workers?.[scriptName];
20486
20668
  if (mapping) {
@@ -20832,9 +21014,9 @@ function parseCloudRunTargetName(targetName) {
20832
21014
  const secondSep = rest.indexOf(FIELD_SEP2);
20833
21015
  if (secondSep === -1) return null;
20834
21016
  const method = rest.slice(0, secondSep);
20835
- const path77 = rest.slice(secondSep + 1);
20836
- if (!serviceName || !method || !path77) return null;
20837
- return { serviceName, method, path: path77 };
21017
+ const path78 = rest.slice(secondSep + 1);
21018
+ if (!serviceName || !method || !path78) return null;
21019
+ return { serviceName, method, path: path78 };
20838
21020
  }
20839
21021
 
20840
21022
  // src/connectors/cloud-run/map.ts
@@ -20863,14 +21045,14 @@ function mapLogEntryToSignal2(entry) {
20863
21045
  if (!req) return null;
20864
21046
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
20865
21047
  const method = req.requestMethod.toUpperCase();
20866
- const path77 = pathFromRequestUrl2(req.requestUrl);
20867
- if (path77 === null) return null;
21048
+ const path78 = pathFromRequestUrl2(req.requestUrl);
21049
+ if (path78 === null) return null;
20868
21050
  const timestamp = entry.timestamp;
20869
21051
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
20870
21052
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
20871
21053
  return {
20872
21054
  targetKind: CLOUD_RUN_TARGET_KIND,
20873
- targetName: packCloudRunTargetName({ serviceName, method, path: path77 }),
21055
+ targetName: packCloudRunTargetName({ serviceName, method, path: path78 }),
20874
21056
  callCount: 1,
20875
21057
  errorCount: isError ? 1 : 0,
20876
21058
  lastObservedIso: timestamp
@@ -20909,14 +21091,14 @@ function createCloudRunResolveTarget(graph, config) {
20909
21091
  if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
20910
21092
  const identity = parseCloudRunTargetName(signal.targetName);
20911
21093
  if (!identity) return null;
20912
- const { serviceName: gcpServiceName, method, path: path77 } = identity;
20913
- const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method, path77) ?? void 0 : void 0);
21094
+ const { serviceName: gcpServiceName, method, path: path78 } = identity;
21095
+ const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method, path78) ?? void 0 : void 0);
20914
21096
  if (mappedService) {
20915
21097
  const routeNodeId = findMatchingRouteNode2(
20916
21098
  graph,
20917
21099
  mappedService,
20918
21100
  method,
20919
- normalizePathTemplate(path77)
21101
+ normalizePathTemplate(path78)
20920
21102
  );
20921
21103
  if (routeNodeId) {
20922
21104
  return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types82.EdgeType.CALLS };
@@ -21052,9 +21234,9 @@ function parseGcpLbTargetName(targetName) {
21052
21234
  const secondSep = rest.indexOf(FIELD_SEP3);
21053
21235
  if (secondSep === -1) return null;
21054
21236
  const method = rest.slice(0, secondSep);
21055
- const path77 = rest.slice(secondSep + 1);
21056
- if (!backendServiceName || !method || !path77) return null;
21057
- return { backendServiceName, method, path: path77 };
21237
+ const path78 = rest.slice(secondSep + 1);
21238
+ if (!backendServiceName || !method || !path78) return null;
21239
+ return { backendServiceName, method, path: path78 };
21058
21240
  }
21059
21241
 
21060
21242
  // src/connectors/gcp-lb/map.ts
@@ -21083,14 +21265,14 @@ function mapLogEntryToSignal3(entry) {
21083
21265
  if (!req) return null;
21084
21266
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
21085
21267
  const method = req.requestMethod.toUpperCase();
21086
- const path77 = pathFromRequestUrl3(req.requestUrl);
21087
- if (path77 === null) return null;
21268
+ const path78 = pathFromRequestUrl3(req.requestUrl);
21269
+ if (path78 === null) return null;
21088
21270
  const timestamp = entry.timestamp;
21089
21271
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
21090
21272
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD5;
21091
21273
  return {
21092
21274
  targetKind: GCP_LB_TARGET_KIND,
21093
- targetName: packGcpLbTargetName({ backendServiceName, method, path: path77 }),
21275
+ targetName: packGcpLbTargetName({ backendServiceName, method, path: path78 }),
21094
21276
  callCount: 1,
21095
21277
  errorCount: isError ? 1 : 0,
21096
21278
  lastObservedIso: timestamp
@@ -21129,14 +21311,14 @@ function createGcpLbResolveTarget(graph, config) {
21129
21311
  if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
21130
21312
  const identity = parseGcpLbTargetName(signal.targetName);
21131
21313
  if (!identity) return null;
21132
- const { backendServiceName, method, path: path77 } = identity;
21133
- const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method, path77) ?? void 0 : void 0);
21314
+ const { backendServiceName, method, path: path78 } = identity;
21315
+ const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method, path78) ?? void 0 : void 0);
21134
21316
  if (mappedService) {
21135
21317
  const routeNodeId = findMatchingRouteNode3(
21136
21318
  graph,
21137
21319
  mappedService,
21138
21320
  method,
21139
- normalizePathTemplate(path77)
21321
+ normalizePathTemplate(path78)
21140
21322
  );
21141
21323
  if (routeNodeId) {
21142
21324
  return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types86.EdgeType.CALLS };
@@ -22398,16 +22580,18 @@ function serializeGraph(graph) {
22398
22580
  });
22399
22581
  return { nodes, edges };
22400
22582
  }
22401
- function projectFromReq(req, singleProject) {
22583
+ function projectFromReq(req, singleProject, registry) {
22402
22584
  const params = req.params;
22403
22585
  const named = params.project;
22404
22586
  if (singleProject) {
22405
22587
  return named === void 0 || named === DEFAULT_PROJECT ? singleProject : named;
22406
22588
  }
22407
- return named ?? DEFAULT_PROJECT;
22589
+ if (named !== void 0) return named;
22590
+ const hosted = registry?.list() ?? [];
22591
+ return hosted.length === 1 ? hosted[0] : DEFAULT_PROJECT;
22408
22592
  }
22409
22593
  function resolveProject(registry, req, reply, bootstrap, singleProject) {
22410
- const name = projectFromReq(req, singleProject);
22594
+ const name = projectFromReq(req, singleProject, registry);
22411
22595
  const ctx = registry.get(name);
22412
22596
  if (!ctx) {
22413
22597
  const phase = bootstrap?.status(name);
@@ -22419,10 +22603,13 @@ function resolveProject(registry, req, reply, bootstrap, singleProject) {
22419
22603
  void reply.code(503).send({ ready: false, project: name, status: "broken" });
22420
22604
  return null;
22421
22605
  }
22606
+ const unnamed = req.params.project === void 0;
22607
+ const hosted = registry.list();
22608
+ const hint = unnamed && name === DEFAULT_PROJECT && hosted.length > 1 ? `This daemon hosts ${hosted.length} projects and none is named \`default\`: ${hosted.join(", ")}. Name one as /projects/<name>/\u2026 , or reach that project's own daemon.` : "This daemon does not host that project. GET /projects lists what it serves (see hostedHere).";
22422
22609
  void reply.code(404).send({
22423
22610
  error: "project not found",
22424
22611
  project: name,
22425
- hint: "This daemon does not host that project. GET /projects lists what it serves (see hostedHere)."
22612
+ hint
22426
22613
  });
22427
22614
  return null;
22428
22615
  }
@@ -23305,8 +23492,8 @@ init_otel_grpc();
23305
23492
 
23306
23493
  // src/search.ts
23307
23494
  init_cjs_shims();
23308
- var import_node_fs39 = require("fs");
23309
- var import_node_path75 = __toESM(require("path"), 1);
23495
+ var import_node_fs40 = require("fs");
23496
+ var import_node_path76 = __toESM(require("path"), 1);
23310
23497
  var import_node_crypto5 = require("crypto");
23311
23498
  var DEFAULT_LIMIT = 10;
23312
23499
  var NOMIC_DIM = 768;
@@ -23460,7 +23647,7 @@ async function pickEmbedder() {
23460
23647
  }
23461
23648
  async function readCache(cachePath) {
23462
23649
  try {
23463
- const raw = await import_node_fs39.promises.readFile(cachePath, "utf8");
23650
+ const raw = await import_node_fs40.promises.readFile(cachePath, "utf8");
23464
23651
  const parsed = JSON.parse(raw);
23465
23652
  if (parsed.version !== 1) return null;
23466
23653
  return parsed;
@@ -23469,8 +23656,8 @@ async function readCache(cachePath) {
23469
23656
  }
23470
23657
  }
23471
23658
  async function writeCache(cachePath, cache) {
23472
- await import_node_fs39.promises.mkdir(import_node_path75.default.dirname(cachePath), { recursive: true });
23473
- await import_node_fs39.promises.writeFile(cachePath, JSON.stringify(cache));
23659
+ await import_node_fs40.promises.mkdir(import_node_path76.default.dirname(cachePath), { recursive: true });
23660
+ await import_node_fs40.promises.writeFile(cachePath, JSON.stringify(cache));
23474
23661
  }
23475
23662
  var VectorIndex = class {
23476
23663
  constructor(embedder, cachePath) {
@@ -23684,14 +23871,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
23684
23871
  async function main() {
23685
23872
  const baseDirEnv = process.env.NEAT_OUT_DIR;
23686
23873
  const legacyOutPath = process.env.NEAT_OUT_PATH;
23687
- const baseDir = baseDirEnv ? import_node_path76.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path76.default.resolve(import_node_path76.default.dirname(legacyOutPath)) : import_node_path76.default.resolve("./neat-out");
23688
- const defaultScanPath = import_node_path76.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
23874
+ const baseDir = baseDirEnv ? import_node_path77.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path77.default.resolve(import_node_path77.default.dirname(legacyOutPath)) : import_node_path77.default.resolve("./neat-out");
23875
+ const defaultScanPath = import_node_path77.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
23689
23876
  const registry = new Projects();
23690
23877
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
23691
23878
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
23692
23879
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
23693
23880
  const projectScan = process.env[envKey];
23694
- await bootProject(registry, name, projectScan ? import_node_path76.default.resolve(projectScan) : void 0, baseDir);
23881
+ await bootProject(registry, name, projectScan ? import_node_path77.default.resolve(projectScan) : void 0, baseDir);
23695
23882
  }
23696
23883
  const host = process.env.HOST ?? "0.0.0.0";
23697
23884
  const port = Number(process.env.PORT ?? 8080);