@neat.is/core 0.10.5 → 0.10.6-dev.20261007

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
@@ -63,8 +63,8 @@ function mountBearerAuth(app, opts) {
63
63
  ]);
64
64
  const publicRead = opts.publicRead === true;
65
65
  app.addHook("preHandler", (req, reply, done) => {
66
- const path78 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
67
- if (exactUnauthPaths.has(path78) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path78)) {
66
+ const path81 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
67
+ if (exactUnauthPaths.has(path81) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path81)) {
68
68
  done();
69
69
  return;
70
70
  }
@@ -201,8 +201,8 @@ function reshapeGrpcRequest(req) {
201
201
  };
202
202
  }
203
203
  function resolveProtoRoot() {
204
- const here = import_node_path56.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
205
- return import_node_path56.default.resolve(here, "..", "proto");
204
+ const here = import_node_path57.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
205
+ return import_node_path57.default.resolve(here, "..", "proto");
206
206
  }
207
207
  function loadTraceService() {
208
208
  const protoRoot = resolveProtoRoot();
@@ -270,13 +270,13 @@ async function startOtelGrpcReceiver(opts) {
270
270
  })
271
271
  };
272
272
  }
273
- var import_node_url, import_node_path56, import_node_crypto2, grpc, protoLoader;
273
+ var import_node_url, import_node_path57, import_node_crypto2, grpc, protoLoader;
274
274
  var init_otel_grpc = __esm({
275
275
  "src/otel-grpc.ts"() {
276
276
  "use strict";
277
277
  init_cjs_shims();
278
278
  import_node_url = require("url");
279
- import_node_path56 = __toESM(require("path"), 1);
279
+ import_node_path57 = __toESM(require("path"), 1);
280
280
  import_node_crypto2 = require("crypto");
281
281
  grpc = __toESM(require("@grpc/grpc-js"), 1);
282
282
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -422,8 +422,8 @@ function websocketChannelPathOf(attrs) {
422
422
  const v = attrs[key];
423
423
  if (typeof v === "string" && v.length > 0) {
424
424
  const q = v.indexOf("?");
425
- const path78 = q === -1 ? v : v.slice(0, q);
426
- if (path78.length > 0) return path78;
425
+ const path81 = q === -1 ? v : v.slice(0, q);
426
+ if (path81.length > 0) return path81;
427
427
  }
428
428
  }
429
429
  return void 0;
@@ -485,10 +485,10 @@ function parseOtlpRequest(body) {
485
485
  return out;
486
486
  }
487
487
  function loadProtoRoot() {
488
- const here = import_node_path57.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
489
- const protoRoot = import_node_path57.default.resolve(here, "..", "proto");
488
+ const here = import_node_path58.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
489
+ const protoRoot = import_node_path58.default.resolve(here, "..", "proto");
490
490
  const root = new import_protobufjs.default.Root();
491
- root.resolvePath = (_origin, target) => import_node_path57.default.resolve(protoRoot, target);
491
+ root.resolvePath = (_origin, target) => import_node_path58.default.resolve(protoRoot, target);
492
492
  root.loadSync(
493
493
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
494
494
  { keepCase: true }
@@ -750,12 +750,12 @@ async function buildOtelReceiver(opts) {
750
750
  };
751
751
  return decorated;
752
752
  }
753
- 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;
753
+ var import_node_path58, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
754
754
  var init_otel = __esm({
755
755
  "src/otel.ts"() {
756
756
  "use strict";
757
757
  init_cjs_shims();
758
- import_node_path57 = __toESM(require("path"), 1);
758
+ import_node_path58 = __toESM(require("path"), 1);
759
759
  import_node_url2 = require("url");
760
760
  import_node_zlib = __toESM(require("zlib"), 1);
761
761
  import_fastify = __toESM(require("fastify"), 1);
@@ -772,7 +772,7 @@ var init_otel = __esm({
772
772
 
773
773
  // src/server.ts
774
774
  init_cjs_shims();
775
- var import_node_path77 = __toESM(require("path"), 1);
775
+ var import_node_path80 = __toESM(require("path"), 1);
776
776
 
777
777
  // src/graph.ts
778
778
  init_cjs_shims();
@@ -795,8 +795,9 @@ function getGraph(project = DEFAULT_PROJECT) {
795
795
  // src/api.ts
796
796
  init_cjs_shims();
797
797
  var import_fastify2 = __toESM(require("fastify"), 1);
798
+ var import_node_crypto6 = require("crypto");
798
799
  var import_cors = __toESM(require("@fastify/cors"), 1);
799
- var import_types101 = require("@neat.is/types");
800
+ var import_types103 = require("@neat.is/types");
800
801
 
801
802
  // src/extend/index.ts
802
803
  init_cjs_shims();
@@ -1514,14 +1515,37 @@ init_cjs_shims();
1514
1515
 
1515
1516
  // src/ingest.ts
1516
1517
  init_cjs_shims();
1517
- var import_node_fs10 = require("fs");
1518
- var import_node_path11 = __toESM(require("path"), 1);
1519
- var sourceMapJs = __toESM(require("source-map-js"), 1);
1518
+ var import_node_fs11 = require("fs");
1519
+ var import_node_path12 = __toESM(require("path"), 1);
1520
1520
 
1521
- // src/policy.ts
1521
+ // src/durable-incident.ts
1522
1522
  init_cjs_shims();
1523
1523
  var import_node_fs4 = require("fs");
1524
1524
  var import_node_path4 = __toESM(require("path"), 1);
1525
+ async function appendRuntimeIncident(errorsPath, project, event, options = {}) {
1526
+ const token = options.token ?? process.env.NEAT_INCIDENT_DURABLE_TOKEN;
1527
+ if (token !== void 0) {
1528
+ if (Buffer.byteLength(token, "utf8") < 32) throw new Error("durable incident sink unavailable");
1529
+ const response = await (options.fetchImpl ?? fetch)("http://127.0.0.1:8081/incident-append", {
1530
+ method: "POST",
1531
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
1532
+ body: JSON.stringify({ project, event }),
1533
+ signal: AbortSignal.timeout(3e4)
1534
+ });
1535
+ if (response.status !== 204) throw new Error("durable incident sink unavailable");
1536
+ return;
1537
+ }
1538
+ await import_node_fs4.promises.mkdir(import_node_path4.default.dirname(errorsPath), { recursive: true });
1539
+ await import_node_fs4.promises.appendFile(errorsPath, JSON.stringify(event) + "\n", "utf8");
1540
+ }
1541
+
1542
+ // src/ingest.ts
1543
+ var sourceMapJs = __toESM(require("source-map-js"), 1);
1544
+
1545
+ // src/policy.ts
1546
+ init_cjs_shims();
1547
+ var import_node_fs5 = require("fs");
1548
+ var import_node_path5 = __toESM(require("path"), 1);
1525
1549
  var import_types2 = require("@neat.is/types");
1526
1550
 
1527
1551
  // src/events.ts
@@ -1990,7 +2014,7 @@ function matchPolicyToNode(graph, policy, nodeId, node) {
1990
2014
  async function loadPolicyFile(policyPath) {
1991
2015
  let raw;
1992
2016
  try {
1993
- raw = await import_node_fs4.promises.readFile(policyPath, "utf8");
2017
+ raw = await import_node_fs5.promises.readFile(policyPath, "utf8");
1994
2018
  } catch (err) {
1995
2019
  if (err.code === "ENOENT") return [];
1996
2020
  throw err;
@@ -2011,8 +2035,8 @@ var PolicyViolationsLog = class {
2011
2035
  if (!this.seen) await this.hydrate();
2012
2036
  if (this.seen.has(v.id)) return false;
2013
2037
  this.seen.add(v.id);
2014
- await import_node_fs4.promises.mkdir(import_node_path4.default.dirname(this.path), { recursive: true });
2015
- await import_node_fs4.promises.appendFile(this.path, JSON.stringify(v) + "\n", "utf8");
2038
+ await import_node_fs5.promises.mkdir(import_node_path5.default.dirname(this.path), { recursive: true });
2039
+ await import_node_fs5.promises.appendFile(this.path, JSON.stringify(v) + "\n", "utf8");
2016
2040
  emitNeatEvent({
2017
2041
  type: "policy-violation",
2018
2042
  project: this.project,
@@ -2022,7 +2046,7 @@ var PolicyViolationsLog = class {
2022
2046
  }
2023
2047
  async readAll() {
2024
2048
  try {
2025
- const raw = await import_node_fs4.promises.readFile(this.path, "utf8");
2049
+ const raw = await import_node_fs5.promises.readFile(this.path, "utf8");
2026
2050
  return raw.split("\n").filter(Boolean).map((line) => JSON.parse(line));
2027
2051
  } catch (err) {
2028
2052
  if (err.code === "ENOENT") return [];
@@ -2041,7 +2065,7 @@ var import_types7 = require("@neat.is/types");
2041
2065
 
2042
2066
  // src/extract/routes.ts
2043
2067
  init_cjs_shims();
2044
- var import_node_path10 = __toESM(require("path"), 1);
2068
+ var import_node_path11 = __toESM(require("path"), 1);
2045
2069
  var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
2046
2070
  var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
2047
2071
  var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
@@ -2053,8 +2077,8 @@ var import_types6 = require("@neat.is/types");
2053
2077
 
2054
2078
  // src/extract/shared.ts
2055
2079
  init_cjs_shims();
2056
- var import_node_fs5 = require("fs");
2057
- var import_node_path5 = __toESM(require("path"), 1);
2080
+ var import_node_fs6 = require("fs");
2081
+ var import_node_path6 = __toESM(require("path"), 1);
2058
2082
  var import_yaml = require("yaml");
2059
2083
  var import_types3 = require("@neat.is/types");
2060
2084
  var SERVICE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".tsx", ".py", ".go", ".rb", ".php", ".cs", ".java", ".kt", ".rs", ".cpp", ".cc", ".cxx", ".c++", ".hpp", ".hh", ".hxx", ".h++"]);
@@ -2098,7 +2122,7 @@ async function isPythonVenvDir(dir) {
2098
2122
  const cached = PYVENV_MARKER_CACHE.get(dir);
2099
2123
  if (cached !== void 0) return cached;
2100
2124
  try {
2101
- const stat = await import_node_fs5.promises.stat(import_node_path5.default.join(dir, "pyvenv.cfg"));
2125
+ const stat = await import_node_fs6.promises.stat(import_node_path6.default.join(dir, "pyvenv.cfg"));
2102
2126
  const ok = stat.isFile();
2103
2127
  PYVENV_MARKER_CACHE.set(dir, ok);
2104
2128
  return ok;
@@ -2108,7 +2132,7 @@ async function isPythonVenvDir(dir) {
2108
2132
  }
2109
2133
  }
2110
2134
  function isConfigFile(name) {
2111
- const ext = import_node_path5.default.extname(name);
2135
+ const ext = import_node_path6.default.extname(name);
2112
2136
  if (CONFIG_FILE_EXTENSIONS.has(ext)) return { match: true, fileType: ext.slice(1) };
2113
2137
  if (JSON_CONFIG_FILENAMES.has(name)) return { match: true, fileType: "json" };
2114
2138
  if (name === ".env" || name.startsWith(".env.")) {
@@ -2225,16 +2249,16 @@ function cleanVersion(raw) {
2225
2249
  return raw.replace(/^[\^~><=v\s]+/, "").trim() || void 0;
2226
2250
  }
2227
2251
  async function readJson(filePath) {
2228
- const raw = await import_node_fs5.promises.readFile(filePath, "utf8");
2252
+ const raw = await import_node_fs6.promises.readFile(filePath, "utf8");
2229
2253
  return JSON.parse(raw);
2230
2254
  }
2231
2255
  async function readYaml(filePath) {
2232
- const raw = await import_node_fs5.promises.readFile(filePath, "utf8");
2256
+ const raw = await import_node_fs6.promises.readFile(filePath, "utf8");
2233
2257
  return (0, import_yaml.parse)(raw);
2234
2258
  }
2235
2259
  async function exists2(p) {
2236
2260
  try {
2237
- await import_node_fs5.promises.access(p);
2261
+ await import_node_fs6.promises.access(p);
2238
2262
  return true;
2239
2263
  } catch {
2240
2264
  return false;
@@ -2243,8 +2267,8 @@ async function exists2(p) {
2243
2267
 
2244
2268
  // src/extract/errors.ts
2245
2269
  init_cjs_shims();
2246
- var import_node_fs6 = require("fs");
2247
- var import_node_path6 = __toESM(require("path"), 1);
2270
+ var import_node_fs7 = require("fs");
2271
+ var import_node_path7 = __toESM(require("path"), 1);
2248
2272
  var sink = [];
2249
2273
  function recordExtractionError(producer, file, err) {
2250
2274
  const e = err instanceof Error ? err : new Error(String(err));
@@ -2263,14 +2287,14 @@ function drainExtractionErrors() {
2263
2287
  }
2264
2288
  async function writeExtractionErrors(errors, errorsPath) {
2265
2289
  if (errors.length === 0) return;
2266
- await import_node_fs6.promises.mkdir(import_node_path6.default.dirname(errorsPath), { recursive: true });
2290
+ await import_node_fs7.promises.mkdir(import_node_path7.default.dirname(errorsPath), { recursive: true });
2267
2291
  const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
2268
- await import_node_fs6.promises.appendFile(errorsPath, lines, "utf8");
2292
+ await import_node_fs7.promises.appendFile(errorsPath, lines, "utf8");
2269
2293
  }
2270
2294
  function extractionHealthPathFor(errorsPath) {
2271
- const dir = import_node_path6.default.dirname(errorsPath);
2272
- const suffix = import_node_path6.default.basename(errorsPath).replace(/^errors/, "").replace(/\.ndjson$/, "");
2273
- return import_node_path6.default.join(dir, `extraction-health${suffix}.json`);
2295
+ const dir = import_node_path7.default.dirname(errorsPath);
2296
+ const suffix = import_node_path7.default.basename(errorsPath).replace(/^errors/, "").replace(/\.ndjson$/, "");
2297
+ return import_node_path7.default.join(dir, `extraction-health${suffix}.json`);
2274
2298
  }
2275
2299
  var HEALTH_FILE_SAMPLE = 100;
2276
2300
  async function writeExtractionHealth(errors, healthPath, now = (/* @__PURE__ */ new Date()).toISOString()) {
@@ -2282,13 +2306,13 @@ async function writeExtractionHealth(errors, healthPath, now = (/* @__PURE__ */
2282
2306
  files: errors.slice(0, HEALTH_FILE_SAMPLE).map((e) => e.file),
2283
2307
  updatedAt: now
2284
2308
  };
2285
- await import_node_fs6.promises.mkdir(import_node_path6.default.dirname(healthPath), { recursive: true });
2286
- await import_node_fs6.promises.writeFile(healthPath, JSON.stringify(coverage), "utf8");
2309
+ await import_node_fs7.promises.mkdir(import_node_path7.default.dirname(healthPath), { recursive: true });
2310
+ await import_node_fs7.promises.writeFile(healthPath, JSON.stringify(coverage), "utf8");
2287
2311
  }
2288
2312
  async function readExtractionHealth(healthPath) {
2289
2313
  let raw;
2290
2314
  try {
2291
- raw = await import_node_fs6.promises.readFile(healthPath, "utf8");
2315
+ raw = await import_node_fs7.promises.readFile(healthPath, "utf8");
2292
2316
  } catch {
2293
2317
  return void 0;
2294
2318
  }
@@ -2324,21 +2348,21 @@ function isRejectedLogEnabled() {
2324
2348
  }
2325
2349
  async function writeRejectedExtracted(drops, rejectedPath) {
2326
2350
  if (drops.length === 0) return;
2327
- await import_node_fs6.promises.mkdir(import_node_path6.default.dirname(rejectedPath), { recursive: true });
2351
+ await import_node_fs7.promises.mkdir(import_node_path7.default.dirname(rejectedPath), { recursive: true });
2328
2352
  const lines = drops.map((d) => JSON.stringify({ ...d, ts: (/* @__PURE__ */ new Date()).toISOString() })).join("\n") + "\n";
2329
- await import_node_fs6.promises.appendFile(rejectedPath, lines, "utf8");
2353
+ await import_node_fs7.promises.appendFile(rejectedPath, lines, "utf8");
2330
2354
  }
2331
2355
 
2332
2356
  // src/extract/calls/shared.ts
2333
2357
  init_cjs_shims();
2334
- var import_node_fs8 = require("fs");
2335
- var import_node_path8 = __toESM(require("path"), 1);
2358
+ var import_node_fs9 = require("fs");
2359
+ var import_node_path9 = __toESM(require("path"), 1);
2336
2360
  var import_types4 = require("@neat.is/types");
2337
2361
 
2338
2362
  // src/extract/gitignore.ts
2339
2363
  init_cjs_shims();
2340
- var import_node_fs7 = require("fs");
2341
- var import_node_path7 = __toESM(require("path"), 1);
2364
+ var import_node_fs8 = require("fs");
2365
+ var import_node_path8 = __toESM(require("path"), 1);
2342
2366
  var import_ignore = __toESM(require("ignore"), 1);
2343
2367
  var LAYER_CACHE = /* @__PURE__ */ new Map();
2344
2368
  async function layerFor(dir) {
@@ -2346,7 +2370,7 @@ async function layerFor(dir) {
2346
2370
  if (cached !== void 0) return cached;
2347
2371
  let layer = null;
2348
2372
  try {
2349
- const raw = await import_node_fs7.promises.readFile(import_node_path7.default.join(dir, ".gitignore"), "utf8");
2373
+ const raw = await import_node_fs8.promises.readFile(import_node_path8.default.join(dir, ".gitignore"), "utf8");
2350
2374
  layer = { dir, ig: (0, import_ignore.default)().add(raw) };
2351
2375
  } catch {
2352
2376
  layer = null;
@@ -2356,7 +2380,7 @@ async function layerFor(dir) {
2356
2380
  }
2357
2381
  async function isRepoRoot(dir) {
2358
2382
  try {
2359
- await import_node_fs7.promises.stat(import_node_path7.default.join(dir, ".git"));
2383
+ await import_node_fs8.promises.stat(import_node_path8.default.join(dir, ".git"));
2360
2384
  return true;
2361
2385
  } catch {
2362
2386
  return false;
@@ -2364,11 +2388,11 @@ async function isRepoRoot(dir) {
2364
2388
  }
2365
2389
  async function loadIgnoreChain(startDir) {
2366
2390
  const dirs = [];
2367
- let current = import_node_path7.default.resolve(startDir);
2391
+ let current = import_node_path8.default.resolve(startDir);
2368
2392
  for (; ; ) {
2369
2393
  dirs.push(current);
2370
2394
  if (await isRepoRoot(current)) break;
2371
- const parent = import_node_path7.default.dirname(current);
2395
+ const parent = import_node_path8.default.dirname(current);
2372
2396
  if (parent === current) break;
2373
2397
  current = parent;
2374
2398
  }
@@ -2381,7 +2405,7 @@ async function loadIgnoreChain(startDir) {
2381
2405
  return layers;
2382
2406
  }
2383
2407
  async function extendIgnoreChain(chain, dir) {
2384
- const layer = await layerFor(import_node_path7.default.resolve(dir));
2408
+ const layer = await layerFor(import_node_path8.default.resolve(dir));
2385
2409
  return layer ? [...chain, layer] : chain;
2386
2410
  }
2387
2411
  function isIgnored(chain, fullPath, isDir) {
@@ -2389,14 +2413,14 @@ function isIgnored(chain, fullPath, isDir) {
2389
2413
  }
2390
2414
  function decide(chain, fullPath, isDir) {
2391
2415
  if (chain.length === 0) return { ignored: false, subtree: chain };
2392
- const abs = import_node_path7.default.resolve(fullPath);
2416
+ const abs = import_node_path8.default.resolve(fullPath);
2393
2417
  let ignored = false;
2394
2418
  let unignoredAt = -1;
2395
2419
  for (let i = 0; i < chain.length; i++) {
2396
2420
  const layer = chain[i];
2397
- const rel = import_node_path7.default.relative(layer.dir, abs);
2398
- if (!rel || rel.startsWith("..") || import_node_path7.default.isAbsolute(rel)) continue;
2399
- const candidate = rel.split(import_node_path7.default.sep).join("/") + (isDir ? "/" : "");
2421
+ const rel = import_node_path8.default.relative(layer.dir, abs);
2422
+ if (!rel || rel.startsWith("..") || import_node_path8.default.isAbsolute(rel)) continue;
2423
+ const candidate = rel.split(import_node_path8.default.sep).join("/") + (isDir ? "/" : "");
2400
2424
  const result = layer.ig.test(candidate);
2401
2425
  if (result.ignored) ignored = true;
2402
2426
  else if (result.unignored) {
@@ -2415,7 +2439,7 @@ function buildServiceHostIndex(services) {
2415
2439
  const knownHosts = /* @__PURE__ */ new Set();
2416
2440
  const hostToNodeId = /* @__PURE__ */ new Map();
2417
2441
  for (const service of services) {
2418
- const base = import_node_path8.default.basename(service.dir);
2442
+ const base = import_node_path9.default.basename(service.dir);
2419
2443
  knownHosts.add(base);
2420
2444
  knownHosts.add(service.pkg.name);
2421
2445
  hostToNodeId.set(base, service.node.id);
@@ -2424,29 +2448,29 @@ function buildServiceHostIndex(services) {
2424
2448
  return { knownHosts, hostToNodeId };
2425
2449
  }
2426
2450
  async function walkSourceFiles(dir, excludeDirs = []) {
2427
- const excluded = new Set(excludeDirs.map((d) => import_node_path8.default.resolve(d)));
2451
+ const excluded = new Set(excludeDirs.map((d) => import_node_path9.default.resolve(d)));
2428
2452
  const out = [];
2429
2453
  const rootChain = await loadIgnoreChain(dir);
2430
2454
  async function walk11(current, inherited) {
2431
- const entries = await import_node_fs8.promises.readdir(current, { withFileTypes: true }).catch(() => []);
2455
+ const entries = await import_node_fs9.promises.readdir(current, { withFileTypes: true }).catch(() => []);
2432
2456
  const chain = entries.some((e) => e.isFile() && e.name === ".gitignore") ? await extendIgnoreChain(inherited, current) : inherited;
2433
2457
  for (const entry of entries) {
2434
- const full = import_node_path8.default.join(current, entry.name);
2458
+ const full = import_node_path9.default.join(current, entry.name);
2435
2459
  if (entry.isDirectory()) {
2436
2460
  if (IGNORED_DIRS.has(entry.name)) continue;
2437
- if (excluded.has(import_node_path8.default.resolve(full))) continue;
2461
+ if (excluded.has(import_node_path9.default.resolve(full))) continue;
2438
2462
  const verdict = decide(chain, full, true);
2439
2463
  if (verdict.ignored) continue;
2440
2464
  if (await isPythonVenvDir(full)) continue;
2441
2465
  await walk11(full, verdict.subtree);
2442
- } 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
2466
+ } else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path9.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
2443
2467
  // would attribute our instrumentation imports to the user's service.
2444
2468
  !isNeatAuthoredSourceFile(entry.name) && !isIgnored(chain, full, false)) {
2445
2469
  out.push(full);
2446
2470
  }
2447
2471
  }
2448
2472
  }
2449
- await walk11(dir, rootChain.filter((l) => import_node_path8.default.resolve(l.dir) !== import_node_path8.default.resolve(dir)));
2473
+ await walk11(dir, rootChain.filter((l) => import_node_path9.default.resolve(l.dir) !== import_node_path9.default.resolve(dir)));
2450
2474
  return out;
2451
2475
  }
2452
2476
  var MINIFIED_LINE_CHARS = 5e3;
@@ -2474,7 +2498,7 @@ async function loadSourceFiles(dir, excludeDirs = []) {
2474
2498
  const out = [];
2475
2499
  for (const p of paths) {
2476
2500
  try {
2477
- const content = await import_node_fs8.promises.readFile(p, "utf8");
2501
+ const content = await import_node_fs9.promises.readFile(p, "utf8");
2478
2502
  const verdict = isMinifiedSource(p, content);
2479
2503
  if (verdict.minified) {
2480
2504
  noteSkippedFile({ path: p, reason: "minified", detail: verdict.detail });
@@ -2502,7 +2526,7 @@ function toPosix(p) {
2502
2526
  return p.split("\\").join("/");
2503
2527
  }
2504
2528
  function languageForPath(relPath) {
2505
- switch (import_node_path8.default.extname(relPath).toLowerCase()) {
2529
+ switch (import_node_path9.default.extname(relPath).toLowerCase()) {
2506
2530
  case ".py":
2507
2531
  return "python";
2508
2532
  case ".go":
@@ -2586,8 +2610,8 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
2586
2610
 
2587
2611
  // src/extract/imports.ts
2588
2612
  init_cjs_shims();
2589
- var import_node_path9 = __toESM(require("path"), 1);
2590
- var import_node_fs9 = require("fs");
2613
+ var import_node_path10 = __toESM(require("path"), 1);
2614
+ var import_node_fs10 = require("fs");
2591
2615
  var import_tree_sitter = __toESM(require("tree-sitter"), 1);
2592
2616
  var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
2593
2617
  var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
@@ -2732,15 +2756,15 @@ function collectPyImports(node, out) {
2732
2756
  }
2733
2757
  async function fileExists2(p) {
2734
2758
  try {
2735
- await import_node_fs9.promises.access(p);
2759
+ await import_node_fs10.promises.access(p);
2736
2760
  return true;
2737
2761
  } catch {
2738
2762
  return false;
2739
2763
  }
2740
2764
  }
2741
2765
  function isWithinServiceDir(candidate, serviceDir) {
2742
- const rel = import_node_path9.default.relative(serviceDir, candidate);
2743
- return rel !== "" && !rel.startsWith("..") && !import_node_path9.default.isAbsolute(rel);
2766
+ const rel = import_node_path10.default.relative(serviceDir, candidate);
2767
+ return rel !== "" && !rel.startsWith("..") && !import_node_path10.default.isAbsolute(rel);
2744
2768
  }
2745
2769
  var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
2746
2770
  var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
@@ -2748,22 +2772,22 @@ async function firstExistingCandidate(base, serviceDir) {
2748
2772
  for (const ext of JS_EXTENSIONS) {
2749
2773
  const candidate = base + ext;
2750
2774
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2751
- return toPosix(import_node_path9.default.relative(serviceDir, candidate));
2775
+ return toPosix(import_node_path10.default.relative(serviceDir, candidate));
2752
2776
  }
2753
2777
  }
2754
2778
  for (const indexFile of JS_INDEX_FILES) {
2755
- const candidate = import_node_path9.default.join(base, indexFile);
2779
+ const candidate = import_node_path10.default.join(base, indexFile);
2756
2780
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2757
- return toPosix(import_node_path9.default.relative(serviceDir, candidate));
2781
+ return toPosix(import_node_path10.default.relative(serviceDir, candidate));
2758
2782
  }
2759
2783
  }
2760
2784
  return null;
2761
2785
  }
2762
2786
  async function loadTsPathConfig(serviceDir) {
2763
- const tsconfigPath = import_node_path9.default.join(serviceDir, "tsconfig.json");
2787
+ const tsconfigPath = import_node_path10.default.join(serviceDir, "tsconfig.json");
2764
2788
  let raw;
2765
2789
  try {
2766
- raw = await import_node_fs9.promises.readFile(tsconfigPath, "utf8");
2790
+ raw = await import_node_fs10.promises.readFile(tsconfigPath, "utf8");
2767
2791
  } catch {
2768
2792
  return null;
2769
2793
  }
@@ -2772,7 +2796,7 @@ async function loadTsPathConfig(serviceDir) {
2772
2796
  const paths = parsed.compilerOptions?.paths;
2773
2797
  if (!paths || Object.keys(paths).length === 0) return null;
2774
2798
  const baseUrl = parsed.compilerOptions?.baseUrl;
2775
- return { paths, baseDir: baseUrl ? import_node_path9.default.resolve(serviceDir, baseUrl) : serviceDir };
2799
+ return { paths, baseDir: baseUrl ? import_node_path10.default.resolve(serviceDir, baseUrl) : serviceDir };
2776
2800
  } catch (err) {
2777
2801
  recordExtractionError("import alias resolution", tsconfigPath, err);
2778
2802
  return null;
@@ -2790,11 +2814,11 @@ async function resolveTsAlias(specifier, config, serviceDir) {
2790
2814
  if (suffix === null) continue;
2791
2815
  for (const target of targets) {
2792
2816
  const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
2793
- const resolvedBase = import_node_path9.default.resolve(config.baseDir, targetBase, suffix);
2817
+ const resolvedBase = import_node_path10.default.resolve(config.baseDir, targetBase, suffix);
2794
2818
  const hit = await firstExistingCandidate(resolvedBase, serviceDir);
2795
2819
  if (hit) return hit;
2796
2820
  if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists2(resolvedBase)) {
2797
- return toPosix(import_node_path9.default.relative(serviceDir, resolvedBase));
2821
+ return toPosix(import_node_path10.default.relative(serviceDir, resolvedBase));
2798
2822
  }
2799
2823
  }
2800
2824
  }
@@ -2803,18 +2827,18 @@ async function resolveTsAlias(specifier, config, serviceDir) {
2803
2827
  async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
2804
2828
  if (!specifier) return null;
2805
2829
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
2806
- const base = import_node_path9.default.resolve(importerDir, specifier);
2807
- const ext = import_node_path9.default.extname(specifier);
2830
+ const base = import_node_path10.default.resolve(importerDir, specifier);
2831
+ const ext = import_node_path10.default.extname(specifier);
2808
2832
  if (ext) {
2809
2833
  if (ext === ".js" || ext === ".jsx") {
2810
2834
  const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
2811
2835
  const tsSibling = base.slice(0, -ext.length) + tsExt;
2812
2836
  if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists2(tsSibling)) {
2813
- return toPosix(import_node_path9.default.relative(serviceDir, tsSibling));
2837
+ return toPosix(import_node_path10.default.relative(serviceDir, tsSibling));
2814
2838
  }
2815
2839
  }
2816
2840
  if (isWithinServiceDir(base, serviceDir) && await fileExists2(base)) {
2817
- return toPosix(import_node_path9.default.relative(serviceDir, base));
2841
+ return toPosix(import_node_path10.default.relative(serviceDir, base));
2818
2842
  }
2819
2843
  if (!JS_EXTENSIONS.includes(ext)) {
2820
2844
  return firstExistingCandidate(base, serviceDir);
@@ -2829,30 +2853,30 @@ async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
2829
2853
  async function resolvePyImport(imp, importerPath, serviceDir) {
2830
2854
  let baseDir;
2831
2855
  if (imp.level > 0) {
2832
- baseDir = import_node_path9.default.dirname(importerPath);
2833
- for (let i = 1; i < imp.level; i++) baseDir = import_node_path9.default.dirname(baseDir);
2856
+ baseDir = import_node_path10.default.dirname(importerPath);
2857
+ for (let i = 1; i < imp.level; i++) baseDir = import_node_path10.default.dirname(baseDir);
2834
2858
  } else {
2835
2859
  baseDir = serviceDir;
2836
2860
  }
2837
- const moduleBase = imp.modulePath ? import_node_path9.default.join(baseDir, imp.modulePath.split(".").join("/")) : baseDir;
2861
+ const moduleBase = imp.modulePath ? import_node_path10.default.join(baseDir, imp.modulePath.split(".").join("/")) : baseDir;
2838
2862
  const resolved = /* @__PURE__ */ new Set();
2839
2863
  let needModuleFile = imp.names.length === 0;
2840
2864
  for (const name of imp.names) {
2841
- const submoduleFile = import_node_path9.default.join(moduleBase, `${name}.py`);
2842
- const subpackageInit = import_node_path9.default.join(moduleBase, name, "__init__.py");
2865
+ const submoduleFile = import_node_path10.default.join(moduleBase, `${name}.py`);
2866
+ const subpackageInit = import_node_path10.default.join(moduleBase, name, "__init__.py");
2843
2867
  if (isWithinServiceDir(submoduleFile, serviceDir) && await fileExists2(submoduleFile)) {
2844
- resolved.add(toPosix(import_node_path9.default.relative(serviceDir, submoduleFile)));
2868
+ resolved.add(toPosix(import_node_path10.default.relative(serviceDir, submoduleFile)));
2845
2869
  } else if (isWithinServiceDir(subpackageInit, serviceDir) && await fileExists2(subpackageInit)) {
2846
- resolved.add(toPosix(import_node_path9.default.relative(serviceDir, subpackageInit)));
2870
+ resolved.add(toPosix(import_node_path10.default.relative(serviceDir, subpackageInit)));
2847
2871
  } else {
2848
2872
  needModuleFile = true;
2849
2873
  }
2850
2874
  }
2851
2875
  if (needModuleFile) {
2852
- const moduleFileCandidates = imp.modulePath ? [`${moduleBase}.py`, import_node_path9.default.join(moduleBase, "__init__.py")] : [import_node_path9.default.join(moduleBase, "__init__.py")];
2876
+ const moduleFileCandidates = imp.modulePath ? [`${moduleBase}.py`, import_node_path10.default.join(moduleBase, "__init__.py")] : [import_node_path10.default.join(moduleBase, "__init__.py")];
2853
2877
  for (const candidate of moduleFileCandidates) {
2854
2878
  if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
2855
- resolved.add(toPosix(import_node_path9.default.relative(serviceDir, candidate)));
2879
+ resolved.add(toPosix(import_node_path10.default.relative(serviceDir, candidate)));
2856
2880
  break;
2857
2881
  }
2858
2882
  }
@@ -2862,11 +2886,11 @@ async function resolvePyImport(imp, importerPath, serviceDir) {
2862
2886
  async function resolveGoImport(specifier, modulePath, serviceDir) {
2863
2887
  if (specifier !== modulePath && !specifier.startsWith(`${modulePath}/`)) return null;
2864
2888
  const suffix = specifier === modulePath ? "" : specifier.slice(modulePath.length + 1);
2865
- const dir = import_node_path9.default.join(serviceDir, suffix);
2866
- const entries = await import_node_fs9.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
2867
- 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));
2889
+ const dir = import_node_path10.default.join(serviceDir, suffix);
2890
+ const entries = await import_node_fs10.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
2891
+ const candidates = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".go") && !entry.name.endsWith("_test.go")).map((entry) => import_node_path10.default.join(dir, entry.name));
2868
2892
  if (candidates.length !== 1) return null;
2869
- return toPosix(import_node_path9.default.relative(serviceDir, candidates[0]));
2893
+ return toPosix(import_node_path10.default.relative(serviceDir, candidates[0]));
2870
2894
  }
2871
2895
  function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
2872
2896
  const importeeFileId = (0, import_types5.fileId)(serviceName, importeeRelPath);
@@ -2896,12 +2920,12 @@ async function addImports(graph, services) {
2896
2920
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
2897
2921
  for (const file of files) {
2898
2922
  if (isTestPath(file.path)) continue;
2899
- const relFile = toPosix(import_node_path9.default.relative(service.dir, file.path));
2923
+ const relFile = toPosix(import_node_path10.default.relative(service.dir, file.path));
2900
2924
  const importerFileId = (0, import_types5.fileId)(service.pkg.name, relFile);
2901
- const isPython = import_node_path9.default.extname(file.path) === ".py";
2902
- const isGo = import_node_path9.default.extname(file.path) === ".go";
2903
- if (import_node_path9.default.extname(file.path) === ".rb") continue;
2904
- if (import_node_path9.default.extname(file.path) === ".php") continue;
2925
+ const isPython = import_node_path10.default.extname(file.path) === ".py";
2926
+ const isGo = import_node_path10.default.extname(file.path) === ".go";
2927
+ if (import_node_path10.default.extname(file.path) === ".rb") continue;
2928
+ if (import_node_path10.default.extname(file.path) === ".php") continue;
2905
2929
  if (isGo) {
2906
2930
  let goImports = [];
2907
2931
  try {
@@ -2911,7 +2935,7 @@ async function addImports(graph, services) {
2911
2935
  recordExtractionError("import extraction", file.path, err);
2912
2936
  continue;
2913
2937
  }
2914
- const goMod = await import_node_fs9.promises.readFile(import_node_path9.default.join(service.dir, "go.mod"), "utf8").catch(() => "");
2938
+ const goMod = await import_node_fs10.promises.readFile(import_node_path10.default.join(service.dir, "go.mod"), "utf8").catch(() => "");
2915
2939
  const modulePath = goMod.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
2916
2940
  if (!modulePath) continue;
2917
2941
  for (const imp of goImports) {
@@ -2955,7 +2979,7 @@ async function addImports(graph, services) {
2955
2979
  continue;
2956
2980
  }
2957
2981
  for (const imp of jsImports) {
2958
- const resolved = await resolveJsImport(imp.specifier, import_node_path9.default.dirname(file.path), service.dir, tsPaths);
2982
+ const resolved = await resolveJsImport(imp.specifier, import_node_path10.default.dirname(file.path), service.dir, tsPaths);
2959
2983
  if (!resolved) continue;
2960
2984
  edgesAdded += emitImportEdge(
2961
2985
  graph,
@@ -3080,8 +3104,8 @@ function chiRoutesFromSource(source, parser) {
3080
3104
  chiWalk(tree.rootNode, "", out);
3081
3105
  return out;
3082
3106
  }
3083
- function stripChiRegex(path78) {
3084
- return path78.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
3107
+ function stripChiRegex(path81) {
3108
+ return path81.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
3085
3109
  }
3086
3110
  function chiWalk(node, prefix, out) {
3087
3111
  for (let i = 0; i < node.namedChildCount; i++) {
@@ -3421,7 +3445,7 @@ function isNextPagesApiFile(relFile) {
3421
3445
  if (pagesIdx === -1 || segs[pagesIdx + 1] !== "api") return false;
3422
3446
  const base = segs[segs.length - 1] ?? "";
3423
3447
  if (/^_(app|document|middleware)\./.test(base)) return false;
3424
- return JS_ROUTE_EXTENSIONS.has(import_node_path10.default.extname(base));
3448
+ return JS_ROUTE_EXTENSIONS.has(import_node_path11.default.extname(base));
3425
3449
  }
3426
3450
  function nextSegment(seg) {
3427
3451
  if (seg.startsWith("(") && seg.endsWith(")")) return null;
@@ -3753,9 +3777,9 @@ function rubyRocketRoute(args) {
3753
3777
  if (!pair || pair.type !== "pair") continue;
3754
3778
  const k = pair.childForFieldName("key");
3755
3779
  if (k?.type !== "string") continue;
3756
- const path78 = rubyLiteral(k);
3757
- if (path78 === null) continue;
3758
- return { path: path78, target: rubyLiteral(pair.childForFieldName("value")) };
3780
+ const path81 = rubyLiteral(k);
3781
+ if (path81 === null) continue;
3782
+ return { path: path81, target: rubyLiteral(pair.childForFieldName("value")) };
3759
3783
  }
3760
3784
  return null;
3761
3785
  }
@@ -3845,23 +3869,23 @@ function railsInferHandler(rawPath) {
3845
3869
  if (segs.length === 1) return `${segs[0]}#index`;
3846
3870
  return `${segs.slice(0, -1).join("/")}#${segs[segs.length - 1]}`;
3847
3871
  }
3848
- function railsResource(call, ctx, out, plural) {
3872
+ function railsResource(call, ctx, out, plural2) {
3849
3873
  if (ctx.depth >= 2) return;
3850
3874
  const args = rubyArgs(call);
3851
3875
  const name = rubyLiteral(rubyPositional(args)[0]);
3852
3876
  if (!name) return;
3853
3877
  const base = `${ctx.path}/${name}`;
3854
- const controller = ctx.module + (plural ? name : railsPluralize(name));
3878
+ const controller = ctx.module + (plural2 ? name : railsPluralize(name));
3855
3879
  const allow = railsActionFilter(args);
3856
3880
  const line = call.startPosition.row + 1;
3857
- for (const row of plural ? RAILS_PLURAL_ROWS : RAILS_SINGULAR_ROWS) {
3881
+ for (const row of plural2 ? RAILS_PLURAL_ROWS : RAILS_SINGULAR_ROWS) {
3858
3882
  if (!allow(row.action)) continue;
3859
3883
  for (const m of row.methods) railsEmit(out, m, base + row.suffix, `${controller}#${row.action}`, line);
3860
3884
  }
3861
3885
  const block = call.childForFieldName("block");
3862
3886
  if (!block) return;
3863
- const memberBase = plural ? `${base}/:id` : base;
3864
- const nestedPath = plural ? `${base}/:${railsSingularize(name)}_id` : base;
3887
+ const memberBase = plural2 ? `${base}/:id` : base;
3888
+ const nestedPath = plural2 ? `${base}/:${railsSingularize(name)}_id` : base;
3865
3889
  for (const child of rubyBlockCalls(block)) {
3866
3890
  const cm = child.childForFieldName("method")?.text;
3867
3891
  if (cm === "member") railsBlockVerbs(child, memberBase, controller, out);
@@ -4603,12 +4627,12 @@ async function expressMountPrefixes(files, serviceDir, tsPaths) {
4603
4627
  const jsParser = makeJsParser2();
4604
4628
  const fileInfo = /* @__PURE__ */ new Map();
4605
4629
  for (const f of files) {
4606
- if (!JS_ROUTE_EXTENSIONS.has(import_node_path10.default.extname(f.path))) continue;
4630
+ if (!JS_ROUTE_EXTENSIONS.has(import_node_path11.default.extname(f.path))) continue;
4607
4631
  if (isTestPath(f.path)) continue;
4608
- const rel = toPosix(import_node_path10.default.relative(serviceDir, f.path));
4632
+ const rel = toPosix(import_node_path11.default.relative(serviceDir, f.path));
4609
4633
  try {
4610
4634
  const tree = parseSource2(jsParser, f.content);
4611
- fileInfo.set(rel, analyzeExpressFile(tree.rootNode, import_node_path10.default.dirname(f.path)));
4635
+ fileInfo.set(rel, analyzeExpressFile(tree.rootNode, import_node_path11.default.dirname(f.path)));
4612
4636
  } catch {
4613
4637
  }
4614
4638
  }
@@ -4707,14 +4731,14 @@ async function addRoutes(graph, services) {
4707
4731
  const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
4708
4732
  for (const file of files) {
4709
4733
  if (isTestPath(file.path)) continue;
4710
- const ext = import_node_path10.default.extname(file.path);
4734
+ const ext = import_node_path11.default.extname(file.path);
4711
4735
  const isPy = ext === ".py";
4712
4736
  const isGo = ext === ".go";
4713
4737
  const isRb = ext === ".rb";
4714
4738
  const isPhp = ext === ".php";
4715
4739
  const isRs = ext === ".rs";
4716
4740
  if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue;
4717
- const relFile = toPosix(import_node_path10.default.relative(service.dir, file.path));
4741
+ const relFile = toPosix(import_node_path11.default.relative(service.dir, file.path));
4718
4742
  let routes;
4719
4743
  try {
4720
4744
  if (isPhp) {
@@ -5128,20 +5152,20 @@ var CODE_LINENO_ATTR = "code.lineno";
5128
5152
  var CODE_FUNCTION_NAME_ATTR = "code.function.name";
5129
5153
  var CODE_FUNCTION_ATTR = "code.function";
5130
5154
  function codeFilepathOf(attrs) {
5131
- const stable = attrs[CODE_FILE_PATH_ATTR];
5132
- if (typeof stable === "string" && stable.length > 0) return stable;
5155
+ const stable2 = attrs[CODE_FILE_PATH_ATTR];
5156
+ if (typeof stable2 === "string" && stable2.length > 0) return stable2;
5133
5157
  const prior = attrs[CODE_FILEPATH_ATTR];
5134
5158
  return typeof prior === "string" && prior.length > 0 ? prior : void 0;
5135
5159
  }
5136
5160
  function codeLinenoOf(attrs) {
5137
- const stable = attrs[CODE_LINE_NUMBER_ATTR];
5138
- if (typeof stable === "number" && Number.isFinite(stable)) return stable;
5161
+ const stable2 = attrs[CODE_LINE_NUMBER_ATTR];
5162
+ if (typeof stable2 === "number" && Number.isFinite(stable2)) return stable2;
5139
5163
  const prior = attrs[CODE_LINENO_ATTR];
5140
5164
  return typeof prior === "number" && Number.isFinite(prior) ? prior : void 0;
5141
5165
  }
5142
5166
  function codeFunctionOf(attrs) {
5143
- const stable = attrs[CODE_FUNCTION_NAME_ATTR];
5144
- if (typeof stable === "string" && stable.length > 0) return stable;
5167
+ const stable2 = attrs[CODE_FUNCTION_NAME_ATTR];
5168
+ if (typeof stable2 === "string" && stable2.length > 0) return stable2;
5145
5169
  const prior = attrs[CODE_FUNCTION_ATTR];
5146
5170
  return typeof prior === "string" && prior.length > 0 ? prior : void 0;
5147
5171
  }
@@ -5171,7 +5195,7 @@ function languageForExt(relPath) {
5171
5195
  function relPathForRuntimeFile(filepath, serviceNode, scanPath) {
5172
5196
  let p = toPosix2(filepath).replace(/^file:\/\//, "");
5173
5197
  if (scanPath && scanPath.length > 0) {
5174
- const absRoot = toPosix2(import_node_path11.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
5198
+ const absRoot = toPosix2(import_node_path12.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
5175
5199
  const anchor = absRoot.endsWith("/") ? absRoot : `${absRoot}/`;
5176
5200
  if (p.startsWith(anchor)) return p.slice(anchor.length);
5177
5201
  }
@@ -5199,10 +5223,10 @@ function resolveDistToSrc(absFilepath, line) {
5199
5223
  entry = null;
5200
5224
  const mapPath = `${absFilepath}.map`;
5201
5225
  try {
5202
- if ((0, import_node_fs10.existsSync)(mapPath)) {
5203
- const raw = JSON.parse((0, import_node_fs10.readFileSync)(mapPath, "utf8"));
5226
+ if ((0, import_node_fs11.existsSync)(mapPath)) {
5227
+ const raw = JSON.parse((0, import_node_fs11.readFileSync)(mapPath, "utf8"));
5204
5228
  const consumer = new sourceMapJs.SourceMapConsumer(raw);
5205
- entry = { consumer, dir: import_node_path11.default.dirname(mapPath) };
5229
+ entry = { consumer, dir: import_node_path12.default.dirname(mapPath) };
5206
5230
  }
5207
5231
  } catch {
5208
5232
  entry = null;
@@ -5222,7 +5246,7 @@ function resolveDistToSrc(absFilepath, line) {
5222
5246
  }
5223
5247
  if (!pos || !pos.source) return null;
5224
5248
  const root = entry.consumer.sourceRoot ?? "";
5225
- const resolved = import_node_path11.default.resolve(entry.dir, root, pos.source);
5249
+ const resolved = import_node_path12.default.resolve(entry.dir, root, pos.source);
5226
5250
  return { filepath: resolved, ...pos.line ? { line: pos.line } : {} };
5227
5251
  } catch {
5228
5252
  return null;
@@ -5766,8 +5790,7 @@ function emitIncidentEvent(project, ev) {
5766
5790
  });
5767
5791
  }
5768
5792
  async function appendErrorEvent(ctx, ev) {
5769
- await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(ctx.errorsPath), { recursive: true });
5770
- await import_node_fs10.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
5793
+ await appendRuntimeIncident(ctx.errorsPath, ctx.project ?? DEFAULT_PROJECT, ev);
5771
5794
  emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
5772
5795
  }
5773
5796
  async function appendConnectorIncident(errorsPath, input, project) {
@@ -5782,8 +5805,7 @@ async function appendConnectorIncident(errorsPath, input, project) {
5782
5805
  ...input.attributes && Object.keys(input.attributes).length > 0 ? { attributes: input.attributes } : {},
5783
5806
  affectedNode: input.affectedNode
5784
5807
  };
5785
- await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(errorsPath), { recursive: true });
5786
- await import_node_fs10.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
5808
+ await appendRuntimeIncident(errorsPath, project ?? DEFAULT_PROJECT, ev);
5787
5809
  if (project) emitIncidentEvent(project, ev);
5788
5810
  }
5789
5811
  function landIncidentCallSite(span, callSite, trusted, graph) {
@@ -6374,13 +6396,13 @@ async function markStaleEdges(graph, options = {}) {
6374
6396
  return { count: events.length, events };
6375
6397
  }
6376
6398
  async function appendStaleEvents(staleEventsPath, events) {
6377
- await import_node_fs10.promises.mkdir(import_node_path11.default.dirname(staleEventsPath), { recursive: true });
6399
+ await import_node_fs11.promises.mkdir(import_node_path12.default.dirname(staleEventsPath), { recursive: true });
6378
6400
  const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
6379
- await import_node_fs10.promises.appendFile(staleEventsPath, lines, "utf8");
6401
+ await import_node_fs11.promises.appendFile(staleEventsPath, lines, "utf8");
6380
6402
  }
6381
6403
  async function readStaleEvents(staleEventsPath) {
6382
6404
  try {
6383
- const raw = await import_node_fs10.promises.readFile(staleEventsPath, "utf8");
6405
+ const raw = await import_node_fs11.promises.readFile(staleEventsPath, "utf8");
6384
6406
  return raw.split("\n").filter((line) => line.length > 0).map((line) => JSON.parse(line));
6385
6407
  } catch (err) {
6386
6408
  if (err.code === "ENOENT") return [];
@@ -6416,7 +6438,7 @@ function startStalenessLoop(graph, options = {}) {
6416
6438
  var INCIDENT_READ_MAX_BYTES = 32 * 1024 * 1024;
6417
6439
  var INCIDENT_READ_MAX_EVENTS = 5e3;
6418
6440
  async function readErrorFileTail(errorsPath, maxBytes) {
6419
- const handle = await import_node_fs10.promises.open(errorsPath, "r");
6441
+ const handle = await import_node_fs11.promises.open(errorsPath, "r");
6420
6442
  try {
6421
6443
  const { size } = await handle.stat();
6422
6444
  if (size <= maxBytes) {
@@ -6452,6 +6474,23 @@ async function readErrorEvents(errorsPath, opts) {
6452
6474
  const cap = opts?.limit !== void 0 && opts.limit > 0 ? Math.min(opts.limit, INCIDENT_READ_MAX_EVENTS) : INCIDENT_READ_MAX_EVENTS;
6453
6475
  return deduped.length > cap ? deduped.slice(deduped.length - cap) : deduped;
6454
6476
  }
6477
+ async function readErrorEventById(errorsPath, id) {
6478
+ let raw;
6479
+ try {
6480
+ raw = await readErrorFileTail(errorsPath, INCIDENT_READ_MAX_BYTES);
6481
+ } catch (err) {
6482
+ if (err.code === "ENOENT") return void 0;
6483
+ throw err;
6484
+ }
6485
+ const lines = raw.split("\n");
6486
+ for (let i = lines.length - 1; i >= 0; i--) {
6487
+ const line = lines[i];
6488
+ if (!line) continue;
6489
+ const event = JSON.parse(line);
6490
+ if (event.id === id) return redactPersistedAttributes(event);
6491
+ }
6492
+ return void 0;
6493
+ }
6455
6494
  function isSynthesizedHttpIncident(ev) {
6456
6495
  if (ev.exceptionType || ev.exceptionStacktrace) return false;
6457
6496
  if (ev.errorType) return false;
@@ -6659,19 +6698,19 @@ function confidenceFromMix(edges, now = Date.now()) {
6659
6698
  function longestIncomingWalk(graph, start, maxDepth) {
6660
6699
  let best = { path: [start], edges: [] };
6661
6700
  const visited = /* @__PURE__ */ new Set([start]);
6662
- function step(node, path78, edges) {
6663
- if (path78.length > best.path.length) {
6664
- best = { path: [...path78], edges: [...edges] };
6701
+ function step(node, path81, edges) {
6702
+ if (path81.length > best.path.length) {
6703
+ best = { path: [...path81], edges: [...edges] };
6665
6704
  }
6666
- if (path78.length - 1 >= maxDepth) return;
6705
+ if (path81.length - 1 >= maxDepth) return;
6667
6706
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
6668
6707
  for (const [srcId, edge] of incoming) {
6669
6708
  if (visited.has(srcId)) continue;
6670
6709
  visited.add(srcId);
6671
- path78.push(srcId);
6710
+ path81.push(srcId);
6672
6711
  edges.push(edge);
6673
- step(srcId, path78, edges);
6674
- path78.pop();
6712
+ step(srcId, path81, edges);
6713
+ path81.pop();
6675
6714
  edges.pop();
6676
6715
  visited.delete(srcId);
6677
6716
  }
@@ -6886,20 +6925,20 @@ function dominantFailingCall(graph, serviceId17, visited) {
6886
6925
  return best;
6887
6926
  }
6888
6927
  function followFailingCallChain(graph, originServiceId, maxDepth) {
6889
- const path78 = [originServiceId];
6928
+ const path81 = [originServiceId];
6890
6929
  const edges = [];
6891
6930
  const visited = /* @__PURE__ */ new Set([originServiceId]);
6892
6931
  let current = originServiceId;
6893
6932
  for (let depth = 0; depth < maxDepth; depth++) {
6894
6933
  const hop = dominantFailingCall(graph, current, visited);
6895
6934
  if (!hop) break;
6896
- path78.push(hop.nextService);
6935
+ path81.push(hop.nextService);
6897
6936
  edges.push(hop.edge);
6898
6937
  visited.add(hop.nextService);
6899
6938
  current = hop.nextService;
6900
6939
  }
6901
6940
  if (edges.length === 0) return null;
6902
- return { path: path78, edges, culprit: current };
6941
+ return { path: path81, edges, culprit: current };
6903
6942
  }
6904
6943
  function isStaleCallEdge(e) {
6905
6944
  return e.type === import_types8.EdgeType.CALLS && e.provenance === import_types8.Provenance.STALE;
@@ -6935,26 +6974,26 @@ function dominantStaleCall(graph, serviceId17, visited) {
6935
6974
  return best;
6936
6975
  }
6937
6976
  function followStaleCallChain(graph, originServiceId, maxDepth) {
6938
- const path78 = [originServiceId];
6977
+ const path81 = [originServiceId];
6939
6978
  const edges = [];
6940
6979
  const visited = /* @__PURE__ */ new Set([originServiceId]);
6941
6980
  let current = originServiceId;
6942
6981
  for (let depth = 0; depth < maxDepth; depth++) {
6943
6982
  const hop = dominantStaleCall(graph, current, visited);
6944
6983
  if (!hop) break;
6945
- path78.push(hop.nextService);
6984
+ path81.push(hop.nextService);
6946
6985
  edges.push(hop.edge);
6947
6986
  visited.add(hop.nextService);
6948
6987
  current = hop.nextService;
6949
6988
  }
6950
6989
  if (edges.length === 0) return null;
6951
- return { path: path78, edges, culprit: current };
6990
+ return { path: path81, edges, culprit: current };
6952
6991
  }
6953
6992
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6954
6993
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
6955
6994
  if (!chain) return null;
6956
6995
  const culprit = chain.culprit;
6957
- const path78 = [...chain.path];
6996
+ const path81 = [...chain.path];
6958
6997
  const edgeProvenances = chain.edges.map((e) => e.provenance);
6959
6998
  const baseConfidence = confidenceFromMix(chain.edges);
6960
6999
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -6962,14 +7001,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6962
7001
  if (loc) {
6963
7002
  let rootCauseNode = culprit;
6964
7003
  if (loc.fileNode) {
6965
- path78.push(loc.fileNode);
7004
+ path81.push(loc.fileNode);
6966
7005
  edgeProvenances.push(import_types8.Provenance.OBSERVED);
6967
7006
  rootCauseNode = loc.fileNode;
6968
7007
  }
6969
7008
  return import_types8.RootCauseResultSchema.parse({
6970
7009
  rootCauseNode,
6971
7010
  rootCauseReason: loc.rootCauseReason,
6972
- traversalPath: path78,
7011
+ traversalPath: path81,
6973
7012
  edgeProvenances,
6974
7013
  confidence,
6975
7014
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -6981,7 +7020,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6981
7020
  return import_types8.RootCauseResultSchema.parse({
6982
7021
  rootCauseNode: culprit,
6983
7022
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
6984
- traversalPath: path78,
7023
+ traversalPath: path81,
6985
7024
  edgeProvenances,
6986
7025
  confidence,
6987
7026
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -7634,10 +7673,10 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
7634
7673
  traversalPath = staleChain.path;
7635
7674
  edgeProvenances = staleChain.edges.map((e) => e.provenance);
7636
7675
  } else if (top.node !== seedNode) {
7637
- const path78 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
7638
- if (path78) {
7639
- traversalPath = path78.nodes;
7640
- edgeProvenances = path78.edges.map((e) => e.provenance);
7676
+ const path81 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
7677
+ if (path81) {
7678
+ traversalPath = path81.nodes;
7679
+ edgeProvenances = path81.edges.map((e) => e.provenance);
7641
7680
  } else {
7642
7681
  traversalPath = [errorNodeId, top.node];
7643
7682
  edgeProvenances = [top.provenance ?? import_types8.Provenance.OBSERVED];
@@ -8399,16 +8438,16 @@ init_cjs_shims();
8399
8438
 
8400
8439
  // src/extract/services.ts
8401
8440
  init_cjs_shims();
8402
- var import_node_fs21 = require("fs");
8403
- var import_node_path23 = __toESM(require("path"), 1);
8441
+ var import_node_fs22 = require("fs");
8442
+ var import_node_path24 = __toESM(require("path"), 1);
8404
8443
  var import_ignore2 = __toESM(require("ignore"), 1);
8405
8444
  var import_minimatch2 = require("minimatch");
8406
8445
  var import_types19 = require("@neat.is/types");
8407
8446
 
8408
8447
  // src/extract/python.ts
8409
8448
  init_cjs_shims();
8410
- var import_node_fs11 = require("fs");
8411
- var import_node_path12 = __toESM(require("path"), 1);
8449
+ var import_node_fs12 = require("fs");
8450
+ var import_node_path13 = __toESM(require("path"), 1);
8412
8451
  var import_smol_toml = require("smol-toml");
8413
8452
  var REQUIREMENT_LINE = /^\s*([A-Za-z0-9_.-]+)(?:\[[^\]]*\])?\s*(?:(==)\s*([A-Za-z0-9_.+-]+))?/;
8414
8453
  function parseRequirementsTxt(content) {
@@ -8441,25 +8480,25 @@ function depsFromPyProject(pyproject) {
8441
8480
  return out;
8442
8481
  }
8443
8482
  async function discoverPythonService(serviceDir) {
8444
- const pyprojectPath = import_node_path12.default.join(serviceDir, "pyproject.toml");
8445
- const requirementsPath = import_node_path12.default.join(serviceDir, "requirements.txt");
8446
- const setupPath = import_node_path12.default.join(serviceDir, "setup.py");
8483
+ const pyprojectPath = import_node_path13.default.join(serviceDir, "pyproject.toml");
8484
+ const requirementsPath = import_node_path13.default.join(serviceDir, "requirements.txt");
8485
+ const setupPath = import_node_path13.default.join(serviceDir, "setup.py");
8447
8486
  const hasPyproject = await exists2(pyprojectPath);
8448
8487
  const hasRequirements = await exists2(requirementsPath);
8449
8488
  const hasSetup = await exists2(setupPath);
8450
8489
  if (!hasPyproject && !hasRequirements && !hasSetup) return null;
8451
- let name = import_node_path12.default.basename(serviceDir);
8490
+ let name = import_node_path13.default.basename(serviceDir);
8452
8491
  let version;
8453
8492
  const dependencies = {};
8454
8493
  if (hasPyproject) {
8455
- const raw = await import_node_fs11.promises.readFile(pyprojectPath, "utf8");
8494
+ const raw = await import_node_fs12.promises.readFile(pyprojectPath, "utf8");
8456
8495
  const pyproject = (0, import_smol_toml.parse)(raw);
8457
8496
  name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name;
8458
8497
  version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? void 0;
8459
8498
  Object.assign(dependencies, depsFromPyProject(pyproject));
8460
8499
  }
8461
8500
  if (hasRequirements) {
8462
- const raw = await import_node_fs11.promises.readFile(requirementsPath, "utf8");
8501
+ const raw = await import_node_fs12.promises.readFile(requirementsPath, "utf8");
8463
8502
  Object.assign(dependencies, parseRequirementsTxt(raw));
8464
8503
  }
8465
8504
  return { name, version, dependencies };
@@ -8474,8 +8513,8 @@ function pythonToPackage(service) {
8474
8513
 
8475
8514
  // src/extract/go.ts
8476
8515
  init_cjs_shims();
8477
- var import_node_fs12 = require("fs");
8478
- var import_node_path13 = __toESM(require("path"), 1);
8516
+ var import_node_fs13 = require("fs");
8517
+ var import_node_path14 = __toESM(require("path"), 1);
8479
8518
  var import_types10 = require("@neat.is/types");
8480
8519
  function parseGoMod(source) {
8481
8520
  const module2 = source.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
@@ -8502,7 +8541,7 @@ function goFramework(deps) {
8502
8541
  async function discoverGoService(scanPath, dir) {
8503
8542
  let raw;
8504
8543
  try {
8505
- raw = await import_node_fs12.promises.readFile(import_node_path13.default.join(dir, "go.mod"), "utf8");
8544
+ raw = await import_node_fs13.promises.readFile(import_node_path14.default.join(dir, "go.mod"), "utf8");
8506
8545
  } catch {
8507
8546
  return null;
8508
8547
  }
@@ -8517,7 +8556,7 @@ async function discoverGoService(scanPath, dir) {
8517
8556
  name,
8518
8557
  language: "go",
8519
8558
  dependencies: mod.dependencies,
8520
- repoPath: import_node_path13.default.relative(scanPath, dir),
8559
+ repoPath: import_node_path14.default.relative(scanPath, dir),
8521
8560
  ...framework ? { framework } : {}
8522
8561
  };
8523
8562
  return { pkg, dir, node };
@@ -8525,8 +8564,8 @@ async function discoverGoService(scanPath, dir) {
8525
8564
 
8526
8565
  // src/extract/ruby.ts
8527
8566
  init_cjs_shims();
8528
- var import_node_fs13 = require("fs");
8529
- var import_node_path14 = __toESM(require("path"), 1);
8567
+ var import_node_fs14 = require("fs");
8568
+ var import_node_path15 = __toESM(require("path"), 1);
8530
8569
  var import_types11 = require("@neat.is/types");
8531
8570
  function parseGemfile(source) {
8532
8571
  const dependencies = {};
@@ -8543,12 +8582,12 @@ function parseGemfile(source) {
8543
8582
  async function discoverRubyService(scanPath, dir) {
8544
8583
  let raw;
8545
8584
  try {
8546
- raw = await import_node_fs13.promises.readFile(import_node_path14.default.join(dir, "Gemfile"), "utf8");
8585
+ raw = await import_node_fs14.promises.readFile(import_node_path15.default.join(dir, "Gemfile"), "utf8");
8547
8586
  } catch {
8548
8587
  return null;
8549
8588
  }
8550
8589
  const gemfile = parseGemfile(raw);
8551
- const name = import_node_path14.default.basename(dir);
8590
+ const name = import_node_path15.default.basename(dir);
8552
8591
  const pkg = { name, dependencies: gemfile.dependencies };
8553
8592
  const node = {
8554
8593
  id: (0, import_types11.serviceId)(name),
@@ -8556,7 +8595,7 @@ async function discoverRubyService(scanPath, dir) {
8556
8595
  name,
8557
8596
  language: "ruby",
8558
8597
  dependencies: gemfile.dependencies,
8559
- repoPath: import_node_path14.default.relative(scanPath, dir),
8598
+ repoPath: import_node_path15.default.relative(scanPath, dir),
8560
8599
  ...gemfile.dependencies["rails"] !== void 0 ? { framework: "rails" } : {}
8561
8600
  };
8562
8601
  return { pkg, dir, node };
@@ -8564,7 +8603,7 @@ async function discoverRubyService(scanPath, dir) {
8564
8603
 
8565
8604
  // src/extract/php.ts
8566
8605
  init_cjs_shims();
8567
- var import_node_path15 = __toESM(require("path"), 1);
8606
+ var import_node_path16 = __toESM(require("path"), 1);
8568
8607
  var import_types12 = require("@neat.is/types");
8569
8608
  function parseComposerJson(composer) {
8570
8609
  return {
@@ -8577,12 +8616,12 @@ function parseComposerJson(composer) {
8577
8616
  async function discoverPhpService(scanPath, dir) {
8578
8617
  let composer;
8579
8618
  try {
8580
- composer = await readJson(import_node_path15.default.join(dir, "composer.json"));
8619
+ composer = await readJson(import_node_path16.default.join(dir, "composer.json"));
8581
8620
  } catch {
8582
8621
  return null;
8583
8622
  }
8584
8623
  const { dependencies } = parseComposerJson(composer);
8585
- const name = import_node_path15.default.basename(dir);
8624
+ const name = import_node_path16.default.basename(dir);
8586
8625
  const pkg = { name, dependencies };
8587
8626
  const node = {
8588
8627
  id: (0, import_types12.serviceId)(name),
@@ -8590,7 +8629,7 @@ async function discoverPhpService(scanPath, dir) {
8590
8629
  name,
8591
8630
  language: "php",
8592
8631
  dependencies,
8593
- repoPath: import_node_path15.default.relative(scanPath, dir),
8632
+ repoPath: import_node_path16.default.relative(scanPath, dir),
8594
8633
  ...dependencies["laravel/framework"] !== void 0 ? { framework: "laravel" } : {}
8595
8634
  };
8596
8635
  return { pkg, dir, node };
@@ -8598,23 +8637,23 @@ async function discoverPhpService(scanPath, dir) {
8598
8637
 
8599
8638
  // src/extract/csharp.ts
8600
8639
  init_cjs_shims();
8601
- var import_node_fs14 = require("fs");
8602
- var import_node_path16 = __toESM(require("path"), 1);
8640
+ var import_node_fs15 = require("fs");
8641
+ var import_node_path17 = __toESM(require("path"), 1);
8603
8642
  var import_types13 = require("@neat.is/types");
8604
8643
  var CSHARP_PROJECT_EXTS = /* @__PURE__ */ new Set([".csproj", ".sln"]);
8605
8644
  async function projectFiles(dir) {
8606
- const entries = await import_node_fs14.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8645
+ const entries = await import_node_fs15.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8607
8646
  const out = [];
8608
8647
  for (const entry of entries) {
8609
8648
  if (!entry.isFile()) continue;
8610
- if (CSHARP_PROJECT_EXTS.has(import_node_path16.default.extname(entry.name).toLowerCase())) out.push(entry.name);
8649
+ if (CSHARP_PROJECT_EXTS.has(import_node_path17.default.extname(entry.name).toLowerCase())) out.push(entry.name);
8611
8650
  }
8612
8651
  return out.sort();
8613
8652
  }
8614
8653
  var NESTED_PROJECT_DIR = "src";
8615
8654
  async function resolveProjectDir(dir) {
8616
8655
  if ((await projectFiles(dir)).length > 0) return dir;
8617
- const nested = import_node_path16.default.join(dir, NESTED_PROJECT_DIR);
8656
+ const nested = import_node_path17.default.join(dir, NESTED_PROJECT_DIR);
8618
8657
  if ((await projectFiles(nested)).length > 0) return nested;
8619
8658
  return null;
8620
8659
  }
@@ -8639,10 +8678,10 @@ async function discoverCsharpService(scanPath, dir) {
8639
8678
  if (projectDir === null) return null;
8640
8679
  const projects = await projectFiles(projectDir);
8641
8680
  const csproj = projects.find((p) => p.toLowerCase().endsWith(".csproj"));
8642
- const name = csproj ? import_node_path16.default.basename(csproj, import_node_path16.default.extname(csproj)) : import_node_path16.default.basename(dir);
8681
+ const name = csproj ? import_node_path17.default.basename(csproj, import_node_path17.default.extname(csproj)) : import_node_path17.default.basename(dir);
8643
8682
  let dependencies = {};
8644
8683
  if (csproj) {
8645
- const raw = await import_node_fs14.promises.readFile(import_node_path16.default.join(projectDir, csproj), "utf8").catch(() => "");
8684
+ const raw = await import_node_fs15.promises.readFile(import_node_path17.default.join(projectDir, csproj), "utf8").catch(() => "");
8646
8685
  dependencies = parseCsproj(raw).dependencies;
8647
8686
  }
8648
8687
  const pkg = { name, dependencies };
@@ -8654,20 +8693,20 @@ async function discoverCsharpService(scanPath, dir) {
8654
8693
  dependencies,
8655
8694
  // Anchor on the directory that holds the project and its `.cs` files, so file
8656
8695
  // attribution reaches the source whether it sits at the root or under `src/`.
8657
- repoPath: import_node_path16.default.relative(scanPath, projectDir)
8696
+ repoPath: import_node_path17.default.relative(scanPath, projectDir)
8658
8697
  };
8659
8698
  return { pkg, dir: projectDir, node };
8660
8699
  }
8661
8700
 
8662
8701
  // src/extract/java.ts
8663
8702
  init_cjs_shims();
8664
- var import_node_fs15 = require("fs");
8665
- var import_node_path17 = __toESM(require("path"), 1);
8703
+ var import_node_fs16 = require("fs");
8704
+ var import_node_path18 = __toESM(require("path"), 1);
8666
8705
  var import_types14 = require("@neat.is/types");
8667
8706
  var JAVA_MANIFESTS = ["pom.xml", "build.gradle", "build.gradle.kts"];
8668
8707
  async function hasJavaManifest(dir) {
8669
8708
  for (const manifest of JAVA_MANIFESTS) {
8670
- if (await exists2(import_node_path17.default.join(dir, manifest))) return true;
8709
+ if (await exists2(import_node_path18.default.join(dir, manifest))) return true;
8671
8710
  }
8672
8711
  return false;
8673
8712
  }
@@ -8702,19 +8741,19 @@ function parseGradle(source) {
8702
8741
  return { dependencies };
8703
8742
  }
8704
8743
  async function discoverJavaService(scanPath, dir) {
8705
- const pomPath = import_node_path17.default.join(dir, "pom.xml");
8706
- const gradlePath = import_node_path17.default.join(dir, "build.gradle");
8707
- const gradleKtsPath = import_node_path17.default.join(dir, "build.gradle.kts");
8744
+ const pomPath = import_node_path18.default.join(dir, "pom.xml");
8745
+ const gradlePath = import_node_path18.default.join(dir, "build.gradle");
8746
+ const gradleKtsPath = import_node_path18.default.join(dir, "build.gradle.kts");
8708
8747
  let manifest = null;
8709
8748
  if (await exists2(pomPath)) {
8710
- manifest = parsePomXml(await import_node_fs15.promises.readFile(pomPath, "utf8").catch(() => ""));
8749
+ manifest = parsePomXml(await import_node_fs16.promises.readFile(pomPath, "utf8").catch(() => ""));
8711
8750
  } else if (await exists2(gradlePath)) {
8712
- manifest = parseGradle(await import_node_fs15.promises.readFile(gradlePath, "utf8").catch(() => ""));
8751
+ manifest = parseGradle(await import_node_fs16.promises.readFile(gradlePath, "utf8").catch(() => ""));
8713
8752
  } else if (await exists2(gradleKtsPath)) {
8714
- manifest = parseGradle(await import_node_fs15.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8753
+ manifest = parseGradle(await import_node_fs16.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8715
8754
  }
8716
8755
  if (!manifest) return null;
8717
- const name = manifest.name?.trim() || import_node_path17.default.basename(dir);
8756
+ const name = manifest.name?.trim() || import_node_path18.default.basename(dir);
8718
8757
  const dependencies = manifest.dependencies;
8719
8758
  const pkg = { name, dependencies };
8720
8759
  const node = {
@@ -8723,15 +8762,15 @@ async function discoverJavaService(scanPath, dir) {
8723
8762
  name,
8724
8763
  language: "java",
8725
8764
  dependencies,
8726
- repoPath: import_node_path17.default.relative(scanPath, dir)
8765
+ repoPath: import_node_path18.default.relative(scanPath, dir)
8727
8766
  };
8728
8767
  return { pkg, dir, node };
8729
8768
  }
8730
8769
 
8731
8770
  // src/extract/kotlin.ts
8732
8771
  init_cjs_shims();
8733
- var import_node_fs16 = require("fs");
8734
- var import_node_path18 = __toESM(require("path"), 1);
8772
+ var import_node_fs17 = require("fs");
8773
+ var import_node_path19 = __toESM(require("path"), 1);
8735
8774
  var import_types15 = require("@neat.is/types");
8736
8775
  var KOTLIN_SOURCE_EXT = ".kt";
8737
8776
  var JAVA_SOURCE_EXT = ".java";
@@ -8741,15 +8780,15 @@ async function dominantJvmSourceLanguage(dir) {
8741
8780
  let java = 0;
8742
8781
  async function recurse(current, depth) {
8743
8782
  if (depth > SOURCE_PROBE_MAX_DEPTH) return;
8744
- const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8783
+ const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8745
8784
  for (const entry of entries) {
8746
8785
  if (entry.isDirectory()) {
8747
8786
  if (IGNORED_DIRS.has(entry.name)) continue;
8748
- await recurse(import_node_path18.default.join(current, entry.name), depth + 1);
8787
+ await recurse(import_node_path19.default.join(current, entry.name), depth + 1);
8749
8788
  continue;
8750
8789
  }
8751
8790
  if (!entry.isFile()) continue;
8752
- const ext = import_node_path18.default.extname(entry.name).toLowerCase();
8791
+ const ext = import_node_path19.default.extname(entry.name).toLowerCase();
8753
8792
  if (ext === KOTLIN_SOURCE_EXT) kt++;
8754
8793
  else if (ext === JAVA_SOURCE_EXT) java++;
8755
8794
  }
@@ -8760,17 +8799,17 @@ async function dominantJvmSourceLanguage(dir) {
8760
8799
  return void 0;
8761
8800
  }
8762
8801
  async function readJvmManifest(dir) {
8763
- const pomPath = import_node_path18.default.join(dir, JAVA_MANIFESTS[0]);
8764
- const gradlePath = import_node_path18.default.join(dir, JAVA_MANIFESTS[1]);
8765
- const gradleKtsPath = import_node_path18.default.join(dir, JAVA_MANIFESTS[2]);
8802
+ const pomPath = import_node_path19.default.join(dir, JAVA_MANIFESTS[0]);
8803
+ const gradlePath = import_node_path19.default.join(dir, JAVA_MANIFESTS[1]);
8804
+ const gradleKtsPath = import_node_path19.default.join(dir, JAVA_MANIFESTS[2]);
8766
8805
  if (await exists2(pomPath)) {
8767
- return parsePomXml(await import_node_fs16.promises.readFile(pomPath, "utf8").catch(() => ""));
8806
+ return parsePomXml(await import_node_fs17.promises.readFile(pomPath, "utf8").catch(() => ""));
8768
8807
  }
8769
8808
  if (await exists2(gradlePath)) {
8770
- return parseGradle(await import_node_fs16.promises.readFile(gradlePath, "utf8").catch(() => ""));
8809
+ return parseGradle(await import_node_fs17.promises.readFile(gradlePath, "utf8").catch(() => ""));
8771
8810
  }
8772
8811
  if (await exists2(gradleKtsPath)) {
8773
- return parseGradle(await import_node_fs16.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8812
+ return parseGradle(await import_node_fs17.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
8774
8813
  }
8775
8814
  return null;
8776
8815
  }
@@ -8779,7 +8818,7 @@ async function discoverKotlinService(scanPath, dir) {
8779
8818
  if (await dominantJvmSourceLanguage(dir) !== "kotlin") return null;
8780
8819
  const manifest = await readJvmManifest(dir);
8781
8820
  if (!manifest) return null;
8782
- const name = manifest.name?.trim() || import_node_path18.default.basename(dir);
8821
+ const name = manifest.name?.trim() || import_node_path19.default.basename(dir);
8783
8822
  const dependencies = manifest.dependencies;
8784
8823
  const pkg = { name, dependencies };
8785
8824
  const node = {
@@ -8788,20 +8827,20 @@ async function discoverKotlinService(scanPath, dir) {
8788
8827
  name,
8789
8828
  language: "kotlin",
8790
8829
  dependencies,
8791
- repoPath: import_node_path18.default.relative(scanPath, dir)
8830
+ repoPath: import_node_path19.default.relative(scanPath, dir)
8792
8831
  };
8793
8832
  return { pkg, dir, node };
8794
8833
  }
8795
8834
 
8796
8835
  // src/extract/rust.ts
8797
8836
  init_cjs_shims();
8798
- var import_node_fs17 = require("fs");
8799
- var import_node_path19 = __toESM(require("path"), 1);
8837
+ var import_node_fs18 = require("fs");
8838
+ var import_node_path20 = __toESM(require("path"), 1);
8800
8839
  var import_smol_toml2 = require("smol-toml");
8801
8840
  var import_types16 = require("@neat.is/types");
8802
8841
  var CARGO_MANIFEST = "Cargo.toml";
8803
8842
  async function hasRustManifest(dir) {
8804
- return exists2(import_node_path19.default.join(dir, CARGO_MANIFEST));
8843
+ return exists2(import_node_path20.default.join(dir, CARGO_MANIFEST));
8805
8844
  }
8806
8845
  function parseCargoToml(source) {
8807
8846
  const dependencies = {};
@@ -8826,10 +8865,10 @@ function parseCargoToml(source) {
8826
8865
  return { name, dependencies };
8827
8866
  }
8828
8867
  async function discoverRustService(scanPath, dir) {
8829
- const cargoPath = import_node_path19.default.join(dir, CARGO_MANIFEST);
8868
+ const cargoPath = import_node_path20.default.join(dir, CARGO_MANIFEST);
8830
8869
  if (!await exists2(cargoPath)) return null;
8831
- const manifest = parseCargoToml(await import_node_fs17.promises.readFile(cargoPath, "utf8").catch(() => ""));
8832
- const name = manifest.name?.trim() || import_node_path19.default.basename(dir);
8870
+ const manifest = parseCargoToml(await import_node_fs18.promises.readFile(cargoPath, "utf8").catch(() => ""));
8871
+ const name = manifest.name?.trim() || import_node_path20.default.basename(dir);
8833
8872
  const dependencies = manifest.dependencies;
8834
8873
  const pkg = { name, dependencies };
8835
8874
  const node = {
@@ -8838,19 +8877,19 @@ async function discoverRustService(scanPath, dir) {
8838
8877
  name,
8839
8878
  language: "rust",
8840
8879
  dependencies,
8841
- repoPath: import_node_path19.default.relative(scanPath, dir)
8880
+ repoPath: import_node_path20.default.relative(scanPath, dir)
8842
8881
  };
8843
8882
  return { pkg, dir, node };
8844
8883
  }
8845
8884
 
8846
8885
  // src/extract/cpp.ts
8847
8886
  init_cjs_shims();
8848
- var import_node_fs18 = require("fs");
8849
- var import_node_path20 = __toESM(require("path"), 1);
8887
+ var import_node_fs19 = require("fs");
8888
+ var import_node_path21 = __toESM(require("path"), 1);
8850
8889
  var import_types17 = require("@neat.is/types");
8851
8890
  var CMAKE_MANIFEST = "CMakeLists.txt";
8852
8891
  async function hasCppManifest(dir) {
8853
- return exists2(import_node_path20.default.join(dir, CMAKE_MANIFEST));
8892
+ return exists2(import_node_path21.default.join(dir, CMAKE_MANIFEST));
8854
8893
  }
8855
8894
  function parseCMakeProjectName(source) {
8856
8895
  const withoutComments = source.replace(/#.*$/gm, "");
@@ -8858,10 +8897,10 @@ function parseCMakeProjectName(source) {
8858
8897
  return m?.[1];
8859
8898
  }
8860
8899
  async function discoverCppService(scanPath, dir) {
8861
- const cmakePath = import_node_path20.default.join(dir, CMAKE_MANIFEST);
8900
+ const cmakePath = import_node_path21.default.join(dir, CMAKE_MANIFEST);
8862
8901
  if (!await exists2(cmakePath)) return null;
8863
- const source = await import_node_fs18.promises.readFile(cmakePath, "utf8").catch(() => "");
8864
- const name = parseCMakeProjectName(source)?.trim() || import_node_path20.default.basename(dir);
8902
+ const source = await import_node_fs19.promises.readFile(cmakePath, "utf8").catch(() => "");
8903
+ const name = parseCMakeProjectName(source)?.trim() || import_node_path21.default.basename(dir);
8865
8904
  const dependencies = {};
8866
8905
  const pkg = { name, dependencies };
8867
8906
  const node = {
@@ -8870,15 +8909,15 @@ async function discoverCppService(scanPath, dir) {
8870
8909
  name,
8871
8910
  language: "cpp",
8872
8911
  dependencies,
8873
- repoPath: import_node_path20.default.relative(scanPath, dir)
8912
+ repoPath: import_node_path21.default.relative(scanPath, dir)
8874
8913
  };
8875
8914
  return { pkg, dir, node };
8876
8915
  }
8877
8916
 
8878
8917
  // src/extract/dockerfile-service.ts
8879
8918
  init_cjs_shims();
8880
- var import_node_fs19 = require("fs");
8881
- var import_node_path21 = __toESM(require("path"), 1);
8919
+ var import_node_fs20 = require("fs");
8920
+ var import_node_path22 = __toESM(require("path"), 1);
8882
8921
  var import_types18 = require("@neat.is/types");
8883
8922
  function languageForSourceExt(ext) {
8884
8923
  switch (ext) {
@@ -8920,12 +8959,12 @@ function languageForSourceExt(ext) {
8920
8959
  }
8921
8960
  var LANGUAGE_PRECEDENCE = ["typescript", "javascript", "python", "go", "ruby", "php", "csharp", "java", "kotlin", "rust", "cpp"];
8922
8961
  async function inferServiceLanguage(dir) {
8923
- const entries = await import_node_fs19.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8962
+ const entries = await import_node_fs20.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
8924
8963
  const counts = /* @__PURE__ */ new Map();
8925
8964
  for (const entry of entries) {
8926
8965
  if (!entry.isFile()) continue;
8927
8966
  if (isNeatAuthoredSourceFile(entry.name)) continue;
8928
- const ext = import_node_path21.default.extname(entry.name).toLowerCase();
8967
+ const ext = import_node_path22.default.extname(entry.name).toLowerCase();
8929
8968
  if (!SERVICE_FILE_EXTENSIONS.has(ext)) continue;
8930
8969
  const lang = languageForSourceExt(ext);
8931
8970
  if (!lang) continue;
@@ -8944,7 +8983,7 @@ async function inferServiceLanguage(dir) {
8944
8983
  return best;
8945
8984
  }
8946
8985
  async function hasLanguageManifest(dir) {
8947
- 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
8986
+ return await exists2(import_node_path22.default.join(dir, "package.json")) || 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")) || await exists2(import_node_path22.default.join(dir, "go.mod")) || await exists2(import_node_path22.default.join(dir, "Gemfile")) || await exists2(import_node_path22.default.join(dir, "composer.json")) || // C#'s marker is a glob (`*.csproj` / `*.sln`), so it reads the directory
8948
8987
  // rather than probing a fixed filename (ADR-196).
8949
8988
  await hasCsharpProject(dir) || // Java (and its JVM sibling Kotlin, ADR-199) key on the same Maven / Gradle
8950
8989
  // build manifest (ADR-197), so this one check stands the Dockerfile fallback
@@ -8954,15 +8993,15 @@ async function hasLanguageManifest(dir) {
8954
8993
  await hasCppManifest(dir);
8955
8994
  }
8956
8995
  async function hasDockerfileDeclaredService(dir) {
8957
- if (!await exists2(import_node_path21.default.join(dir, "Dockerfile"))) return false;
8996
+ if (!await exists2(import_node_path22.default.join(dir, "Dockerfile"))) return false;
8958
8997
  return await inferServiceLanguage(dir) !== null;
8959
8998
  }
8960
8999
  async function discoverDockerfileService(scanPath, dir) {
8961
- if (!await exists2(import_node_path21.default.join(dir, "Dockerfile"))) return null;
9000
+ if (!await exists2(import_node_path22.default.join(dir, "Dockerfile"))) return null;
8962
9001
  if (await hasLanguageManifest(dir)) return null;
8963
9002
  const language = await inferServiceLanguage(dir);
8964
9003
  if (!language) return null;
8965
- const name = import_node_path21.default.basename(dir);
9004
+ const name = import_node_path22.default.basename(dir);
8966
9005
  const pkg = { name, dependencies: {} };
8967
9006
  const node = {
8968
9007
  id: (0, import_types18.serviceId)(name),
@@ -8970,24 +9009,24 @@ async function discoverDockerfileService(scanPath, dir) {
8970
9009
  name,
8971
9010
  language,
8972
9011
  dependencies: {},
8973
- repoPath: import_node_path21.default.relative(scanPath, dir)
9012
+ repoPath: import_node_path22.default.relative(scanPath, dir)
8974
9013
  };
8975
9014
  return { pkg, dir, node };
8976
9015
  }
8977
9016
 
8978
9017
  // src/extract/owners.ts
8979
9018
  init_cjs_shims();
8980
- var import_node_fs20 = require("fs");
8981
- var import_node_path22 = __toESM(require("path"), 1);
9019
+ var import_node_fs21 = require("fs");
9020
+ var import_node_path23 = __toESM(require("path"), 1);
8982
9021
  var import_minimatch = require("minimatch");
8983
9022
  async function loadCodeowners(scanPath) {
8984
9023
  const candidates = [
8985
- import_node_path22.default.join(scanPath, "CODEOWNERS"),
8986
- import_node_path22.default.join(scanPath, ".github", "CODEOWNERS")
9024
+ import_node_path23.default.join(scanPath, "CODEOWNERS"),
9025
+ import_node_path23.default.join(scanPath, ".github", "CODEOWNERS")
8987
9026
  ];
8988
9027
  for (const file of candidates) {
8989
9028
  if (await exists2(file)) {
8990
- const raw = await import_node_fs20.promises.readFile(file, "utf8");
9029
+ const raw = await import_node_fs21.promises.readFile(file, "utf8");
8991
9030
  return parseCodeowners(raw);
8992
9031
  }
8993
9032
  }
@@ -9005,7 +9044,7 @@ function parseCodeowners(raw) {
9005
9044
  return { rules };
9006
9045
  }
9007
9046
  function matchOwner(file, repoPath) {
9008
- const normalized = repoPath.split(import_node_path22.default.sep).join("/");
9047
+ const normalized = repoPath.split(import_node_path23.default.sep).join("/");
9009
9048
  for (const rule of file.rules) {
9010
9049
  if (matchesPattern(rule.pattern, normalized)) return rule.owners;
9011
9050
  }
@@ -9021,7 +9060,7 @@ function matchesPattern(rawPattern, repoPath) {
9021
9060
  return false;
9022
9061
  }
9023
9062
  async function readPackageJsonAuthor(serviceDir) {
9024
- const pkgPath = import_node_path22.default.join(serviceDir, "package.json");
9063
+ const pkgPath = import_node_path23.default.join(serviceDir, "package.json");
9025
9064
  if (!await exists2(pkgPath)) return null;
9026
9065
  try {
9027
9066
  const pkg = await readJson(pkgPath);
@@ -9058,36 +9097,36 @@ function workspaceGlobs(pkg) {
9058
9097
  return null;
9059
9098
  }
9060
9099
  async function hasPythonManifest(dir) {
9061
- 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"));
9100
+ return await exists2(import_node_path24.default.join(dir, "pyproject.toml")) || await exists2(import_node_path24.default.join(dir, "requirements.txt")) || await exists2(import_node_path24.default.join(dir, "setup.py"));
9062
9101
  }
9063
9102
  async function hasGoManifest(dir) {
9064
- return exists2(import_node_path23.default.join(dir, "go.mod"));
9103
+ return exists2(import_node_path24.default.join(dir, "go.mod"));
9065
9104
  }
9066
9105
  async function hasRubyManifest(dir) {
9067
- return exists2(import_node_path23.default.join(dir, "Gemfile"));
9106
+ return exists2(import_node_path24.default.join(dir, "Gemfile"));
9068
9107
  }
9069
9108
  async function hasPhpManifest(dir) {
9070
- return exists2(import_node_path23.default.join(dir, "composer.json"));
9109
+ return exists2(import_node_path24.default.join(dir, "composer.json"));
9071
9110
  }
9072
9111
  async function hasCsharpManifest(dir) {
9073
9112
  return hasCsharpProject(dir);
9074
9113
  }
9075
9114
  async function loadGitignore(scanPath) {
9076
- const gitignorePath = import_node_path23.default.join(scanPath, ".gitignore");
9115
+ const gitignorePath = import_node_path24.default.join(scanPath, ".gitignore");
9077
9116
  if (!await exists2(gitignorePath)) return null;
9078
- const raw = await import_node_fs21.promises.readFile(gitignorePath, "utf8");
9117
+ const raw = await import_node_fs22.promises.readFile(gitignorePath, "utf8");
9079
9118
  return (0, import_ignore2.default)().add(raw);
9080
9119
  }
9081
9120
  async function walkDirs(start, scanPath, options, visit) {
9082
9121
  async function recurse(current, depth) {
9083
9122
  if (depth > options.maxDepth) return;
9084
- const entries = await import_node_fs21.promises.readdir(current, { withFileTypes: true }).catch(() => []);
9123
+ const entries = await import_node_fs22.promises.readdir(current, { withFileTypes: true }).catch(() => []);
9085
9124
  for (const entry of entries) {
9086
9125
  if (!entry.isDirectory()) continue;
9087
9126
  if (IGNORED_DIRS.has(entry.name)) continue;
9088
- const child = import_node_path23.default.join(current, entry.name);
9127
+ const child = import_node_path24.default.join(current, entry.name);
9089
9128
  if (options.ig) {
9090
- const rel = import_node_path23.default.relative(scanPath, child).split(import_node_path23.default.sep).join("/");
9129
+ const rel = import_node_path24.default.relative(scanPath, child).split(import_node_path24.default.sep).join("/");
9091
9130
  if (rel && options.ig.ignores(rel + "/")) continue;
9092
9131
  }
9093
9132
  if (await isPythonVenvDir(child)) continue;
@@ -9103,8 +9142,8 @@ async function expandWorkspaceGlobs(scanPath, globs) {
9103
9142
  for (const raw of globs) {
9104
9143
  const pattern = raw.replace(/^\.\//, "");
9105
9144
  if (!pattern.includes("*")) {
9106
- const candidate = import_node_path23.default.join(scanPath, pattern);
9107
- if (await exists2(import_node_path23.default.join(candidate, "package.json"))) found.add(candidate);
9145
+ const candidate = import_node_path24.default.join(scanPath, pattern);
9146
+ if (await exists2(import_node_path24.default.join(candidate, "package.json"))) found.add(candidate);
9108
9147
  continue;
9109
9148
  }
9110
9149
  const segments = pattern.split("/");
@@ -9113,13 +9152,13 @@ async function expandWorkspaceGlobs(scanPath, globs) {
9113
9152
  if (seg.includes("*")) break;
9114
9153
  staticSegments.push(seg);
9115
9154
  }
9116
- const start = import_node_path23.default.join(scanPath, ...staticSegments);
9155
+ const start = import_node_path24.default.join(scanPath, ...staticSegments);
9117
9156
  if (!await exists2(start)) continue;
9118
9157
  const hasDoubleStar = pattern.includes("**");
9119
9158
  const walkDepth = hasDoubleStar ? scanDepth : Math.max(0, segments.length - staticSegments.length - 1);
9120
9159
  await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {
9121
- const rel = import_node_path23.default.relative(scanPath, dir).split(import_node_path23.default.sep).join("/");
9122
- if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path23.default.join(dir, "package.json"))) {
9160
+ const rel = import_node_path24.default.relative(scanPath, dir).split(import_node_path24.default.sep).join("/");
9161
+ if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path24.default.join(dir, "package.json"))) {
9123
9162
  found.add(dir);
9124
9163
  }
9125
9164
  });
@@ -9142,18 +9181,18 @@ function detectJsFramework(pkg) {
9142
9181
  async function detectJsServiceLanguage(dir, pkg) {
9143
9182
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
9144
9183
  if (deps["typescript"] !== void 0) return "typescript";
9145
- const entries = await import_node_fs21.promises.readdir(dir).catch(() => []);
9184
+ const entries = await import_node_fs22.promises.readdir(dir).catch(() => []);
9146
9185
  if (entries.some((name) => /^tsconfig(\..+)?\.json$/.test(name))) return "typescript";
9147
9186
  return "javascript";
9148
9187
  }
9149
9188
  async function discoverNodeService(scanPath, dir) {
9150
- const pkgPath = import_node_path23.default.join(dir, "package.json");
9189
+ const pkgPath = import_node_path24.default.join(dir, "package.json");
9151
9190
  if (!await exists2(pkgPath)) return null;
9152
9191
  let pkg;
9153
9192
  try {
9154
9193
  pkg = await readJson(pkgPath);
9155
9194
  } catch (err) {
9156
- recordExtractionError("services", import_node_path23.default.relative(scanPath, pkgPath), err);
9195
+ recordExtractionError("services", import_node_path24.default.relative(scanPath, pkgPath), err);
9157
9196
  return null;
9158
9197
  }
9159
9198
  if (!pkg.name) return null;
@@ -9166,7 +9205,7 @@ async function discoverNodeService(scanPath, dir) {
9166
9205
  language,
9167
9206
  version: pkg.version,
9168
9207
  dependencies: pkg.dependencies ?? {},
9169
- repoPath: import_node_path23.default.relative(scanPath, dir),
9208
+ repoPath: import_node_path24.default.relative(scanPath, dir),
9170
9209
  ...pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {},
9171
9210
  ...framework ? { framework } : {}
9172
9211
  };
@@ -9183,12 +9222,12 @@ async function discoverPyService(scanPath, dir) {
9183
9222
  language: "python",
9184
9223
  version: py.version,
9185
9224
  dependencies: py.dependencies,
9186
- repoPath: import_node_path23.default.relative(scanPath, dir)
9225
+ repoPath: import_node_path24.default.relative(scanPath, dir)
9187
9226
  };
9188
9227
  return { pkg, dir, node };
9189
9228
  }
9190
9229
  async function discoverServices(scanPath) {
9191
- const rootPkgPath = import_node_path23.default.join(scanPath, "package.json");
9230
+ const rootPkgPath = import_node_path24.default.join(scanPath, "package.json");
9192
9231
  let rootPkg = null;
9193
9232
  if (await exists2(rootPkgPath)) {
9194
9233
  try {
@@ -9196,7 +9235,7 @@ async function discoverServices(scanPath) {
9196
9235
  } catch (err) {
9197
9236
  recordExtractionError(
9198
9237
  "services workspaces",
9199
- import_node_path23.default.relative(scanPath, rootPkgPath),
9238
+ import_node_path24.default.relative(scanPath, rootPkgPath),
9200
9239
  err
9201
9240
  );
9202
9241
  }
@@ -9217,7 +9256,7 @@ async function discoverServices(scanPath) {
9217
9256
  scanPath,
9218
9257
  { maxDepth: parseScanDepth(), ig },
9219
9258
  async (dir) => {
9220
- if (await exists2(import_node_path23.default.join(dir, "package.json"))) {
9259
+ if (await exists2(import_node_path24.default.join(dir, "package.json"))) {
9221
9260
  candidateDirs.push(dir);
9222
9261
  } 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)) {
9223
9262
  candidateDirs.push(dir);
@@ -9245,8 +9284,8 @@ async function discoverServices(scanPath) {
9245
9284
  seenDirs.add(service.dir);
9246
9285
  const existingDir = seen.get(service.node.name);
9247
9286
  if (existingDir !== void 0) {
9248
- const a = import_node_path23.default.relative(scanPath, existingDir) || ".";
9249
- const b = import_node_path23.default.relative(scanPath, dir) || ".";
9287
+ const a = import_node_path24.default.relative(scanPath, existingDir) || ".";
9288
+ const b = import_node_path24.default.relative(scanPath, dir) || ".";
9250
9289
  console.warn(
9251
9290
  `[neat] duplicate package name "${service.node.name}" \u2014 keeping ${a}, ignoring ${b}`
9252
9291
  );
@@ -9260,14 +9299,14 @@ async function discoverServices(scanPath) {
9260
9299
  const owner = await computeServiceOwner(codeowners, service.node.repoPath, service.dir);
9261
9300
  if (owner !== void 0) service.node.owner = owner;
9262
9301
  }
9263
- const resolvedDirs = out.map((s) => import_node_path23.default.resolve(s.dir));
9302
+ const resolvedDirs = out.map((s) => import_node_path24.default.resolve(s.dir));
9264
9303
  for (let i = 0; i < out.length; i++) {
9265
9304
  const self = resolvedDirs[i];
9266
9305
  const nested = [];
9267
9306
  for (let j = 0; j < out.length; j++) {
9268
9307
  if (i === j) continue;
9269
9308
  const other = resolvedDirs[j];
9270
- if (other.startsWith(self + import_node_path23.default.sep)) nested.push(other);
9309
+ if (other.startsWith(self + import_node_path24.default.sep)) nested.push(other);
9271
9310
  }
9272
9311
  out[i].excludeDirs = nested;
9273
9312
  }
@@ -9294,8 +9333,8 @@ function addServiceNodes(graph, services) {
9294
9333
 
9295
9334
  // src/extract/aliases.ts
9296
9335
  init_cjs_shims();
9297
- var import_node_path24 = __toESM(require("path"), 1);
9298
- var import_node_fs22 = require("fs");
9336
+ var import_node_path25 = __toESM(require("path"), 1);
9337
+ var import_node_fs23 = require("fs");
9299
9338
  var import_yaml2 = require("yaml");
9300
9339
  var import_types20 = require("@neat.is/types");
9301
9340
  var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
@@ -9322,14 +9361,14 @@ function indexServicesByName(services) {
9322
9361
  const map = /* @__PURE__ */ new Map();
9323
9362
  for (const s of services) {
9324
9363
  map.set(s.node.name, s.node.id);
9325
- map.set(import_node_path24.default.basename(s.dir), s.node.id);
9364
+ map.set(import_node_path25.default.basename(s.dir), s.node.id);
9326
9365
  }
9327
9366
  return map;
9328
9367
  }
9329
9368
  async function collectComposeAliases(graph, scanPath, serviceIndex) {
9330
9369
  let composePath = null;
9331
9370
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
9332
- const abs = import_node_path24.default.join(scanPath, name);
9371
+ const abs = import_node_path25.default.join(scanPath, name);
9333
9372
  if (await exists2(abs)) {
9334
9373
  composePath = abs;
9335
9374
  break;
@@ -9342,7 +9381,7 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
9342
9381
  } catch (err) {
9343
9382
  recordExtractionError(
9344
9383
  "aliases compose",
9345
- import_node_path24.default.relative(scanPath, composePath),
9384
+ import_node_path25.default.relative(scanPath, composePath),
9346
9385
  err
9347
9386
  );
9348
9387
  return;
@@ -9385,11 +9424,11 @@ function parseDockerfileLabels(content) {
9385
9424
  }
9386
9425
  async function collectDockerfileAliases(graph, services) {
9387
9426
  for (const service of services) {
9388
- const dockerfilePath = import_node_path24.default.join(service.dir, "Dockerfile");
9427
+ const dockerfilePath = import_node_path25.default.join(service.dir, "Dockerfile");
9389
9428
  if (!await exists2(dockerfilePath)) continue;
9390
9429
  let content;
9391
9430
  try {
9392
- content = await import_node_fs22.promises.readFile(dockerfilePath, "utf8");
9431
+ content = await import_node_fs23.promises.readFile(dockerfilePath, "utf8");
9393
9432
  } catch (err) {
9394
9433
  recordExtractionError("aliases dockerfile", dockerfilePath, err);
9395
9434
  continue;
@@ -9401,15 +9440,15 @@ async function collectDockerfileAliases(graph, services) {
9401
9440
  async function walkYamlFiles(start, depth = 0, max = 5) {
9402
9441
  if (depth > max) return [];
9403
9442
  const out = [];
9404
- const entries = await import_node_fs22.promises.readdir(start, { withFileTypes: true }).catch(() => []);
9443
+ const entries = await import_node_fs23.promises.readdir(start, { withFileTypes: true }).catch(() => []);
9405
9444
  for (const entry of entries) {
9406
9445
  if (entry.isDirectory()) {
9407
9446
  if (IGNORED_DIRS.has(entry.name)) continue;
9408
- const child = import_node_path24.default.join(start, entry.name);
9447
+ const child = import_node_path25.default.join(start, entry.name);
9409
9448
  if (await isPythonVenvDir(child)) continue;
9410
9449
  out.push(...await walkYamlFiles(child, depth + 1, max));
9411
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path24.default.extname(entry.name))) {
9412
- out.push(import_node_path24.default.join(start, entry.name));
9450
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path25.default.extname(entry.name))) {
9451
+ out.push(import_node_path25.default.join(start, entry.name));
9413
9452
  }
9414
9453
  }
9415
9454
  return out;
@@ -9436,7 +9475,7 @@ function k8sServiceTarget(doc, byName) {
9436
9475
  async function collectK8sAliases(graph, scanPath, serviceIndex) {
9437
9476
  const files = await walkYamlFiles(scanPath);
9438
9477
  for (const file of files) {
9439
- const content = await import_node_fs22.promises.readFile(file, "utf8");
9478
+ const content = await import_node_fs23.promises.readFile(file, "utf8");
9440
9479
  let docs;
9441
9480
  try {
9442
9481
  docs = (0, import_yaml2.parseAllDocuments)(content).map((d) => d.toJSON());
@@ -9461,14 +9500,14 @@ async function addServiceAliases(graph, scanPath, services) {
9461
9500
 
9462
9501
  // src/extract/files.ts
9463
9502
  init_cjs_shims();
9464
- var import_node_path25 = __toESM(require("path"), 1);
9503
+ var import_node_path26 = __toESM(require("path"), 1);
9465
9504
  async function addFiles(graph, services) {
9466
9505
  let nodesAdded = 0;
9467
9506
  let edgesAdded = 0;
9468
9507
  for (const service of services) {
9469
9508
  const filePaths = await walkSourceFiles(service.dir, service.excludeDirs);
9470
9509
  for (const filePath of filePaths) {
9471
- const relPath = toPosix(import_node_path25.default.relative(service.dir, filePath));
9510
+ const relPath = toPosix(import_node_path26.default.relative(service.dir, filePath));
9472
9511
  const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
9473
9512
  graph,
9474
9513
  service.pkg.name,
@@ -9484,7 +9523,7 @@ async function addFiles(graph, services) {
9484
9523
 
9485
9524
  // src/extract/symbols.ts
9486
9525
  init_cjs_shims();
9487
- var import_node_path26 = __toESM(require("path"), 1);
9526
+ var import_node_path27 = __toESM(require("path"), 1);
9488
9527
  var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
9489
9528
  var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
9490
9529
  var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript"), 1);
@@ -10236,10 +10275,10 @@ async function addSymbols(graph, services) {
10236
10275
  for (const service of services) {
10237
10276
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10238
10277
  for (const file of files) {
10239
- const ext = import_node_path26.default.extname(file.path);
10278
+ const ext = import_node_path27.default.extname(file.path);
10240
10279
  const parser = parserForExt5(ext);
10241
10280
  if (!parser) continue;
10242
- const relPath = toPosix(import_node_path26.default.relative(service.dir, file.path));
10281
+ const relPath = toPosix(import_node_path27.default.relative(service.dir, file.path));
10243
10282
  let defs;
10244
10283
  try {
10245
10284
  const tree = parseSource3(parser, file.content);
@@ -10299,7 +10338,7 @@ async function addSymbols(graph, services) {
10299
10338
 
10300
10339
  // src/extract/symbol-edges.ts
10301
10340
  init_cjs_shims();
10302
- var import_node_path27 = __toESM(require("path"), 1);
10341
+ var import_node_path28 = __toESM(require("path"), 1);
10303
10342
  var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
10304
10343
  var import_types22 = require("@neat.is/types");
10305
10344
  function extendsInfo(classHeritage) {
@@ -10406,10 +10445,10 @@ async function addSymbolEdges(graph, services) {
10406
10445
  const tsPaths = await loadTsPathConfig(service.dir);
10407
10446
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10408
10447
  for (const file of files) {
10409
- const parser = parserForExt5(import_node_path27.default.extname(file.path));
10448
+ const parser = parserForExt5(import_node_path28.default.extname(file.path));
10410
10449
  if (!parser) continue;
10411
- const relPath = toPosix(import_node_path27.default.relative(service.dir, file.path));
10412
- const fileDir = import_node_path27.default.dirname(file.path);
10450
+ const relPath = toPosix(import_node_path28.default.relative(service.dir, file.path));
10451
+ const fileDir = import_node_path28.default.dirname(file.path);
10413
10452
  let root;
10414
10453
  try {
10415
10454
  root = parseSource3(parser, file.content).rootNode;
@@ -10544,7 +10583,7 @@ async function addSymbolEdges(graph, services) {
10544
10583
 
10545
10584
  // src/extract/actions.ts
10546
10585
  init_cjs_shims();
10547
- var import_node_path28 = __toESM(require("path"), 1);
10586
+ var import_node_path29 = __toESM(require("path"), 1);
10548
10587
  var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
10549
10588
  var import_types23 = require("@neat.is/types");
10550
10589
  function stringLiteralText2(node) {
@@ -10691,9 +10730,9 @@ async function addServerActions(graph, services) {
10691
10730
  const files = await loadSourceFiles(service.dir, service.excludeDirs);
10692
10731
  for (const file of files) {
10693
10732
  if (isTestPath(file.path)) continue;
10694
- const parser = parserForExt5(import_node_path28.default.extname(file.path));
10733
+ const parser = parserForExt5(import_node_path29.default.extname(file.path));
10695
10734
  if (!parser) continue;
10696
- const relPath = toPosix(import_node_path28.default.relative(service.dir, file.path));
10735
+ const relPath = toPosix(import_node_path29.default.relative(service.dir, file.path));
10697
10736
  let root;
10698
10737
  try {
10699
10738
  root = parseSource3(parser, file.content).rootNode;
@@ -10754,10 +10793,10 @@ async function addServerActions(graph, services) {
10754
10793
  }
10755
10794
  for (const file of files) {
10756
10795
  if (isTestPath(file.path)) continue;
10757
- const parser = parserForExt5(import_node_path28.default.extname(file.path));
10796
+ const parser = parserForExt5(import_node_path29.default.extname(file.path));
10758
10797
  if (!parser) continue;
10759
- const relPath = toPosix(import_node_path28.default.relative(service.dir, file.path));
10760
- const fileDir = import_node_path28.default.dirname(file.path);
10798
+ const relPath = toPosix(import_node_path29.default.relative(service.dir, file.path));
10799
+ const fileDir = import_node_path29.default.dirname(file.path);
10761
10800
  let root;
10762
10801
  try {
10763
10802
  root = parseSource3(parser, file.content).rootNode;
@@ -10810,14 +10849,14 @@ async function addServerActions(graph, services) {
10810
10849
 
10811
10850
  // src/extract/databases/index.ts
10812
10851
  init_cjs_shims();
10813
- var import_node_path37 = __toESM(require("path"), 1);
10852
+ var import_node_path38 = __toESM(require("path"), 1);
10814
10853
  var import_types24 = require("@neat.is/types");
10815
10854
 
10816
10855
  // src/extract/databases/db-config-yaml.ts
10817
10856
  init_cjs_shims();
10818
- var import_node_path29 = __toESM(require("path"), 1);
10857
+ var import_node_path30 = __toESM(require("path"), 1);
10819
10858
  async function parse(serviceDir) {
10820
- const yamlPath = import_node_path29.default.join(serviceDir, "db-config.yaml");
10859
+ const yamlPath = import_node_path30.default.join(serviceDir, "db-config.yaml");
10821
10860
  if (!await exists2(yamlPath)) return [];
10822
10861
  const raw = await readYaml(yamlPath);
10823
10862
  return [
@@ -10835,13 +10874,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
10835
10874
 
10836
10875
  // src/extract/databases/dotenv.ts
10837
10876
  init_cjs_shims();
10838
- var import_node_fs24 = require("fs");
10839
- var import_node_path31 = __toESM(require("path"), 1);
10877
+ var import_node_fs25 = require("fs");
10878
+ var import_node_path32 = __toESM(require("path"), 1);
10840
10879
 
10841
10880
  // src/extract/databases/shared.ts
10842
10881
  init_cjs_shims();
10843
- var import_node_fs23 = require("fs");
10844
- var import_node_path30 = __toESM(require("path"), 1);
10882
+ var import_node_fs24 = require("fs");
10883
+ var import_node_path31 = __toESM(require("path"), 1);
10845
10884
  function schemeToEngine(scheme) {
10846
10885
  const s = scheme.toLowerCase().split("+")[0];
10847
10886
  switch (s) {
@@ -10880,18 +10919,18 @@ function parseConnectionString(url) {
10880
10919
  }
10881
10920
  async function readIfExists(filePath) {
10882
10921
  try {
10883
- return await import_node_fs23.promises.readFile(filePath, "utf8");
10922
+ return await import_node_fs24.promises.readFile(filePath, "utf8");
10884
10923
  } catch {
10885
10924
  return null;
10886
10925
  }
10887
10926
  }
10888
10927
  async function resolveEnvVar(serviceDir, name) {
10889
- const entries = await import_node_fs23.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10928
+ const entries = await import_node_fs24.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10890
10929
  const envNames = entries.filter((e) => e.isFile() && (e.name === ".env" || e.name.startsWith(".env."))).map((e) => e.name);
10891
10930
  const rank = (n) => n === ".env.local" ? 0 : n === ".env" ? 1 : 2;
10892
10931
  envNames.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
10893
10932
  for (const fileName of envNames) {
10894
- const content = await readIfExists(import_node_path30.default.join(serviceDir, fileName));
10933
+ const content = await readIfExists(import_node_path31.default.join(serviceDir, fileName));
10895
10934
  if (!content) continue;
10896
10935
  for (const line of content.split("\n")) {
10897
10936
  const trimmed = line.trim();
@@ -10910,7 +10949,7 @@ async function resolveEnvVar(serviceDir, name) {
10910
10949
  }
10911
10950
  async function findFirst(serviceDir, candidates) {
10912
10951
  for (const rel of candidates) {
10913
- const abs = import_node_path30.default.join(serviceDir, rel);
10952
+ const abs = import_node_path31.default.join(serviceDir, rel);
10914
10953
  const content = await readIfExists(abs);
10915
10954
  if (content !== null) return abs;
10916
10955
  }
@@ -10968,15 +11007,15 @@ function parseDotenvLine(line) {
10968
11007
  return { key, value };
10969
11008
  }
10970
11009
  async function parse2(serviceDir) {
10971
- const entries = await import_node_fs24.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
11010
+ const entries = await import_node_fs25.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
10972
11011
  const configs = [];
10973
11012
  const seen = /* @__PURE__ */ new Set();
10974
11013
  for (const entry of entries) {
10975
11014
  if (!entry.isFile()) continue;
10976
11015
  const match = isConfigFile(entry.name);
10977
11016
  if (!match.match || match.fileType !== "env") continue;
10978
- const filePath = import_node_path31.default.join(serviceDir, entry.name);
10979
- const content = await import_node_fs24.promises.readFile(filePath, "utf8");
11017
+ const filePath = import_node_path32.default.join(serviceDir, entry.name);
11018
+ const content = await import_node_fs25.promises.readFile(filePath, "utf8");
10980
11019
  for (const line of content.split("\n")) {
10981
11020
  const parsed = parseDotenvLine(line);
10982
11021
  if (!parsed) continue;
@@ -10995,9 +11034,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
10995
11034
 
10996
11035
  // src/extract/databases/prisma.ts
10997
11036
  init_cjs_shims();
10998
- var import_node_path32 = __toESM(require("path"), 1);
11037
+ var import_node_path33 = __toESM(require("path"), 1);
10999
11038
  async function parse3(serviceDir) {
11000
- const schemaPath = import_node_path32.default.join(serviceDir, "prisma", "schema.prisma");
11039
+ const schemaPath = import_node_path33.default.join(serviceDir, "prisma", "schema.prisma");
11001
11040
  const content = await readIfExists(schemaPath);
11002
11041
  if (!content) return [];
11003
11042
  const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
@@ -11155,10 +11194,10 @@ var knexParser = { name: "knex", parse: parse5 };
11155
11194
 
11156
11195
  // src/extract/databases/ormconfig.ts
11157
11196
  init_cjs_shims();
11158
- var import_node_path33 = __toESM(require("path"), 1);
11197
+ var import_node_path34 = __toESM(require("path"), 1);
11159
11198
  async function parse6(serviceDir) {
11160
11199
  for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
11161
- const abs = import_node_path33.default.join(serviceDir, candidate);
11200
+ const abs = import_node_path34.default.join(serviceDir, candidate);
11162
11201
  if (!await exists2(abs)) continue;
11163
11202
  const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
11164
11203
  const entries = Array.isArray(raw) ? raw : [raw];
@@ -11218,9 +11257,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
11218
11257
 
11219
11258
  // src/extract/databases/sequelize.ts
11220
11259
  init_cjs_shims();
11221
- var import_node_path34 = __toESM(require("path"), 1);
11260
+ var import_node_path35 = __toESM(require("path"), 1);
11222
11261
  async function parse8(serviceDir) {
11223
- const configPath = import_node_path34.default.join(serviceDir, "config", "config.json");
11262
+ const configPath = import_node_path35.default.join(serviceDir, "config", "config.json");
11224
11263
  if (!await exists2(configPath)) return [];
11225
11264
  const raw = await readJson(configPath);
11226
11265
  const out = [];
@@ -11247,8 +11286,8 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
11247
11286
 
11248
11287
  // src/extract/databases/csharp.ts
11249
11288
  init_cjs_shims();
11250
- var import_node_fs25 = require("fs");
11251
- var import_node_path35 = __toESM(require("path"), 1);
11289
+ var import_node_fs26 = require("fs");
11290
+ var import_node_path36 = __toESM(require("path"), 1);
11252
11291
  var CS_EXT = ".cs";
11253
11292
  var NPGSQL_GATE = /\bUseNpgsql\b|\bNpgsql\b/;
11254
11293
  var REDIS_GATE = /\bConnectionMultiplexer\b|\bStackExchange\.Redis\b|\bConfigurationOptions\.Parse\b|\bAddStackExchangeRedisCache\b/;
@@ -11295,12 +11334,12 @@ function parseRedisEndpoint(raw) {
11295
11334
  return { host, port, database: "", engine: "redis", engineVersion: "unknown" };
11296
11335
  }
11297
11336
  async function resolveEnvUpTree(startDir, name) {
11298
- let dir = import_node_path35.default.resolve(startDir);
11337
+ let dir = import_node_path36.default.resolve(startDir);
11299
11338
  for (let depth = 0; depth < 12; depth++) {
11300
11339
  const value = await resolveEnvVar(dir, name);
11301
11340
  if (value !== null) return value;
11302
- const atRepoRoot = await import_node_fs25.promises.access(import_node_path35.default.join(dir, ".git")).then(() => true).catch(() => false);
11303
- const parent = import_node_path35.default.dirname(dir);
11341
+ const atRepoRoot = await import_node_fs26.promises.access(import_node_path36.default.join(dir, ".git")).then(() => true).catch(() => false);
11342
+ const parent = import_node_path36.default.dirname(dir);
11304
11343
  if (atRepoRoot || parent === dir) break;
11305
11344
  dir = parent;
11306
11345
  }
@@ -11355,12 +11394,12 @@ async function resolveConfigs(literals, keys, serviceDir, looksLike, parse11) {
11355
11394
  }
11356
11395
  async function parse9(serviceDir) {
11357
11396
  const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(
11358
- (f) => import_node_path35.default.extname(f) === CS_EXT
11397
+ (f) => import_node_path36.default.extname(f) === CS_EXT
11359
11398
  );
11360
11399
  if (files.length === 0) return [];
11361
11400
  const sources = [];
11362
11401
  for (const file of files) {
11363
- const content = await import_node_fs25.promises.readFile(file, "utf8").catch(() => null);
11402
+ const content = await import_node_fs26.promises.readFile(file, "utf8").catch(() => null);
11364
11403
  if (content !== null) sources.push({ file, content });
11365
11404
  }
11366
11405
  let pgGateFile = null;
@@ -11401,7 +11440,7 @@ var csharpParser = { name: "csharp", parse: parse9 };
11401
11440
 
11402
11441
  // src/extract/databases/docker-compose.ts
11403
11442
  init_cjs_shims();
11404
- var import_node_path36 = __toESM(require("path"), 1);
11443
+ var import_node_path37 = __toESM(require("path"), 1);
11405
11444
  function portFromService(svc) {
11406
11445
  for (const raw of svc.ports ?? []) {
11407
11446
  const str = String(raw);
@@ -11428,7 +11467,7 @@ function databaseFromEnv(svc) {
11428
11467
  }
11429
11468
  async function parse10(serviceDir) {
11430
11469
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
11431
- const abs = import_node_path36.default.join(serviceDir, name);
11470
+ const abs = import_node_path37.default.join(serviceDir, name);
11432
11471
  if (!await exists2(abs)) continue;
11433
11472
  const raw = await readYaml(abs);
11434
11473
  if (!raw?.services) return [];
@@ -11601,7 +11640,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11601
11640
  discoveredVia: mergedDiscoveredVia
11602
11641
  });
11603
11642
  }
11604
- const relConfigFile = toPosix(import_node_path37.default.relative(service.dir, config.sourceFile));
11643
+ const relConfigFile = toPosix(import_node_path38.default.relative(service.dir, config.sourceFile));
11605
11644
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11606
11645
  graph,
11607
11646
  service.pkg.name,
@@ -11610,7 +11649,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11610
11649
  );
11611
11650
  nodesAdded += fn;
11612
11651
  edgesAdded += fe;
11613
- const evidenceFile = toPosix(import_node_path37.default.relative(scanPath, config.sourceFile));
11652
+ const evidenceFile = toPosix(import_node_path38.default.relative(scanPath, config.sourceFile));
11614
11653
  const edge = {
11615
11654
  id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types24.EdgeType.CONNECTS_TO),
11616
11655
  source: fileNodeId,
@@ -11631,15 +11670,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11631
11670
  if (allConfigs.length === 1) {
11632
11671
  const primary = allConfigs[0];
11633
11672
  service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
11634
- const relPath = import_node_path37.default.relative(scanPath, primary.sourceFile);
11673
+ const relPath = import_node_path38.default.relative(scanPath, primary.sourceFile);
11635
11674
  const cfgId = (0, import_types24.configId)(relPath);
11636
11675
  if (!graph.hasNode(cfgId)) {
11637
11676
  const cfgNode = {
11638
11677
  id: cfgId,
11639
11678
  type: import_types24.NodeType.ConfigNode,
11640
- name: import_node_path37.default.basename(primary.sourceFile),
11679
+ name: import_node_path38.default.basename(primary.sourceFile),
11641
11680
  path: relPath,
11642
- fileType: isConfigFile(import_node_path37.default.basename(primary.sourceFile)).fileType || "config"
11681
+ fileType: isConfigFile(import_node_path38.default.basename(primary.sourceFile)).fileType || "config"
11643
11682
  };
11644
11683
  graph.addNode(cfgId, cfgNode);
11645
11684
  nodesAdded++;
@@ -11680,19 +11719,19 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
11680
11719
 
11681
11720
  // src/extract/configs.ts
11682
11721
  init_cjs_shims();
11683
- var import_node_fs26 = require("fs");
11684
- var import_node_path38 = __toESM(require("path"), 1);
11722
+ var import_node_fs27 = require("fs");
11723
+ var import_node_path39 = __toESM(require("path"), 1);
11685
11724
  var import_types25 = require("@neat.is/types");
11686
11725
  async function walkConfigFiles(dir, excludeDirs = []) {
11687
- const excluded = new Set(excludeDirs.map((d) => import_node_path38.default.resolve(d)));
11726
+ const excluded = new Set(excludeDirs.map((d) => import_node_path39.default.resolve(d)));
11688
11727
  const out = [];
11689
11728
  async function walk11(current) {
11690
- const entries = await import_node_fs26.promises.readdir(current, { withFileTypes: true });
11729
+ const entries = await import_node_fs27.promises.readdir(current, { withFileTypes: true });
11691
11730
  for (const entry of entries) {
11692
- const full = import_node_path38.default.join(current, entry.name);
11731
+ const full = import_node_path39.default.join(current, entry.name);
11693
11732
  if (entry.isDirectory()) {
11694
11733
  if (IGNORED_DIRS.has(entry.name)) continue;
11695
- if (excluded.has(import_node_path38.default.resolve(full))) continue;
11734
+ if (excluded.has(import_node_path39.default.resolve(full))) continue;
11696
11735
  if (await isPythonVenvDir(full)) continue;
11697
11736
  await walk11(full);
11698
11737
  } else if (entry.isFile() && isConfigFile(entry.name).match) {
@@ -11709,19 +11748,19 @@ async function addConfigNodes(graph, services, scanPath) {
11709
11748
  for (const service of services) {
11710
11749
  const configFiles = await walkConfigFiles(service.dir, service.excludeDirs);
11711
11750
  for (const file of configFiles) {
11712
- const relPath = import_node_path38.default.relative(scanPath, file);
11751
+ const relPath = import_node_path39.default.relative(scanPath, file);
11713
11752
  const node = {
11714
11753
  id: (0, import_types25.configId)(relPath),
11715
11754
  type: import_types25.NodeType.ConfigNode,
11716
- name: import_node_path38.default.basename(file),
11755
+ name: import_node_path39.default.basename(file),
11717
11756
  path: relPath,
11718
- fileType: isConfigFile(import_node_path38.default.basename(file)).fileType
11757
+ fileType: isConfigFile(import_node_path39.default.basename(file)).fileType
11719
11758
  };
11720
11759
  if (!graph.hasNode(node.id)) {
11721
11760
  graph.addNode(node.id, node);
11722
11761
  nodesAdded++;
11723
11762
  }
11724
- const relToService = toPosix(import_node_path38.default.relative(service.dir, file));
11763
+ const relToService = toPosix(import_node_path39.default.relative(service.dir, file));
11725
11764
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11726
11765
  graph,
11727
11766
  service.pkg.name,
@@ -11737,7 +11776,7 @@ async function addConfigNodes(graph, services, scanPath) {
11737
11776
  type: import_types25.EdgeType.CONFIGURED_BY,
11738
11777
  provenance: import_types25.Provenance.EXTRACTED,
11739
11778
  confidence: (0, import_types25.confidenceForExtracted)("structural"),
11740
- evidence: { file: relPath.split(import_node_path38.default.sep).join("/") }
11779
+ evidence: { file: relPath.split(import_node_path39.default.sep).join("/") }
11741
11780
  };
11742
11781
  if (!graph.hasEdge(edge.id)) {
11743
11782
  graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
@@ -11750,8 +11789,8 @@ async function addConfigNodes(graph, services, scanPath) {
11750
11789
 
11751
11790
  // src/extract/proto.ts
11752
11791
  init_cjs_shims();
11753
- var import_node_fs27 = require("fs");
11754
- var import_node_path39 = __toESM(require("path"), 1);
11792
+ var import_node_fs28 = require("fs");
11793
+ var import_node_path40 = __toESM(require("path"), 1);
11755
11794
  var import_types26 = require("@neat.is/types");
11756
11795
  var PROTO_EXTENSION = ".proto";
11757
11796
  function packageOf(content) {
@@ -11778,10 +11817,10 @@ function grpcMethodsFromProto(content, fqPackage) {
11778
11817
  }
11779
11818
  const body = content.slice(bodyStart, i - 1);
11780
11819
  const rpcRe = /\brpc\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/g;
11781
- let rm;
11782
- while ((rm = rpcRe.exec(body)) !== null) {
11783
- const rpcMethod = rm[1];
11784
- const line = lineAt(content, bodyStart + rm.index);
11820
+ let rm2;
11821
+ while ((rm2 = rpcRe.exec(body)) !== null) {
11822
+ const rpcMethod = rm2[1];
11823
+ const line = lineAt(content, bodyStart + rm2.index);
11785
11824
  out.push({ rpcService, rpcMethod, line });
11786
11825
  }
11787
11826
  serviceRe.lastIndex = i;
@@ -11789,18 +11828,18 @@ function grpcMethodsFromProto(content, fqPackage) {
11789
11828
  return out;
11790
11829
  }
11791
11830
  async function walkProtoFiles(dir, excludeDirs = []) {
11792
- const excluded = new Set(excludeDirs.map((d) => import_node_path39.default.resolve(d)));
11831
+ const excluded = new Set(excludeDirs.map((d) => import_node_path40.default.resolve(d)));
11793
11832
  const out = [];
11794
11833
  async function walk11(current) {
11795
- const entries = await import_node_fs27.promises.readdir(current, { withFileTypes: true }).catch(() => []);
11834
+ const entries = await import_node_fs28.promises.readdir(current, { withFileTypes: true }).catch(() => []);
11796
11835
  for (const entry of entries) {
11797
- const full = import_node_path39.default.join(current, entry.name);
11836
+ const full = import_node_path40.default.join(current, entry.name);
11798
11837
  if (entry.isDirectory()) {
11799
11838
  if (IGNORED_DIRS.has(entry.name)) continue;
11800
- if (excluded.has(import_node_path39.default.resolve(full))) continue;
11839
+ if (excluded.has(import_node_path40.default.resolve(full))) continue;
11801
11840
  if (await isPythonVenvDir(full)) continue;
11802
11841
  await walk11(full);
11803
- } else if (entry.isFile() && import_node_path39.default.extname(entry.name) === PROTO_EXTENSION) {
11842
+ } else if (entry.isFile() && import_node_path40.default.extname(entry.name) === PROTO_EXTENSION) {
11804
11843
  out.push(full);
11805
11844
  }
11806
11845
  }
@@ -11815,10 +11854,10 @@ async function addGrpcMethods(graph, services) {
11815
11854
  const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs);
11816
11855
  for (const protoPath of protoPaths) {
11817
11856
  if (isTestPath(protoPath)) continue;
11818
- const relFile = toPosix(import_node_path39.default.relative(service.dir, protoPath));
11857
+ const relFile = toPosix(import_node_path40.default.relative(service.dir, protoPath));
11819
11858
  let content;
11820
11859
  try {
11821
- content = await import_node_fs27.promises.readFile(protoPath, "utf8");
11860
+ content = await import_node_fs28.promises.readFile(protoPath, "utf8");
11822
11861
  } catch (err) {
11823
11862
  recordExtractionError("proto extraction", protoPath, err);
11824
11863
  continue;
@@ -11877,7 +11916,7 @@ var import_types46 = require("@neat.is/types");
11877
11916
 
11878
11917
  // src/extract/calls/http.ts
11879
11918
  init_cjs_shims();
11880
- var import_node_path40 = __toESM(require("path"), 1);
11919
+ var import_node_path41 = __toESM(require("path"), 1);
11881
11920
  var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
11882
11921
  var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
11883
11922
  var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
@@ -11960,7 +11999,7 @@ async function addHttpCallEdges(graph, services) {
11960
11999
  const seen = /* @__PURE__ */ new Set();
11961
12000
  for (const file of files) {
11962
12001
  if (isTestPath(file.path)) continue;
11963
- const parser = parserForExt(import_node_path40.default.extname(file.path), parserCache);
12002
+ const parser = parserForExt(import_node_path41.default.extname(file.path), parserCache);
11964
12003
  let sites;
11965
12004
  try {
11966
12005
  sites = callsFromSource(file.content, parser, knownHosts);
@@ -11969,7 +12008,7 @@ async function addHttpCallEdges(graph, services) {
11969
12008
  continue;
11970
12009
  }
11971
12010
  if (sites.length === 0) continue;
11972
- const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
12011
+ const relFile = toPosix(import_node_path41.default.relative(service.dir, file.path));
11973
12012
  for (const site of sites) {
11974
12013
  const targetId = hostToNodeId.get(site.host);
11975
12014
  if (!targetId || targetId === service.node.id) continue;
@@ -12023,7 +12062,7 @@ async function addHttpCallEdges(graph, services) {
12023
12062
 
12024
12063
  // src/extract/calls/route-match.ts
12025
12064
  init_cjs_shims();
12026
- var import_node_path41 = __toESM(require("path"), 1);
12065
+ var import_node_path42 = __toESM(require("path"), 1);
12027
12066
  var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
12028
12067
  var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
12029
12068
  var import_types28 = require("@neat.is/types");
@@ -12301,7 +12340,7 @@ async function addRouteCallEdges(graph, services) {
12301
12340
  const seen = /* @__PURE__ */ new Set();
12302
12341
  for (const file of files) {
12303
12342
  if (isTestPath(file.path)) continue;
12304
- if (!JS_CLIENT_EXTENSIONS.has(import_node_path41.default.extname(file.path))) continue;
12343
+ if (!JS_CLIENT_EXTENSIONS.has(import_node_path42.default.extname(file.path))) continue;
12305
12344
  let sites;
12306
12345
  try {
12307
12346
  sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
@@ -12310,7 +12349,7 @@ async function addRouteCallEdges(graph, services) {
12310
12349
  continue;
12311
12350
  }
12312
12351
  if (sites.length === 0) continue;
12313
- const relFile = toPosix(import_node_path41.default.relative(service.dir, file.path));
12352
+ const relFile = toPosix(import_node_path42.default.relative(service.dir, file.path));
12314
12353
  for (const site of sites) {
12315
12354
  if (site.host === null) {
12316
12355
  const dedupKey2 = `${relFile}|unresolved-host`;
@@ -12403,7 +12442,7 @@ async function addRouteCallEdges(graph, services) {
12403
12442
 
12404
12443
  // src/extract/calls/kafka.ts
12405
12444
  init_cjs_shims();
12406
- var import_node_path42 = __toESM(require("path"), 1);
12445
+ var import_node_path43 = __toESM(require("path"), 1);
12407
12446
  var import_types29 = require("@neat.is/types");
12408
12447
  var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
12409
12448
  var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
@@ -12491,13 +12530,13 @@ function kafkaEndpointsFromFile(file, serviceDir) {
12491
12530
  // call sites — verified-call-site tier (ADR-066).
12492
12531
  confidenceKind: "verified-call-site",
12493
12532
  evidence: {
12494
- file: import_node_path42.default.relative(serviceDir, file.path),
12533
+ file: import_node_path43.default.relative(serviceDir, file.path),
12495
12534
  line,
12496
12535
  snippet: snippet(file.content, line)
12497
12536
  }
12498
12537
  });
12499
12538
  };
12500
- if (import_node_path42.default.extname(file.path) === ".go") {
12539
+ if (import_node_path43.default.extname(file.path) === ".go") {
12501
12540
  goSaramaEndpoints(file.content, make);
12502
12541
  } else {
12503
12542
  for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
@@ -12508,7 +12547,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
12508
12547
 
12509
12548
  // src/extract/calls/redis.ts
12510
12549
  init_cjs_shims();
12511
- var import_node_path43 = __toESM(require("path"), 1);
12550
+ var import_node_path44 = __toESM(require("path"), 1);
12512
12551
  var import_types30 = require("@neat.is/types");
12513
12552
  var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
12514
12553
  function redisEndpointsFromFile(file, serviceDir) {
@@ -12531,7 +12570,7 @@ function redisEndpointsFromFile(file, serviceDir) {
12531
12570
  // support tier (ADR-066).
12532
12571
  confidenceKind: "url-with-structural-support",
12533
12572
  evidence: {
12534
- file: import_node_path43.default.relative(serviceDir, file.path),
12573
+ file: import_node_path44.default.relative(serviceDir, file.path),
12535
12574
  line,
12536
12575
  snippet: snippet(file.content, line)
12537
12576
  }
@@ -12542,7 +12581,7 @@ function redisEndpointsFromFile(file, serviceDir) {
12542
12581
 
12543
12582
  // src/extract/calls/aws.ts
12544
12583
  init_cjs_shims();
12545
- var import_node_path44 = __toESM(require("path"), 1);
12584
+ var import_node_path45 = __toESM(require("path"), 1);
12546
12585
  var import_types31 = require("@neat.is/types");
12547
12586
  var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
12548
12587
  var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
@@ -12576,7 +12615,7 @@ function awsEndpointsFromFile(file, serviceDir) {
12576
12615
  // (ADR-066).
12577
12616
  confidenceKind: "verified-call-site",
12578
12617
  evidence: {
12579
- file: import_node_path44.default.relative(serviceDir, file.path),
12618
+ file: import_node_path45.default.relative(serviceDir, file.path),
12580
12619
  line,
12581
12620
  snippet: snippet(file.content, line)
12582
12621
  }
@@ -12601,7 +12640,7 @@ function awsEndpointsFromFile(file, serviceDir) {
12601
12640
 
12602
12641
  // src/extract/calls/grpc.ts
12603
12642
  init_cjs_shims();
12604
- var import_node_path45 = __toESM(require("path"), 1);
12643
+ var import_node_path46 = __toESM(require("path"), 1);
12605
12644
  var import_types32 = require("@neat.is/types");
12606
12645
  var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
12607
12646
  var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
@@ -12660,7 +12699,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
12660
12699
  // tier (ADR-066).
12661
12700
  confidenceKind: "verified-call-site",
12662
12701
  evidence: {
12663
- file: import_node_path45.default.relative(serviceDir, file.path),
12702
+ file: import_node_path46.default.relative(serviceDir, file.path),
12664
12703
  line,
12665
12704
  snippet: snippet(file.content, line)
12666
12705
  }
@@ -12671,7 +12710,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
12671
12710
 
12672
12711
  // src/extract/calls/supabase.ts
12673
12712
  init_cjs_shims();
12674
- var import_node_path46 = __toESM(require("path"), 1);
12713
+ var import_node_path47 = __toESM(require("path"), 1);
12675
12714
  var import_types33 = require("@neat.is/types");
12676
12715
  var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
12677
12716
  var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
@@ -12730,7 +12769,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12730
12769
  // tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
12731
12770
  confidenceKind: "verified-call-site",
12732
12771
  evidence: {
12733
- file: import_node_path46.default.relative(serviceDir, file.path),
12772
+ file: import_node_path47.default.relative(serviceDir, file.path),
12734
12773
  line,
12735
12774
  snippet: snippet(file.content, line)
12736
12775
  }
@@ -12757,7 +12796,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12757
12796
  edgeType: "CALLS",
12758
12797
  confidenceKind: "verified-call-site",
12759
12798
  evidence: {
12760
- file: import_node_path46.default.relative(serviceDir, file.path),
12799
+ file: import_node_path47.default.relative(serviceDir, file.path),
12761
12800
  line,
12762
12801
  snippet: snippet(file.content, line)
12763
12802
  }
@@ -12769,7 +12808,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
12769
12808
 
12770
12809
  // src/extract/calls/firestore.ts
12771
12810
  init_cjs_shims();
12772
- var import_node_path47 = __toESM(require("path"), 1);
12811
+ var import_node_path48 = __toESM(require("path"), 1);
12773
12812
  var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
12774
12813
  var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
12775
12814
  var import_types34 = require("@neat.is/types");
@@ -12942,7 +12981,7 @@ function firestoreEndpointsFromFile(file, serviceDir, imported) {
12942
12981
  if (!hasClient && !hasAdmin && importedNames.size === 0) return [];
12943
12982
  const ownSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12944
12983
  const fileSdk = !hasClient && !hasAdmin ? imported?.sdk ?? null : ownSdk;
12945
- const tree = parseSource3(parserForExt2(import_node_path47.default.extname(file.path)), file.content);
12984
+ const tree = parseSource3(parserForExt2(import_node_path48.default.extname(file.path)), file.content);
12946
12985
  const clientVars = firestoreClientVars(tree.rootNode);
12947
12986
  for (const n of importedNames) clientVars.add(n);
12948
12987
  const collLine = /* @__PURE__ */ new Map();
@@ -13047,7 +13086,7 @@ function firestoreEndpointsFromFile(file, serviceDir, imported) {
13047
13086
  ...columnSet.size > 0 ? { columns: [...columnSet] } : {},
13048
13087
  ...sdkWrites ? { sdkWrites } : {},
13049
13088
  evidence: {
13050
- file: import_node_path47.default.relative(serviceDir, file.path),
13089
+ file: import_node_path48.default.relative(serviceDir, file.path),
13051
13090
  line,
13052
13091
  snippet: snippet(file.content, line)
13053
13092
  }
@@ -13107,7 +13146,7 @@ function sdkOf(content) {
13107
13146
  return hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
13108
13147
  }
13109
13148
  function parseOrNull(file) {
13110
- const ext = import_node_path47.default.extname(file.path);
13149
+ const ext = import_node_path48.default.extname(file.path);
13111
13150
  if (!(ext in GRAMMAR_BY_EXT)) return null;
13112
13151
  try {
13113
13152
  return parseSource3(parserForExt2(ext), file.content).rootNode;
@@ -13123,7 +13162,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
13123
13162
  if (!root) continue;
13124
13163
  const names = exportedFirestoreClients(root);
13125
13164
  if (names.size === 0) continue;
13126
- registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
13165
+ registry.set(toPosix(import_node_path48.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
13127
13166
  }
13128
13167
  if (registry.size === 0) return [];
13129
13168
  const out = [];
@@ -13136,7 +13175,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
13136
13175
  const names = /* @__PURE__ */ new Set();
13137
13176
  let sdk = null;
13138
13177
  for (const b of bindings) {
13139
- const rel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
13178
+ const rel = await resolveJsImport(b.specifier, import_node_path48.default.dirname(f.path), serviceDir, null);
13140
13179
  if (!rel) continue;
13141
13180
  const entry = registry.get(rel);
13142
13181
  if (!entry || !entry.names.has(b.imported)) continue;
@@ -13151,7 +13190,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
13151
13190
 
13152
13191
  // src/extract/calls/mongoose.ts
13153
13192
  init_cjs_shims();
13154
- var import_node_path48 = __toESM(require("path"), 1);
13193
+ var import_node_path49 = __toESM(require("path"), 1);
13155
13194
  var import_types35 = require("@neat.is/types");
13156
13195
  var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
13157
13196
  var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
@@ -13302,7 +13341,7 @@ function endpoint(r, file, serviceDir, matchText) {
13302
13341
  kind: r.kind,
13303
13342
  edgeType: "CALLS",
13304
13343
  confidenceKind: "verified-call-site",
13305
- evidence: { file: import_node_path48.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13344
+ evidence: { file: import_node_path49.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13306
13345
  };
13307
13346
  }
13308
13347
  function mongooseEndpointsFromFile(file, serviceDir) {
@@ -13392,7 +13431,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13392
13431
  const registry = /* @__PURE__ */ new Map();
13393
13432
  for (const f of mongooseFiles) {
13394
13433
  const fx = fileExportsOf(f.content, pluralizeOn);
13395
- if (fx) registry.set(toPosix(import_node_path48.default.relative(serviceDir, f.path)), fx);
13434
+ if (fx) registry.set(toPosix(import_node_path49.default.relative(serviceDir, f.path)), fx);
13396
13435
  }
13397
13436
  if (registry.size === 0) return [];
13398
13437
  const out = [];
@@ -13403,7 +13442,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13403
13442
  const directColl = /* @__PURE__ */ new Map();
13404
13443
  const nsExports = /* @__PURE__ */ new Map();
13405
13444
  for (const b of bindings) {
13406
- const resolvedRel = await resolveJsImport(b.specifier, import_node_path48.default.dirname(f.path), serviceDir, null);
13445
+ const resolvedRel = await resolveJsImport(b.specifier, import_node_path49.default.dirname(f.path), serviceDir, null);
13407
13446
  if (!resolvedRel) continue;
13408
13447
  const fx = registry.get(resolvedRel);
13409
13448
  if (!fx) continue;
@@ -13447,7 +13486,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
13447
13486
 
13448
13487
  // src/extract/calls/sqlalchemy.ts
13449
13488
  init_cjs_shims();
13450
- var import_node_path49 = __toESM(require("path"), 1);
13489
+ var import_node_path50 = __toESM(require("path"), 1);
13451
13490
  var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
13452
13491
  var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
13453
13492
  var import_types36 = require("@neat.is/types");
@@ -13586,7 +13625,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
13586
13625
  childTable,
13587
13626
  parentTable,
13588
13627
  evidence: {
13589
- file: import_node_path49.default.relative(serviceDir, file.path),
13628
+ file: import_node_path50.default.relative(serviceDir, file.path),
13590
13629
  line,
13591
13630
  snippet: snippet(file.content, line)
13592
13631
  }
@@ -13611,7 +13650,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
13611
13650
  confidenceKind: "verified-call-site",
13612
13651
  ...columns && columns.length > 0 ? { columns } : {},
13613
13652
  evidence: {
13614
- file: import_node_path49.default.relative(serviceDir, file.path),
13653
+ file: import_node_path50.default.relative(serviceDir, file.path),
13615
13654
  line,
13616
13655
  snippet: snippet(file.content, line)
13617
13656
  }
@@ -13718,7 +13757,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
13718
13757
  edgeType: "CALLS",
13719
13758
  confidenceKind: "verified-call-site",
13720
13759
  evidence: {
13721
- file: import_node_path49.default.relative(serviceDir, file.path),
13760
+ file: import_node_path50.default.relative(serviceDir, file.path),
13722
13761
  line,
13723
13762
  snippet: snippet(file.content, line)
13724
13763
  }
@@ -13730,7 +13769,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
13730
13769
 
13731
13770
  // src/extract/calls/socket.ts
13732
13771
  init_cjs_shims();
13733
- var import_node_path50 = __toESM(require("path"), 1);
13772
+ var import_node_path51 = __toESM(require("path"), 1);
13734
13773
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
13735
13774
  var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
13736
13775
  var import_types37 = require("@neat.is/types");
@@ -13806,7 +13845,7 @@ function socketEndpointsFromFile(file, serviceDir) {
13806
13845
  // A verified `socket.socket(...)` + `.connect((host, port))` call site.
13807
13846
  confidenceKind: "verified-call-site",
13808
13847
  evidence: {
13809
- file: import_node_path50.default.relative(serviceDir, file.path),
13848
+ file: import_node_path51.default.relative(serviceDir, file.path),
13810
13849
  line,
13811
13850
  snippet: snippet(file.content, line)
13812
13851
  }
@@ -13817,7 +13856,7 @@ function socketEndpointsFromFile(file, serviceDir) {
13817
13856
 
13818
13857
  // src/extract/calls/django-orm.ts
13819
13858
  init_cjs_shims();
13820
- var import_node_path51 = __toESM(require("path"), 1);
13859
+ var import_node_path52 = __toESM(require("path"), 1);
13821
13860
  var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
13822
13861
  var import_tree_sitter_python7 = __toESM(require("tree-sitter-python"), 1);
13823
13862
  var import_types38 = require("@neat.is/types");
@@ -13887,7 +13926,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13887
13926
  const tree = parseSource8(makePyParser5(), file.content);
13888
13927
  const out = [];
13889
13928
  const seen = /* @__PURE__ */ new Set();
13890
- const defaultAppLabel = import_node_path51.default.basename(import_node_path51.default.dirname(file.path));
13929
+ const defaultAppLabel = import_node_path52.default.basename(import_node_path52.default.dirname(file.path));
13891
13930
  walk5(tree.rootNode, (node) => {
13892
13931
  if (node.type !== "class_definition") return;
13893
13932
  if (!extendsDjangoModel(node)) return;
@@ -13905,7 +13944,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13905
13944
  kind: "sql-table",
13906
13945
  edgeType: "CALLS",
13907
13946
  confidenceKind: "verified-call-site",
13908
- evidence: { file: import_node_path51.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13947
+ evidence: { file: import_node_path52.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
13909
13948
  });
13910
13949
  });
13911
13950
  return out;
@@ -13913,7 +13952,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13913
13952
 
13914
13953
  // src/extract/calls/drizzle.ts
13915
13954
  init_cjs_shims();
13916
- var import_node_path52 = __toESM(require("path"), 1);
13955
+ var import_node_path53 = __toESM(require("path"), 1);
13917
13956
  var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
13918
13957
  var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
13919
13958
  var import_types39 = require("@neat.is/types");
@@ -13991,7 +14030,7 @@ function columnsFromObject(obj) {
13991
14030
  }
13992
14031
  function drizzleEndpointsFromFile(file, serviceDir) {
13993
14032
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
13994
- const tree = parseSource3(parserForExt3(import_node_path52.default.extname(file.path)), file.content);
14033
+ const tree = parseSource3(parserForExt3(import_node_path53.default.extname(file.path)), file.content);
13995
14034
  const out = [];
13996
14035
  const seen = /* @__PURE__ */ new Set();
13997
14036
  const walk11 = (node) => {
@@ -14014,7 +14053,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
14014
14053
  confidenceKind: "structural",
14015
14054
  columns,
14016
14055
  evidence: {
14017
- file: import_node_path52.default.relative(serviceDir, file.path),
14056
+ file: import_node_path53.default.relative(serviceDir, file.path),
14018
14057
  line,
14019
14058
  snippet: snippet(file.content, line)
14020
14059
  }
@@ -14080,7 +14119,7 @@ function referencesTargetVar(call) {
14080
14119
  }
14081
14120
  function drizzleForeignKeys(file, serviceDir) {
14082
14121
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
14083
- const tree = parseSource3(parserForExt3(import_node_path52.default.extname(file.path)), file.content);
14122
+ const tree = parseSource3(parserForExt3(import_node_path53.default.extname(file.path)), file.content);
14084
14123
  const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
14085
14124
  const out = [];
14086
14125
  const seen = /* @__PURE__ */ new Set();
@@ -14099,7 +14138,7 @@ function drizzleForeignKeys(file, serviceDir) {
14099
14138
  childTable: table.tableName,
14100
14139
  parentTable,
14101
14140
  evidence: {
14102
- file: import_node_path52.default.relative(serviceDir, file.path),
14141
+ file: import_node_path53.default.relative(serviceDir, file.path),
14103
14142
  line,
14104
14143
  snippet: snippet(file.content, line)
14105
14144
  }
@@ -14116,7 +14155,7 @@ function drizzleForeignKeys(file, serviceDir) {
14116
14155
 
14117
14156
  // src/extract/calls/prisma.ts
14118
14157
  init_cjs_shims();
14119
- var import_node_path53 = __toESM(require("path"), 1);
14158
+ var import_node_path54 = __toESM(require("path"), 1);
14120
14159
  var import_types40 = require("@neat.is/types");
14121
14160
  var SCALAR_TYPES = /* @__PURE__ */ new Set([
14122
14161
  "Int",
@@ -14172,7 +14211,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
14172
14211
  confidenceKind: "structural",
14173
14212
  columns: b.columns,
14174
14213
  evidence: {
14175
- file: import_node_path53.default.relative(serviceDir, file.path),
14214
+ file: import_node_path54.default.relative(serviceDir, file.path),
14176
14215
  line: b.startLine,
14177
14216
  snippet: snippet(content, b.startLine)
14178
14217
  }
@@ -14233,7 +14272,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
14233
14272
  }
14234
14273
  async function prismaColumnEndpoints(serviceDir) {
14235
14274
  const schemaPath = await findFirst(serviceDir, [
14236
- import_node_path53.default.join("prisma", "schema.prisma"),
14275
+ import_node_path54.default.join("prisma", "schema.prisma"),
14237
14276
  "schema.prisma"
14238
14277
  ]);
14239
14278
  if (!schemaPath) return [];
@@ -14308,7 +14347,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
14308
14347
  childTable: current.table,
14309
14348
  parentTable,
14310
14349
  evidence: {
14311
- file: import_node_path53.default.relative(serviceDir, file.path),
14350
+ file: import_node_path54.default.relative(serviceDir, file.path),
14312
14351
  line: lineNo,
14313
14352
  snippet: snippet(content, lineNo)
14314
14353
  }
@@ -14323,7 +14362,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
14323
14362
  }
14324
14363
  async function prismaForeignKeys(serviceDir) {
14325
14364
  const schemaPath = await findFirst(serviceDir, [
14326
- import_node_path53.default.join("prisma", "schema.prisma"),
14365
+ import_node_path54.default.join("prisma", "schema.prisma"),
14327
14366
  "schema.prisma"
14328
14367
  ]);
14329
14368
  if (!schemaPath) return [];
@@ -14334,7 +14373,7 @@ async function prismaForeignKeys(serviceDir) {
14334
14373
 
14335
14374
  // src/extract/calls/activerecord.ts
14336
14375
  init_cjs_shims();
14337
- var import_node_path54 = __toESM(require("path"), 1);
14376
+ var import_node_path55 = __toESM(require("path"), 1);
14338
14377
  var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
14339
14378
  var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
14340
14379
  var import_types41 = require("@neat.is/types");
@@ -14542,7 +14581,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
14542
14581
  confidenceKind: "structural",
14543
14582
  ...table.columns.length > 0 ? { columns: table.columns } : {},
14544
14583
  evidence: {
14545
- file: import_node_path54.default.relative(serviceDir, file.path),
14584
+ file: import_node_path55.default.relative(serviceDir, file.path),
14546
14585
  line: table.line,
14547
14586
  snippet: snippet(file.content, table.line)
14548
14587
  }
@@ -14564,7 +14603,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
14564
14603
  childTable,
14565
14604
  parentTable,
14566
14605
  evidence: {
14567
- file: import_node_path54.default.relative(serviceDir, file.path),
14606
+ file: import_node_path55.default.relative(serviceDir, file.path),
14568
14607
  line,
14569
14608
  snippet: snippet(file.content, line)
14570
14609
  }
@@ -14647,7 +14686,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
14647
14686
  edgeType: "CALLS",
14648
14687
  confidenceKind: "verified-call-site",
14649
14688
  evidence: {
14650
- file: import_node_path54.default.relative(serviceDir, file.path),
14689
+ file: import_node_path55.default.relative(serviceDir, file.path),
14651
14690
  line,
14652
14691
  snippet: snippet(file.content, line)
14653
14692
  }
@@ -14684,7 +14723,7 @@ function railsModelForeignKeys(file, serviceDir) {
14684
14723
  childTable,
14685
14724
  parentTable,
14686
14725
  evidence: {
14687
- file: import_node_path54.default.relative(serviceDir, file.path),
14726
+ file: import_node_path55.default.relative(serviceDir, file.path),
14688
14727
  line,
14689
14728
  snippet: snippet(file.content, line)
14690
14729
  }
@@ -14696,7 +14735,7 @@ function railsModelForeignKeys(file, serviceDir) {
14696
14735
 
14697
14736
  // src/extract/calls/eloquent.ts
14698
14737
  init_cjs_shims();
14699
- var import_node_path55 = __toESM(require("path"), 1);
14738
+ var import_node_path56 = __toESM(require("path"), 1);
14700
14739
  var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
14701
14740
  var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
14702
14741
  var import_types42 = require("@neat.is/types");
@@ -14953,7 +14992,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
14953
14992
  confidenceKind: "structural",
14954
14993
  ...columns.length > 0 ? { columns } : {},
14955
14994
  evidence: {
14956
- file: import_node_path55.default.relative(serviceDir, file.path),
14995
+ file: import_node_path56.default.relative(serviceDir, file.path),
14957
14996
  line: bp.line,
14958
14997
  snippet: snippet(file.content, bp.line)
14959
14998
  }
@@ -14975,7 +15014,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
14975
15014
  childTable,
14976
15015
  parentTable,
14977
15016
  evidence: {
14978
- file: import_node_path55.default.relative(serviceDir, file.path),
15017
+ file: import_node_path56.default.relative(serviceDir, file.path),
14979
15018
  line,
14980
15019
  snippet: snippet(file.content, line)
14981
15020
  }
@@ -15095,7 +15134,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
15095
15134
  edgeType: "CALLS",
15096
15135
  confidenceKind: "verified-call-site",
15097
15136
  evidence: {
15098
- file: import_node_path55.default.relative(serviceDir, file.path),
15137
+ file: import_node_path56.default.relative(serviceDir, file.path),
15099
15138
  line,
15100
15139
  snippet: snippet(file.content, line)
15101
15140
  }
@@ -15131,7 +15170,7 @@ function laravelModelForeignKeys(file, serviceDir) {
15131
15170
  childTable,
15132
15171
  parentTable,
15133
15172
  evidence: {
15134
- file: import_node_path55.default.relative(serviceDir, file.path),
15173
+ file: import_node_path56.default.relative(serviceDir, file.path),
15135
15174
  line,
15136
15175
  snippet: snippet(file.content, line)
15137
15176
  }
@@ -15143,7 +15182,7 @@ function laravelModelForeignKeys(file, serviceDir) {
15143
15182
 
15144
15183
  // src/extract/calls/go.ts
15145
15184
  init_cjs_shims();
15146
- var import_node_path58 = __toESM(require("path"), 1);
15185
+ var import_node_path59 = __toESM(require("path"), 1);
15147
15186
  var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
15148
15187
  var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
15149
15188
  var import_types43 = require("@neat.is/types");
@@ -15218,7 +15257,7 @@ function firstStringLiteralArg(argsNode) {
15218
15257
  return null;
15219
15258
  }
15220
15259
  function goSqlEndpointsFromFile(file, serviceDir) {
15221
- if (import_node_path58.default.extname(file.path) !== ".go") return [];
15260
+ if (import_node_path59.default.extname(file.path) !== ".go") return [];
15222
15261
  if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
15223
15262
  const tree = parseSource11(makeGoParser3(), file.content);
15224
15263
  const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
@@ -15247,7 +15286,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
15247
15286
  confidenceKind: "verified-call-site",
15248
15287
  ...columns.length > 0 ? { columns } : {},
15249
15288
  evidence: {
15250
- file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
15289
+ file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15251
15290
  line,
15252
15291
  snippet: snippet(file.content, line)
15253
15292
  }
@@ -15258,7 +15297,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
15258
15297
 
15259
15298
  // src/extract/calls/gorm.ts
15260
15299
  init_cjs_shims();
15261
- var import_node_path59 = __toESM(require("path"), 1);
15300
+ var import_node_path60 = __toESM(require("path"), 1);
15262
15301
  var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
15263
15302
  var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
15264
15303
  var import_types44 = require("@neat.is/types");
@@ -15691,7 +15730,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
15691
15730
  seen.delete(struct.name);
15692
15731
  }
15693
15732
  function gormEndpointsFromFile(file, serviceDir) {
15694
- if (import_node_path59.default.extname(file.path) !== ".go") return [];
15733
+ if (import_node_path60.default.extname(file.path) !== ".go") return [];
15695
15734
  if (!GORM_IMPORT_RE.test(file.content)) return [];
15696
15735
  const tree = parseSource12(makeGoParser4(), file.content);
15697
15736
  const { structs, models, tableFor } = analyze(tree);
@@ -15713,7 +15752,7 @@ function gormEndpointsFromFile(file, serviceDir) {
15713
15752
  confidenceKind: "structural",
15714
15753
  ...columns.length > 0 ? { columns } : {},
15715
15754
  evidence: {
15716
- file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15755
+ file: toPosix(import_node_path60.default.relative(serviceDir, file.path)),
15717
15756
  line: struct.line,
15718
15757
  snippet: snippet(file.content, struct.line)
15719
15758
  }
@@ -15722,7 +15761,7 @@ function gormEndpointsFromFile(file, serviceDir) {
15722
15761
  return out;
15723
15762
  }
15724
15763
  function gormForeignKeys(file, serviceDir) {
15725
- if (import_node_path59.default.extname(file.path) !== ".go") return [];
15764
+ if (import_node_path60.default.extname(file.path) !== ".go") return [];
15726
15765
  if (!GORM_IMPORT_RE.test(file.content)) return [];
15727
15766
  const tree = parseSource12(makeGoParser4(), file.content);
15728
15767
  const { structs, models, tableFor } = analyze(tree);
@@ -15737,7 +15776,7 @@ function gormForeignKeys(file, serviceDir) {
15737
15776
  childTable,
15738
15777
  parentTable,
15739
15778
  evidence: {
15740
- file: toPosix(import_node_path59.default.relative(serviceDir, file.path)),
15779
+ file: toPosix(import_node_path60.default.relative(serviceDir, file.path)),
15741
15780
  line,
15742
15781
  snippet: snippet(file.content, line)
15743
15782
  }
@@ -15774,7 +15813,7 @@ function gormForeignKeys(file, serviceDir) {
15774
15813
 
15775
15814
  // src/extract/calls/efcore.ts
15776
15815
  init_cjs_shims();
15777
- var import_node_path60 = __toESM(require("path"), 1);
15816
+ var import_node_path61 = __toESM(require("path"), 1);
15778
15817
  var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
15779
15818
  var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
15780
15819
  var import_types45 = require("@neat.is/types");
@@ -15853,7 +15892,7 @@ function tableFromToTable(call) {
15853
15892
  return value ? csStringLiteral(value) : null;
15854
15893
  }
15855
15894
  function efcoreEndpointsFromFile(file, serviceDir) {
15856
- if (import_node_path60.default.extname(file.path) !== ".cs") return [];
15895
+ if (import_node_path61.default.extname(file.path) !== ".cs") return [];
15857
15896
  if (!EFCORE_GATE.test(file.content)) return [];
15858
15897
  const tree = parseSource13(makeCsParser(), file.content);
15859
15898
  const out = [];
@@ -15868,7 +15907,7 @@ function efcoreEndpointsFromFile(file, serviceDir) {
15868
15907
  edgeType: "CALLS",
15869
15908
  confidenceKind: "structural",
15870
15909
  evidence: {
15871
- file: toPosix(import_node_path60.default.relative(serviceDir, file.path)),
15910
+ file: toPosix(import_node_path61.default.relative(serviceDir, file.path)),
15872
15911
  line,
15873
15912
  snippet: snippet(file.content, line)
15874
15913
  }
@@ -16123,7 +16162,7 @@ init_cjs_shims();
16123
16162
 
16124
16163
  // src/extract/infra/docker-compose.ts
16125
16164
  init_cjs_shims();
16126
- var import_node_path61 = __toESM(require("path"), 1);
16165
+ var import_node_path62 = __toESM(require("path"), 1);
16127
16166
  var import_types49 = require("@neat.is/types");
16128
16167
 
16129
16168
  // src/extract/infra/shared.ts
@@ -16194,7 +16233,7 @@ function dependsOnList(value) {
16194
16233
  }
16195
16234
  function serviceNameToServiceNode(name, services) {
16196
16235
  for (const s of services) {
16197
- if (s.node.name === name || import_node_path61.default.basename(s.dir) === name) return s.node.id;
16236
+ if (s.node.name === name || import_node_path62.default.basename(s.dir) === name) return s.node.id;
16198
16237
  }
16199
16238
  return null;
16200
16239
  }
@@ -16203,7 +16242,7 @@ async function addComposeInfra(graph, scanPath, services) {
16203
16242
  let edgesAdded = 0;
16204
16243
  let composePath = null;
16205
16244
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
16206
- const abs = import_node_path61.default.join(scanPath, name);
16245
+ const abs = import_node_path62.default.join(scanPath, name);
16207
16246
  if (await exists2(abs)) {
16208
16247
  composePath = abs;
16209
16248
  break;
@@ -16216,13 +16255,13 @@ async function addComposeInfra(graph, scanPath, services) {
16216
16255
  } catch (err) {
16217
16256
  recordExtractionError(
16218
16257
  "infra docker-compose",
16219
- import_node_path61.default.relative(scanPath, composePath),
16258
+ import_node_path62.default.relative(scanPath, composePath),
16220
16259
  err
16221
16260
  );
16222
16261
  return { nodesAdded, edgesAdded };
16223
16262
  }
16224
16263
  if (!compose?.services) return { nodesAdded, edgesAdded };
16225
- const evidenceFile = import_node_path61.default.relative(scanPath, composePath).split(import_node_path61.default.sep).join("/");
16264
+ const evidenceFile = import_node_path62.default.relative(scanPath, composePath).split(import_node_path62.default.sep).join("/");
16226
16265
  const composeNameToNodeId = /* @__PURE__ */ new Map();
16227
16266
  for (const [composeName, svc] of Object.entries(compose.services)) {
16228
16267
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -16264,8 +16303,8 @@ async function addComposeInfra(graph, scanPath, services) {
16264
16303
 
16265
16304
  // src/extract/infra/dockerfile.ts
16266
16305
  init_cjs_shims();
16267
- var import_node_path62 = __toESM(require("path"), 1);
16268
- var import_node_fs28 = require("fs");
16306
+ var import_node_path63 = __toESM(require("path"), 1);
16307
+ var import_node_fs29 = require("fs");
16269
16308
  var import_types50 = require("@neat.is/types");
16270
16309
  function readDockerfile(content) {
16271
16310
  let image = null;
@@ -16295,15 +16334,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16295
16334
  let nodesAdded = 0;
16296
16335
  let edgesAdded = 0;
16297
16336
  for (const service of services) {
16298
- const dockerfilePath = import_node_path62.default.join(service.dir, "Dockerfile");
16337
+ const dockerfilePath = import_node_path63.default.join(service.dir, "Dockerfile");
16299
16338
  if (!await exists2(dockerfilePath)) continue;
16300
16339
  let content;
16301
16340
  try {
16302
- content = await import_node_fs28.promises.readFile(dockerfilePath, "utf8");
16341
+ content = await import_node_fs29.promises.readFile(dockerfilePath, "utf8");
16303
16342
  } catch (err) {
16304
16343
  recordExtractionError(
16305
16344
  "infra dockerfile",
16306
- import_node_path62.default.relative(scanPath, dockerfilePath),
16345
+ import_node_path63.default.relative(scanPath, dockerfilePath),
16307
16346
  err
16308
16347
  );
16309
16348
  continue;
@@ -16315,8 +16354,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16315
16354
  graph.addNode(node.id, node);
16316
16355
  nodesAdded++;
16317
16356
  }
16318
- const relDockerfile = toPosix(import_node_path62.default.relative(service.dir, dockerfilePath));
16319
- const evidenceFile = toPosix(import_node_path62.default.relative(scanPath, dockerfilePath));
16357
+ const relDockerfile = toPosix(import_node_path63.default.relative(service.dir, dockerfilePath));
16358
+ const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, dockerfilePath));
16320
16359
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
16321
16360
  graph,
16322
16361
  service.pkg.name,
@@ -16368,23 +16407,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
16368
16407
 
16369
16408
  // src/extract/infra/terraform.ts
16370
16409
  init_cjs_shims();
16371
- var import_node_fs29 = require("fs");
16372
- var import_node_path63 = __toESM(require("path"), 1);
16410
+ var import_node_fs30 = require("fs");
16411
+ var import_node_path64 = __toESM(require("path"), 1);
16373
16412
  var import_types51 = require("@neat.is/types");
16374
16413
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
16375
16414
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
16376
16415
  async function walkTfFiles(start, depth = 0, max = 5) {
16377
16416
  if (depth > max) return [];
16378
16417
  const out = [];
16379
- const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16418
+ const entries = await import_node_fs30.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16380
16419
  for (const entry of entries) {
16381
16420
  if (entry.isDirectory()) {
16382
16421
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
16383
- const child = import_node_path63.default.join(start, entry.name);
16422
+ const child = import_node_path64.default.join(start, entry.name);
16384
16423
  if (await isPythonVenvDir(child)) continue;
16385
16424
  out.push(...await walkTfFiles(child, depth + 1, max));
16386
16425
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
16387
- out.push(import_node_path63.default.join(start, entry.name));
16426
+ out.push(import_node_path64.default.join(start, entry.name));
16388
16427
  }
16389
16428
  }
16390
16429
  return out;
@@ -16415,8 +16454,8 @@ async function addTerraformResources(graph, scanPath) {
16415
16454
  let edgesAdded = 0;
16416
16455
  const files = await walkTfFiles(scanPath);
16417
16456
  for (const file of files) {
16418
- const content = await import_node_fs29.promises.readFile(file, "utf8");
16419
- const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, file));
16457
+ const content = await import_node_fs30.promises.readFile(file, "utf8");
16458
+ const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, file));
16420
16459
  const resources = [];
16421
16460
  const byKey = /* @__PURE__ */ new Map();
16422
16461
  RESOURCE_RE.lastIndex = 0;
@@ -16473,8 +16512,8 @@ async function addTerraformResources(graph, scanPath) {
16473
16512
 
16474
16513
  // src/extract/infra/k8s.ts
16475
16514
  init_cjs_shims();
16476
- var import_node_fs30 = require("fs");
16477
- var import_node_path64 = __toESM(require("path"), 1);
16515
+ var import_node_fs31 = require("fs");
16516
+ var import_node_path65 = __toESM(require("path"), 1);
16478
16517
  var import_yaml3 = require("yaml");
16479
16518
  var import_types52 = require("@neat.is/types");
16480
16519
  var K8S_KIND_TO_INFRA_KIND = {
@@ -16490,15 +16529,15 @@ var WORKLOAD_KINDS = /* @__PURE__ */ new Set(["Deployment", "StatefulSet", "Daem
16490
16529
  async function walkYamlFiles2(start, depth = 0, max = 5) {
16491
16530
  if (depth > max) return [];
16492
16531
  const out = [];
16493
- const entries = await import_node_fs30.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16532
+ const entries = await import_node_fs31.promises.readdir(start, { withFileTypes: true }).catch(() => []);
16494
16533
  for (const entry of entries) {
16495
16534
  if (entry.isDirectory()) {
16496
16535
  if (IGNORED_DIRS.has(entry.name)) continue;
16497
- const child = import_node_path64.default.join(start, entry.name);
16536
+ const child = import_node_path65.default.join(start, entry.name);
16498
16537
  if (await isPythonVenvDir(child)) continue;
16499
16538
  out.push(...await walkYamlFiles2(child, depth + 1, max));
16500
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path64.default.extname(entry.name))) {
16501
- out.push(import_node_path64.default.join(start, entry.name));
16539
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path65.default.extname(entry.name))) {
16540
+ out.push(import_node_path65.default.join(start, entry.name));
16502
16541
  }
16503
16542
  }
16504
16543
  return out;
@@ -16508,14 +16547,14 @@ async function addK8sResources(graph, scanPath) {
16508
16547
  let edgesAdded = 0;
16509
16548
  const files = await walkYamlFiles2(scanPath);
16510
16549
  for (const file of files) {
16511
- const content = await import_node_fs30.promises.readFile(file, "utf8");
16550
+ const content = await import_node_fs31.promises.readFile(file, "utf8");
16512
16551
  let docs;
16513
16552
  try {
16514
16553
  docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
16515
16554
  } catch {
16516
16555
  continue;
16517
16556
  }
16518
- const relFile = toPosix(import_node_path64.default.relative(scanPath, file));
16557
+ const relFile = toPosix(import_node_path65.default.relative(scanPath, file));
16519
16558
  for (const doc of docs) {
16520
16559
  if (!doc?.kind || !doc.metadata?.name) continue;
16521
16560
  const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind];
@@ -16564,16 +16603,16 @@ async function addK8sResources(graph, scanPath) {
16564
16603
 
16565
16604
  // src/extract/infra/cloudflare.ts
16566
16605
  init_cjs_shims();
16567
- var import_node_fs31 = require("fs");
16568
- var import_node_path65 = __toESM(require("path"), 1);
16606
+ var import_node_fs32 = require("fs");
16607
+ var import_node_path66 = __toESM(require("path"), 1);
16569
16608
  var import_smol_toml3 = require("smol-toml");
16570
16609
  var import_types53 = require("@neat.is/types");
16571
16610
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
16572
16611
  async function readWranglerConfig(dir) {
16573
16612
  for (const filename of WRANGLER_FILENAMES) {
16574
- const abs = import_node_path65.default.join(dir, filename);
16613
+ const abs = import_node_path66.default.join(dir, filename);
16575
16614
  if (!await exists2(abs)) continue;
16576
- const raw = await import_node_fs31.promises.readFile(abs, "utf8");
16615
+ const raw = await import_node_fs32.promises.readFile(abs, "utf8");
16577
16616
  const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
16578
16617
  return { config, relFile: filename, raw };
16579
16618
  }
@@ -16634,11 +16673,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16634
16673
  try {
16635
16674
  read = await readWranglerConfig(service.dir);
16636
16675
  } catch (err) {
16637
- recordExtractionError("infra cloudflare", import_node_path65.default.relative(scanPath, service.dir), err);
16676
+ recordExtractionError("infra cloudflare", import_node_path66.default.relative(scanPath, service.dir), err);
16638
16677
  continue;
16639
16678
  }
16640
16679
  if (!read || !read.config.name) continue;
16641
- const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, read.relFile)));
16680
+ const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, read.relFile)));
16642
16681
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
16643
16682
  }
16644
16683
  for (const worker of discovered) {
@@ -16650,7 +16689,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16650
16689
  }
16651
16690
  let anchorId = service.node.id;
16652
16691
  if (config.main) {
16653
- const entryRelPath = toPosix(import_node_path65.default.normalize(config.main));
16692
+ const entryRelPath = toPosix(import_node_path66.default.normalize(config.main));
16654
16693
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
16655
16694
  graph,
16656
16695
  service.pkg.name,
@@ -16797,24 +16836,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
16797
16836
 
16798
16837
  // src/extract/infra/vercel.ts
16799
16838
  init_cjs_shims();
16800
- var import_node_fs32 = require("fs");
16801
- var import_node_path66 = __toESM(require("path"), 1);
16839
+ var import_node_fs33 = require("fs");
16840
+ var import_node_path67 = __toESM(require("path"), 1);
16802
16841
  var import_types54 = require("@neat.is/types");
16803
16842
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
16804
16843
  async function readVercelConfig(dir) {
16805
16844
  for (const filename of VERCEL_CONFIG_FILENAMES) {
16806
- const abs = import_node_path66.default.join(dir, filename);
16845
+ const abs = import_node_path67.default.join(dir, filename);
16807
16846
  if (!await exists2(abs)) continue;
16808
- const raw = await import_node_fs32.promises.readFile(abs, "utf8");
16847
+ const raw = await import_node_fs33.promises.readFile(abs, "utf8");
16809
16848
  const config = JSON.parse(maskCommentsInSource(raw));
16810
16849
  return { config, relFile: filename, raw };
16811
16850
  }
16812
16851
  return null;
16813
16852
  }
16814
16853
  async function readLinkedProjectName(dir) {
16815
- const abs = import_node_path66.default.join(dir, ".vercel", "project.json");
16854
+ const abs = import_node_path67.default.join(dir, ".vercel", "project.json");
16816
16855
  if (!await exists2(abs)) return void 0;
16817
- const parsed = JSON.parse(await import_node_fs32.promises.readFile(abs, "utf8"));
16856
+ const parsed = JSON.parse(await import_node_fs33.promises.readFile(abs, "utf8"));
16818
16857
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
16819
16858
  }
16820
16859
  function routeSource(route) {
@@ -16830,7 +16869,7 @@ async function addVercelServices(graph, services, scanPath) {
16830
16869
  read = await readVercelConfig(service.dir);
16831
16870
  projectName = await readLinkedProjectName(service.dir);
16832
16871
  } catch (err) {
16833
- recordExtractionError("infra vercel", import_node_path66.default.relative(scanPath, service.dir), err);
16872
+ recordExtractionError("infra vercel", import_node_path67.default.relative(scanPath, service.dir), err);
16834
16873
  continue;
16835
16874
  }
16836
16875
  if (!read && !projectName) continue;
@@ -16846,7 +16885,7 @@ async function addVercelServices(graph, services, scanPath) {
16846
16885
  const anchorId = service.node.id;
16847
16886
  if (!read) continue;
16848
16887
  const { config, relFile, raw } = read;
16849
- const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
16888
+ const evidenceFile = toPosix(import_node_path67.default.relative(scanPath, import_node_path67.default.join(service.dir, relFile)));
16850
16889
  const add = (edgeType, kind, name) => {
16851
16890
  if (!name) return;
16852
16891
  const result = emitPlatformResourceEdge(
@@ -16875,16 +16914,16 @@ async function addVercelServices(graph, services, scanPath) {
16875
16914
 
16876
16915
  // src/extract/infra/railway.ts
16877
16916
  init_cjs_shims();
16878
- var import_node_fs33 = require("fs");
16879
- var import_node_path67 = __toESM(require("path"), 1);
16917
+ var import_node_fs34 = require("fs");
16918
+ var import_node_path68 = __toESM(require("path"), 1);
16880
16919
  var import_smol_toml4 = require("smol-toml");
16881
16920
  var import_types55 = require("@neat.is/types");
16882
16921
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
16883
16922
  async function readRailwayConfig(dir) {
16884
16923
  for (const filename of RAILWAY_FILENAMES) {
16885
- const abs = import_node_path67.default.join(dir, filename);
16924
+ const abs = import_node_path68.default.join(dir, filename);
16886
16925
  if (!await exists2(abs)) continue;
16887
- const raw = await import_node_fs33.promises.readFile(abs, "utf8");
16926
+ const raw = await import_node_fs34.promises.readFile(abs, "utf8");
16888
16927
  const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
16889
16928
  return { config, relFile: filename, raw };
16890
16929
  }
@@ -16898,7 +16937,7 @@ async function addRailwayServices(graph, services, scanPath) {
16898
16937
  try {
16899
16938
  read = await readRailwayConfig(service.dir);
16900
16939
  } catch (err) {
16901
- recordExtractionError("infra railway", import_node_path67.default.relative(scanPath, service.dir), err);
16940
+ recordExtractionError("infra railway", import_node_path68.default.relative(scanPath, service.dir), err);
16902
16941
  continue;
16903
16942
  }
16904
16943
  if (!read) continue;
@@ -16908,7 +16947,7 @@ async function addRailwayServices(graph, services, scanPath) {
16908
16947
  }
16909
16948
  const anchorId = service.node.id;
16910
16949
  const { config, relFile, raw } = read;
16911
- const evidenceFile = toPosix(import_node_path67.default.relative(scanPath, import_node_path67.default.join(service.dir, relFile)));
16950
+ const evidenceFile = toPosix(import_node_path68.default.relative(scanPath, import_node_path68.default.join(service.dir, relFile)));
16912
16951
  const add = (edgeType, kind, name) => {
16913
16952
  if (!name) return;
16914
16953
  const result = emitPlatformResourceEdge(
@@ -16933,15 +16972,15 @@ async function addRailwayServices(graph, services, scanPath) {
16933
16972
 
16934
16973
  // src/extract/infra/supabase.ts
16935
16974
  init_cjs_shims();
16936
- var import_node_fs34 = require("fs");
16937
- var import_node_path68 = __toESM(require("path"), 1);
16975
+ var import_node_fs35 = require("fs");
16976
+ var import_node_path69 = __toESM(require("path"), 1);
16938
16977
  var import_smol_toml5 = require("smol-toml");
16939
16978
  var import_types56 = require("@neat.is/types");
16940
16979
  async function readSupabaseConfig(dir) {
16941
- const relFile = import_node_path68.default.join("supabase", "config.toml");
16942
- const abs = import_node_path68.default.join(dir, relFile);
16980
+ const relFile = import_node_path69.default.join("supabase", "config.toml");
16981
+ const abs = import_node_path69.default.join(dir, relFile);
16943
16982
  if (!await exists2(abs)) return null;
16944
- const raw = await import_node_fs34.promises.readFile(abs, "utf8");
16983
+ const raw = await import_node_fs35.promises.readFile(abs, "utf8");
16945
16984
  const config = (0, import_smol_toml5.parse)(raw);
16946
16985
  return { config, relFile, raw };
16947
16986
  }
@@ -16953,7 +16992,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
16953
16992
  try {
16954
16993
  read = await readSupabaseConfig(service.dir);
16955
16994
  } catch (err) {
16956
- recordExtractionError("infra supabase", import_node_path68.default.relative(scanPath, service.dir), err);
16995
+ recordExtractionError("infra supabase", import_node_path69.default.relative(scanPath, service.dir), err);
16957
16996
  continue;
16958
16997
  }
16959
16998
  if (!read) continue;
@@ -16968,7 +17007,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
16968
17007
  });
16969
17008
  }
16970
17009
  const anchorId = service.node.id;
16971
- const evidenceFile = toPosix(import_node_path68.default.relative(scanPath, import_node_path68.default.join(service.dir, relFile)));
17010
+ const evidenceFile = toPosix(import_node_path69.default.relative(scanPath, import_node_path69.default.join(service.dir, relFile)));
16972
17011
  const add = (edgeType, kind, name) => {
16973
17012
  if (!name) return;
16974
17013
  const result = emitPlatformResourceEdge(
@@ -17010,7 +17049,7 @@ async function addInfra(graph, scanPath, services) {
17010
17049
 
17011
17050
  // src/extract/zod-shapes.ts
17012
17051
  init_cjs_shims();
17013
- var import_node_path69 = __toESM(require("path"), 1);
17052
+ var import_node_path70 = __toESM(require("path"), 1);
17014
17053
  var import_tree_sitter18 = __toESM(require("tree-sitter"), 1);
17015
17054
  var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
17016
17055
  var import_types57 = require("@neat.is/types");
@@ -17105,7 +17144,7 @@ function topLevelSchemas(root) {
17105
17144
  }
17106
17145
  function zodShapesFromFile(file, serviceDir) {
17107
17146
  if (!ZOD_IMPORT_RE.test(file.content)) return [];
17108
- const tree = parseSource3(parserForExt4(import_node_path69.default.extname(file.path)), file.content);
17147
+ const tree = parseSource3(parserForExt4(import_node_path70.default.extname(file.path)), file.content);
17109
17148
  const out = [];
17110
17149
  const seen = /* @__PURE__ */ new Set();
17111
17150
  for (const { name, call } of topLevelSchemas(tree.rootNode)) {
@@ -17123,7 +17162,7 @@ function zodShapesFromFile(file, serviceDir) {
17123
17162
  name,
17124
17163
  fields,
17125
17164
  evidence: {
17126
- file: import_node_path69.default.relative(serviceDir, file.path),
17165
+ file: import_node_path70.default.relative(serviceDir, file.path),
17127
17166
  line,
17128
17167
  snippet: snippet(file.content, line)
17129
17168
  }
@@ -17391,12 +17430,12 @@ async function addFirestoreRules(graph, services) {
17391
17430
  }
17392
17431
 
17393
17432
  // src/extract/index.ts
17394
- var import_node_path71 = __toESM(require("path"), 1);
17433
+ var import_node_path72 = __toESM(require("path"), 1);
17395
17434
 
17396
17435
  // src/extract/retire.ts
17397
17436
  init_cjs_shims();
17398
- var import_node_fs35 = require("fs");
17399
- var import_node_path70 = __toESM(require("path"), 1);
17437
+ var import_node_fs36 = require("fs");
17438
+ var import_node_path71 = __toESM(require("path"), 1);
17400
17439
  var import_types59 = require("@neat.is/types");
17401
17440
  function dropOrphanedFileNodes(graph, source) {
17402
17441
  const orphans = [];
@@ -17430,11 +17469,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = [], so
17430
17469
  if (outOfScope(graph, edge, source)) return;
17431
17470
  const evidenceFile = edge.evidence?.file;
17432
17471
  if (!evidenceFile) return;
17433
- if (import_node_path70.default.isAbsolute(evidenceFile)) {
17434
- if (!(0, import_node_fs35.existsSync)(evidenceFile)) toDrop.push(id);
17472
+ if (import_node_path71.default.isAbsolute(evidenceFile)) {
17473
+ if (!(0, import_node_fs36.existsSync)(evidenceFile)) toDrop.push(id);
17435
17474
  return;
17436
17475
  }
17437
- const found = bases.some((base) => (0, import_node_fs35.existsSync)(import_node_path70.default.join(base, evidenceFile)));
17476
+ const found = bases.some((base) => (0, import_node_fs36.existsSync)(import_node_path71.default.join(base, evidenceFile)));
17438
17477
  if (!found) toDrop.push(id);
17439
17478
  });
17440
17479
  for (const id of toDrop) graph.dropEdge(id);
@@ -17443,7 +17482,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = [], so
17443
17482
  }
17444
17483
 
17445
17484
  // src/extract/index.ts
17446
- async function extractFromDirectory(graph, scanPath, opts = {}) {
17485
+ var passQueue = Promise.resolve();
17486
+ function extractFromDirectory(graph, scanPath, opts = {}) {
17487
+ const pass = passQueue.then(() => runExtractionPass(graph, scanPath, opts));
17488
+ passQueue = pass.catch(() => {
17489
+ });
17490
+ return pass;
17491
+ }
17492
+ async function runExtractionPass(graph, scanPath, opts) {
17447
17493
  await ensureCompatLoaded();
17448
17494
  drainExtractionErrors();
17449
17495
  drainSkippedFiles();
@@ -17495,7 +17541,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
17495
17541
  const droppedEntries = drainDroppedExtracted();
17496
17542
  const skippedEntries = drainSkippedFiles();
17497
17543
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
17498
- const rejectedPath = import_node_path71.default.join(import_node_path71.default.dirname(opts.errorsPath), "rejected.ndjson");
17544
+ const rejectedPath = import_node_path72.default.join(import_node_path72.default.dirname(opts.errorsPath), "rejected.ndjson");
17499
17545
  try {
17500
17546
  await writeRejectedExtracted(droppedEntries, rejectedPath);
17501
17547
  } catch (err) {
@@ -17517,7 +17563,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
17517
17563
  skippedFiles: skippedEntries.length,
17518
17564
  skippedEntries
17519
17565
  };
17520
- emitNeatEvent({
17566
+ if (opts.announce !== false) emitNeatEvent({
17521
17567
  type: "extraction-complete",
17522
17568
  project: opts.project ?? DEFAULT_PROJECT,
17523
17569
  payload: {
@@ -18435,7 +18481,7 @@ async function askGraph(graph, question, opts = {}) {
18435
18481
 
18436
18482
  // src/diff.ts
18437
18483
  init_cjs_shims();
18438
- var import_node_fs36 = require("fs");
18484
+ var import_node_fs37 = require("fs");
18439
18485
  async function loadSnapshotForDiff(target) {
18440
18486
  if (/^https?:\/\//i.test(target)) {
18441
18487
  const res = await fetch(target);
@@ -18444,7 +18490,7 @@ async function loadSnapshotForDiff(target) {
18444
18490
  }
18445
18491
  return await res.json();
18446
18492
  }
18447
- const raw = await import_node_fs36.promises.readFile(target, "utf8");
18493
+ const raw = await import_node_fs37.promises.readFile(target, "utf8");
18448
18494
  return JSON.parse(raw);
18449
18495
  }
18450
18496
  function indexEntries(entries) {
@@ -18512,8 +18558,8 @@ function canonicalJson(value) {
18512
18558
 
18513
18559
  // src/persist.ts
18514
18560
  init_cjs_shims();
18515
- var import_node_fs37 = require("fs");
18516
- var import_node_path72 = __toESM(require("path"), 1);
18561
+ var import_node_fs38 = require("fs");
18562
+ var import_node_path73 = __toESM(require("path"), 1);
18517
18563
  var import_types62 = require("@neat.is/types");
18518
18564
  var SCHEMA_VERSION = 7;
18519
18565
  function migrateV1ToV2(payload) {
@@ -18568,7 +18614,7 @@ function migrateV2ToV3(payload) {
18568
18614
  return { ...payload, schemaVersion: 3 };
18569
18615
  }
18570
18616
  async function ensureDir(filePath) {
18571
- await import_node_fs37.promises.mkdir(import_node_path72.default.dirname(filePath), { recursive: true });
18617
+ await import_node_fs38.promises.mkdir(import_node_path73.default.dirname(filePath), { recursive: true });
18572
18618
  }
18573
18619
  var WRITE_FLUSH_CHARS = 4 * 1024 * 1024;
18574
18620
  function jsonOrUndefined(value) {
@@ -18614,7 +18660,7 @@ async function saveGraphToDisk(graph, outPath) {
18614
18660
  graph: graph.export()
18615
18661
  };
18616
18662
  const tmp = `${outPath}.tmp`;
18617
- const handle = await import_node_fs37.promises.open(tmp, "w");
18663
+ const handle = await import_node_fs38.promises.open(tmp, "w");
18618
18664
  try {
18619
18665
  let buffered = "";
18620
18666
  for (const chunk of serializeGraphChunks(payload)) {
@@ -18628,7 +18674,7 @@ async function saveGraphToDisk(graph, outPath) {
18628
18674
  } finally {
18629
18675
  await handle.close();
18630
18676
  }
18631
- await import_node_fs37.promises.rename(tmp, outPath);
18677
+ await import_node_fs38.promises.rename(tmp, outPath);
18632
18678
  }
18633
18679
  function migrateSnapshot(input) {
18634
18680
  let payload = input;
@@ -18660,7 +18706,7 @@ function migrateSnapshot(input) {
18660
18706
  async function loadGraphFromDisk(graph, outPath) {
18661
18707
  let raw;
18662
18708
  try {
18663
- raw = await import_node_fs37.promises.readFile(outPath, "utf8");
18709
+ raw = await import_node_fs38.promises.readFile(outPath, "utf8");
18664
18710
  } catch (err) {
18665
18711
  if (err.code === "ENOENT") return;
18666
18712
  throw err;
@@ -18711,23 +18757,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
18711
18757
 
18712
18758
  // src/projects.ts
18713
18759
  init_cjs_shims();
18714
- var import_node_path73 = __toESM(require("path"), 1);
18760
+ var import_node_path74 = __toESM(require("path"), 1);
18715
18761
  function pathsForProject(project, baseDir) {
18716
18762
  if (project === DEFAULT_PROJECT) {
18717
18763
  return {
18718
- snapshotPath: import_node_path73.default.join(baseDir, "graph.json"),
18719
- errorsPath: import_node_path73.default.join(baseDir, "errors.ndjson"),
18720
- staleEventsPath: import_node_path73.default.join(baseDir, "stale-events.ndjson"),
18721
- embeddingsCachePath: import_node_path73.default.join(baseDir, "embeddings.json"),
18722
- policyViolationsPath: import_node_path73.default.join(baseDir, "policy-violations.ndjson")
18764
+ snapshotPath: import_node_path74.default.join(baseDir, "graph.json"),
18765
+ errorsPath: import_node_path74.default.join(baseDir, "errors.ndjson"),
18766
+ staleEventsPath: import_node_path74.default.join(baseDir, "stale-events.ndjson"),
18767
+ embeddingsCachePath: import_node_path74.default.join(baseDir, "embeddings.json"),
18768
+ policyViolationsPath: import_node_path74.default.join(baseDir, "policy-violations.ndjson")
18723
18769
  };
18724
18770
  }
18725
18771
  return {
18726
- snapshotPath: import_node_path73.default.join(baseDir, `${project}.json`),
18727
- errorsPath: import_node_path73.default.join(baseDir, `errors.${project}.ndjson`),
18728
- staleEventsPath: import_node_path73.default.join(baseDir, `stale-events.${project}.ndjson`),
18729
- embeddingsCachePath: import_node_path73.default.join(baseDir, `embeddings.${project}.json`),
18730
- policyViolationsPath: import_node_path73.default.join(baseDir, `policy-violations.${project}.ndjson`)
18772
+ snapshotPath: import_node_path74.default.join(baseDir, `${project}.json`),
18773
+ errorsPath: import_node_path74.default.join(baseDir, `errors.${project}.ndjson`),
18774
+ staleEventsPath: import_node_path74.default.join(baseDir, `stale-events.${project}.ndjson`),
18775
+ embeddingsCachePath: import_node_path74.default.join(baseDir, `embeddings.${project}.json`),
18776
+ policyViolationsPath: import_node_path74.default.join(baseDir, `policy-violations.${project}.ndjson`)
18731
18777
  };
18732
18778
  }
18733
18779
  var Projects = class {
@@ -18767,20 +18813,20 @@ function parseExtraProjects(raw) {
18767
18813
 
18768
18814
  // src/registry.ts
18769
18815
  init_cjs_shims();
18770
- var import_node_fs38 = require("fs");
18816
+ var import_node_fs39 = require("fs");
18771
18817
  var import_node_os3 = __toESM(require("os"), 1);
18772
- var import_node_path74 = __toESM(require("path"), 1);
18818
+ var import_node_path75 = __toESM(require("path"), 1);
18773
18819
  var import_types63 = require("@neat.is/types");
18774
18820
  function neatHome() {
18775
18821
  const override = process.env.NEAT_HOME;
18776
- if (override && override.length > 0) return import_node_path74.default.resolve(override);
18777
- return import_node_path74.default.join(import_node_os3.default.homedir(), ".neat");
18822
+ if (override && override.length > 0) return import_node_path75.default.resolve(override);
18823
+ return import_node_path75.default.join(import_node_os3.default.homedir(), ".neat");
18778
18824
  }
18779
18825
  function registryPath() {
18780
- return import_node_path74.default.join(neatHome(), "projects.json");
18826
+ return import_node_path75.default.join(neatHome(), "projects.json");
18781
18827
  }
18782
18828
  function daemonsDir() {
18783
- return import_node_path74.default.join(neatHome(), "daemons");
18829
+ return import_node_path75.default.join(neatHome(), "daemons");
18784
18830
  }
18785
18831
  function isFiniteInt(v) {
18786
18832
  return typeof v === "number" && Number.isFinite(v);
@@ -18813,7 +18859,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
18813
18859
  const dir = daemonsDir();
18814
18860
  let names;
18815
18861
  try {
18816
- names = await import_node_fs38.promises.readdir(dir);
18862
+ names = await import_node_fs39.promises.readdir(dir);
18817
18863
  } catch (err) {
18818
18864
  if (err.code === "ENOENT") return [];
18819
18865
  throw err;
@@ -18821,10 +18867,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
18821
18867
  const out = [];
18822
18868
  for (const name of names) {
18823
18869
  if (!name.endsWith(".json")) continue;
18824
- const file = import_node_path74.default.join(dir, name);
18870
+ const file = import_node_path75.default.join(dir, name);
18825
18871
  let raw;
18826
18872
  try {
18827
- raw = await import_node_fs38.promises.readFile(file, "utf8");
18873
+ raw = await import_node_fs39.promises.readFile(file, "utf8");
18828
18874
  } catch {
18829
18875
  continue;
18830
18876
  }
@@ -18852,7 +18898,7 @@ async function readRegistry() {
18852
18898
  const file = registryPath();
18853
18899
  let raw;
18854
18900
  try {
18855
- raw = await import_node_fs38.promises.readFile(file, "utf8");
18901
+ raw = await import_node_fs39.promises.readFile(file, "utf8");
18856
18902
  } catch (err) {
18857
18903
  if (err.code === "ENOENT") {
18858
18904
  return { version: 1, projects: [] };
@@ -18875,8 +18921,64 @@ var DEFAULT_PRUNE_TTL_MS = 7 * DAY_MS2;
18875
18921
 
18876
18922
  // src/streaming.ts
18877
18923
  init_cjs_shims();
18924
+ var import_node_fs40 = require("fs");
18925
+ var import_zod = require("zod");
18926
+ var import_types64 = require("@neat.is/types");
18878
18927
  var SSE_HEARTBEAT_MS = 3e4;
18879
18928
  var SSE_BACKPRESSURE_CAP = 1e3;
18929
+ var INCIDENT_TRIGGER_STREAM_SCOPE = "incident-only-v1";
18930
+ var IncidentTriggerSchema = import_types64.IncidentEventPayloadSchema.extend({
18931
+ incidentId: import_zod.z.string().regex(/^[A-Za-z0-9:_-]{1,100}$/),
18932
+ affectedNode: import_zod.z.string().min(1).max(512),
18933
+ service: import_zod.z.string().min(1).max(256),
18934
+ at: import_zod.z.string().datetime()
18935
+ });
18936
+ var MAX_REPLAY_BYTES = 16 * 1024 * 1024;
18937
+ var MAX_REPLAY_EVENTS = 1e4;
18938
+ function isExtractionFailure(row) {
18939
+ const keys = Object.keys(row);
18940
+ return keys.every((key) => ["source", "producer", "file", "error", "stack", "ts"].includes(key)) && typeof row.producer === "string" && typeof row.file === "string" && typeof row.error === "string" && typeof row.ts === "string" && (row.stack === void 0 || typeof row.stack === "string") && !Number.isNaN(Date.parse(row.ts));
18941
+ }
18942
+ function loadIncidentReplay(errorsPath, cursor) {
18943
+ if (cursor !== void 0 && !/^[A-Za-z0-9:_-]{1,100}$/.test(cursor)) throw new Error("incident replay unavailable");
18944
+ try {
18945
+ if ((0, import_node_fs40.statSync)(errorsPath).size > MAX_REPLAY_BYTES) throw new Error("incident replay unavailable");
18946
+ const raw = (0, import_node_fs40.readFileSync)(errorsPath, "utf8");
18947
+ if (raw && !raw.endsWith("\n")) throw new Error("incident replay unavailable");
18948
+ const seen = /* @__PURE__ */ new Map();
18949
+ const events = [];
18950
+ for (const line of raw.split("\n")) {
18951
+ if (!line) continue;
18952
+ if (events.length >= MAX_REPLAY_EVENTS) throw new Error("incident replay unavailable");
18953
+ const row = JSON.parse(line);
18954
+ if (row !== null && typeof row === "object" && !Array.isArray(row) && "source" in row && row.source === "extract") {
18955
+ if (!isExtractionFailure(row)) throw new Error("incident replay unavailable");
18956
+ continue;
18957
+ }
18958
+ const event = import_types64.ErrorEventSchema.parse(row);
18959
+ const trigger = IncidentTriggerSchema.parse({
18960
+ incidentId: event.id,
18961
+ affectedNode: event.affectedNode,
18962
+ service: event.service,
18963
+ incidentKind: (0, import_types64.incidentKindOf)(event),
18964
+ at: event.timestamp
18965
+ });
18966
+ const prior = seen.get(trigger.incidentId), encoded = JSON.stringify(trigger);
18967
+ if (prior !== void 0) {
18968
+ if (prior !== encoded) throw new Error("incident replay unavailable");
18969
+ continue;
18970
+ }
18971
+ seen.set(trigger.incidentId, encoded);
18972
+ events.push(trigger);
18973
+ }
18974
+ if (cursor === void 0) return events;
18975
+ const at = events.findIndex((event) => event.incidentId === cursor);
18976
+ if (at < 0) throw new Error("incident replay unavailable");
18977
+ return events.slice(at + 1);
18978
+ } catch {
18979
+ throw new Error("incident replay unavailable");
18980
+ }
18981
+ }
18880
18982
  function handleSse(req, reply, opts) {
18881
18983
  const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS;
18882
18984
  const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP;
@@ -18884,8 +18986,20 @@ function handleSse(req, reply, opts) {
18884
18986
  reply.raw.setHeader("Cache-Control", "no-cache, no-transform");
18885
18987
  reply.raw.setHeader("Connection", "keep-alive");
18886
18988
  reply.raw.setHeader("X-Accel-Buffering", "no");
18989
+ if (opts.incidentOnly) {
18990
+ reply.raw.setHeader("X-NEAT-Event-Scope", INCIDENT_TRIGGER_STREAM_SCOPE);
18991
+ reply.raw.setHeader("X-NEAT-Project", opts.project);
18992
+ if (opts.incidentReplay) reply.raw.setHeader("X-NEAT-Replay-Complete", "1");
18993
+ }
18887
18994
  reply.raw.flushHeaders?.();
18888
18995
  reply.raw.write(":open\n\n");
18996
+ for (const trigger of opts.incidentReplay ?? []) {
18997
+ reply.raw.write(`id: ${trigger.incidentId}
18998
+ event: incident
18999
+ data: ${JSON.stringify(trigger)}
19000
+
19001
+ `);
19002
+ }
18889
19003
  let pending = 0;
18890
19004
  let dropped = false;
18891
19005
  const closeConnection = () => {
@@ -18913,6 +19027,17 @@ data: ${JSON.stringify({ reason: "backpressure" })}
18913
19027
  };
18914
19028
  const listener = (envelope) => {
18915
19029
  if (envelope.project !== opts.project) return;
19030
+ if (opts.incidentOnly) {
19031
+ if (envelope.type !== "incident") return;
19032
+ const trigger = IncidentTriggerSchema.safeParse(envelope.payload);
19033
+ if (!trigger.success) return;
19034
+ writeFrame(`id: ${trigger.data.incidentId}
19035
+ event: incident
19036
+ data: ${JSON.stringify(trigger.data)}
19037
+
19038
+ `);
19039
+ return;
19040
+ }
18916
19041
  writeFrame(`event: ${envelope.type}
18917
19042
  data: ${JSON.stringify(envelope.payload)}
18918
19043
 
@@ -18932,11 +19057,501 @@ data: ${JSON.stringify(envelope.payload)}
18932
19057
  // src/api.ts
18933
19058
  init_auth();
18934
19059
 
18935
- // src/connectors-config.ts
19060
+ // src/pr-verdict.ts
19061
+ init_cjs_shims();
19062
+ var import_node_crypto3 = require("crypto");
19063
+ var import_node_fs42 = require("fs");
19064
+ var import_node_os5 = __toESM(require("os"), 1);
19065
+ var import_node_path77 = __toESM(require("path"), 1);
19066
+
19067
+ // ../action/src/graph.mjs
19068
+ init_cjs_shims();
19069
+ var import_node_fs41 = require("fs");
19070
+ var MARKER = "<!-- neat-action:graph-impact -->";
19071
+ var shortId = (id) => String(id).split(":").slice(-1)[0];
19072
+ var fence = (s) => "`" + s + "`";
19073
+ function graphFromExport(raw) {
19074
+ const g = raw.graph ?? raw;
19075
+ const nodes = new Map((g.nodes ?? []).map((n) => [n.key, n.attributes ?? {}]));
19076
+ const edges = (g.edges ?? []).map((e) => ({
19077
+ key: e.key,
19078
+ source: e.source,
19079
+ target: e.target,
19080
+ ...e.attributes ?? {}
19081
+ }));
19082
+ return { nodes, edges };
19083
+ }
19084
+ var namesByType = (entries, type) => entries.filter(([, a]) => a.type === type).map(([k, a]) => a.name ?? shortId(k));
19085
+ function diffGraphs(base, head) {
19086
+ const added = [...head.nodes].filter(([k]) => !base.nodes.has(k));
19087
+ const removed = [...base.nodes].filter(([k]) => !head.nodes.has(k));
19088
+ return {
19089
+ routesAdded: namesByType(added, "RouteNode"),
19090
+ routesRemoved: namesByType(removed, "RouteNode"),
19091
+ tablesAdded: namesByType(added, "InfraNode"),
19092
+ tablesRemoved: namesByType(removed, "InfraNode")
19093
+ };
19094
+ }
19095
+ function changedFileNodeIds(graph, changedPaths) {
19096
+ const ids = [];
19097
+ for (const [key, attrs] of graph.nodes) {
19098
+ if (attrs.type !== "FileNode" || !attrs.path) continue;
19099
+ if (changedPaths.some((c) => c === attrs.path || c.endsWith("/" + attrs.path))) ids.push(key);
19100
+ }
19101
+ return ids;
19102
+ }
19103
+ function changedNodeIds(base, head) {
19104
+ if (!base) return [...head.nodes.keys()];
19105
+ return [
19106
+ ...[...head.nodes.keys()].filter((k) => !base.nodes.has(k)),
19107
+ ...[...base.nodes.keys()].filter((k) => !head.nodes.has(k))
19108
+ ];
19109
+ }
19110
+ function formatDivergences(data, changedIds) {
19111
+ const findings = Array.isArray(data) ? data : data?.divergences ?? data?.findings ?? data?.items ?? [];
19112
+ const changed = new Set(changedIds);
19113
+ return findings.filter((f) => changed.has(f.source) || changed.has(f.target) || changed.has(f.nodeId)).slice(0, 10).map((f) => {
19114
+ const kind = f.kind || f.type || "divergence";
19115
+ const s = shortId(f.source ?? f.nodeId ?? "");
19116
+ const t = f.target ? " \u2192 `" + shortId(f.target) + "`" : "";
19117
+ const why = f.reason || f.message || "";
19118
+ return `${kind}: \`${s}\`${t}${why ? " \u2014 " + why : ""}`;
19119
+ });
19120
+ }
19121
+ function observedBreakFrom(node, data) {
19122
+ const observed = Boolean(data?.observed);
19123
+ const dependentCount = Number(data?.inboundObservedCount ?? 0);
19124
+ const callCount = Array.isArray(data?.dependencies) ? data.dependencies.length : 0;
19125
+ if (!observed && dependentCount === 0 && callCount === 0) return null;
19126
+ const inboundVolume = typeof data.inboundVolume === "number" ? data.inboundVolume : void 0;
19127
+ const window = typeof data.window === "string" ? data.window : void 0;
19128
+ const inboundLastObserved = typeof data.inboundLastObserved === "string" ? data.inboundLastObserved : void 0;
19129
+ return {
19130
+ id: node.id,
19131
+ type: node.type,
19132
+ label: node.label,
19133
+ change: node.change,
19134
+ dependentCount,
19135
+ callCount,
19136
+ ...inboundVolume !== void 0 ? { inboundVolume } : {},
19137
+ ...window !== void 0 ? { window } : {},
19138
+ ...inboundLastObserved !== void 0 ? { inboundLastObserved } : {}
19139
+ };
19140
+ }
19141
+ function blastRadius(graph, nodeId, maxDepth = 10) {
19142
+ const inbound = /* @__PURE__ */ new Map();
19143
+ for (const e of graph.edges) {
19144
+ if (!inbound.has(e.target)) inbound.set(e.target, []);
19145
+ inbound.get(e.target).push({ source: e.source, type: e.type });
19146
+ }
19147
+ const seen = /* @__PURE__ */ new Set([nodeId]);
19148
+ const dependents = [];
19149
+ let frontier = [nodeId];
19150
+ for (let d = 0; d < maxDepth && frontier.length; d++) {
19151
+ const next = [];
19152
+ for (const n of frontier) {
19153
+ for (const { source } of inbound.get(n) ?? []) {
19154
+ if (seen.has(source)) continue;
19155
+ seen.add(source);
19156
+ dependents.push(source);
19157
+ next.push(source);
19158
+ }
19159
+ }
19160
+ frontier = next;
19161
+ }
19162
+ return dependents;
19163
+ }
19164
+ var stable = (obj) => JSON.stringify(obj, Object.keys(obj ?? {}).sort());
19165
+ function changedNodesForObservedScan(base, head, { limit = 25 } = {}) {
19166
+ const out = [];
19167
+ for (const [key, attrs] of base.nodes) {
19168
+ if (!head.nodes.has(key)) {
19169
+ out.push({ id: key, type: attrs.type, label: attrs.name ?? shortId(key), change: "removed" });
19170
+ }
19171
+ }
19172
+ for (const [key, attrs] of head.nodes) {
19173
+ const b = base.nodes.get(key);
19174
+ if (b && stable(b) !== stable(attrs)) {
19175
+ out.push({ id: key, type: attrs.type, label: attrs.name ?? shortId(key), change: "changed" });
19176
+ }
19177
+ }
19178
+ return out.slice(0, limit);
19179
+ }
19180
+ var plural = (n) => n === 1 ? "" : "s";
19181
+ function formatAge(iso) {
19182
+ const t = Date.parse(iso);
19183
+ if (!Number.isFinite(t)) return null;
19184
+ const ms = Date.now() - t;
19185
+ if (ms < 0) return "just now";
19186
+ const s = Math.round(ms / 1e3);
19187
+ if (s < 60) return `${s}s ago`;
19188
+ const m = Math.round(s / 60);
19189
+ if (m < 60) return `${m}m ago`;
19190
+ const h = Math.round(m / 60);
19191
+ if (h < 48) return `${h}h ago`;
19192
+ return `${Math.round(h / 24)}d ago`;
19193
+ }
19194
+ function windowPhrase(window) {
19195
+ if (window === "7d") return "in 7d";
19196
+ if (window === "lifetime") return "(lifetime)";
19197
+ return "";
19198
+ }
19199
+ function observedTraffic(b) {
19200
+ if (typeof b.inboundVolume !== "number") return null;
19201
+ const win = windowPhrase(b.window);
19202
+ const served = `served ${b.inboundVolume.toLocaleString("en-US")}\xD7${win ? " " + win : ""}`;
19203
+ const age = b.inboundLastObserved ? formatAge(b.inboundLastObserved) : null;
19204
+ return age ? `${served}, last seen ${age}` : served;
19205
+ }
19206
+ var FUSION_NOTE = "<sub>Fused view \u2014 the static graph (EXTRACTED) weighted against production traffic (OBSERVED) from the connected NEAT host. Observed-break checks ran live against that host.</sub>";
19207
+ var TONE_COPY = {
19208
+ loud: {
19209
+ green: "## \u2705 NEAT \u2014 all clear",
19210
+ yellow: "## \u26A0\uFE0F NEAT \u2014 a few minor problems",
19211
+ red: "## \u{1F6D1} NEAT \u2014 FUCK NO. Here are the problems:"
19212
+ },
19213
+ professional: {
19214
+ green: "## \u2705 NEAT \u2014 all clear",
19215
+ yellow: "## \u26A0\uFE0F NEAT \u2014 Minor issues to review",
19216
+ red: "## \u{1F6D1} NEAT \u2014 Critical: production will break"
19217
+ }
19218
+ };
19219
+ function breakHeadline(b) {
19220
+ const verb = b.change === "removed" ? "deletes" : "changes";
19221
+ const what = fence(b.label) + (b.type === "InfraNode" ? " (data store)" : "");
19222
+ const consequence = b.type === "RouteNode" ? "Live callers 404." : b.type === "InfraNode" ? "Live readers and writers fail." : "Live callers break.";
19223
+ const traffic = observedTraffic(b);
19224
+ if (traffic) {
19225
+ return `**\u{1F534} Production will break** \u2014 this PR ${verb} ${what}, ${traffic} (OBSERVED). ${consequence}`;
19226
+ }
19227
+ if (b.dependentCount > 0) {
19228
+ return `**\u{1F534} Production will break** \u2014 this PR ${verb} ${what}, ${b.dependentCount} observed dependent${plural(b.dependentCount)} (OBSERVED). ${consequence}`;
19229
+ }
19230
+ return `**\u{1F534} Production will break** \u2014 this PR ${verb} ${what}, seen live in production making ${b.callCount} observed call${plural(b.callCount)} (OBSERVED). Runtime behavior changes.`;
19231
+ }
19232
+ function breakDetail(b) {
19233
+ return "- " + fence(b.label) + ` \u2014 ${b.change} ${b.type ?? "node"}; ${b.dependentCount} observed inbound dependent${plural(b.dependentCount)}, ${b.callCount} observed outbound call${plural(b.callCount)}. Provenance: OBSERVED (live traffic on the connected host).`;
19234
+ }
19235
+ function renderVerdict({
19236
+ graph,
19237
+ delta,
19238
+ changedFiles = [],
19239
+ divergences = [],
19240
+ observedBreaks = [],
19241
+ tone = "loud",
19242
+ sniperDispatchUrl = "",
19243
+ graphDiffUrl = ""
19244
+ }) {
19245
+ const copy = TONE_COPY[tone] ?? TONE_COPY.loud;
19246
+ const brokenRoutes = new Set(
19247
+ observedBreaks.filter((b) => b.type === "RouteNode").map((b) => b.label)
19248
+ );
19249
+ const brokenTables = new Set(
19250
+ observedBreaks.filter((b) => b.type === "InfraNode").map((b) => b.label)
19251
+ );
19252
+ const staticConcerns = [];
19253
+ for (const r of delta.routesRemoved ?? []) {
19254
+ if (brokenRoutes.has(r)) continue;
19255
+ staticConcerns.push({
19256
+ headline: `**\u{1F7E0} Removed route** \u2014 ${fence(r)} no longer exists; confirm nothing in-repo still calls it.`,
19257
+ detail: `- Route ${fence(r)} removed. The connected host observed no production traffic on it \u2014 static-only concern.`
19258
+ });
19259
+ }
19260
+ for (const t of delta.tablesRemoved ?? []) {
19261
+ if (brokenTables.has(t)) continue;
19262
+ staticConcerns.push({
19263
+ headline: `**\u{1F7E0} Removed reference** \u2014 ${fence(t)} no longer exists; confirm nothing in-repo still reads it.`,
19264
+ detail: `- Table/infra ${fence(t)} removed. The connected host observed no production traffic on it \u2014 static-only concern.`
19265
+ });
19266
+ }
19267
+ const findings = [
19268
+ ...observedBreaks.map((b) => ({ headline: breakHeadline(b), detail: breakDetail(b) })),
19269
+ ...divergences.map((d) => ({
19270
+ headline: `**\u{1F7E0} Divergence** \u2014 ${d}`,
19271
+ detail: `- ${d}`
19272
+ })),
19273
+ ...staticConcerns
19274
+ ];
19275
+ const tier = observedBreaks.length > 0 ? "red" : findings.length > 0 ? "yellow" : "green";
19276
+ const actionLinks = [];
19277
+ if (sniperDispatchUrl)
19278
+ actionLinks.push(`**[\u26A1 Dispatch Sniper to fix these \u2192](${sniperDispatchUrl})**`);
19279
+ if (graphDiffUrl) actionLinks.push(`[Full graph diff \u2192](${graphDiffUrl})`);
19280
+ const L = [MARKER, ""];
19281
+ if (tier === "green") {
19282
+ L.push(
19283
+ copy.green,
19284
+ "",
19285
+ "Nothing this PR touches is observed in production, and it introduces no new divergences.",
19286
+ "",
19287
+ FUSION_NOTE
19288
+ );
19289
+ return { marker: MARKER, body: L.join("\n"), tier };
19290
+ }
19291
+ if (tier === "yellow") {
19292
+ L.push(
19293
+ copy.yellow,
19294
+ "",
19295
+ `${findings.length} minor problem${plural(findings.length)} \u2014 read ${findings.length === 1 ? "it" : "them"} below.`,
19296
+ "",
19297
+ "<details><summary>Read them \u2192</summary>",
19298
+ ""
19299
+ );
19300
+ findings.forEach((f, i) => L.push(`${i + 1}. ${f.headline}`));
19301
+ L.push("", ...findings.map((f) => f.detail));
19302
+ L.push("", "</details>");
19303
+ if (actionLinks.length) L.push("", ...actionLinks);
19304
+ L.push("", FUSION_NOTE);
19305
+ return { marker: MARKER, body: L.join("\n"), tier };
19306
+ }
19307
+ L.push(copy.red, "");
19308
+ findings.forEach((f, i) => L.push(`${i + 1}. ${f.headline}`));
19309
+ L.push("", "<details><summary>Full detail \u2192</summary>", "");
19310
+ L.push(...findings.map((f) => f.detail));
19311
+ const anyDelta = (delta.routesAdded?.length ?? 0) + (delta.routesRemoved?.length ?? 0) + (delta.tablesAdded?.length ?? 0) + (delta.tablesRemoved?.length ?? 0);
19312
+ if (anyDelta) {
19313
+ L.push("", "**Graph delta**");
19314
+ if (delta.routesAdded?.length) L.push("- \u2795 routes: " + delta.routesAdded.map(fence).join(", "));
19315
+ if (delta.routesRemoved?.length)
19316
+ L.push("- \u2796 routes: " + delta.routesRemoved.map(fence).join(", "));
19317
+ if (delta.tablesAdded?.length) L.push("- \u2795 tables: " + delta.tablesAdded.map(fence).join(", "));
19318
+ if (delta.tablesRemoved?.length)
19319
+ L.push("- \u2796 tables: " + delta.tablesRemoved.map(fence).join(", "));
19320
+ }
19321
+ const filesInGraph = (changedFiles ?? []).filter((f) => graph?.nodes?.has(f));
19322
+ if (filesInGraph.length) {
19323
+ L.push("", "**Blast radius (in-repo)**");
19324
+ for (const f of filesInGraph) {
19325
+ const deps = blastRadius(graph, f).filter((d) => d.startsWith("file:")).map(shortId);
19326
+ L.push(
19327
+ "- " + fence(shortId(f)) + " \u2192 depended on by " + (deps.length ? deps.map(fence).join(", ") : "_nothing else in-repo_")
19328
+ );
19329
+ }
19330
+ }
19331
+ L.push("", "</details>");
19332
+ if (actionLinks.length) L.push("", ...actionLinks);
19333
+ L.push("", FUSION_NOTE);
19334
+ return { marker: MARKER, body: L.join("\n"), tier };
19335
+ }
19336
+
19337
+ // src/pr-verdict.ts
19338
+ var import_types65 = require("@neat.is/types");
19339
+
19340
+ // src/connectors/hosted-repos.ts
18936
19341
  init_cjs_shims();
18937
19342
  var import_node_os4 = __toESM(require("os"), 1);
18938
- var import_node_path75 = __toESM(require("path"), 1);
18939
- var import_node_fs39 = require("fs");
19343
+ var import_node_path76 = __toESM(require("path"), 1);
19344
+ var import_promises = require("fs/promises");
19345
+ var DEFAULT_SYNC_INTERVAL_MS = 5 * 6e4;
19346
+ var CLONE_TIMEOUT_MS = 5 * 6e4;
19347
+ function scrubToken(s) {
19348
+ return s.replace(/x-access-token:[^@\s]+@/g, "x-access-token:***@");
19349
+ }
19350
+ var defaultCloneCommit = async (cloneUrl, sha, destDir) => {
19351
+ const [{ default: git }, httpMod, fs42] = await Promise.all([
19352
+ import("isomorphic-git"),
19353
+ import("isomorphic-git/http/node"),
19354
+ import("fs")
19355
+ ]);
19356
+ const http = httpMod.default ?? httpMod;
19357
+ const parsed = new URL(cloneUrl);
19358
+ const password = parsed.password || parsed.username;
19359
+ const username = parsed.password ? parsed.username : "x-access-token";
19360
+ const cleanUrl = `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
19361
+ const clone = (async () => {
19362
+ await git.init({ fs: fs42, dir: destDir });
19363
+ await git.addRemote({ fs: fs42, dir: destDir, remote: "origin", url: cleanUrl });
19364
+ await git.fetch({
19365
+ fs: fs42,
19366
+ http,
19367
+ dir: destDir,
19368
+ remote: "origin",
19369
+ // A full SHA is fetched as itself; the remote doesn't have to advertise a ref that points at it.
19370
+ ref: sha,
19371
+ remoteRef: sha,
19372
+ singleBranch: true,
19373
+ depth: 1,
19374
+ tags: false,
19375
+ ...password ? { onAuth: () => ({ username, password }) } : {}
19376
+ });
19377
+ await git.checkout({ fs: fs42, dir: destDir, ref: sha, force: true });
19378
+ })();
19379
+ clone.catch(() => {
19380
+ });
19381
+ let timer;
19382
+ const timeout = new Promise((_, reject) => {
19383
+ timer = setTimeout(() => reject(new Error(`clone timed out after ${CLONE_TIMEOUT_MS}ms`)), CLONE_TIMEOUT_MS);
19384
+ });
19385
+ try {
19386
+ await Promise.race([clone, timeout]);
19387
+ } finally {
19388
+ if (timer) clearTimeout(timer);
19389
+ }
19390
+ };
19391
+ function scrubCloneToken(s) {
19392
+ return scrubToken(s);
19393
+ }
19394
+
19395
+ // src/pr-verdict.ts
19396
+ var DEFAULT_PR_VERDICT_TIMEOUT_MS = 24e4;
19397
+ var MAX_CHANGED_FILES = 3e3;
19398
+ var PrVerdictError = class extends Error {
19399
+ constructor(message, status2, stage, details) {
19400
+ super(message);
19401
+ this.status = status2;
19402
+ this.stage = stage;
19403
+ this.details = details;
19404
+ this.name = "PrVerdictError";
19405
+ }
19406
+ status;
19407
+ stage;
19408
+ details;
19409
+ };
19410
+ function parsePrVerdictRequest(body) {
19411
+ const parsed = import_types65.PrVerdictBodySchema.safeParse(body);
19412
+ if (!parsed.success) {
19413
+ throw new PrVerdictError("invalid pr-verdict body", 400, void 0, parsed.error.issues);
19414
+ }
19415
+ const { changedFiles, tone, ...rest } = parsed.data;
19416
+ return {
19417
+ ...rest,
19418
+ ...changedFiles ? { changedFiles: changedFiles.slice(0, MAX_CHANGED_FILES) } : {},
19419
+ ...tone ? { tone } : {}
19420
+ };
19421
+ }
19422
+ function createPrVerdictRunner(deps = {}) {
19423
+ let busy = false;
19424
+ return async (req, ctx) => {
19425
+ if (busy) throw new PrVerdictError("a verdict is already being computed on this daemon", 429);
19426
+ busy = true;
19427
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_PR_VERDICT_TIMEOUT_MS;
19428
+ const deadline = (deps.now ?? Date.now)() + timeoutMs;
19429
+ const work = computePrVerdict(req, ctx, deps, deadline).finally(() => {
19430
+ busy = false;
19431
+ });
19432
+ let timer;
19433
+ const timeout = new Promise((_, reject) => {
19434
+ timer = setTimeout(
19435
+ () => reject(new PrVerdictError(`verdict did not finish within ${timeoutMs}ms`, 504)),
19436
+ timeoutMs
19437
+ );
19438
+ });
19439
+ try {
19440
+ return await Promise.race([work, timeout]);
19441
+ } finally {
19442
+ if (timer) clearTimeout(timer);
19443
+ work.catch(() => {
19444
+ });
19445
+ }
19446
+ };
19447
+ }
19448
+ async function computePrVerdict(req, ctx, deps, deadline) {
19449
+ const now = deps.now ?? Date.now;
19450
+ const startedAt = now();
19451
+ const cloneCommit = deps.cloneCommit ?? defaultCloneCommit;
19452
+ const extract = deps.extract ?? extractFromDirectory;
19453
+ const root = await import_node_fs42.promises.mkdtemp(import_node_path77.default.join(deps.tmpRoot ?? import_node_os5.default.tmpdir(), "neat-pr-"));
19454
+ const baseDir = import_node_path77.default.join(root, "base");
19455
+ const headDir = import_node_path77.default.join(root, "head");
19456
+ const stage = async (name, run) => {
19457
+ const left = deadline - now();
19458
+ if (left <= 0) throw new PrVerdictError(`verdict ran out of time before ${name}`, 504, name);
19459
+ const work = run();
19460
+ work.catch(() => {
19461
+ });
19462
+ let timer;
19463
+ const expired = new Promise((_, reject) => {
19464
+ timer = setTimeout(() => reject(new PrVerdictError(`verdict ran out of time during ${name}`, 504, name)), left);
19465
+ });
19466
+ try {
19467
+ return await Promise.race([work, expired]);
19468
+ } catch (err) {
19469
+ if (err instanceof PrVerdictError) throw err;
19470
+ const why = scrubCloneToken(err.message ?? String(err)).slice(0, 300);
19471
+ throw new PrVerdictError(`${name} failed \u2014 ${why}`, 422, name);
19472
+ } finally {
19473
+ if (timer) clearTimeout(timer);
19474
+ }
19475
+ };
19476
+ const extractOpts = { source: `${req.owner}/${req.name}`, announce: false };
19477
+ try {
19478
+ await import_node_fs42.promises.mkdir(baseDir);
19479
+ await import_node_fs42.promises.mkdir(headDir);
19480
+ await stage("clone-base", () => cloneCommit(req.cloneUrl, req.baseSha, baseDir));
19481
+ await stage("clone-head", () => cloneCommit(req.cloneUrl, req.headSha, headDir));
19482
+ const baseGraph = makeGraph();
19483
+ const headGraph = makeGraph();
19484
+ await stage("extract-base", () => extract(baseGraph, baseDir, extractOpts));
19485
+ await stage("extract-head", () => extract(headGraph, headDir, extractOpts));
19486
+ const base = graphFromExport(baseGraph.export());
19487
+ const head = graphFromExport(headGraph.export());
19488
+ const delta = diffGraphs(base, head);
19489
+ const changedPaths = req.changedFiles ?? await changedPathsBetween(baseDir, headDir);
19490
+ const changedFiles = changedFileNodeIds(head, changedPaths);
19491
+ const divergences = formatDivergences(
19492
+ computeDivergences(ctx.liveGraph, { incidents: ctx.incidents ?? [] }),
19493
+ changedNodeIds(base, head)
19494
+ );
19495
+ const observedBreaks = [];
19496
+ for (const node of changedNodesForObservedScan(base, head)) {
19497
+ if (!ctx.liveGraph.hasNode(node.id)) continue;
19498
+ const found = observedBreakFrom(node, getObservedDependencies(ctx.liveGraph, node.id));
19499
+ if (found) observedBreaks.push(found);
19500
+ }
19501
+ const { marker, body } = renderVerdict({
19502
+ graph: head,
19503
+ delta,
19504
+ changedFiles,
19505
+ divergences,
19506
+ observedBreaks,
19507
+ tone: req.tone ?? "loud"
19508
+ });
19509
+ return {
19510
+ marker,
19511
+ body,
19512
+ base: { sha: req.baseSha, nodes: baseGraph.order, edges: baseGraph.size },
19513
+ head: { sha: req.headSha, nodes: headGraph.order, edges: headGraph.size },
19514
+ changedFiles: changedFiles.length,
19515
+ observedBreaks: observedBreaks.length,
19516
+ divergences: divergences.length,
19517
+ durationMs: now() - startedAt
19518
+ };
19519
+ } finally {
19520
+ await import_node_fs42.promises.rm(root, { recursive: true, force: true }).catch(() => {
19521
+ });
19522
+ }
19523
+ }
19524
+ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "neat-out"]);
19525
+ async function hashTree(dir) {
19526
+ const out = /* @__PURE__ */ new Map();
19527
+ const walk11 = async (rel) => {
19528
+ const entries = await import_node_fs42.promises.readdir(import_node_path77.default.join(dir, rel), { withFileTypes: true }).catch(() => []);
19529
+ for (const entry of entries) {
19530
+ const child = rel ? `${rel}/${entry.name}` : entry.name;
19531
+ if (entry.isDirectory()) {
19532
+ if (!SKIP_DIRS.has(entry.name)) await walk11(child);
19533
+ } else if (entry.isFile()) {
19534
+ const bytes = await import_node_fs42.promises.readFile(import_node_path77.default.join(dir, child)).catch(() => null);
19535
+ if (bytes) out.set(child, (0, import_node_crypto3.createHash)("sha1").update(bytes).digest("hex"));
19536
+ }
19537
+ }
19538
+ };
19539
+ await walk11("");
19540
+ return out;
19541
+ }
19542
+ async function changedPathsBetween(baseDir, headDir) {
19543
+ const [base, head] = await Promise.all([hashTree(baseDir), hashTree(headDir)]);
19544
+ const changed = [];
19545
+ for (const [file, hash] of head) if (base.get(file) !== hash) changed.push(file);
19546
+ for (const file of base.keys()) if (!head.has(file)) changed.push(file);
19547
+ return changed.sort().slice(0, MAX_CHANGED_FILES);
19548
+ }
19549
+
19550
+ // src/connectors-config.ts
19551
+ init_cjs_shims();
19552
+ var import_node_os6 = __toESM(require("os"), 1);
19553
+ var import_node_path78 = __toESM(require("path"), 1);
19554
+ var import_node_fs43 = require("fs");
18940
19555
  var CONNECTORS_CONFIG_VERSION = 1;
18941
19556
  var EnvRefUnsetError = class extends Error {
18942
19557
  ref;
@@ -18950,17 +19565,17 @@ var EnvRefUnsetError = class extends Error {
18950
19565
  };
18951
19566
  function neatHome2() {
18952
19567
  const override = process.env.NEAT_HOME;
18953
- if (override && override.length > 0) return import_node_path75.default.resolve(override);
18954
- return import_node_path75.default.join(import_node_os4.default.homedir(), ".neat");
19568
+ if (override && override.length > 0) return import_node_path78.default.resolve(override);
19569
+ return import_node_path78.default.join(import_node_os6.default.homedir(), ".neat");
18955
19570
  }
18956
19571
  function connectorsConfigPath(home = neatHome2()) {
18957
- return import_node_path75.default.join(home, "connectors.json");
19572
+ return import_node_path78.default.join(home, "connectors.json");
18958
19573
  }
18959
19574
  var MODE_MASK_LOOSER_THAN_0600 = 63;
18960
19575
  async function warnIfModeLooserThan0600(file) {
18961
19576
  if (process.platform === "win32") return;
18962
19577
  try {
18963
- const stat = await import_node_fs39.promises.stat(file);
19578
+ const stat = await import_node_fs43.promises.stat(file);
18964
19579
  if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
18965
19580
  const mode = (stat.mode & 511).toString(8).padStart(3, "0");
18966
19581
  console.warn(
@@ -18974,7 +19589,7 @@ async function readConnectorsConfig(home = neatHome2()) {
18974
19589
  const file = connectorsConfigPath(home);
18975
19590
  let raw;
18976
19591
  try {
18977
- raw = await import_node_fs39.promises.readFile(file, "utf8");
19592
+ raw = await import_node_fs43.promises.readFile(file, "utf8");
18978
19593
  } catch (err) {
18979
19594
  if (err.code === "ENOENT") {
18980
19595
  return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
@@ -19141,15 +19756,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
19141
19756
 
19142
19757
  // src/connectors/index.ts
19143
19758
  init_cjs_shims();
19144
- var import_types64 = require("@neat.is/types");
19759
+ var import_types66 = require("@neat.is/types");
19145
19760
  var NO_ENV = "unknown";
19146
19761
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
19147
19762
  if (!graph.hasNode(targetNodeId)) return void 0;
19148
19763
  const sites = [];
19149
19764
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
19150
19765
  const edge = graph.getEdgeAttributes(edgeId);
19151
- if (edge.provenance !== import_types64.Provenance.EXTRACTED) continue;
19152
- const parsed = (0, import_types64.parseFileId)(edge.source);
19766
+ if (edge.provenance !== import_types66.Provenance.EXTRACTED) continue;
19767
+ const parsed = (0, import_types66.parseFileId)(edge.source);
19153
19768
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
19154
19769
  const site = { relPath: edge.evidence.file };
19155
19770
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -19160,7 +19775,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
19160
19775
  function routeCallSiteFor(graph, targetNodeId) {
19161
19776
  if (!graph.hasNode(targetNodeId)) return void 0;
19162
19777
  const attrs = graph.getNodeAttributes(targetNodeId);
19163
- if (attrs.type !== import_types64.NodeType.RouteNode || !attrs.path) return void 0;
19778
+ if (attrs.type !== import_types66.NodeType.RouteNode || !attrs.path) return void 0;
19164
19779
  const site = { relPath: attrs.path };
19165
19780
  if (attrs.line !== void 0) site.line = attrs.line;
19166
19781
  return site;
@@ -19246,7 +19861,7 @@ init_cjs_shims();
19246
19861
 
19247
19862
  // src/connectors/gcp-auth.ts
19248
19863
  init_cjs_shims();
19249
- var import_node_crypto3 = require("crypto");
19864
+ var import_node_crypto4 = require("crypto");
19250
19865
 
19251
19866
  // src/connectors/junction.ts
19252
19867
  init_cjs_shims();
@@ -19558,7 +20173,7 @@ function buildServiceAccountAssertion(key, scope, tokenUri, nowMs) {
19558
20173
  exp: iat + ASSERTION_LIFETIME_S
19559
20174
  };
19560
20175
  const signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(claims))}`;
19561
- const signature = (0, import_node_crypto3.createSign)("RSA-SHA256").update(signingInput).end().sign(key.private_key);
20176
+ const signature = (0, import_node_crypto4.createSign)("RSA-SHA256").update(signingInput).end().sign(key.private_key);
19562
20177
  return `${signingInput}.${base64url(signature)}`;
19563
20178
  }
19564
20179
  async function mintGcpAccessToken(key, scope, opts = {}) {
@@ -19728,10 +20343,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
19728
20343
  // src/connectors/supabase/map.ts
19729
20344
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
19730
20345
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
19731
- function targetFromRestPath(path78) {
19732
- const rpcMatch = REST_RPC_PATH_RE.exec(path78);
20346
+ function targetFromRestPath(path81) {
20347
+ const rpcMatch = REST_RPC_PATH_RE.exec(path81);
19733
20348
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
19734
- const tableMatch = REST_TABLE_PATH_RE.exec(path78);
20349
+ const tableMatch = REST_TABLE_PATH_RE.exec(path81);
19735
20350
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
19736
20351
  return null;
19737
20352
  }
@@ -19842,23 +20457,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
19842
20457
 
19843
20458
  // src/connectors/supabase/resolve.ts
19844
20459
  init_cjs_shims();
19845
- var import_types66 = require("@neat.is/types");
20460
+ var import_types68 = require("@neat.is/types");
19846
20461
  function createSupabaseResolveTarget(graph, config) {
19847
20462
  return (signal, _ctx) => {
19848
20463
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
19849
20464
  return null;
19850
20465
  }
19851
- const subResourceId = (0, import_types66.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
20466
+ const subResourceId = (0, import_types68.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
19852
20467
  if (graph.hasNode(subResourceId)) {
19853
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
20468
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
19854
20469
  }
19855
- const bareResourceId = (0, import_types66.infraId)(signal.targetKind, signal.targetName);
20470
+ const bareResourceId = (0, import_types68.infraId)(signal.targetKind, signal.targetName);
19856
20471
  if (graph.hasNode(bareResourceId)) {
19857
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
20472
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
19858
20473
  }
19859
- const projectLevelId = (0, import_types66.infraId)("supabase", config.nodeRef);
20474
+ const projectLevelId = (0, import_types68.infraId)("supabase", config.nodeRef);
19860
20475
  if (graph.hasNode(projectLevelId)) {
19861
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
20476
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
19862
20477
  }
19863
20478
  return null;
19864
20479
  };
@@ -19951,7 +20566,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
19951
20566
 
19952
20567
  // src/connectors/railway/index.ts
19953
20568
  init_cjs_shims();
19954
- var import_types70 = require("@neat.is/types");
20569
+ var import_types72 = require("@neat.is/types");
19955
20570
 
19956
20571
  // src/connectors/railway/client.ts
19957
20572
  init_cjs_shims();
@@ -20102,7 +20717,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
20102
20717
  const out = [];
20103
20718
  graph.forEachNode((_id, attrs) => {
20104
20719
  const node = attrs;
20105
- if (node.type !== import_types70.NodeType.RouteNode) return;
20720
+ if (node.type !== import_types72.NodeType.RouteNode) return;
20106
20721
  const route = attrs;
20107
20722
  if (route.service !== serviceName) return;
20108
20723
  out.push({
@@ -20206,12 +20821,12 @@ function createRailwayResolveTarget(config) {
20206
20821
  const serviceName = config.serviceNameById[config.serviceId];
20207
20822
  if (!serviceName) return null;
20208
20823
  if (signal.targetKind === ROUTE_TARGET_KIND) {
20209
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types70.EdgeType.CALLS };
20824
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types72.EdgeType.CALLS };
20210
20825
  }
20211
20826
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
20212
20827
  const peerName = config.serviceNameById[signal.targetName];
20213
20828
  if (!peerName) return null;
20214
- return { targetNodeId: (0, import_types70.serviceId)(peerName), serviceName, edgeType: import_types70.EdgeType.CONNECTS_TO };
20829
+ return { targetNodeId: (0, import_types72.serviceId)(peerName), serviceName, edgeType: import_types72.EdgeType.CONNECTS_TO };
20215
20830
  }
20216
20831
  return null;
20217
20832
  };
@@ -20335,9 +20950,9 @@ function parseFirebaseTargetName(targetName) {
20335
20950
  const secondSep = rest.indexOf(FIELD_SEP);
20336
20951
  if (secondSep === -1) return null;
20337
20952
  const method = rest.slice(0, secondSep);
20338
- const path78 = rest.slice(secondSep + 1);
20339
- if (!resourceName || !method || !path78) return null;
20340
- return { resourceName, method, path: path78 };
20953
+ const path81 = rest.slice(secondSep + 1);
20954
+ if (!resourceName || !method || !path81) return null;
20955
+ return { resourceName, method, path: path81 };
20341
20956
  }
20342
20957
  function resourceNameFor(type, labels) {
20343
20958
  if (!labels) return null;
@@ -20375,14 +20990,14 @@ function mapLogEntryToSignal(entry) {
20375
20990
  if (!req) return null;
20376
20991
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
20377
20992
  const method = req.requestMethod.toUpperCase();
20378
- const path78 = pathFromRequestUrl(req.requestUrl);
20379
- if (path78 === null) return null;
20993
+ const path81 = pathFromRequestUrl(req.requestUrl);
20994
+ if (path81 === null) return null;
20380
20995
  const timestamp = entry.timestamp;
20381
20996
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
20382
20997
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
20383
20998
  return {
20384
20999
  targetKind: resourceType,
20385
- targetName: packFirebaseTargetName({ resourceName, method, path: path78 }),
21000
+ targetName: packFirebaseTargetName({ resourceName, method, path: path81 }),
20386
21001
  callCount: 1,
20387
21002
  errorCount: isError ? 1 : 0,
20388
21003
  lastObservedIso: timestamp
@@ -20399,26 +21014,26 @@ function mapLogEntriesToSignals(entries) {
20399
21014
 
20400
21015
  // src/connectors/firebase/resolve.ts
20401
21016
  init_cjs_shims();
20402
- var import_types72 = require("@neat.is/types");
21017
+ var import_types74 = require("@neat.is/types");
20403
21018
 
20404
21019
  // src/connectors/infer-service.ts
20405
21020
  init_cjs_shims();
20406
- var import_types71 = require("@neat.is/types");
21021
+ var import_types73 = require("@neat.is/types");
20407
21022
  function normalizeName(name) {
20408
21023
  return name.toLowerCase().replace(/[^a-z0-9]/g, "");
20409
21024
  }
20410
- function inferServiceName(graph, resourceName, method, path78) {
21025
+ function inferServiceName(graph, resourceName, method, path81) {
20411
21026
  const wantedMethod = method.toUpperCase();
20412
- const wantedPath = normalizePathTemplate(path78);
21027
+ const wantedPath = normalizePathTemplate(path81);
20413
21028
  const services = [];
20414
21029
  const owners = /* @__PURE__ */ new Set();
20415
21030
  graph.forEachNode((_id, attrs) => {
20416
21031
  const node = attrs;
20417
- if (node.type === import_types71.NodeType.ServiceNode && typeof node.name === "string") {
21032
+ if (node.type === import_types73.NodeType.ServiceNode && typeof node.name === "string") {
20418
21033
  services.push(node.name);
20419
21034
  return;
20420
21035
  }
20421
- if (node.type !== import_types71.NodeType.RouteNode) return;
21036
+ if (node.type !== import_types73.NodeType.RouteNode) return;
20422
21037
  const route = attrs;
20423
21038
  if (!route.pathTemplate || normalizePathTemplate(route.pathTemplate) !== wantedPath) return;
20424
21039
  const routeMethod = route.method.toUpperCase();
@@ -20445,7 +21060,7 @@ function routeEntriesFor(graph, serviceName) {
20445
21060
  const entries = [];
20446
21061
  graph.forEachNode((_id, attrs) => {
20447
21062
  const node = attrs;
20448
- if (node.type !== import_types72.NodeType.RouteNode) return;
21063
+ if (node.type !== import_types74.NodeType.RouteNode) return;
20449
21064
  const route = attrs;
20450
21065
  if (route.service !== serviceName) return;
20451
21066
  entries.push({
@@ -20477,7 +21092,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
20477
21092
  return {
20478
21093
  targetNodeId: match.routeNodeId,
20479
21094
  serviceName,
20480
- edgeType: import_types72.EdgeType.CALLS
21095
+ edgeType: import_types74.EdgeType.CALLS
20481
21096
  };
20482
21097
  };
20483
21098
  }
@@ -20510,11 +21125,11 @@ init_cjs_shims();
20510
21125
 
20511
21126
  // src/connectors/cloudflare/connector.ts
20512
21127
  init_cjs_shims();
20513
- var import_types74 = require("@neat.is/types");
21128
+ var import_types76 = require("@neat.is/types");
20514
21129
 
20515
21130
  // src/connectors/cloudflare/client.ts
20516
21131
  init_cjs_shims();
20517
- var import_node_crypto4 = require("crypto");
21132
+ var import_node_crypto5 = require("crypto");
20518
21133
  var DEFAULT_BASE_URL = "https://api.cloudflare.com/client/v4";
20519
21134
  var DEFAULT_EVENT_LIMIT = 1e3;
20520
21135
  async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
@@ -20527,7 +21142,7 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
20527
21142
  const body = {
20528
21143
  // Cloudflare's schema requires an identifier per query even for an
20529
21144
  // ad-hoc, unsaved one — a fresh id per tick, never reused.
20530
- queryId: `neat-connector-${(0, import_node_crypto4.randomUUID)()}`,
21145
+ queryId: `neat-connector-${(0, import_node_crypto5.randomUUID)()}`,
20531
21146
  timeframe: { from: window.fromMs, to: window.toMs },
20532
21147
  view: "events",
20533
21148
  limit: config.eventLimit ?? DEFAULT_EVENT_LIMIT,
@@ -20626,7 +21241,7 @@ function mapEventToSignal(event) {
20626
21241
  if (Number.isNaN(observedAt.getTime())) return null;
20627
21242
  const statusCode = metadata?.statusCode;
20628
21243
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
20629
- const path78 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
21244
+ const path81 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
20630
21245
  return {
20631
21246
  targetKind: CLOUDFLARE_TARGET_KIND,
20632
21247
  targetName: scriptName,
@@ -20634,7 +21249,7 @@ function mapEventToSignal(event) {
20634
21249
  errorCount: isError ? 1 : 0,
20635
21250
  lastObservedIso: observedAt.toISOString(),
20636
21251
  method,
20637
- ...path78 ? { path: path78 } : {},
21252
+ ...path81 ? { path: path81 } : {},
20638
21253
  ...typeof statusCode === "number" ? { statusCode } : {},
20639
21254
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
20640
21255
  };
@@ -20674,19 +21289,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
20674
21289
  graph.forEachNode((id, attrs) => {
20675
21290
  if (found) return;
20676
21291
  const a = attrs;
20677
- if (a.type === import_types74.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
21292
+ if (a.type === import_types76.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
20678
21293
  found = id;
20679
21294
  }
20680
21295
  });
20681
21296
  return found;
20682
21297
  }
20683
- function findMatchingRouteNode(graph, serviceName, method, path78) {
20684
- const normalizedPath = normalizePathTemplate(path78);
21298
+ function findMatchingRouteNode(graph, serviceName, method, path81) {
21299
+ const normalizedPath = normalizePathTemplate(path81);
20685
21300
  let found = null;
20686
21301
  graph.forEachNode((id, attrs) => {
20687
21302
  if (found) return;
20688
21303
  const a = attrs;
20689
- if (a.type !== import_types74.NodeType.RouteNode || a.service !== serviceName) return;
21304
+ if (a.type !== import_types76.NodeType.RouteNode || a.service !== serviceName) return;
20690
21305
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
20691
21306
  const routeMethod = (a.method ?? "").toUpperCase();
20692
21307
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -20698,18 +21313,18 @@ function createCloudflareResolveTarget(config, graph) {
20698
21313
  return (signal) => {
20699
21314
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
20700
21315
  const scriptName = signal.targetName;
20701
- const { method, path: path78 } = signal;
21316
+ const { method, path: path81 } = signal;
20702
21317
  const resolveRouteGrain = (serviceName, wholeFileId) => {
20703
- if (!method || !path78) return wholeFileId;
20704
- return findMatchingRouteNode(graph, serviceName, method, path78) ?? wholeFileId;
21318
+ if (!method || !path81) return wholeFileId;
21319
+ return findMatchingRouteNode(graph, serviceName, method, path81) ?? wholeFileId;
20705
21320
  };
20706
21321
  const mapping = config.workers?.[scriptName];
20707
21322
  if (mapping) {
20708
- const wholeFileId = (0, import_types74.fileId)(mapping.service, mapping.entryFile);
21323
+ const wholeFileId = (0, import_types76.fileId)(mapping.service, mapping.entryFile);
20709
21324
  return {
20710
21325
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
20711
21326
  serviceName: mapping.service,
20712
- edgeType: import_types74.EdgeType.CALLS
21327
+ edgeType: import_types76.EdgeType.CALLS
20713
21328
  };
20714
21329
  }
20715
21330
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -20718,13 +21333,13 @@ function createCloudflareResolveTarget(config, graph) {
20718
21333
  return {
20719
21334
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
20720
21335
  serviceName: fileNode.service,
20721
- edgeType: import_types74.EdgeType.CALLS
21336
+ edgeType: import_types76.EdgeType.CALLS
20722
21337
  };
20723
21338
  }
20724
21339
  return {
20725
- targetNodeId: (0, import_types74.infraId)("cloudflare-worker", scriptName),
21340
+ targetNodeId: (0, import_types76.infraId)("cloudflare-worker", scriptName),
20726
21341
  serviceName: scriptName,
20727
- edgeType: import_types74.EdgeType.CALLS,
21342
+ edgeType: import_types76.EdgeType.CALLS,
20728
21343
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
20729
21344
  };
20730
21345
  };
@@ -20920,14 +21535,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
20920
21535
 
20921
21536
  // src/connectors/neon/resolve.ts
20922
21537
  init_cjs_shims();
20923
- var import_types78 = require("@neat.is/types");
21538
+ var import_types80 = require("@neat.is/types");
20924
21539
  function createNeonResolveTarget(config) {
20925
21540
  return (signal) => {
20926
21541
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
20927
21542
  return {
20928
- targetNodeId: (0, import_types78.infraId)("sql-table", signal.targetName),
21543
+ targetNodeId: (0, import_types80.infraId)("sql-table", signal.targetName),
20929
21544
  serviceName: config.serviceName,
20930
- edgeType: import_types78.EdgeType.CALLS,
21545
+ edgeType: import_types80.EdgeType.CALLS,
20931
21546
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
20932
21547
  };
20933
21548
  };
@@ -21053,9 +21668,9 @@ function parseCloudRunTargetName(targetName) {
21053
21668
  const secondSep = rest.indexOf(FIELD_SEP2);
21054
21669
  if (secondSep === -1) return null;
21055
21670
  const method = rest.slice(0, secondSep);
21056
- const path78 = rest.slice(secondSep + 1);
21057
- if (!serviceName || !method || !path78) return null;
21058
- return { serviceName, method, path: path78 };
21671
+ const path81 = rest.slice(secondSep + 1);
21672
+ if (!serviceName || !method || !path81) return null;
21673
+ return { serviceName, method, path: path81 };
21059
21674
  }
21060
21675
 
21061
21676
  // src/connectors/cloud-run/map.ts
@@ -21084,14 +21699,14 @@ function mapLogEntryToSignal2(entry) {
21084
21699
  if (!req) return null;
21085
21700
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
21086
21701
  const method = req.requestMethod.toUpperCase();
21087
- const path78 = pathFromRequestUrl2(req.requestUrl);
21088
- if (path78 === null) return null;
21702
+ const path81 = pathFromRequestUrl2(req.requestUrl);
21703
+ if (path81 === null) return null;
21089
21704
  const timestamp = entry.timestamp;
21090
21705
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
21091
21706
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
21092
21707
  return {
21093
21708
  targetKind: CLOUD_RUN_TARGET_KIND,
21094
- targetName: packCloudRunTargetName({ serviceName, method, path: path78 }),
21709
+ targetName: packCloudRunTargetName({ serviceName, method, path: path81 }),
21095
21710
  callCount: 1,
21096
21711
  errorCount: isError ? 1 : 0,
21097
21712
  lastObservedIso: timestamp
@@ -21108,14 +21723,14 @@ function mapLogEntriesToSignals2(entries) {
21108
21723
 
21109
21724
  // src/connectors/cloud-run/resolve.ts
21110
21725
  init_cjs_shims();
21111
- var import_types82 = require("@neat.is/types");
21726
+ var import_types84 = require("@neat.is/types");
21112
21727
  var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
21113
21728
  function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
21114
21729
  let found = null;
21115
21730
  graph.forEachNode((_id, attrs) => {
21116
21731
  if (found) return;
21117
21732
  const node = attrs;
21118
- if (node.type !== import_types82.NodeType.RouteNode) return;
21733
+ if (node.type !== import_types84.NodeType.RouteNode) return;
21119
21734
  const route = attrs;
21120
21735
  if (route.service !== serviceName || !route.pathTemplate) return;
21121
21736
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -21130,23 +21745,23 @@ function createCloudRunResolveTarget(graph, config) {
21130
21745
  if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
21131
21746
  const identity = parseCloudRunTargetName(signal.targetName);
21132
21747
  if (!identity) return null;
21133
- const { serviceName: gcpServiceName, method, path: path78 } = identity;
21134
- const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method, path78) ?? void 0 : void 0);
21748
+ const { serviceName: gcpServiceName, method, path: path81 } = identity;
21749
+ const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method, path81) ?? void 0 : void 0);
21135
21750
  if (mappedService) {
21136
21751
  const routeNodeId = findMatchingRouteNode2(
21137
21752
  graph,
21138
21753
  mappedService,
21139
21754
  method,
21140
- normalizePathTemplate(path78)
21755
+ normalizePathTemplate(path81)
21141
21756
  );
21142
21757
  if (routeNodeId) {
21143
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types82.EdgeType.CALLS };
21758
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types84.EdgeType.CALLS };
21144
21759
  }
21145
21760
  }
21146
21761
  return {
21147
- targetNodeId: (0, import_types82.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
21762
+ targetNodeId: (0, import_types84.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
21148
21763
  serviceName: mappedService ?? gcpServiceName,
21149
- edgeType: import_types82.EdgeType.CALLS,
21764
+ edgeType: import_types84.EdgeType.CALLS,
21150
21765
  ensureInfraNode: {
21151
21766
  kind: CLOUD_RUN_SERVICE_INFRA_KIND,
21152
21767
  name: gcpServiceName,
@@ -21273,9 +21888,9 @@ function parseGcpLbTargetName(targetName) {
21273
21888
  const secondSep = rest.indexOf(FIELD_SEP3);
21274
21889
  if (secondSep === -1) return null;
21275
21890
  const method = rest.slice(0, secondSep);
21276
- const path78 = rest.slice(secondSep + 1);
21277
- if (!backendServiceName || !method || !path78) return null;
21278
- return { backendServiceName, method, path: path78 };
21891
+ const path81 = rest.slice(secondSep + 1);
21892
+ if (!backendServiceName || !method || !path81) return null;
21893
+ return { backendServiceName, method, path: path81 };
21279
21894
  }
21280
21895
 
21281
21896
  // src/connectors/gcp-lb/map.ts
@@ -21304,14 +21919,14 @@ function mapLogEntryToSignal3(entry) {
21304
21919
  if (!req) return null;
21305
21920
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
21306
21921
  const method = req.requestMethod.toUpperCase();
21307
- const path78 = pathFromRequestUrl3(req.requestUrl);
21308
- if (path78 === null) return null;
21922
+ const path81 = pathFromRequestUrl3(req.requestUrl);
21923
+ if (path81 === null) return null;
21309
21924
  const timestamp = entry.timestamp;
21310
21925
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
21311
21926
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD5;
21312
21927
  return {
21313
21928
  targetKind: GCP_LB_TARGET_KIND,
21314
- targetName: packGcpLbTargetName({ backendServiceName, method, path: path78 }),
21929
+ targetName: packGcpLbTargetName({ backendServiceName, method, path: path81 }),
21315
21930
  callCount: 1,
21316
21931
  errorCount: isError ? 1 : 0,
21317
21932
  lastObservedIso: timestamp
@@ -21328,14 +21943,14 @@ function mapLogEntriesToSignals3(entries) {
21328
21943
 
21329
21944
  // src/connectors/gcp-lb/resolve.ts
21330
21945
  init_cjs_shims();
21331
- var import_types86 = require("@neat.is/types");
21946
+ var import_types88 = require("@neat.is/types");
21332
21947
  var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
21333
21948
  function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
21334
21949
  let found = null;
21335
21950
  graph.forEachNode((_id, attrs) => {
21336
21951
  if (found) return;
21337
21952
  const node = attrs;
21338
- if (node.type !== import_types86.NodeType.RouteNode) return;
21953
+ if (node.type !== import_types88.NodeType.RouteNode) return;
21339
21954
  const route = attrs;
21340
21955
  if (route.service !== serviceName || !route.pathTemplate) return;
21341
21956
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -21350,23 +21965,23 @@ function createGcpLbResolveTarget(graph, config) {
21350
21965
  if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
21351
21966
  const identity = parseGcpLbTargetName(signal.targetName);
21352
21967
  if (!identity) return null;
21353
- const { backendServiceName, method, path: path78 } = identity;
21354
- const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method, path78) ?? void 0 : void 0);
21968
+ const { backendServiceName, method, path: path81 } = identity;
21969
+ const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method, path81) ?? void 0 : void 0);
21355
21970
  if (mappedService) {
21356
21971
  const routeNodeId = findMatchingRouteNode3(
21357
21972
  graph,
21358
21973
  mappedService,
21359
21974
  method,
21360
- normalizePathTemplate(path78)
21975
+ normalizePathTemplate(path81)
21361
21976
  );
21362
21977
  if (routeNodeId) {
21363
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types86.EdgeType.CALLS };
21978
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types88.EdgeType.CALLS };
21364
21979
  }
21365
21980
  }
21366
21981
  return {
21367
- targetNodeId: (0, import_types86.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
21982
+ targetNodeId: (0, import_types88.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
21368
21983
  serviceName: mappedService ?? backendServiceName,
21369
- edgeType: import_types86.EdgeType.CALLS,
21984
+ edgeType: import_types88.EdgeType.CALLS,
21370
21985
  ensureInfraNode: {
21371
21986
  kind: GCP_LB_BACKEND_INFRA_KIND,
21372
21987
  name: backendServiceName,
@@ -21407,7 +22022,7 @@ function createGcpLbConnector(graph, config = {}) {
21407
22022
 
21408
22023
  // src/connectors/render/index.ts
21409
22024
  init_cjs_shims();
21410
- var import_types89 = require("@neat.is/types");
22025
+ var import_types91 = require("@neat.is/types");
21411
22026
 
21412
22027
  // src/connectors/render/types.ts
21413
22028
  init_cjs_shims();
@@ -21485,7 +22100,7 @@ function buildRenderRouteIndex(graph, serviceName) {
21485
22100
  const out = [];
21486
22101
  graph.forEachNode((_id, attrs) => {
21487
22102
  const node = attrs;
21488
- if (node.type !== import_types89.NodeType.RouteNode) return;
22103
+ if (node.type !== import_types91.NodeType.RouteNode) return;
21489
22104
  const route = attrs;
21490
22105
  if (route.service !== serviceName) return;
21491
22106
  out.push({
@@ -21570,7 +22185,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
21570
22185
  function createRenderResolveTarget(config) {
21571
22186
  return (signal) => {
21572
22187
  if (signal.targetKind === ROUTE_TARGET_KIND2) {
21573
- return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types89.EdgeType.CALLS };
22188
+ return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types91.EdgeType.CALLS };
21574
22189
  }
21575
22190
  return null;
21576
22191
  };
@@ -21708,21 +22323,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
21708
22323
 
21709
22324
  // src/connectors/planetscale/resolve.ts
21710
22325
  init_cjs_shims();
21711
- var import_types93 = require("@neat.is/types");
22326
+ var import_types95 = require("@neat.is/types");
21712
22327
  var PLANETSCALE_DATABASE_KIND = "planetscale-database";
21713
22328
  function createPlanetscaleResolveTarget(graph, config) {
21714
22329
  const databaseName = `${config.organization}/${config.database}`;
21715
22330
  return (signal, _ctx) => {
21716
22331
  if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
21717
- const tableId = (0, import_types93.infraId)("sql-table", signal.targetName);
22332
+ const tableId = (0, import_types95.infraId)("sql-table", signal.targetName);
21718
22333
  if (graph.hasNode(tableId)) {
21719
- return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types93.EdgeType.CALLS };
22334
+ return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types95.EdgeType.CALLS };
21720
22335
  }
21721
- const providerId = (0, import_types93.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
22336
+ const providerId = (0, import_types95.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
21722
22337
  return {
21723
22338
  targetNodeId: providerId,
21724
22339
  serviceName: config.serviceName,
21725
- edgeType: import_types93.EdgeType.CALLS,
22340
+ edgeType: import_types95.EdgeType.CALLS,
21726
22341
  ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
21727
22342
  };
21728
22343
  };
@@ -21987,7 +22602,7 @@ function mapBuildsToSignals(builds, serviceName) {
21987
22602
 
21988
22603
  // src/connectors/eas/resolve.ts
21989
22604
  init_cjs_shims();
21990
- var import_types98 = require("@neat.is/types");
22605
+ var import_types100 = require("@neat.is/types");
21991
22606
  var NO_ENV2 = "unknown";
21992
22607
  var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
21993
22608
  var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
@@ -22003,8 +22618,8 @@ function configBasenamesForPhase(phase) {
22003
22618
  function configNodeService(graph, configNodeId) {
22004
22619
  for (const edgeId of graph.inboundEdges(configNodeId)) {
22005
22620
  const edge = graph.getEdgeAttributes(edgeId);
22006
- if (edge.type !== import_types98.EdgeType.CONFIGURED_BY) continue;
22007
- const parsed = (0, import_types98.parseFileId)(edge.source);
22621
+ if (edge.type !== import_types100.EdgeType.CONFIGURED_BY) continue;
22622
+ const parsed = (0, import_types100.parseFileId)(edge.source);
22008
22623
  if (parsed) return parsed.service;
22009
22624
  }
22010
22625
  return null;
@@ -22015,7 +22630,7 @@ function findConfigNode(graph, basenames, serviceName) {
22015
22630
  graph.forEachNode((id, attrs) => {
22016
22631
  if (scoped) return;
22017
22632
  const node = attrs;
22018
- if (node.type !== import_types98.NodeType.ConfigNode) return;
22633
+ if (node.type !== import_types100.NodeType.ConfigNode) return;
22019
22634
  if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
22020
22635
  if (anyMatch === null) anyMatch = id;
22021
22636
  if (configNodeService(graph, id) === serviceName) scoped = id;
@@ -22032,13 +22647,13 @@ function createEasResolveTarget(graph) {
22032
22647
  if (basenames.length > 0) {
22033
22648
  const configNodeId = findConfigNode(graph, basenames, serviceName);
22034
22649
  if (configNodeId) {
22035
- return { targetNodeId: configNodeId, serviceName, edgeType: import_types98.EdgeType.CALLS };
22650
+ return { targetNodeId: configNodeId, serviceName, edgeType: import_types100.EdgeType.CALLS };
22036
22651
  }
22037
22652
  }
22038
22653
  return {
22039
22654
  targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
22040
22655
  serviceName,
22041
- edgeType: import_types98.EdgeType.CALLS
22656
+ edgeType: import_types100.EdgeType.CALLS
22042
22657
  };
22043
22658
  };
22044
22659
  }
@@ -22682,6 +23297,35 @@ function registerRoutes(scope, ctx) {
22682
23297
  if (!proj) return;
22683
23298
  handleSse(req, reply, { project: proj.name });
22684
23299
  });
23300
+ scope.get(
23301
+ "/incident-triggers",
23302
+ { config: BEARER_DELEGATED },
23303
+ (req, reply) => {
23304
+ const token = ctx.incidentStreamToken;
23305
+ if (!token || Buffer.byteLength(token, "utf8") < 32 || token === ctx.generalAuthToken || !ctx.incidentReplayDurable) {
23306
+ return reply.code(503).send({ error: "incident trigger stream unavailable" });
23307
+ }
23308
+ const header = req.headers.authorization;
23309
+ const supplied = typeof header === "string" && header.startsWith("Bearer ") ? Buffer.from(header.slice("Bearer ".length), "utf8") : void 0;
23310
+ const expected = Buffer.from(token, "utf8");
23311
+ if (!supplied || supplied.length !== expected.length || !(0, import_node_crypto6.timingSafeEqual)(supplied, expected)) {
23312
+ return reply.code(401).send({ error: "unauthorized" });
23313
+ }
23314
+ const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
23315
+ if (!proj) return;
23316
+ const errorsPath = errorsPathFor(proj);
23317
+ if (!errorsPath) return reply.code(503).send({ error: "incident replay unavailable" });
23318
+ let replay;
23319
+ try {
23320
+ const cursor = req.headers["last-event-id"];
23321
+ if (Array.isArray(cursor)) throw new Error("invalid cursor");
23322
+ replay = loadIncidentReplay(errorsPath, cursor);
23323
+ } catch {
23324
+ return reply.code(409).send({ error: "incident replay unavailable" });
23325
+ }
23326
+ handleSse(req, reply, { project: proj.name, incidentOnly: true, incidentReplay: replay });
23327
+ }
23328
+ );
22685
23329
  if (ctx.scope === "project") {
22686
23330
  scope.get("/health", async (req, reply) => {
22687
23331
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
@@ -22771,11 +23415,11 @@ function registerRoutes(scope, ctx) {
22771
23415
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
22772
23416
  const parsed = [];
22773
23417
  for (const c of candidates) {
22774
- const r = import_types101.DivergenceTypeSchema.safeParse(c);
23418
+ const r = import_types103.DivergenceTypeSchema.safeParse(c);
22775
23419
  if (!r.success) {
22776
23420
  return reply.code(400).send({
22777
23421
  error: `unknown divergence type "${c}"`,
22778
- allowed: import_types101.DivergenceTypeSchema.options
23422
+ allowed: import_types103.DivergenceTypeSchema.options
22779
23423
  });
22780
23424
  }
22781
23425
  parsed.push(r.data);
@@ -22967,7 +23611,7 @@ function registerRoutes(scope, ctx) {
22967
23611
  const incidents = epath ? await readErrorEvents(epath) : [];
22968
23612
  let errorEvent;
22969
23613
  if (req.query.errorId) {
22970
- errorEvent = incidents.find((e) => e.id === req.query.errorId);
23614
+ errorEvent = incidents.find((e) => e.id === req.query.errorId) ?? (epath ? await readErrorEventById(epath, req.query.errorId) : void 0);
22971
23615
  if (!errorEvent) {
22972
23616
  return reply.code(404).send({ error: "error event not found", id: req.query.errorId });
22973
23617
  }
@@ -23153,6 +23797,26 @@ function registerRoutes(scope, ctx) {
23153
23797
  }
23154
23798
  return reply.code(202).send({ project: proj.name, ...syncNow() });
23155
23799
  });
23800
+ scope.post("/pr-verdict", async (req, reply) => {
23801
+ const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
23802
+ if (!proj) return;
23803
+ try {
23804
+ const request = parsePrVerdictRequest(req.body);
23805
+ const epath = errorsPathFor(proj);
23806
+ const incidents = epath ? await readErrorEvents(epath) : [];
23807
+ const verdict = await ctx.prVerdict(request, { liveGraph: proj.graph, incidents });
23808
+ return { project: proj.name, ...verdict };
23809
+ } catch (err) {
23810
+ if (!(err instanceof PrVerdictError)) throw err;
23811
+ if (err.status === 429) void reply.header("retry-after", "30");
23812
+ return reply.code(err.status).send({
23813
+ error: err.message,
23814
+ project: proj.name,
23815
+ ...err.stage ? { stage: err.stage } : {},
23816
+ ...err.details !== void 0 ? { details: err.details } : {}
23817
+ });
23818
+ }
23819
+ });
23156
23820
  scope.post("/graph/scan", async (req, reply) => {
23157
23821
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
23158
23822
  if (!proj) return;
@@ -23192,7 +23856,7 @@ function registerRoutes(scope, ctx) {
23192
23856
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
23193
23857
  let violations = await log.readAll();
23194
23858
  if (req.query.severity) {
23195
- const sev = import_types101.PolicySeveritySchema.safeParse(req.query.severity);
23859
+ const sev = import_types103.PolicySeveritySchema.safeParse(req.query.severity);
23196
23860
  if (!sev.success) {
23197
23861
  return reply.code(400).send({
23198
23862
  error: "invalid severity",
@@ -23231,7 +23895,7 @@ function registerRoutes(scope, ctx) {
23231
23895
  scope.post("/policies/check", async (req, reply) => {
23232
23896
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
23233
23897
  if (!proj) return;
23234
- const parsed = import_types101.PoliciesCheckBodySchema.safeParse(req.body ?? {});
23898
+ const parsed = import_types103.PoliciesCheckBodySchema.safeParse(req.body ?? {});
23235
23899
  if (!parsed.success) {
23236
23900
  return reply.code(400).send({
23237
23901
  error: "invalid /policies/check body",
@@ -23440,6 +24104,8 @@ async function buildApi(opts) {
23440
24104
  const authToken = opts.authToken ?? env.authToken;
23441
24105
  const trustProxy = opts.trustProxy ?? env.trustProxy;
23442
24106
  const publicRead = opts.publicRead ?? env.publicRead;
24107
+ const incidentStreamToken = opts.incidentStreamToken ?? process.env.NEAT_INCIDENT_STREAM_TOKEN;
24108
+ const incidentReplayDurable = opts.incidentReplayDurable ?? (process.env.NEAT_INCIDENT_REPLAY_DURABLE === "1" && Buffer.byteLength(process.env.NEAT_INCIDENT_DURABLE_TOKEN ?? "", "utf8") >= 32);
23443
24109
  mountBearerAuth(app, {
23444
24110
  token: authToken,
23445
24111
  trustProxy,
@@ -23475,6 +24141,9 @@ async function buildApi(opts) {
23475
24141
  const routeCtx = {
23476
24142
  registry,
23477
24143
  startedAt,
24144
+ incidentStreamToken,
24145
+ incidentReplayDurable,
24146
+ generalAuthToken: authToken,
23478
24147
  scope: "root",
23479
24148
  errorsPathFor,
23480
24149
  staleEventsPathFor,
@@ -23483,6 +24152,7 @@ async function buildApi(opts) {
23483
24152
  singleProject: opts.singleProject?.name,
23484
24153
  connectorsHome: opts.connectorsHome,
23485
24154
  repoSync: opts.repoSync,
24155
+ prVerdict: opts.prVerdict ?? createPrVerdictRunner(),
23486
24156
  runPoll: opts.runPoll ?? runConnectorPoll
23487
24157
  };
23488
24158
  app.get("/health", async () => {
@@ -23587,9 +24257,9 @@ init_otel_grpc();
23587
24257
 
23588
24258
  // src/search.ts
23589
24259
  init_cjs_shims();
23590
- var import_node_fs40 = require("fs");
23591
- var import_node_path76 = __toESM(require("path"), 1);
23592
- var import_node_crypto5 = require("crypto");
24260
+ var import_node_fs44 = require("fs");
24261
+ var import_node_path79 = __toESM(require("path"), 1);
24262
+ var import_node_crypto7 = require("crypto");
23593
24263
  var DEFAULT_LIMIT = 10;
23594
24264
  var NOMIC_DIM = 768;
23595
24265
  var MINI_LM_DIM = 384;
@@ -23653,7 +24323,7 @@ function embedText(node) {
23653
24323
  return parts.join(" ");
23654
24324
  }
23655
24325
  function attrsHash(node) {
23656
- return (0, import_node_crypto5.createHash)("sha1").update(embedText(node)).digest("hex").slice(0, 16);
24326
+ return (0, import_node_crypto7.createHash)("sha1").update(embedText(node)).digest("hex").slice(0, 16);
23657
24327
  }
23658
24328
  function cosine(a, b) {
23659
24329
  if (a.length !== b.length) return 0;
@@ -23742,7 +24412,7 @@ async function pickEmbedder() {
23742
24412
  }
23743
24413
  async function readCache(cachePath) {
23744
24414
  try {
23745
- const raw = await import_node_fs40.promises.readFile(cachePath, "utf8");
24415
+ const raw = await import_node_fs44.promises.readFile(cachePath, "utf8");
23746
24416
  const parsed = JSON.parse(raw);
23747
24417
  if (parsed.version !== 1) return null;
23748
24418
  return parsed;
@@ -23751,8 +24421,8 @@ async function readCache(cachePath) {
23751
24421
  }
23752
24422
  }
23753
24423
  async function writeCache(cachePath, cache) {
23754
- await import_node_fs40.promises.mkdir(import_node_path76.default.dirname(cachePath), { recursive: true });
23755
- await import_node_fs40.promises.writeFile(cachePath, JSON.stringify(cache));
24424
+ await import_node_fs44.promises.mkdir(import_node_path79.default.dirname(cachePath), { recursive: true });
24425
+ await import_node_fs44.promises.writeFile(cachePath, JSON.stringify(cache));
23756
24426
  }
23757
24427
  var VectorIndex = class {
23758
24428
  constructor(embedder, cachePath) {
@@ -23966,14 +24636,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
23966
24636
  async function main() {
23967
24637
  const baseDirEnv = process.env.NEAT_OUT_DIR;
23968
24638
  const legacyOutPath = process.env.NEAT_OUT_PATH;
23969
- 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");
23970
- const defaultScanPath = import_node_path77.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
24639
+ const baseDir = baseDirEnv ? import_node_path80.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path80.default.resolve(import_node_path80.default.dirname(legacyOutPath)) : import_node_path80.default.resolve("./neat-out");
24640
+ const defaultScanPath = import_node_path80.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
23971
24641
  const registry = new Projects();
23972
24642
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
23973
24643
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
23974
24644
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
23975
24645
  const projectScan = process.env[envKey];
23976
- await bootProject(registry, name, projectScan ? import_node_path77.default.resolve(projectScan) : void 0, baseDir);
24646
+ await bootProject(registry, name, projectScan ? import_node_path80.default.resolve(projectScan) : void 0, baseDir);
23977
24647
  }
23978
24648
  const host = process.env.HOST ?? "0.0.0.0";
23979
24649
  const port = Number(process.env.PORT ?? 8080);