@neat.is/core 0.8.1-dev.20260817 → 0.8.2-dev.20260818

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.cjs CHANGED
@@ -59,8 +59,8 @@ function mountBearerAuth(app, opts) {
59
59
  ]);
60
60
  const publicRead = opts.publicRead === true;
61
61
  app.addHook("preHandler", (req, reply, done) => {
62
- const path68 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
- if (exactUnauthPaths.has(path68) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path68)) {
62
+ const path71 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
+ if (exactUnauthPaths.has(path71) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path71)) {
64
64
  done();
65
65
  return;
66
66
  }
@@ -192,8 +192,8 @@ function reshapeGrpcRequest(req) {
192
192
  };
193
193
  }
194
194
  function resolveProtoRoot() {
195
- const here = import_node_path47.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
- return import_node_path47.default.resolve(here, "..", "proto");
195
+ const here = import_node_path50.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
+ return import_node_path50.default.resolve(here, "..", "proto");
197
197
  }
198
198
  function loadTraceService() {
199
199
  const protoRoot = resolveProtoRoot();
@@ -261,13 +261,13 @@ async function startOtelGrpcReceiver(opts) {
261
261
  })
262
262
  };
263
263
  }
264
- var import_node_url, import_node_path47, import_node_crypto2, grpc, protoLoader;
264
+ var import_node_url, import_node_path50, import_node_crypto2, grpc, protoLoader;
265
265
  var init_otel_grpc = __esm({
266
266
  "src/otel-grpc.ts"() {
267
267
  "use strict";
268
268
  init_cjs_shims();
269
269
  import_node_url = require("url");
270
- import_node_path47 = __toESM(require("path"), 1);
270
+ import_node_path50 = __toESM(require("path"), 1);
271
271
  import_node_crypto2 = require("crypto");
272
272
  grpc = __toESM(require("@grpc/grpc-js"), 1);
273
273
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -413,8 +413,8 @@ function websocketChannelPathOf(attrs) {
413
413
  const v = attrs[key];
414
414
  if (typeof v === "string" && v.length > 0) {
415
415
  const q = v.indexOf("?");
416
- const path68 = q === -1 ? v : v.slice(0, q);
417
- if (path68.length > 0) return path68;
416
+ const path71 = q === -1 ? v : v.slice(0, q);
417
+ if (path71.length > 0) return path71;
418
418
  }
419
419
  }
420
420
  return void 0;
@@ -476,10 +476,10 @@ function parseOtlpRequest(body) {
476
476
  return out;
477
477
  }
478
478
  function loadProtoRoot() {
479
- const here = import_node_path48.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
480
- const protoRoot = import_node_path48.default.resolve(here, "..", "proto");
479
+ const here = import_node_path51.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
480
+ const protoRoot = import_node_path51.default.resolve(here, "..", "proto");
481
481
  const root = new import_protobufjs.default.Root();
482
- root.resolvePath = (_origin, target) => import_node_path48.default.resolve(protoRoot, target);
482
+ root.resolvePath = (_origin, target) => import_node_path51.default.resolve(protoRoot, target);
483
483
  root.loadSync(
484
484
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
485
485
  { keepCase: true }
@@ -710,12 +710,12 @@ async function buildOtelReceiver(opts) {
710
710
  };
711
711
  return decorated;
712
712
  }
713
- var import_node_path48, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
713
+ var import_node_path51, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
714
714
  var init_otel = __esm({
715
715
  "src/otel.ts"() {
716
716
  "use strict";
717
717
  init_cjs_shims();
718
- import_node_path48 = __toESM(require("path"), 1);
718
+ import_node_path51 = __toESM(require("path"), 1);
719
719
  import_node_url2 = require("url");
720
720
  import_fastify = __toESM(require("fastify"), 1);
721
721
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -731,7 +731,7 @@ var init_otel = __esm({
731
731
 
732
732
  // src/server.ts
733
733
  init_cjs_shims();
734
- var import_node_path67 = __toESM(require("path"), 1);
734
+ var import_node_path70 = __toESM(require("path"), 1);
735
735
 
736
736
  // src/graph.ts
737
737
  init_cjs_shims();
@@ -755,7 +755,7 @@ function getGraph(project = DEFAULT_PROJECT) {
755
755
  init_cjs_shims();
756
756
  var import_fastify2 = __toESM(require("fastify"), 1);
757
757
  var import_cors = __toESM(require("@fastify/cors"), 1);
758
- var import_types85 = require("@neat.is/types");
758
+ var import_types88 = require("@neat.is/types");
759
759
 
760
760
  // src/extend/index.ts
761
761
  init_cjs_shims();
@@ -2015,7 +2015,7 @@ var import_node_fs5 = require("fs");
2015
2015
  var import_node_path5 = __toESM(require("path"), 1);
2016
2016
  var import_yaml = require("yaml");
2017
2017
  var import_types3 = require("@neat.is/types");
2018
- var SERVICE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".tsx", ".py", ".go", ".rb", ".php"]);
2018
+ var SERVICE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".tsx", ".py", ".go", ".rb", ".php", ".cs", ".java"]);
2019
2019
  var CONFIG_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".yaml", ".yml"]);
2020
2020
  var JSON_CONFIG_FILENAMES = /* @__PURE__ */ new Set(["app.json", "app.config.json", "eas.json"]);
2021
2021
  var IGNORED_DIRS = /* @__PURE__ */ new Set([
@@ -2338,6 +2338,10 @@ function languageForPath(relPath) {
2338
2338
  return "ruby";
2339
2339
  case ".php":
2340
2340
  return "php";
2341
+ case ".cs":
2342
+ return "csharp";
2343
+ case ".java":
2344
+ return "java";
2341
2345
  case ".ts":
2342
2346
  case ".tsx":
2343
2347
  return "typescript";
@@ -2874,8 +2878,8 @@ function chiRoutesFromSource(source, parser) {
2874
2878
  chiWalk(tree.rootNode, "", out);
2875
2879
  return out;
2876
2880
  }
2877
- function stripChiRegex(path68) {
2878
- return path68.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
2881
+ function stripChiRegex(path71) {
2882
+ return path71.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
2879
2883
  }
2880
2884
  function chiWalk(node, prefix, out) {
2881
2885
  for (let i = 0; i < node.namedChildCount; i++) {
@@ -3547,9 +3551,9 @@ function rubyRocketRoute(args) {
3547
3551
  if (!pair || pair.type !== "pair") continue;
3548
3552
  const k = pair.childForFieldName("key");
3549
3553
  if (k?.type !== "string") continue;
3550
- const path68 = rubyLiteral(k);
3551
- if (path68 === null) continue;
3552
- return { path: path68, target: rubyLiteral(pair.childForFieldName("value")) };
3554
+ const path71 = rubyLiteral(k);
3555
+ if (path71 === null) continue;
3556
+ return { path: path71, target: rubyLiteral(pair.childForFieldName("value")) };
3553
3557
  }
3554
3558
  return null;
3555
3559
  }
@@ -4777,7 +4781,7 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
4777
4781
  }
4778
4782
  return sid;
4779
4783
  }
4780
- function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
4784
+ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint = true) {
4781
4785
  const line = callSite.line;
4782
4786
  if (line === void 0) return fileNodeId;
4783
4787
  let sawSymbol = false;
@@ -4792,7 +4796,7 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
4792
4796
  }
4793
4797
  });
4794
4798
  if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn);
4795
- if (sawSymbol && callSite.fn) {
4799
+ if (mint && sawSymbol && callSite.fn) {
4796
4800
  return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line);
4797
4801
  }
4798
4802
  return fileNodeId;
@@ -5198,6 +5202,20 @@ function incidentAffectedNode(span, graph, scanPath) {
5198
5202
  const callSite = callSiteFromSpan(span, serviceNode, scanPath);
5199
5203
  if (callSite) {
5200
5204
  const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
5205
+ const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
5206
+ if (graph) {
5207
+ const fusedFileId = (0, import_types7.fileId)(canonicalService, relPath);
5208
+ if (graph.hasNode(fusedFileId)) {
5209
+ return landObservedSymbol(
5210
+ graph,
5211
+ fusedFileId,
5212
+ canonicalService,
5213
+ relPath,
5214
+ { ...callSite, relPath },
5215
+ false
5216
+ );
5217
+ }
5218
+ }
5201
5219
  return (0, import_types7.fileId)(span.service, relPath);
5202
5220
  }
5203
5221
  return sid;
@@ -5536,7 +5554,11 @@ async function handleSpan(ctx, span) {
5536
5554
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
5537
5555
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
5538
5556
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
5539
- affectedNode
5557
+ // Attribute to where the failure originated — the symbol / file / service
5558
+ // the throwing span named (incidentAffectedNode, ADR-191) — the same
5559
+ // source-based attribution the durable receiver write uses, not the
5560
+ // outbound edge target this span happened to mint.
5561
+ affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
5540
5562
  };
5541
5563
  await appendErrorEvent(ctx, ev);
5542
5564
  }
@@ -5574,29 +5596,29 @@ function promoteFrontierNodes(graph, opts = {}) {
5574
5596
  toPromote.push({ frontierId: id, serviceId: target });
5575
5597
  });
5576
5598
  let promoted = 0;
5577
- for (const { frontierId: frontierId2, serviceId: serviceId9 } of toPromote) {
5599
+ for (const { frontierId: frontierId2, serviceId: serviceId12 } of toPromote) {
5578
5600
  if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {
5579
5601
  const gate = canPromoteFrontier(graph, frontierId2, opts.policies, opts.policyCtx);
5580
5602
  if (!gate.allowed) {
5581
5603
  continue;
5582
5604
  }
5583
5605
  }
5584
- rewireFrontierEdges(graph, frontierId2, serviceId9);
5606
+ rewireFrontierEdges(graph, frontierId2, serviceId12);
5585
5607
  graph.dropNode(frontierId2);
5586
5608
  promoted++;
5587
5609
  }
5588
5610
  return promoted;
5589
5611
  }
5590
- function rewireFrontierEdges(graph, frontierId2, serviceId9) {
5612
+ function rewireFrontierEdges(graph, frontierId2, serviceId12) {
5591
5613
  const inbound = [...graph.inboundEdges(frontierId2)];
5592
5614
  const outbound = [...graph.outboundEdges(frontierId2)];
5593
5615
  for (const edgeId of inbound) {
5594
5616
  const edge = graph.getEdgeAttributes(edgeId);
5595
- rebuildEdge(graph, edge, edge.source, serviceId9, edgeId);
5617
+ rebuildEdge(graph, edge, edge.source, serviceId12, edgeId);
5596
5618
  }
5597
5619
  for (const edgeId of outbound) {
5598
5620
  const edge = graph.getEdgeAttributes(edgeId);
5599
- rebuildEdge(graph, edge, serviceId9, edge.target, edgeId);
5621
+ rebuildEdge(graph, edge, serviceId12, edge.target, edgeId);
5600
5622
  }
5601
5623
  }
5602
5624
  function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
@@ -5915,19 +5937,19 @@ function confidenceFromMix(edges, now = Date.now()) {
5915
5937
  function longestIncomingWalk(graph, start, maxDepth) {
5916
5938
  let best = { path: [start], edges: [] };
5917
5939
  const visited = /* @__PURE__ */ new Set([start]);
5918
- function step(node, path68, edges) {
5919
- if (path68.length > best.path.length) {
5920
- best = { path: [...path68], edges: [...edges] };
5940
+ function step(node, path71, edges) {
5941
+ if (path71.length > best.path.length) {
5942
+ best = { path: [...path71], edges: [...edges] };
5921
5943
  }
5922
- if (path68.length - 1 >= maxDepth) return;
5944
+ if (path71.length - 1 >= maxDepth) return;
5923
5945
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
5924
5946
  for (const [srcId, edge] of incoming) {
5925
5947
  if (visited.has(srcId)) continue;
5926
5948
  visited.add(srcId);
5927
- path68.push(srcId);
5949
+ path71.push(srcId);
5928
5950
  edges.push(edge);
5929
- step(srcId, path68, edges);
5930
- path68.pop();
5951
+ step(srcId, path71, edges);
5952
+ path71.pop();
5931
5953
  edges.pop();
5932
5954
  visited.delete(srcId);
5933
5955
  }
@@ -5942,7 +5964,7 @@ function databaseRootCauseShape(graph, origin, walk9) {
5942
5964
  for (const id of walk9.path) {
5943
5965
  const owner = resolveOwningService(graph, id);
5944
5966
  if (!owner) continue;
5945
- const { id: serviceId9, svc } = owner;
5967
+ const { id: serviceId12, svc } = owner;
5946
5968
  const deps = svc.dependencies ?? {};
5947
5969
  for (const pair of candidatePairs) {
5948
5970
  const declared = deps[pair.driver];
@@ -5955,7 +5977,7 @@ function databaseRootCauseShape(graph, origin, walk9) {
5955
5977
  );
5956
5978
  if (!result.compatible) {
5957
5979
  return {
5958
- rootCauseNode: serviceId9,
5980
+ rootCauseNode: serviceId12,
5959
5981
  rootCauseReason: result.reason ?? "incompatible driver",
5960
5982
  ...result.minDriverVersion ? {
5961
5983
  fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`
@@ -5970,7 +5992,7 @@ function serviceRootCauseShape(graph, _origin, walk9) {
5970
5992
  for (const id of walk9.path) {
5971
5993
  const owner = resolveOwningService(graph, id);
5972
5994
  if (!owner) continue;
5973
- const { id: serviceId9, svc } = owner;
5995
+ const { id: serviceId12, svc } = owner;
5974
5996
  const deps = svc.dependencies ?? {};
5975
5997
  const serviceNodeEngine = svc.nodeEngine;
5976
5998
  for (const constraint of nodeEngineConstraints()) {
@@ -5979,7 +6001,7 @@ function serviceRootCauseShape(graph, _origin, walk9) {
5979
6001
  const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine);
5980
6002
  if (!result.compatible && result.reason) {
5981
6003
  return {
5982
- rootCauseNode: serviceId9,
6004
+ rootCauseNode: serviceId12,
5983
6005
  rootCauseReason: result.reason,
5984
6006
  ...result.requiredNodeVersion ? {
5985
6007
  fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`
@@ -5994,7 +6016,7 @@ function serviceRootCauseShape(graph, _origin, walk9) {
5994
6016
  const result = checkPackageConflict(conflict, declared, requiredDeclared);
5995
6017
  if (!result.compatible && result.reason) {
5996
6018
  return {
5997
- rootCauseNode: serviceId9,
6019
+ rootCauseNode: serviceId12,
5998
6020
  rootCauseReason: result.reason,
5999
6021
  fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`
6000
6022
  };
@@ -6046,7 +6068,11 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
6046
6068
  }
6047
6069
  var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
6048
6070
  function incidentMatchesNode(ev, nodeId) {
6049
- return ev.affectedNode === nodeId || ev.service === nodeId.replace(/^service:/, "");
6071
+ if (ev.affectedNode === nodeId) return true;
6072
+ if (ev.service === nodeId.replace(/^service:/, "")) return true;
6073
+ const sym = (0, import_types8.parseSymbolId)(ev.affectedNode);
6074
+ if (sym && (0, import_types8.fileId)(sym.service, sym.relPath) === nodeId) return true;
6075
+ return false;
6050
6076
  }
6051
6077
  function localizeFromIncidents(nodeId, incidents, errorEvent) {
6052
6078
  const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : [];
@@ -6064,8 +6090,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
6064
6090
  const reasonParts = [`${latest.service}: ${latest.errorMessage}`];
6065
6091
  if (location) reasonParts.push(`surfaced at ${location}`);
6066
6092
  const rootCauseReason = `${reasonParts.join(" \u2014 ")}${tail}`;
6067
- const localizesToFile = latest.affectedNode !== nodeId && latest.affectedNode.startsWith("file:");
6068
- const fileNode = localizesToFile ? latest.affectedNode : void 0;
6093
+ const localizesFiner = latest.affectedNode !== nodeId && (latest.affectedNode.startsWith("file:") || latest.affectedNode.startsWith("symbol:"));
6094
+ const fileNode = localizesFiner ? latest.affectedNode : void 0;
6069
6095
  const fixRecommendation = location ? `Inspect ${location}${route ? ` handling ${route}` : ""}` : route ? `Inspect ${latest.service}'s handler for ${route}` : void 0;
6070
6096
  return {
6071
6097
  rootCauseNode: fileNode ?? nodeId,
@@ -6091,9 +6117,9 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
6091
6117
  function isFailingCallEdge(e) {
6092
6118
  return e.type === import_types8.EdgeType.CALLS && (e.signal?.errorCount ?? 0) > 0;
6093
6119
  }
6094
- function callSourcesForService(graph, serviceId9) {
6095
- const ids = [serviceId9];
6096
- for (const edgeId of graph.outboundEdges(serviceId9)) {
6120
+ function callSourcesForService(graph, serviceId12) {
6121
+ const ids = [serviceId12];
6122
+ for (const edgeId of graph.outboundEdges(serviceId12)) {
6097
6123
  const e = graph.getEdgeAttributes(edgeId);
6098
6124
  if (e.type !== import_types8.EdgeType.CONTAINS) continue;
6099
6125
  const tgt = graph.getNodeAttributes(e.target);
@@ -6117,9 +6143,9 @@ function failingCallDominates(e, id, curEdge, curId) {
6117
6143
  }
6118
6144
  return id < curId;
6119
6145
  }
6120
- function dominantFailingCall(graph, serviceId9, visited) {
6146
+ function dominantFailingCall(graph, serviceId12, visited) {
6121
6147
  let best = null;
6122
- for (const src of callSourcesForService(graph, serviceId9)) {
6148
+ for (const src of callSourcesForService(graph, serviceId12)) {
6123
6149
  for (const edgeId of graph.outboundEdges(src)) {
6124
6150
  const e = graph.getEdgeAttributes(edgeId);
6125
6151
  if (!isFailingCallEdge(e)) continue;
@@ -6134,26 +6160,26 @@ function dominantFailingCall(graph, serviceId9, visited) {
6134
6160
  return best;
6135
6161
  }
6136
6162
  function followFailingCallChain(graph, originServiceId, maxDepth) {
6137
- const path68 = [originServiceId];
6163
+ const path71 = [originServiceId];
6138
6164
  const edges = [];
6139
6165
  const visited = /* @__PURE__ */ new Set([originServiceId]);
6140
6166
  let current = originServiceId;
6141
6167
  for (let depth = 0; depth < maxDepth; depth++) {
6142
6168
  const hop = dominantFailingCall(graph, current, visited);
6143
6169
  if (!hop) break;
6144
- path68.push(hop.nextService);
6170
+ path71.push(hop.nextService);
6145
6171
  edges.push(hop.edge);
6146
6172
  visited.add(hop.nextService);
6147
6173
  current = hop.nextService;
6148
6174
  }
6149
6175
  if (edges.length === 0) return null;
6150
- return { path: path68, edges, culprit: current };
6176
+ return { path: path71, edges, culprit: current };
6151
6177
  }
6152
6178
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6153
6179
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
6154
6180
  if (!chain) return null;
6155
6181
  const culprit = chain.culprit;
6156
- const path68 = [...chain.path];
6182
+ const path71 = [...chain.path];
6157
6183
  const edgeProvenances = chain.edges.map((e) => e.provenance);
6158
6184
  const baseConfidence = confidenceFromMix(chain.edges);
6159
6185
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -6161,14 +6187,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6161
6187
  if (loc) {
6162
6188
  let rootCauseNode = culprit;
6163
6189
  if (loc.fileNode) {
6164
- path68.push(loc.fileNode);
6190
+ path71.push(loc.fileNode);
6165
6191
  edgeProvenances.push(import_types8.Provenance.OBSERVED);
6166
6192
  rootCauseNode = loc.fileNode;
6167
6193
  }
6168
6194
  return import_types8.RootCauseResultSchema.parse({
6169
6195
  rootCauseNode,
6170
6196
  rootCauseReason: loc.rootCauseReason,
6171
- traversalPath: path68,
6197
+ traversalPath: path71,
6172
6198
  edgeProvenances,
6173
6199
  confidence,
6174
6200
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -6180,7 +6206,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
6180
6206
  return import_types8.RootCauseResultSchema.parse({
6181
6207
  rootCauseNode: culprit,
6182
6208
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
6183
- traversalPath: path68,
6209
+ traversalPath: path71,
6184
6210
  edgeProvenances,
6185
6211
  confidence,
6186
6212
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -6550,6 +6576,22 @@ function findLoadOrigin(graph, alertNodeId, incidents, now) {
6550
6576
  }
6551
6577
  return best ? { node: best.node, ctx: best.ctx } : null;
6552
6578
  }
6579
+ var LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9;
6580
+ function loadOriginConfidence(originCtx, seedCtx) {
6581
+ const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0;
6582
+ const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere;
6583
+ let evidence = 0;
6584
+ evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0;
6585
+ evidence += seedCtx.stale ? 0.2 : 0;
6586
+ evidence += isSaturated(seedCtx) ? 0.15 : 0;
6587
+ evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4;
6588
+ const anchor = 0.45;
6589
+ const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor);
6590
+ return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence));
6591
+ }
6592
+ function displayNameOf(nodeId) {
6593
+ return nodeId.replace(/^[a-z]+:/, "");
6594
+ }
6553
6595
  function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
6554
6596
  const legacy = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
6555
6597
  if (!legacy) return null;
@@ -6564,20 +6606,20 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
6564
6606
  const candidates = [];
6565
6607
  if (seedCtx && isVictimSeed(seedCtx)) {
6566
6608
  const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
6609
+ const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
6610
+ const satNote = isSaturated(seedCtx) ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
6567
6611
  if (origin) {
6568
- const path68 = findPath(graph, errorNodeId, origin.node, "up", ROOT_CAUSE_MAX_DEPTH);
6569
- const originConfidence = confidenceFromMix(path68?.edges ?? [], now);
6612
+ const originName = displayNameOf(origin.node);
6613
+ const seedName = displayNameOf(seedNode);
6570
6614
  candidates.push({
6571
6615
  node: origin.node,
6572
6616
  classification: "primary-failure",
6573
- reason: `Highest-volume upstream source (${origin.ctx.outboundVolume} observed outbound calls) driving a saturated/stale subgraph; the alerting path decays downstream into a starved victim rather than a fault at the callee.`,
6617
+ reason: `${originName} is the root cause: it overloads the failing subgraph, and the alerting node ${seedName} is a downstream symptom, not the fault \u2014 errors reach ${seedName} from its callers (${seedCtx.errorsFromCallers}), none originate there${staleNote}${satNote}. ${originName} is the upstream source driving that load (${origin.ctx.outboundVolume} observed outbound calls).`,
6574
6618
  context: origin.ctx,
6575
- confidence: Math.max(0.3, Math.min(0.8, originConfidence || 0.5)),
6619
+ confidence: loadOriginConfidence(origin.ctx, seedCtx),
6576
6620
  provenance: import_types8.Provenance.OBSERVED
6577
6621
  });
6578
6622
  }
6579
- const staleNote = seedCtx.stale ? "; the node has gone STALE" : "";
6580
- const satNote = isSaturated(seedCtx) ? `; inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
6581
6623
  candidates.push({
6582
6624
  node: seedNode,
6583
6625
  classification: "symptom-only",
@@ -6600,25 +6642,36 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
6600
6642
  let traversalPath = legacy.traversalPath;
6601
6643
  let edgeProvenances = legacy.edgeProvenances;
6602
6644
  if (top.node !== seedNode) {
6603
- const path68 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
6604
- if (path68) {
6605
- traversalPath = path68.nodes;
6606
- edgeProvenances = path68.edges.map((e) => e.provenance);
6645
+ const path71 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
6646
+ if (path71) {
6647
+ traversalPath = path71.nodes;
6648
+ edgeProvenances = path71.edges.map((e) => e.provenance);
6607
6649
  } else {
6608
6650
  traversalPath = [errorNodeId, top.node];
6609
6651
  edgeProvenances = [top.provenance ?? import_types8.Provenance.OBSERVED];
6610
6652
  }
6611
6653
  }
6654
+ const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy);
6612
6655
  return import_types8.RootCauseResultSchema.parse({
6613
6656
  rootCauseNode: top.node,
6614
6657
  rootCauseReason: top.reason,
6615
6658
  traversalPath,
6616
6659
  edgeProvenances,
6617
6660
  confidence: top.confidence,
6618
- ...legacy.fixRecommendation ? { fixRecommendation: legacy.fixRecommendation } : {},
6661
+ ...fixRecommendation ? { fixRecommendation } : {},
6619
6662
  candidates
6620
6663
  });
6621
6664
  }
6665
+ function fixRecommendationForTop(top, seedNode, legacy) {
6666
+ if (top.classification === "primary-failure" && top.node === seedNode) {
6667
+ return legacy.fixRecommendation;
6668
+ }
6669
+ const name = top.node.replace(/^service:/, "");
6670
+ if (top.classification === "primary-failure") {
6671
+ return `Reduce or throttle the load from ${name} (or scale the saturated downstream capacity it drives) \u2014 the failure originates at this overloading source, not the starved callee.`;
6672
+ }
6673
+ return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`;
6674
+ }
6622
6675
 
6623
6676
  // src/divergences.ts
6624
6677
  function bucketKey(source, target, type) {
@@ -7004,11 +7057,11 @@ init_cjs_shims();
7004
7057
 
7005
7058
  // src/extract/services.ts
7006
7059
  init_cjs_shims();
7007
- var import_node_fs14 = require("fs");
7008
- var import_node_path16 = __toESM(require("path"), 1);
7060
+ var import_node_fs17 = require("fs");
7061
+ var import_node_path19 = __toESM(require("path"), 1);
7009
7062
  var import_ignore = __toESM(require("ignore"), 1);
7010
7063
  var import_minimatch2 = require("minimatch");
7011
- var import_types13 = require("@neat.is/types");
7064
+ var import_types16 = require("@neat.is/types");
7012
7065
 
7013
7066
  // src/extract/python.ts
7014
7067
  init_cjs_shims();
@@ -7201,19 +7254,234 @@ async function discoverPhpService(scanPath, dir) {
7201
7254
  return { pkg, dir, node };
7202
7255
  }
7203
7256
 
7204
- // src/extract/owners.ts
7257
+ // src/extract/csharp.ts
7205
7258
  init_cjs_shims();
7206
7259
  var import_node_fs13 = require("fs");
7207
7260
  var import_node_path15 = __toESM(require("path"), 1);
7261
+ var import_types13 = require("@neat.is/types");
7262
+ var CSHARP_PROJECT_EXTS = /* @__PURE__ */ new Set([".csproj", ".sln"]);
7263
+ async function projectFiles(dir) {
7264
+ const entries = await import_node_fs13.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
7265
+ const out = [];
7266
+ for (const entry of entries) {
7267
+ if (!entry.isFile()) continue;
7268
+ if (CSHARP_PROJECT_EXTS.has(import_node_path15.default.extname(entry.name).toLowerCase())) out.push(entry.name);
7269
+ }
7270
+ return out.sort();
7271
+ }
7272
+ var NESTED_PROJECT_DIR = "src";
7273
+ async function resolveProjectDir(dir) {
7274
+ if ((await projectFiles(dir)).length > 0) return dir;
7275
+ const nested = import_node_path15.default.join(dir, NESTED_PROJECT_DIR);
7276
+ if ((await projectFiles(nested)).length > 0) return nested;
7277
+ return null;
7278
+ }
7279
+ async function hasCsharpProject(dir) {
7280
+ return await resolveProjectDir(dir) !== null;
7281
+ }
7282
+ function parseCsproj(source) {
7283
+ const dependencies = {};
7284
+ const re = /<PackageReference\b([^>]*?)\/?>/g;
7285
+ let m;
7286
+ while ((m = re.exec(source)) !== null) {
7287
+ const attrs = m[1] ?? "";
7288
+ const include = attrs.match(/\bInclude\s*=\s*"([^"]+)"/)?.[1];
7289
+ if (!include) continue;
7290
+ const version = attrs.match(/\bVersion\s*=\s*"([^"]+)"/)?.[1];
7291
+ dependencies[include] = version ?? "";
7292
+ }
7293
+ return { dependencies };
7294
+ }
7295
+ async function discoverCsharpService(scanPath, dir) {
7296
+ const projectDir = await resolveProjectDir(dir);
7297
+ if (projectDir === null) return null;
7298
+ const projects = await projectFiles(projectDir);
7299
+ const csproj = projects.find((p) => p.toLowerCase().endsWith(".csproj"));
7300
+ const name = csproj ? import_node_path15.default.basename(csproj, import_node_path15.default.extname(csproj)) : import_node_path15.default.basename(dir);
7301
+ let dependencies = {};
7302
+ if (csproj) {
7303
+ const raw = await import_node_fs13.promises.readFile(import_node_path15.default.join(projectDir, csproj), "utf8").catch(() => "");
7304
+ dependencies = parseCsproj(raw).dependencies;
7305
+ }
7306
+ const pkg = { name, dependencies };
7307
+ const node = {
7308
+ id: (0, import_types13.serviceId)(name),
7309
+ type: import_types13.NodeType.ServiceNode,
7310
+ name,
7311
+ language: "csharp",
7312
+ dependencies,
7313
+ // Anchor on the directory that holds the project and its `.cs` files, so file
7314
+ // attribution reaches the source whether it sits at the root or under `src/`.
7315
+ repoPath: import_node_path15.default.relative(scanPath, projectDir)
7316
+ };
7317
+ return { pkg, dir: projectDir, node };
7318
+ }
7319
+
7320
+ // src/extract/java.ts
7321
+ init_cjs_shims();
7322
+ var import_node_fs14 = require("fs");
7323
+ var import_node_path16 = __toESM(require("path"), 1);
7324
+ var import_types14 = require("@neat.is/types");
7325
+ var JAVA_MANIFESTS = ["pom.xml", "build.gradle", "build.gradle.kts"];
7326
+ async function hasJavaManifest(dir) {
7327
+ for (const manifest of JAVA_MANIFESTS) {
7328
+ if (await exists2(import_node_path16.default.join(dir, manifest))) return true;
7329
+ }
7330
+ return false;
7331
+ }
7332
+ function parsePomXml(source) {
7333
+ const dependencies = {};
7334
+ const depBlock = /<dependency\b[^>]*>([\s\S]*?)<\/dependency>/g;
7335
+ let d;
7336
+ while ((d = depBlock.exec(source)) !== null) {
7337
+ const body = d[1] ?? "";
7338
+ const groupId = body.match(/<groupId>\s*([^<]+?)\s*<\/groupId>/)?.[1];
7339
+ const artifactId = body.match(/<artifactId>\s*([^<]+?)\s*<\/artifactId>/)?.[1];
7340
+ if (!groupId || !artifactId) continue;
7341
+ const version = body.match(/<version>\s*([^<]+?)\s*<\/version>/)?.[1];
7342
+ dependencies[`${groupId}:${artifactId}`] = version ?? "";
7343
+ }
7344
+ const withoutBlocks = source.replace(/<parent\b[^>]*>[\s\S]*?<\/parent>/g, "").replace(/<dependencyManagement\b[^>]*>[\s\S]*?<\/dependencyManagement>/g, "").replace(/<dependencies\b[^>]*>[\s\S]*?<\/dependencies>/g, "").replace(/<build\b[^>]*>[\s\S]*?<\/build>/g, "");
7345
+ const name = withoutBlocks.match(/<artifactId>\s*([^<]+?)\s*<\/artifactId>/)?.[1];
7346
+ return { name, dependencies };
7347
+ }
7348
+ var GRADLE_CONFIGS = "implementation|api|compileOnly|runtimeOnly|compileOnlyApi|testImplementation|testRuntimeOnly|testCompileOnly|annotationProcessor|developmentOnly|runtimeClasspath";
7349
+ function parseGradle(source) {
7350
+ const dependencies = {};
7351
+ const re = new RegExp(`\\b(?:${GRADLE_CONFIGS})\\s*\\(?\\s*(['"])([^'"]+)\\1`, "g");
7352
+ let m;
7353
+ while ((m = re.exec(source)) !== null) {
7354
+ const coord = m[2] ?? "";
7355
+ const parts = coord.split(":");
7356
+ if (parts.length < 2 || !parts[0] || !parts[1]) continue;
7357
+ const key = `${parts[0]}:${parts[1]}`;
7358
+ dependencies[key] = parts.slice(2).join(":");
7359
+ }
7360
+ return { dependencies };
7361
+ }
7362
+ async function discoverJavaService(scanPath, dir) {
7363
+ const pomPath = import_node_path16.default.join(dir, "pom.xml");
7364
+ const gradlePath = import_node_path16.default.join(dir, "build.gradle");
7365
+ const gradleKtsPath = import_node_path16.default.join(dir, "build.gradle.kts");
7366
+ let manifest = null;
7367
+ if (await exists2(pomPath)) {
7368
+ manifest = parsePomXml(await import_node_fs14.promises.readFile(pomPath, "utf8").catch(() => ""));
7369
+ } else if (await exists2(gradlePath)) {
7370
+ manifest = parseGradle(await import_node_fs14.promises.readFile(gradlePath, "utf8").catch(() => ""));
7371
+ } else if (await exists2(gradleKtsPath)) {
7372
+ manifest = parseGradle(await import_node_fs14.promises.readFile(gradleKtsPath, "utf8").catch(() => ""));
7373
+ }
7374
+ if (!manifest) return null;
7375
+ const name = manifest.name?.trim() || import_node_path16.default.basename(dir);
7376
+ const dependencies = manifest.dependencies;
7377
+ const pkg = { name, dependencies };
7378
+ const node = {
7379
+ id: (0, import_types14.serviceId)(name),
7380
+ type: import_types14.NodeType.ServiceNode,
7381
+ name,
7382
+ language: "java",
7383
+ dependencies,
7384
+ repoPath: import_node_path16.default.relative(scanPath, dir)
7385
+ };
7386
+ return { pkg, dir, node };
7387
+ }
7388
+
7389
+ // src/extract/dockerfile-service.ts
7390
+ init_cjs_shims();
7391
+ var import_node_fs15 = require("fs");
7392
+ var import_node_path17 = __toESM(require("path"), 1);
7393
+ var import_types15 = require("@neat.is/types");
7394
+ function languageForSourceExt(ext) {
7395
+ switch (ext) {
7396
+ case ".py":
7397
+ return "python";
7398
+ case ".go":
7399
+ return "go";
7400
+ case ".rb":
7401
+ return "ruby";
7402
+ case ".php":
7403
+ return "php";
7404
+ case ".cs":
7405
+ return "csharp";
7406
+ case ".java":
7407
+ return "java";
7408
+ case ".ts":
7409
+ case ".tsx":
7410
+ return "typescript";
7411
+ case ".js":
7412
+ case ".mjs":
7413
+ case ".cjs":
7414
+ return "javascript";
7415
+ default:
7416
+ return null;
7417
+ }
7418
+ }
7419
+ var LANGUAGE_PRECEDENCE = ["typescript", "javascript", "python", "go", "ruby", "php", "csharp", "java"];
7420
+ async function inferServiceLanguage(dir) {
7421
+ const entries = await import_node_fs15.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
7422
+ const counts = /* @__PURE__ */ new Map();
7423
+ for (const entry of entries) {
7424
+ if (!entry.isFile()) continue;
7425
+ if (isNeatAuthoredSourceFile(entry.name)) continue;
7426
+ const ext = import_node_path17.default.extname(entry.name).toLowerCase();
7427
+ if (!SERVICE_FILE_EXTENSIONS.has(ext)) continue;
7428
+ const lang = languageForSourceExt(ext);
7429
+ if (!lang) continue;
7430
+ counts.set(lang, (counts.get(lang) ?? 0) + 1);
7431
+ }
7432
+ if (counts.size === 0) return null;
7433
+ let best = null;
7434
+ let bestCount = -1;
7435
+ for (const lang of LANGUAGE_PRECEDENCE) {
7436
+ const c = counts.get(lang) ?? 0;
7437
+ if (c > bestCount) {
7438
+ best = lang;
7439
+ bestCount = c;
7440
+ }
7441
+ }
7442
+ return best;
7443
+ }
7444
+ async function hasLanguageManifest(dir) {
7445
+ return await exists2(import_node_path17.default.join(dir, "package.json")) || await exists2(import_node_path17.default.join(dir, "pyproject.toml")) || await exists2(import_node_path17.default.join(dir, "requirements.txt")) || await exists2(import_node_path17.default.join(dir, "setup.py")) || await exists2(import_node_path17.default.join(dir, "go.mod")) || await exists2(import_node_path17.default.join(dir, "Gemfile")) || await exists2(import_node_path17.default.join(dir, "composer.json")) || // C#'s marker is a glob (`*.csproj` / `*.sln`), so it reads the directory
7446
+ // rather than probing a fixed filename (ADR-196).
7447
+ await hasCsharpProject(dir) || // Java keys on a Maven / Gradle build manifest (ADR-197).
7448
+ await hasJavaManifest(dir);
7449
+ }
7450
+ async function hasDockerfileDeclaredService(dir) {
7451
+ if (!await exists2(import_node_path17.default.join(dir, "Dockerfile"))) return false;
7452
+ return await inferServiceLanguage(dir) !== null;
7453
+ }
7454
+ async function discoverDockerfileService(scanPath, dir) {
7455
+ if (!await exists2(import_node_path17.default.join(dir, "Dockerfile"))) return null;
7456
+ if (await hasLanguageManifest(dir)) return null;
7457
+ const language = await inferServiceLanguage(dir);
7458
+ if (!language) return null;
7459
+ const name = import_node_path17.default.basename(dir);
7460
+ const pkg = { name, dependencies: {} };
7461
+ const node = {
7462
+ id: (0, import_types15.serviceId)(name),
7463
+ type: import_types15.NodeType.ServiceNode,
7464
+ name,
7465
+ language,
7466
+ dependencies: {},
7467
+ repoPath: import_node_path17.default.relative(scanPath, dir)
7468
+ };
7469
+ return { pkg, dir, node };
7470
+ }
7471
+
7472
+ // src/extract/owners.ts
7473
+ init_cjs_shims();
7474
+ var import_node_fs16 = require("fs");
7475
+ var import_node_path18 = __toESM(require("path"), 1);
7208
7476
  var import_minimatch = require("minimatch");
7209
7477
  async function loadCodeowners(scanPath) {
7210
7478
  const candidates = [
7211
- import_node_path15.default.join(scanPath, "CODEOWNERS"),
7212
- import_node_path15.default.join(scanPath, ".github", "CODEOWNERS")
7479
+ import_node_path18.default.join(scanPath, "CODEOWNERS"),
7480
+ import_node_path18.default.join(scanPath, ".github", "CODEOWNERS")
7213
7481
  ];
7214
7482
  for (const file of candidates) {
7215
7483
  if (await exists2(file)) {
7216
- const raw = await import_node_fs13.promises.readFile(file, "utf8");
7484
+ const raw = await import_node_fs16.promises.readFile(file, "utf8");
7217
7485
  return parseCodeowners(raw);
7218
7486
  }
7219
7487
  }
@@ -7231,7 +7499,7 @@ function parseCodeowners(raw) {
7231
7499
  return { rules };
7232
7500
  }
7233
7501
  function matchOwner(file, repoPath) {
7234
- const normalized = repoPath.split(import_node_path15.default.sep).join("/");
7502
+ const normalized = repoPath.split(import_node_path18.default.sep).join("/");
7235
7503
  for (const rule of file.rules) {
7236
7504
  if (matchesPattern(rule.pattern, normalized)) return rule.owners;
7237
7505
  }
@@ -7247,7 +7515,7 @@ function matchesPattern(rawPattern, repoPath) {
7247
7515
  return false;
7248
7516
  }
7249
7517
  async function readPackageJsonAuthor(serviceDir) {
7250
- const pkgPath = import_node_path15.default.join(serviceDir, "package.json");
7518
+ const pkgPath = import_node_path18.default.join(serviceDir, "package.json");
7251
7519
  if (!await exists2(pkgPath)) return null;
7252
7520
  try {
7253
7521
  const pkg = await readJson(pkgPath);
@@ -7284,33 +7552,36 @@ function workspaceGlobs(pkg) {
7284
7552
  return null;
7285
7553
  }
7286
7554
  async function hasPythonManifest(dir) {
7287
- return await exists2(import_node_path16.default.join(dir, "pyproject.toml")) || await exists2(import_node_path16.default.join(dir, "requirements.txt")) || await exists2(import_node_path16.default.join(dir, "setup.py"));
7555
+ return await exists2(import_node_path19.default.join(dir, "pyproject.toml")) || await exists2(import_node_path19.default.join(dir, "requirements.txt")) || await exists2(import_node_path19.default.join(dir, "setup.py"));
7288
7556
  }
7289
7557
  async function hasGoManifest(dir) {
7290
- return exists2(import_node_path16.default.join(dir, "go.mod"));
7558
+ return exists2(import_node_path19.default.join(dir, "go.mod"));
7291
7559
  }
7292
7560
  async function hasRubyManifest(dir) {
7293
- return exists2(import_node_path16.default.join(dir, "Gemfile"));
7561
+ return exists2(import_node_path19.default.join(dir, "Gemfile"));
7294
7562
  }
7295
7563
  async function hasPhpManifest(dir) {
7296
- return exists2(import_node_path16.default.join(dir, "composer.json"));
7564
+ return exists2(import_node_path19.default.join(dir, "composer.json"));
7565
+ }
7566
+ async function hasCsharpManifest(dir) {
7567
+ return hasCsharpProject(dir);
7297
7568
  }
7298
7569
  async function loadGitignore(scanPath) {
7299
- const gitignorePath = import_node_path16.default.join(scanPath, ".gitignore");
7570
+ const gitignorePath = import_node_path19.default.join(scanPath, ".gitignore");
7300
7571
  if (!await exists2(gitignorePath)) return null;
7301
- const raw = await import_node_fs14.promises.readFile(gitignorePath, "utf8");
7572
+ const raw = await import_node_fs17.promises.readFile(gitignorePath, "utf8");
7302
7573
  return (0, import_ignore.default)().add(raw);
7303
7574
  }
7304
7575
  async function walkDirs(start, scanPath, options, visit) {
7305
7576
  async function recurse(current, depth) {
7306
7577
  if (depth > options.maxDepth) return;
7307
- const entries = await import_node_fs14.promises.readdir(current, { withFileTypes: true }).catch(() => []);
7578
+ const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
7308
7579
  for (const entry of entries) {
7309
7580
  if (!entry.isDirectory()) continue;
7310
7581
  if (IGNORED_DIRS.has(entry.name)) continue;
7311
- const child = import_node_path16.default.join(current, entry.name);
7582
+ const child = import_node_path19.default.join(current, entry.name);
7312
7583
  if (options.ig) {
7313
- const rel = import_node_path16.default.relative(scanPath, child).split(import_node_path16.default.sep).join("/");
7584
+ const rel = import_node_path19.default.relative(scanPath, child).split(import_node_path19.default.sep).join("/");
7314
7585
  if (rel && options.ig.ignores(rel + "/")) continue;
7315
7586
  }
7316
7587
  if (await isPythonVenvDir(child)) continue;
@@ -7326,8 +7597,8 @@ async function expandWorkspaceGlobs(scanPath, globs) {
7326
7597
  for (const raw of globs) {
7327
7598
  const pattern = raw.replace(/^\.\//, "");
7328
7599
  if (!pattern.includes("*")) {
7329
- const candidate = import_node_path16.default.join(scanPath, pattern);
7330
- if (await exists2(import_node_path16.default.join(candidate, "package.json"))) found.add(candidate);
7600
+ const candidate = import_node_path19.default.join(scanPath, pattern);
7601
+ if (await exists2(import_node_path19.default.join(candidate, "package.json"))) found.add(candidate);
7331
7602
  continue;
7332
7603
  }
7333
7604
  const segments = pattern.split("/");
@@ -7336,13 +7607,13 @@ async function expandWorkspaceGlobs(scanPath, globs) {
7336
7607
  if (seg.includes("*")) break;
7337
7608
  staticSegments.push(seg);
7338
7609
  }
7339
- const start = import_node_path16.default.join(scanPath, ...staticSegments);
7610
+ const start = import_node_path19.default.join(scanPath, ...staticSegments);
7340
7611
  if (!await exists2(start)) continue;
7341
7612
  const hasDoubleStar = pattern.includes("**");
7342
7613
  const walkDepth = hasDoubleStar ? scanDepth : Math.max(0, segments.length - staticSegments.length - 1);
7343
7614
  await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {
7344
- const rel = import_node_path16.default.relative(scanPath, dir).split(import_node_path16.default.sep).join("/");
7345
- if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path16.default.join(dir, "package.json"))) {
7615
+ const rel = import_node_path19.default.relative(scanPath, dir).split(import_node_path19.default.sep).join("/");
7616
+ if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists2(import_node_path19.default.join(dir, "package.json"))) {
7346
7617
  found.add(dir);
7347
7618
  }
7348
7619
  });
@@ -7365,31 +7636,31 @@ function detectJsFramework(pkg) {
7365
7636
  async function detectJsServiceLanguage(dir, pkg) {
7366
7637
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
7367
7638
  if (deps["typescript"] !== void 0) return "typescript";
7368
- const entries = await import_node_fs14.promises.readdir(dir).catch(() => []);
7639
+ const entries = await import_node_fs17.promises.readdir(dir).catch(() => []);
7369
7640
  if (entries.some((name) => /^tsconfig(\..+)?\.json$/.test(name))) return "typescript";
7370
7641
  return "javascript";
7371
7642
  }
7372
7643
  async function discoverNodeService(scanPath, dir) {
7373
- const pkgPath = import_node_path16.default.join(dir, "package.json");
7644
+ const pkgPath = import_node_path19.default.join(dir, "package.json");
7374
7645
  if (!await exists2(pkgPath)) return null;
7375
7646
  let pkg;
7376
7647
  try {
7377
7648
  pkg = await readJson(pkgPath);
7378
7649
  } catch (err) {
7379
- recordExtractionError("services", import_node_path16.default.relative(scanPath, pkgPath), err);
7650
+ recordExtractionError("services", import_node_path19.default.relative(scanPath, pkgPath), err);
7380
7651
  return null;
7381
7652
  }
7382
7653
  if (!pkg.name) return null;
7383
7654
  const framework = detectJsFramework(pkg);
7384
7655
  const language = await detectJsServiceLanguage(dir, pkg);
7385
7656
  const node = {
7386
- id: (0, import_types13.serviceId)(pkg.name),
7387
- type: import_types13.NodeType.ServiceNode,
7657
+ id: (0, import_types16.serviceId)(pkg.name),
7658
+ type: import_types16.NodeType.ServiceNode,
7388
7659
  name: pkg.name,
7389
7660
  language,
7390
7661
  version: pkg.version,
7391
7662
  dependencies: pkg.dependencies ?? {},
7392
- repoPath: import_node_path16.default.relative(scanPath, dir),
7663
+ repoPath: import_node_path19.default.relative(scanPath, dir),
7393
7664
  ...pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {},
7394
7665
  ...framework ? { framework } : {}
7395
7666
  };
@@ -7400,18 +7671,18 @@ async function discoverPyService(scanPath, dir) {
7400
7671
  if (!py) return null;
7401
7672
  const pkg = pythonToPackage(py);
7402
7673
  const node = {
7403
- id: (0, import_types13.serviceId)(py.name),
7404
- type: import_types13.NodeType.ServiceNode,
7674
+ id: (0, import_types16.serviceId)(py.name),
7675
+ type: import_types16.NodeType.ServiceNode,
7405
7676
  name: py.name,
7406
7677
  language: "python",
7407
7678
  version: py.version,
7408
7679
  dependencies: py.dependencies,
7409
- repoPath: import_node_path16.default.relative(scanPath, dir)
7680
+ repoPath: import_node_path19.default.relative(scanPath, dir)
7410
7681
  };
7411
7682
  return { pkg, dir, node };
7412
7683
  }
7413
7684
  async function discoverServices(scanPath) {
7414
- const rootPkgPath = import_node_path16.default.join(scanPath, "package.json");
7685
+ const rootPkgPath = import_node_path19.default.join(scanPath, "package.json");
7415
7686
  let rootPkg = null;
7416
7687
  if (await exists2(rootPkgPath)) {
7417
7688
  try {
@@ -7419,7 +7690,7 @@ async function discoverServices(scanPath) {
7419
7690
  } catch (err) {
7420
7691
  recordExtractionError(
7421
7692
  "services workspaces",
7422
- import_node_path16.default.relative(scanPath, rootPkgPath),
7693
+ import_node_path19.default.relative(scanPath, rootPkgPath),
7423
7694
  err
7424
7695
  );
7425
7696
  }
@@ -7431,7 +7702,7 @@ async function discoverServices(scanPath) {
7431
7702
  } else {
7432
7703
  if (rootPkg && rootPkg.name) {
7433
7704
  candidateDirs.push(scanPath);
7434
- } else if (await hasPythonManifest(scanPath) || await hasGoManifest(scanPath) || await hasRubyManifest(scanPath) || await hasPhpManifest(scanPath)) {
7705
+ } else if (await hasPythonManifest(scanPath) || await hasGoManifest(scanPath) || await hasRubyManifest(scanPath) || await hasPhpManifest(scanPath) || await hasCsharpManifest(scanPath) || await hasJavaManifest(scanPath)) {
7435
7706
  candidateDirs.push(scanPath);
7436
7707
  }
7437
7708
  const ig = await loadGitignore(scanPath);
@@ -7440,9 +7711,11 @@ async function discoverServices(scanPath) {
7440
7711
  scanPath,
7441
7712
  { maxDepth: parseScanDepth(), ig },
7442
7713
  async (dir) => {
7443
- if (await exists2(import_node_path16.default.join(dir, "package.json"))) {
7714
+ if (await exists2(import_node_path19.default.join(dir, "package.json"))) {
7444
7715
  candidateDirs.push(dir);
7445
- } else if (await hasPythonManifest(dir) || await hasGoManifest(dir) || await hasRubyManifest(dir) || await hasPhpManifest(dir)) {
7716
+ } else if (await hasPythonManifest(dir) || await hasGoManifest(dir) || await hasRubyManifest(dir) || await hasPhpManifest(dir) || await hasCsharpManifest(dir) || await hasJavaManifest(dir)) {
7717
+ candidateDirs.push(dir);
7718
+ } else if (await hasDockerfileDeclaredService(dir)) {
7446
7719
  candidateDirs.push(dir);
7447
7720
  }
7448
7721
  }
@@ -7450,14 +7723,17 @@ async function discoverServices(scanPath) {
7450
7723
  }
7451
7724
  candidateDirs.sort();
7452
7725
  const seen = /* @__PURE__ */ new Map();
7726
+ const seenDirs = /* @__PURE__ */ new Set();
7453
7727
  const out = [];
7454
7728
  for (const dir of candidateDirs) {
7455
- const service = await discoverNodeService(scanPath, dir) ?? await discoverPyService(scanPath, dir) ?? await discoverGoService(scanPath, dir) ?? await discoverRubyService(scanPath, dir) ?? await discoverPhpService(scanPath, dir);
7729
+ const service = await discoverNodeService(scanPath, dir) ?? await discoverPyService(scanPath, dir) ?? await discoverGoService(scanPath, dir) ?? await discoverRubyService(scanPath, dir) ?? await discoverPhpService(scanPath, dir) ?? await discoverCsharpService(scanPath, dir) ?? await discoverJavaService(scanPath, dir) ?? await discoverDockerfileService(scanPath, dir);
7456
7730
  if (!service) continue;
7731
+ if (seenDirs.has(service.dir)) continue;
7732
+ seenDirs.add(service.dir);
7457
7733
  const existingDir = seen.get(service.node.name);
7458
7734
  if (existingDir !== void 0) {
7459
- const a = import_node_path16.default.relative(scanPath, existingDir) || ".";
7460
- const b = import_node_path16.default.relative(scanPath, dir) || ".";
7735
+ const a = import_node_path19.default.relative(scanPath, existingDir) || ".";
7736
+ const b = import_node_path19.default.relative(scanPath, dir) || ".";
7461
7737
  console.warn(
7462
7738
  `[neat] duplicate package name "${service.node.name}" \u2014 keeping ${a}, ignoring ${b}`
7463
7739
  );
@@ -7494,20 +7770,20 @@ function addServiceNodes(graph, services) {
7494
7770
 
7495
7771
  // src/extract/aliases.ts
7496
7772
  init_cjs_shims();
7497
- var import_node_path17 = __toESM(require("path"), 1);
7498
- var import_node_fs15 = require("fs");
7773
+ var import_node_path20 = __toESM(require("path"), 1);
7774
+ var import_node_fs18 = require("fs");
7499
7775
  var import_yaml2 = require("yaml");
7500
- var import_types14 = require("@neat.is/types");
7776
+ var import_types17 = require("@neat.is/types");
7501
7777
  var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
7502
7778
  "Service",
7503
7779
  "Deployment",
7504
7780
  "StatefulSet",
7505
7781
  "DaemonSet"
7506
7782
  ]);
7507
- function addAliases(graph, serviceId9, candidates) {
7508
- if (!graph.hasNode(serviceId9)) return;
7509
- const node = graph.getNodeAttributes(serviceId9);
7510
- if (node.type !== import_types14.NodeType.ServiceNode) return;
7783
+ function addAliases(graph, serviceId12, candidates) {
7784
+ if (!graph.hasNode(serviceId12)) return;
7785
+ const node = graph.getNodeAttributes(serviceId12);
7786
+ if (node.type !== import_types17.NodeType.ServiceNode) return;
7511
7787
  const set = new Set(node.aliases ?? []);
7512
7788
  for (const c of candidates) {
7513
7789
  if (!c) continue;
@@ -7516,20 +7792,20 @@ function addAliases(graph, serviceId9, candidates) {
7516
7792
  }
7517
7793
  if (set.size === 0) return;
7518
7794
  const updated = { ...node, aliases: [...set].sort() };
7519
- graph.replaceNodeAttributes(serviceId9, updated);
7795
+ graph.replaceNodeAttributes(serviceId12, updated);
7520
7796
  }
7521
7797
  function indexServicesByName(services) {
7522
7798
  const map = /* @__PURE__ */ new Map();
7523
7799
  for (const s of services) {
7524
7800
  map.set(s.node.name, s.node.id);
7525
- map.set(import_node_path17.default.basename(s.dir), s.node.id);
7801
+ map.set(import_node_path20.default.basename(s.dir), s.node.id);
7526
7802
  }
7527
7803
  return map;
7528
7804
  }
7529
7805
  async function collectComposeAliases(graph, scanPath, serviceIndex) {
7530
7806
  let composePath = null;
7531
7807
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
7532
- const abs = import_node_path17.default.join(scanPath, name);
7808
+ const abs = import_node_path20.default.join(scanPath, name);
7533
7809
  if (await exists2(abs)) {
7534
7810
  composePath = abs;
7535
7811
  break;
@@ -7542,19 +7818,19 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
7542
7818
  } catch (err) {
7543
7819
  recordExtractionError(
7544
7820
  "aliases compose",
7545
- import_node_path17.default.relative(scanPath, composePath),
7821
+ import_node_path20.default.relative(scanPath, composePath),
7546
7822
  err
7547
7823
  );
7548
7824
  return;
7549
7825
  }
7550
7826
  if (!compose?.services) return;
7551
7827
  for (const [composeName, svc] of Object.entries(compose.services)) {
7552
- const serviceId9 = serviceIndex.get(composeName);
7553
- if (!serviceId9) continue;
7828
+ const serviceId12 = serviceIndex.get(composeName);
7829
+ if (!serviceId12) continue;
7554
7830
  const aliases = /* @__PURE__ */ new Set([composeName]);
7555
7831
  if (svc.container_name) aliases.add(svc.container_name);
7556
7832
  if (svc.hostname) aliases.add(svc.hostname);
7557
- addAliases(graph, serviceId9, aliases);
7833
+ addAliases(graph, serviceId12, aliases);
7558
7834
  }
7559
7835
  }
7560
7836
  var LABEL_KEYS = /* @__PURE__ */ new Set([
@@ -7585,11 +7861,11 @@ function parseDockerfileLabels(content) {
7585
7861
  }
7586
7862
  async function collectDockerfileAliases(graph, services) {
7587
7863
  for (const service of services) {
7588
- const dockerfilePath = import_node_path17.default.join(service.dir, "Dockerfile");
7864
+ const dockerfilePath = import_node_path20.default.join(service.dir, "Dockerfile");
7589
7865
  if (!await exists2(dockerfilePath)) continue;
7590
7866
  let content;
7591
7867
  try {
7592
- content = await import_node_fs15.promises.readFile(dockerfilePath, "utf8");
7868
+ content = await import_node_fs18.promises.readFile(dockerfilePath, "utf8");
7593
7869
  } catch (err) {
7594
7870
  recordExtractionError("aliases dockerfile", dockerfilePath, err);
7595
7871
  continue;
@@ -7601,15 +7877,15 @@ async function collectDockerfileAliases(graph, services) {
7601
7877
  async function walkYamlFiles(start, depth = 0, max = 5) {
7602
7878
  if (depth > max) return [];
7603
7879
  const out = [];
7604
- const entries = await import_node_fs15.promises.readdir(start, { withFileTypes: true }).catch(() => []);
7880
+ const entries = await import_node_fs18.promises.readdir(start, { withFileTypes: true }).catch(() => []);
7605
7881
  for (const entry of entries) {
7606
7882
  if (entry.isDirectory()) {
7607
7883
  if (IGNORED_DIRS.has(entry.name)) continue;
7608
- const child = import_node_path17.default.join(start, entry.name);
7884
+ const child = import_node_path20.default.join(start, entry.name);
7609
7885
  if (await isPythonVenvDir(child)) continue;
7610
7886
  out.push(...await walkYamlFiles(child, depth + 1, max));
7611
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path17.default.extname(entry.name))) {
7612
- out.push(import_node_path17.default.join(start, entry.name));
7887
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path20.default.extname(entry.name))) {
7888
+ out.push(import_node_path20.default.join(start, entry.name));
7613
7889
  }
7614
7890
  }
7615
7891
  return out;
@@ -7636,7 +7912,7 @@ function k8sServiceTarget(doc, byName) {
7636
7912
  async function collectK8sAliases(graph, scanPath, serviceIndex) {
7637
7913
  const files = await walkYamlFiles(scanPath);
7638
7914
  for (const file of files) {
7639
- const content = await import_node_fs15.promises.readFile(file, "utf8");
7915
+ const content = await import_node_fs18.promises.readFile(file, "utf8");
7640
7916
  let docs;
7641
7917
  try {
7642
7918
  docs = (0, import_yaml2.parseAllDocuments)(content).map((d) => d.toJSON());
@@ -7661,14 +7937,14 @@ async function addServiceAliases(graph, scanPath, services) {
7661
7937
 
7662
7938
  // src/extract/files.ts
7663
7939
  init_cjs_shims();
7664
- var import_node_path18 = __toESM(require("path"), 1);
7940
+ var import_node_path21 = __toESM(require("path"), 1);
7665
7941
  async function addFiles(graph, services) {
7666
7942
  let nodesAdded = 0;
7667
7943
  let edgesAdded = 0;
7668
7944
  for (const service of services) {
7669
7945
  const filePaths = await walkSourceFiles(service.dir);
7670
7946
  for (const filePath of filePaths) {
7671
- const relPath = toPosix(import_node_path18.default.relative(service.dir, filePath));
7947
+ const relPath = toPosix(import_node_path21.default.relative(service.dir, filePath));
7672
7948
  const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
7673
7949
  graph,
7674
7950
  service.pkg.name,
@@ -7684,11 +7960,17 @@ async function addFiles(graph, services) {
7684
7960
 
7685
7961
  // src/extract/symbols.ts
7686
7962
  init_cjs_shims();
7687
- var import_node_path19 = __toESM(require("path"), 1);
7963
+ var import_node_path22 = __toESM(require("path"), 1);
7688
7964
  var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
7689
7965
  var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
7690
7966
  var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript"), 1);
7691
- var import_types15 = require("@neat.is/types");
7967
+ var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
7968
+ var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
7969
+ var import_tree_sitter_ruby2 = __toESM(require("tree-sitter-ruby"), 1);
7970
+ var import_tree_sitter_php2 = __toESM(require("tree-sitter-php"), 1);
7971
+ var import_tree_sitter_c_sharp = __toESM(require("tree-sitter-c-sharp"), 1);
7972
+ var import_tree_sitter_java = __toESM(require("tree-sitter-java"), 1);
7973
+ var import_types18 = require("@neat.is/types");
7692
7974
  var PARSE_CHUNK3 = 16384;
7693
7975
  var GRAMMAR_BY_EXT = {
7694
7976
  ".ts": import_tree_sitter_typescript.default.typescript,
@@ -7698,6 +7980,15 @@ var GRAMMAR_BY_EXT = {
7698
7980
  ".mjs": import_tree_sitter_javascript3.default,
7699
7981
  ".cjs": import_tree_sitter_javascript3.default
7700
7982
  };
7983
+ var SYMBOL_GRAMMAR_BY_EXT = {
7984
+ ...GRAMMAR_BY_EXT,
7985
+ ".py": import_tree_sitter_python3.default,
7986
+ ".go": import_tree_sitter_go3.default,
7987
+ ".rb": import_tree_sitter_ruby2.default,
7988
+ ".php": import_tree_sitter_php2.default.php_only,
7989
+ ".cs": import_tree_sitter_c_sharp.default,
7990
+ ".java": import_tree_sitter_java.default
7991
+ };
7701
7992
  function parseSource3(parser, source) {
7702
7993
  return parser.parse(
7703
7994
  (index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK3)
@@ -7758,14 +8049,375 @@ function collectSymbolDefs(root) {
7758
8049
  break;
7759
8050
  }
7760
8051
  }
7761
- for (let i = 0; i < node.namedChildCount; i++) {
7762
- const child = node.namedChild(i);
7763
- if (child) visit(child, classCtx);
7764
- }
8052
+ for (let i = 0; i < node.namedChildCount; i++) {
8053
+ const child = node.namedChild(i);
8054
+ if (child) visit(child, classCtx);
8055
+ }
8056
+ };
8057
+ visit(root, void 0);
8058
+ return out;
8059
+ }
8060
+ function collectPythonSymbolDefs(root) {
8061
+ const out = [];
8062
+ const push = (kind, qualname, node) => {
8063
+ out.push({
8064
+ kind,
8065
+ qualname,
8066
+ startLine: node.startPosition.row + 1,
8067
+ endLine: node.endPosition.row + 1
8068
+ });
8069
+ };
8070
+ const visit = (node, classCtx) => {
8071
+ switch (node.type) {
8072
+ case "function_definition": {
8073
+ const name = node.childForFieldName("name")?.text;
8074
+ if (name) {
8075
+ if (classCtx) {
8076
+ const kind = name === "__init__" ? "constructor" : "method";
8077
+ push(kind, `${classCtx}.${name}`, node);
8078
+ } else {
8079
+ push("function", name, node);
8080
+ }
8081
+ }
8082
+ const body = node.childForFieldName("body");
8083
+ if (body) {
8084
+ for (let i = 0; i < body.namedChildCount; i++) {
8085
+ const child = body.namedChild(i);
8086
+ if (child) visit(child, void 0);
8087
+ }
8088
+ }
8089
+ return;
8090
+ }
8091
+ case "class_definition": {
8092
+ const name = node.childForFieldName("name")?.text;
8093
+ if (name) push("class", name, node);
8094
+ const body = node.childForFieldName("body");
8095
+ if (body) {
8096
+ for (let i = 0; i < body.namedChildCount; i++) {
8097
+ const child = body.namedChild(i);
8098
+ if (child) visit(child, name ?? classCtx);
8099
+ }
8100
+ }
8101
+ return;
8102
+ }
8103
+ case "decorated_definition": {
8104
+ const def = node.childForFieldName("definition");
8105
+ if (def) visit(def, classCtx);
8106
+ return;
8107
+ }
8108
+ }
8109
+ for (let i = 0; i < node.namedChildCount; i++) {
8110
+ const child = node.namedChild(i);
8111
+ if (child) visit(child, classCtx);
8112
+ }
8113
+ };
8114
+ visit(root, void 0);
8115
+ return out;
8116
+ }
8117
+ function goReceiverType(node) {
8118
+ const receiver = node.childForFieldName("receiver");
8119
+ if (!receiver) return void 0;
8120
+ for (let i = 0; i < receiver.namedChildCount; i++) {
8121
+ const param = receiver.namedChild(i);
8122
+ if (param?.type !== "parameter_declaration") continue;
8123
+ let typeNode = param.childForFieldName("type");
8124
+ if (typeNode?.type === "pointer_type") typeNode = typeNode.namedChild(0) ?? typeNode;
8125
+ if (typeNode?.type === "generic_type") {
8126
+ typeNode = typeNode.childForFieldName("type") ?? typeNode.namedChild(0) ?? typeNode;
8127
+ }
8128
+ if (typeNode?.type === "type_identifier") return typeNode.text;
8129
+ return typeNode?.text;
8130
+ }
8131
+ return void 0;
8132
+ }
8133
+ function collectGoSymbolDefs(root) {
8134
+ const out = [];
8135
+ const push = (kind, qualname, node) => {
8136
+ out.push({
8137
+ kind,
8138
+ qualname,
8139
+ startLine: node.startPosition.row + 1,
8140
+ endLine: node.endPosition.row + 1
8141
+ });
8142
+ };
8143
+ const visit = (node) => {
8144
+ switch (node.type) {
8145
+ case "function_declaration": {
8146
+ const name = node.childForFieldName("name")?.text;
8147
+ if (name) push("function", name, node);
8148
+ break;
8149
+ }
8150
+ case "method_declaration": {
8151
+ const name = node.childForFieldName("name")?.text;
8152
+ if (name) {
8153
+ const recv = goReceiverType(node);
8154
+ push("method", recv ? `${recv}.${name}` : name, node);
8155
+ }
8156
+ break;
8157
+ }
8158
+ }
8159
+ for (let i = 0; i < node.namedChildCount; i++) {
8160
+ const child = node.namedChild(i);
8161
+ if (child) visit(child);
8162
+ }
8163
+ };
8164
+ visit(root);
8165
+ return out;
8166
+ }
8167
+ function collectRubySymbolDefs(root) {
8168
+ const out = [];
8169
+ const push = (kind, qualname, node) => {
8170
+ out.push({
8171
+ kind,
8172
+ qualname,
8173
+ startLine: node.startPosition.row + 1,
8174
+ endLine: node.endPosition.row + 1
8175
+ });
8176
+ };
8177
+ const nameText = (node) => node.childForFieldName("name")?.text.replace(/::/g, ".");
8178
+ const walkBody = (node, ctx) => {
8179
+ const body = node.childForFieldName("body");
8180
+ if (!body) return;
8181
+ for (let i = 0; i < body.namedChildCount; i++) {
8182
+ const child = body.namedChild(i);
8183
+ if (child) visit(child, ctx);
8184
+ }
8185
+ };
8186
+ const visit = (node, classCtx) => {
8187
+ switch (node.type) {
8188
+ case "method":
8189
+ case "singleton_method": {
8190
+ const name = node.childForFieldName("name")?.text;
8191
+ if (name) {
8192
+ if (classCtx) {
8193
+ const kind = node.type === "method" && name === "initialize" ? "constructor" : "method";
8194
+ push(kind, `${classCtx}.${name}`, node);
8195
+ } else {
8196
+ push("function", name, node);
8197
+ }
8198
+ }
8199
+ walkBody(node, void 0);
8200
+ return;
8201
+ }
8202
+ case "class":
8203
+ case "module": {
8204
+ const name = nameText(node);
8205
+ if (name) push("class", classCtx ? `${classCtx}.${name}` : name, node);
8206
+ walkBody(node, name ? classCtx ? `${classCtx}.${name}` : name : classCtx);
8207
+ return;
8208
+ }
8209
+ }
8210
+ for (let i = 0; i < node.namedChildCount; i++) {
8211
+ const child = node.namedChild(i);
8212
+ if (child) visit(child, classCtx);
8213
+ }
8214
+ };
8215
+ visit(root, void 0);
8216
+ return out;
8217
+ }
8218
+ function collectPhpSymbolDefs(root) {
8219
+ const out = [];
8220
+ const push = (kind, qualname, node) => {
8221
+ out.push({
8222
+ kind,
8223
+ qualname,
8224
+ startLine: node.startPosition.row + 1,
8225
+ endLine: node.endPosition.row + 1
8226
+ });
8227
+ };
8228
+ const dot = (s) => s.replace(/\\/g, ".").replace(/::/g, ".").replace(/^\.+/, "");
8229
+ const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
8230
+ const walkChildren = (container, nsCtx, classCtx) => {
8231
+ let ns = nsCtx;
8232
+ for (let i = 0; i < container.namedChildCount; i++) {
8233
+ const child = container.namedChild(i);
8234
+ if (!child) continue;
8235
+ if (child.type === "namespace_definition" && !child.childForFieldName("body")) {
8236
+ const nameNode = child.childForFieldName("name");
8237
+ if (nameNode) ns = dot(nameNode.text);
8238
+ continue;
8239
+ }
8240
+ visit(child, ns, classCtx);
8241
+ }
8242
+ };
8243
+ const walkBody = (node, nsCtx, classCtx) => {
8244
+ const body = node.childForFieldName("body");
8245
+ if (body) walkChildren(body, nsCtx, classCtx);
8246
+ };
8247
+ const visit = (node, nsCtx, classCtx) => {
8248
+ switch (node.type) {
8249
+ case "function_definition": {
8250
+ const name = node.childForFieldName("name")?.text;
8251
+ if (name) push("function", join(nsCtx, name), node);
8252
+ walkBody(node, nsCtx, void 0);
8253
+ return;
8254
+ }
8255
+ case "class_declaration":
8256
+ case "trait_declaration":
8257
+ case "interface_declaration": {
8258
+ const name = node.childForFieldName("name")?.text;
8259
+ const full = name ? join(nsCtx, name) : classCtx;
8260
+ if (name) push("class", full, node);
8261
+ walkBody(node, nsCtx, full);
8262
+ return;
8263
+ }
8264
+ case "method_declaration": {
8265
+ const name = node.childForFieldName("name")?.text;
8266
+ if (name) {
8267
+ const kind = name === "__construct" ? "constructor" : "method";
8268
+ push(kind, join(classCtx ?? nsCtx, name), node);
8269
+ }
8270
+ return;
8271
+ }
8272
+ case "namespace_definition": {
8273
+ const nameNode = node.childForFieldName("name");
8274
+ const ns = nameNode ? dot(nameNode.text) : nsCtx;
8275
+ walkBody(node, ns, classCtx);
8276
+ return;
8277
+ }
8278
+ }
8279
+ walkChildren(node, nsCtx, classCtx);
8280
+ };
8281
+ walkChildren(root, void 0, void 0);
8282
+ return out;
8283
+ }
8284
+ function collectCsharpSymbolDefs(root) {
8285
+ const out = [];
8286
+ const push = (kind, qualname, node) => {
8287
+ out.push({
8288
+ kind,
8289
+ qualname,
8290
+ startLine: node.startPosition.row + 1,
8291
+ endLine: node.endPosition.row + 1
8292
+ });
8293
+ };
8294
+ const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
8295
+ const walkChildren = (container, nsCtx, classCtx) => {
8296
+ let ns = nsCtx;
8297
+ for (let i = 0; i < container.namedChildCount; i++) {
8298
+ const child = container.namedChild(i);
8299
+ if (!child) continue;
8300
+ if (child.type === "file_scoped_namespace_declaration") {
8301
+ const nameNode = child.childForFieldName("name");
8302
+ if (nameNode) ns = join(nsCtx, nameNode.text);
8303
+ continue;
8304
+ }
8305
+ visit(child, ns, classCtx);
8306
+ }
8307
+ };
8308
+ const walkBody = (node, nsCtx, classCtx) => {
8309
+ const body = node.childForFieldName("body");
8310
+ if (body) walkChildren(body, nsCtx, classCtx);
8311
+ };
8312
+ const visit = (node, nsCtx, classCtx) => {
8313
+ switch (node.type) {
8314
+ case "namespace_declaration": {
8315
+ const nameNode = node.childForFieldName("name");
8316
+ const ns = nameNode ? join(nsCtx, nameNode.text) : nsCtx;
8317
+ walkBody(node, ns, classCtx);
8318
+ return;
8319
+ }
8320
+ case "class_declaration":
8321
+ case "interface_declaration":
8322
+ case "struct_declaration":
8323
+ case "record_declaration": {
8324
+ const name = node.childForFieldName("name")?.text;
8325
+ const full = name ? join(classCtx ?? nsCtx, name) : classCtx;
8326
+ if (name) push("class", full, node);
8327
+ walkBody(node, nsCtx, full);
8328
+ return;
8329
+ }
8330
+ case "method_declaration": {
8331
+ const name = node.childForFieldName("name")?.text;
8332
+ if (name) push("method", join(classCtx ?? nsCtx, name), node);
8333
+ return;
8334
+ }
8335
+ case "constructor_declaration": {
8336
+ const name = node.childForFieldName("name")?.text;
8337
+ if (name) push("constructor", join(classCtx ?? nsCtx, name), node);
8338
+ return;
8339
+ }
8340
+ }
8341
+ walkChildren(node, nsCtx, classCtx);
8342
+ };
8343
+ walkChildren(root, void 0, void 0);
8344
+ return out;
8345
+ }
8346
+ function collectJavaSymbolDefs(root) {
8347
+ const out = [];
8348
+ const push = (kind, qualname, node) => {
8349
+ out.push({
8350
+ kind,
8351
+ qualname,
8352
+ startLine: node.startPosition.row + 1,
8353
+ endLine: node.endPosition.row + 1
8354
+ });
8355
+ };
8356
+ const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
8357
+ let pkg;
8358
+ for (let i = 0; i < root.namedChildCount; i++) {
8359
+ const child = root.namedChild(i);
8360
+ if (child?.type === "package_declaration") {
8361
+ pkg = child.namedChild(0)?.text;
8362
+ break;
8363
+ }
8364
+ }
8365
+ const walkChildren = (container, classCtx) => {
8366
+ for (let i = 0; i < container.namedChildCount; i++) {
8367
+ const child = container.namedChild(i);
8368
+ if (child) visit(child, classCtx);
8369
+ }
8370
+ };
8371
+ const walkBody = (node, classCtx) => {
8372
+ const body = node.childForFieldName("body");
8373
+ if (body) walkChildren(body, classCtx);
8374
+ };
8375
+ const visit = (node, classCtx) => {
8376
+ switch (node.type) {
8377
+ case "class_declaration":
8378
+ case "interface_declaration":
8379
+ case "enum_declaration":
8380
+ case "record_declaration": {
8381
+ const name = node.childForFieldName("name")?.text;
8382
+ const full = name ? join(classCtx ?? pkg, name) : classCtx;
8383
+ if (name) push("class", full, node);
8384
+ walkBody(node, full);
8385
+ return;
8386
+ }
8387
+ case "method_declaration": {
8388
+ const name = node.childForFieldName("name")?.text;
8389
+ if (name) push("method", join(classCtx ?? pkg, name), node);
8390
+ return;
8391
+ }
8392
+ case "constructor_declaration": {
8393
+ const name = node.childForFieldName("name")?.text;
8394
+ if (name) push("constructor", join(classCtx ?? pkg, name), node);
8395
+ return;
8396
+ }
8397
+ }
8398
+ walkChildren(node, classCtx);
7765
8399
  };
7766
- visit(root, void 0);
8400
+ walkChildren(root, void 0);
7767
8401
  return out;
7768
8402
  }
8403
+ function collectSymbolDefsForExt(ext, root) {
8404
+ switch (ext) {
8405
+ case ".py":
8406
+ return collectPythonSymbolDefs(root);
8407
+ case ".go":
8408
+ return collectGoSymbolDefs(root);
8409
+ case ".rb":
8410
+ return collectRubySymbolDefs(root);
8411
+ case ".php":
8412
+ return collectPhpSymbolDefs(root);
8413
+ case ".cs":
8414
+ return collectCsharpSymbolDefs(root);
8415
+ case ".java":
8416
+ return collectJavaSymbolDefs(root);
8417
+ default:
8418
+ return collectSymbolDefs(root);
8419
+ }
8420
+ }
7769
8421
  function disambiguate(defs) {
7770
8422
  const counts = /* @__PURE__ */ new Map();
7771
8423
  for (const def of defs) counts.set(def.qualname, (counts.get(def.qualname) ?? 0) + 1);
@@ -7780,7 +8432,7 @@ function disambiguate(defs) {
7780
8432
  async function addSymbols(graph, services) {
7781
8433
  const parsers = /* @__PURE__ */ new Map();
7782
8434
  const parserForExt5 = (ext) => {
7783
- const grammar = GRAMMAR_BY_EXT[ext];
8435
+ const grammar = SYMBOL_GRAMMAR_BY_EXT[ext];
7784
8436
  if (!grammar) return null;
7785
8437
  let parser = parsers.get(ext);
7786
8438
  if (!parser) {
@@ -7795,13 +8447,14 @@ async function addSymbols(graph, services) {
7795
8447
  for (const service of services) {
7796
8448
  const files = await loadSourceFiles(service.dir);
7797
8449
  for (const file of files) {
7798
- const parser = parserForExt5(import_node_path19.default.extname(file.path));
8450
+ const ext = import_node_path22.default.extname(file.path);
8451
+ const parser = parserForExt5(ext);
7799
8452
  if (!parser) continue;
7800
- const relPath = toPosix(import_node_path19.default.relative(service.dir, file.path));
8453
+ const relPath = toPosix(import_node_path22.default.relative(service.dir, file.path));
7801
8454
  let defs;
7802
8455
  try {
7803
8456
  const tree = parseSource3(parser, file.content);
7804
- defs = collectSymbolDefs(tree.rootNode);
8457
+ defs = collectSymbolDefsForExt(ext, tree.rootNode);
7805
8458
  } catch (err) {
7806
8459
  recordExtractionError("symbol extraction", file.path, err);
7807
8460
  continue;
@@ -7816,11 +8469,11 @@ async function addSymbols(graph, services) {
7816
8469
  nodesAdded += fn;
7817
8470
  edgesAdded += fe;
7818
8471
  for (const { def, disambiguator } of disambiguate(defs)) {
7819
- const sid = (0, import_types15.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
8472
+ const sid = (0, import_types18.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
7820
8473
  if (!graph.hasNode(sid)) {
7821
8474
  const node = {
7822
8475
  id: sid,
7823
- type: import_types15.NodeType.SymbolNode,
8476
+ type: import_types18.NodeType.SymbolNode,
7824
8477
  kind: def.kind,
7825
8478
  qualname: def.qualname,
7826
8479
  span: { startLine: def.startLine, endLine: def.endLine },
@@ -7831,15 +8484,15 @@ async function addSymbols(graph, services) {
7831
8484
  graph.addNode(sid, node);
7832
8485
  nodesAdded++;
7833
8486
  }
7834
- const containsId = (0, import_types15.extractedEdgeId)(fileNodeId, sid, import_types15.EdgeType.CONTAINS);
8487
+ const containsId = (0, import_types18.extractedEdgeId)(fileNodeId, sid, import_types18.EdgeType.CONTAINS);
7835
8488
  if (!graph.hasEdge(containsId)) {
7836
8489
  const edge = {
7837
8490
  id: containsId,
7838
8491
  source: fileNodeId,
7839
8492
  target: sid,
7840
- type: import_types15.EdgeType.CONTAINS,
7841
- provenance: import_types15.Provenance.EXTRACTED,
7842
- confidence: (0, import_types15.confidenceForExtracted)("structural"),
8493
+ type: import_types18.EdgeType.CONTAINS,
8494
+ provenance: import_types18.Provenance.EXTRACTED,
8495
+ confidence: (0, import_types18.confidenceForExtracted)("structural"),
7843
8496
  evidence: {
7844
8497
  file: relPath,
7845
8498
  line: def.startLine,
@@ -7857,9 +8510,9 @@ async function addSymbols(graph, services) {
7857
8510
 
7858
8511
  // src/extract/symbol-edges.ts
7859
8512
  init_cjs_shims();
7860
- var import_node_path20 = __toESM(require("path"), 1);
8513
+ var import_node_path23 = __toESM(require("path"), 1);
7861
8514
  var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
7862
- var import_types16 = require("@neat.is/types");
8515
+ var import_types19 = require("@neat.is/types");
7863
8516
  function extendsInfo(classHeritage) {
7864
8517
  for (let i = 0; i < classHeritage.namedChildCount; i++) {
7865
8518
  const child = classHeritage.namedChild(i);
@@ -7964,10 +8617,10 @@ async function addSymbolEdges(graph, services) {
7964
8617
  const tsPaths = await loadTsPathConfig(service.dir);
7965
8618
  const files = await loadSourceFiles(service.dir);
7966
8619
  for (const file of files) {
7967
- const parser = parserForExt5(import_node_path20.default.extname(file.path));
8620
+ const parser = parserForExt5(import_node_path23.default.extname(file.path));
7968
8621
  if (!parser) continue;
7969
- const relPath = toPosix(import_node_path20.default.relative(service.dir, file.path));
7970
- const fileDir = import_node_path20.default.dirname(file.path);
8622
+ const relPath = toPosix(import_node_path23.default.relative(service.dir, file.path));
8623
+ const fileDir = import_node_path23.default.dirname(file.path);
7971
8624
  let root;
7972
8625
  try {
7973
8626
  root = parseSource3(parser, file.content).rootNode;
@@ -7977,7 +8630,7 @@ async function addSymbolEdges(graph, services) {
7977
8630
  }
7978
8631
  const disambiguated = disambiguate(collectSymbolDefs(root));
7979
8632
  const locals = disambiguated.map(({ def, disambiguator }) => ({
7980
- sid: (0, import_types16.symbolId)(serviceName, relPath, def.qualname, disambiguator),
8633
+ sid: (0, import_types19.symbolId)(serviceName, relPath, def.qualname, disambiguator),
7981
8634
  qualname: def.qualname,
7982
8635
  kind: def.kind,
7983
8636
  startLine: def.startLine,
@@ -8006,10 +8659,10 @@ async function addSymbolEdges(graph, services) {
8006
8659
  if (local) return local.kind === wantKind ? local.sid : null;
8007
8660
  const imp = resolvedImports.get(name);
8008
8661
  if (imp) {
8009
- const candidate = (0, import_types16.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
8662
+ const candidate = (0, import_types19.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
8010
8663
  if (graph.hasNode(candidate)) {
8011
8664
  const node = graph.getNodeAttributes(candidate);
8012
- if (node.type === import_types16.NodeType.SymbolNode && node.kind === wantKind) return candidate;
8665
+ if (node.type === import_types19.NodeType.SymbolNode && node.kind === wantKind) return candidate;
8013
8666
  }
8014
8667
  }
8015
8668
  return null;
@@ -8036,7 +8689,7 @@ async function addSymbolEdges(graph, services) {
8036
8689
  sourceSid: self.sid,
8037
8690
  targetName: ext.name,
8038
8691
  wantKind: "class",
8039
- edgeType: import_types16.EdgeType.INHERITS,
8692
+ edgeType: import_types19.EdgeType.INHERITS,
8040
8693
  line: ext.line
8041
8694
  });
8042
8695
  }
@@ -8045,7 +8698,7 @@ async function addSymbolEdges(graph, services) {
8045
8698
  sourceSid: self.sid,
8046
8699
  targetName: impl.name,
8047
8700
  wantKind: "class",
8048
- edgeType: import_types16.EdgeType.IMPLEMENTS,
8701
+ edgeType: import_types19.EdgeType.IMPLEMENTS,
8049
8702
  line: impl.line
8050
8703
  });
8051
8704
  }
@@ -8061,7 +8714,7 @@ async function addSymbolEdges(graph, services) {
8061
8714
  sourceSid: caller.sid,
8062
8715
  targetName: fn.text,
8063
8716
  wantKind: "function",
8064
- edgeType: import_types16.EdgeType.CALLS,
8717
+ edgeType: import_types19.EdgeType.CALLS,
8065
8718
  line
8066
8719
  });
8067
8720
  }
@@ -8077,15 +8730,15 @@ async function addSymbolEdges(graph, services) {
8077
8730
  const targetSid = resolveTarget(req.targetName, req.wantKind);
8078
8731
  if (!targetSid) continue;
8079
8732
  if (targetSid === req.sourceSid) continue;
8080
- const edgeId = (0, import_types16.extractedEdgeId)(req.sourceSid, targetSid, req.edgeType);
8733
+ const edgeId = (0, import_types19.extractedEdgeId)(req.sourceSid, targetSid, req.edgeType);
8081
8734
  if (graph.hasEdge(edgeId)) continue;
8082
8735
  const edge = {
8083
8736
  id: edgeId,
8084
8737
  source: req.sourceSid,
8085
8738
  target: targetSid,
8086
8739
  type: req.edgeType,
8087
- provenance: import_types16.Provenance.EXTRACTED,
8088
- confidence: (0, import_types16.confidenceForExtracted)("structural"),
8740
+ provenance: import_types19.Provenance.EXTRACTED,
8741
+ confidence: (0, import_types19.confidenceForExtracted)("structural"),
8089
8742
  evidence: {
8090
8743
  file: relPath,
8091
8744
  line: req.line,
@@ -8102,9 +8755,9 @@ async function addSymbolEdges(graph, services) {
8102
8755
 
8103
8756
  // src/extract/actions.ts
8104
8757
  init_cjs_shims();
8105
- var import_node_path21 = __toESM(require("path"), 1);
8758
+ var import_node_path24 = __toESM(require("path"), 1);
8106
8759
  var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
8107
- var import_types17 = require("@neat.is/types");
8760
+ var import_types20 = require("@neat.is/types");
8108
8761
  function stringLiteralText2(node) {
8109
8762
  for (let i = 0; i < node.childCount; i++) {
8110
8763
  const child = node.child(i);
@@ -8249,9 +8902,9 @@ async function addServerActions(graph, services) {
8249
8902
  const files = await loadSourceFiles(service.dir);
8250
8903
  for (const file of files) {
8251
8904
  if (isTestPath(file.path)) continue;
8252
- const parser = parserForExt5(import_node_path21.default.extname(file.path));
8905
+ const parser = parserForExt5(import_node_path24.default.extname(file.path));
8253
8906
  if (!parser) continue;
8254
- const relPath = toPosix(import_node_path21.default.relative(service.dir, file.path));
8907
+ const relPath = toPosix(import_node_path24.default.relative(service.dir, file.path));
8255
8908
  let root;
8256
8909
  try {
8257
8910
  root = parseSource3(parser, file.content).rootNode;
@@ -8274,11 +8927,11 @@ async function addServerActions(graph, services) {
8274
8927
  nodesAdded += fn;
8275
8928
  edgesAdded += fe;
8276
8929
  for (const action of actions) {
8277
- const aid = (0, import_types17.serverActionId)(service.pkg.name, relPath, action.exportName);
8930
+ const aid = (0, import_types20.serverActionId)(service.pkg.name, relPath, action.exportName);
8278
8931
  if (!graph.hasNode(aid)) {
8279
8932
  const node = {
8280
8933
  id: aid,
8281
- type: import_types17.NodeType.ServerActionNode,
8934
+ type: import_types20.NodeType.ServerActionNode,
8282
8935
  name: action.exportName,
8283
8936
  service: service.pkg.name,
8284
8937
  module: relPath,
@@ -8290,15 +8943,15 @@ async function addServerActions(graph, services) {
8290
8943
  graph.addNode(aid, node);
8291
8944
  nodesAdded++;
8292
8945
  }
8293
- const containsId = (0, import_types17.extractedEdgeId)(fileNodeId, aid, import_types17.EdgeType.CONTAINS);
8946
+ const containsId = (0, import_types20.extractedEdgeId)(fileNodeId, aid, import_types20.EdgeType.CONTAINS);
8294
8947
  if (!graph.hasEdge(containsId)) {
8295
8948
  const edge = {
8296
8949
  id: containsId,
8297
8950
  source: fileNodeId,
8298
8951
  target: aid,
8299
- type: import_types17.EdgeType.CONTAINS,
8300
- provenance: import_types17.Provenance.EXTRACTED,
8301
- confidence: (0, import_types17.confidenceForExtracted)("structural"),
8952
+ type: import_types20.EdgeType.CONTAINS,
8953
+ provenance: import_types20.Provenance.EXTRACTED,
8954
+ confidence: (0, import_types20.confidenceForExtracted)("structural"),
8302
8955
  evidence: {
8303
8956
  file: relPath,
8304
8957
  line: action.line,
@@ -8312,10 +8965,10 @@ async function addServerActions(graph, services) {
8312
8965
  }
8313
8966
  for (const file of files) {
8314
8967
  if (isTestPath(file.path)) continue;
8315
- const parser = parserForExt5(import_node_path21.default.extname(file.path));
8968
+ const parser = parserForExt5(import_node_path24.default.extname(file.path));
8316
8969
  if (!parser) continue;
8317
- const relPath = toPosix(import_node_path21.default.relative(service.dir, file.path));
8318
- const fileDir = import_node_path21.default.dirname(file.path);
8970
+ const relPath = toPosix(import_node_path24.default.relative(service.dir, file.path));
8971
+ const fileDir = import_node_path24.default.dirname(file.path);
8319
8972
  let root;
8320
8973
  try {
8321
8974
  root = parseSource3(parser, file.content).rootNode;
@@ -8328,7 +8981,7 @@ async function addServerActions(graph, services) {
8328
8981
  for (const [local, binding] of bindings) {
8329
8982
  const target = await resolveJsImport(binding.specifier, fileDir, service.dir, tsPaths);
8330
8983
  if (!target) continue;
8331
- const aid = (0, import_types17.serverActionId)(service.pkg.name, target, binding.importedName);
8984
+ const aid = (0, import_types20.serverActionId)(service.pkg.name, target, binding.importedName);
8332
8985
  if (graph.hasNode(aid)) actionBindings.set(local, aid);
8333
8986
  }
8334
8987
  if (actionBindings.size === 0) continue;
@@ -8343,15 +8996,15 @@ async function addServerActions(graph, services) {
8343
8996
  nodesAdded += ensured.nodesAdded;
8344
8997
  edgesAdded += ensured.edgesAdded;
8345
8998
  }
8346
- const callsId = (0, import_types17.extractedEdgeId)(clientFileId, aid, import_types17.EdgeType.CALLS);
8999
+ const callsId = (0, import_types20.extractedEdgeId)(clientFileId, aid, import_types20.EdgeType.CALLS);
8347
9000
  if (graph.hasEdge(callsId)) continue;
8348
9001
  const edge = {
8349
9002
  id: callsId,
8350
9003
  source: clientFileId,
8351
9004
  target: aid,
8352
- type: import_types17.EdgeType.CALLS,
8353
- provenance: import_types17.Provenance.EXTRACTED,
8354
- confidence: (0, import_types17.confidenceForExtracted)("structural"),
9005
+ type: import_types20.EdgeType.CALLS,
9006
+ provenance: import_types20.Provenance.EXTRACTED,
9007
+ confidence: (0, import_types20.confidenceForExtracted)("structural"),
8355
9008
  evidence: {
8356
9009
  file: relPath,
8357
9010
  line,
@@ -8368,14 +9021,14 @@ async function addServerActions(graph, services) {
8368
9021
 
8369
9022
  // src/extract/databases/index.ts
8370
9023
  init_cjs_shims();
8371
- var import_node_path29 = __toESM(require("path"), 1);
8372
- var import_types18 = require("@neat.is/types");
9024
+ var import_node_path32 = __toESM(require("path"), 1);
9025
+ var import_types21 = require("@neat.is/types");
8373
9026
 
8374
9027
  // src/extract/databases/db-config-yaml.ts
8375
9028
  init_cjs_shims();
8376
- var import_node_path22 = __toESM(require("path"), 1);
9029
+ var import_node_path25 = __toESM(require("path"), 1);
8377
9030
  async function parse(serviceDir) {
8378
- const yamlPath = import_node_path22.default.join(serviceDir, "db-config.yaml");
9031
+ const yamlPath = import_node_path25.default.join(serviceDir, "db-config.yaml");
8379
9032
  if (!await exists2(yamlPath)) return [];
8380
9033
  const raw = await readYaml(yamlPath);
8381
9034
  return [
@@ -8393,13 +9046,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
8393
9046
 
8394
9047
  // src/extract/databases/dotenv.ts
8395
9048
  init_cjs_shims();
8396
- var import_node_fs17 = require("fs");
8397
- var import_node_path24 = __toESM(require("path"), 1);
9049
+ var import_node_fs20 = require("fs");
9050
+ var import_node_path27 = __toESM(require("path"), 1);
8398
9051
 
8399
9052
  // src/extract/databases/shared.ts
8400
9053
  init_cjs_shims();
8401
- var import_node_fs16 = require("fs");
8402
- var import_node_path23 = __toESM(require("path"), 1);
9054
+ var import_node_fs19 = require("fs");
9055
+ var import_node_path26 = __toESM(require("path"), 1);
8403
9056
  function schemeToEngine(scheme) {
8404
9057
  const s = scheme.toLowerCase().split("+")[0];
8405
9058
  switch (s) {
@@ -8438,18 +9091,18 @@ function parseConnectionString(url) {
8438
9091
  }
8439
9092
  async function readIfExists(filePath) {
8440
9093
  try {
8441
- return await import_node_fs16.promises.readFile(filePath, "utf8");
9094
+ return await import_node_fs19.promises.readFile(filePath, "utf8");
8442
9095
  } catch {
8443
9096
  return null;
8444
9097
  }
8445
9098
  }
8446
9099
  async function resolveEnvVar(serviceDir, name) {
8447
- const entries = await import_node_fs16.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
9100
+ const entries = await import_node_fs19.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
8448
9101
  const envNames = entries.filter((e) => e.isFile() && (e.name === ".env" || e.name.startsWith(".env."))).map((e) => e.name);
8449
9102
  const rank = (n) => n === ".env.local" ? 0 : n === ".env" ? 1 : 2;
8450
9103
  envNames.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
8451
9104
  for (const fileName of envNames) {
8452
- const content = await readIfExists(import_node_path23.default.join(serviceDir, fileName));
9105
+ const content = await readIfExists(import_node_path26.default.join(serviceDir, fileName));
8453
9106
  if (!content) continue;
8454
9107
  for (const line of content.split("\n")) {
8455
9108
  const trimmed = line.trim();
@@ -8468,7 +9121,7 @@ async function resolveEnvVar(serviceDir, name) {
8468
9121
  }
8469
9122
  async function findFirst(serviceDir, candidates) {
8470
9123
  for (const rel of candidates) {
8471
- const abs = import_node_path23.default.join(serviceDir, rel);
9124
+ const abs = import_node_path26.default.join(serviceDir, rel);
8472
9125
  const content = await readIfExists(abs);
8473
9126
  if (content !== null) return abs;
8474
9127
  }
@@ -8526,15 +9179,15 @@ function parseDotenvLine(line) {
8526
9179
  return { key, value };
8527
9180
  }
8528
9181
  async function parse2(serviceDir) {
8529
- const entries = await import_node_fs17.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
9182
+ const entries = await import_node_fs20.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
8530
9183
  const configs = [];
8531
9184
  const seen = /* @__PURE__ */ new Set();
8532
9185
  for (const entry of entries) {
8533
9186
  if (!entry.isFile()) continue;
8534
9187
  const match = isConfigFile(entry.name);
8535
9188
  if (!match.match || match.fileType !== "env") continue;
8536
- const filePath = import_node_path24.default.join(serviceDir, entry.name);
8537
- const content = await import_node_fs17.promises.readFile(filePath, "utf8");
9189
+ const filePath = import_node_path27.default.join(serviceDir, entry.name);
9190
+ const content = await import_node_fs20.promises.readFile(filePath, "utf8");
8538
9191
  for (const line of content.split("\n")) {
8539
9192
  const parsed = parseDotenvLine(line);
8540
9193
  if (!parsed) continue;
@@ -8553,9 +9206,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
8553
9206
 
8554
9207
  // src/extract/databases/prisma.ts
8555
9208
  init_cjs_shims();
8556
- var import_node_path25 = __toESM(require("path"), 1);
9209
+ var import_node_path28 = __toESM(require("path"), 1);
8557
9210
  async function parse3(serviceDir) {
8558
- const schemaPath = import_node_path25.default.join(serviceDir, "prisma", "schema.prisma");
9211
+ const schemaPath = import_node_path28.default.join(serviceDir, "prisma", "schema.prisma");
8559
9212
  const content = await readIfExists(schemaPath);
8560
9213
  if (!content) return [];
8561
9214
  const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
@@ -8713,10 +9366,10 @@ var knexParser = { name: "knex", parse: parse5 };
8713
9366
 
8714
9367
  // src/extract/databases/ormconfig.ts
8715
9368
  init_cjs_shims();
8716
- var import_node_path26 = __toESM(require("path"), 1);
9369
+ var import_node_path29 = __toESM(require("path"), 1);
8717
9370
  async function parse6(serviceDir) {
8718
9371
  for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
8719
- const abs = import_node_path26.default.join(serviceDir, candidate);
9372
+ const abs = import_node_path29.default.join(serviceDir, candidate);
8720
9373
  if (!await exists2(abs)) continue;
8721
9374
  const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
8722
9375
  const entries = Array.isArray(raw) ? raw : [raw];
@@ -8776,9 +9429,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
8776
9429
 
8777
9430
  // src/extract/databases/sequelize.ts
8778
9431
  init_cjs_shims();
8779
- var import_node_path27 = __toESM(require("path"), 1);
9432
+ var import_node_path30 = __toESM(require("path"), 1);
8780
9433
  async function parse8(serviceDir) {
8781
- const configPath = import_node_path27.default.join(serviceDir, "config", "config.json");
9434
+ const configPath = import_node_path30.default.join(serviceDir, "config", "config.json");
8782
9435
  if (!await exists2(configPath)) return [];
8783
9436
  const raw = await readJson(configPath);
8784
9437
  const out = [];
@@ -8805,7 +9458,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
8805
9458
 
8806
9459
  // src/extract/databases/docker-compose.ts
8807
9460
  init_cjs_shims();
8808
- var import_node_path28 = __toESM(require("path"), 1);
9461
+ var import_node_path31 = __toESM(require("path"), 1);
8809
9462
  function portFromService(svc) {
8810
9463
  for (const raw of svc.ports ?? []) {
8811
9464
  const str = String(raw);
@@ -8832,7 +9485,7 @@ function databaseFromEnv(svc) {
8832
9485
  }
8833
9486
  async function parse9(serviceDir) {
8834
9487
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
8835
- const abs = import_node_path28.default.join(serviceDir, name);
9488
+ const abs = import_node_path31.default.join(serviceDir, name);
8836
9489
  if (!await exists2(abs)) continue;
8837
9490
  const raw = await readYaml(abs);
8838
9491
  if (!raw?.services) return [];
@@ -8873,8 +9526,8 @@ function compatibleDriversFor(engine) {
8873
9526
  }
8874
9527
  function toDatabaseNode(config) {
8875
9528
  return {
8876
- id: (0, import_types18.databaseId)(config.host),
8877
- type: import_types18.NodeType.DatabaseNode,
9529
+ id: (0, import_types21.databaseId)(config.host),
9530
+ type: import_types21.NodeType.DatabaseNode,
8878
9531
  name: config.database || config.host,
8879
9532
  engine: config.engine,
8880
9533
  engineVersion: config.engineVersion,
@@ -9004,7 +9657,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
9004
9657
  discoveredVia: mergedDiscoveredVia
9005
9658
  });
9006
9659
  }
9007
- const relConfigFile = toPosix(import_node_path29.default.relative(service.dir, config.sourceFile));
9660
+ const relConfigFile = toPosix(import_node_path32.default.relative(service.dir, config.sourceFile));
9008
9661
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9009
9662
  graph,
9010
9663
  service.pkg.name,
@@ -9013,14 +9666,14 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
9013
9666
  );
9014
9667
  nodesAdded += fn;
9015
9668
  edgesAdded += fe;
9016
- const evidenceFile = toPosix(import_node_path29.default.relative(scanPath, config.sourceFile));
9669
+ const evidenceFile = toPosix(import_node_path32.default.relative(scanPath, config.sourceFile));
9017
9670
  const edge = {
9018
- id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types18.EdgeType.CONNECTS_TO),
9671
+ id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types21.EdgeType.CONNECTS_TO),
9019
9672
  source: fileNodeId,
9020
9673
  target: dbNode.id,
9021
- type: import_types18.EdgeType.CONNECTS_TO,
9022
- provenance: import_types18.Provenance.EXTRACTED,
9023
- confidence: (0, import_types18.confidenceForExtracted)("structural"),
9674
+ type: import_types21.EdgeType.CONNECTS_TO,
9675
+ provenance: import_types21.Provenance.EXTRACTED,
9676
+ confidence: (0, import_types21.confidenceForExtracted)("structural"),
9024
9677
  evidence: { file: evidenceFile }
9025
9678
  };
9026
9679
  if (!graph.hasEdge(edge.id)) {
@@ -9031,26 +9684,26 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
9031
9684
  if (allConfigs.length === 1) {
9032
9685
  const primary = allConfigs[0];
9033
9686
  service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
9034
- const relPath = import_node_path29.default.relative(scanPath, primary.sourceFile);
9035
- const cfgId = (0, import_types18.configId)(relPath);
9687
+ const relPath = import_node_path32.default.relative(scanPath, primary.sourceFile);
9688
+ const cfgId = (0, import_types21.configId)(relPath);
9036
9689
  if (!graph.hasNode(cfgId)) {
9037
9690
  const cfgNode = {
9038
9691
  id: cfgId,
9039
- type: import_types18.NodeType.ConfigNode,
9040
- name: import_node_path29.default.basename(primary.sourceFile),
9692
+ type: import_types21.NodeType.ConfigNode,
9693
+ name: import_node_path32.default.basename(primary.sourceFile),
9041
9694
  path: relPath,
9042
- fileType: isConfigFile(import_node_path29.default.basename(primary.sourceFile)).fileType || "config"
9695
+ fileType: isConfigFile(import_node_path32.default.basename(primary.sourceFile)).fileType || "config"
9043
9696
  };
9044
9697
  graph.addNode(cfgId, cfgNode);
9045
9698
  nodesAdded++;
9046
9699
  }
9047
9700
  const cfgEdge = {
9048
- id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types18.EdgeType.CONFIGURED_BY),
9701
+ id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types21.EdgeType.CONFIGURED_BY),
9049
9702
  source: service.node.id,
9050
9703
  target: cfgId,
9051
- type: import_types18.EdgeType.CONFIGURED_BY,
9052
- provenance: import_types18.Provenance.EXTRACTED,
9053
- confidence: (0, import_types18.confidenceForExtracted)("structural"),
9704
+ type: import_types21.EdgeType.CONFIGURED_BY,
9705
+ provenance: import_types21.Provenance.EXTRACTED,
9706
+ confidence: (0, import_types21.confidenceForExtracted)("structural"),
9054
9707
  evidence: { file: toPosix(relPath) }
9055
9708
  };
9056
9709
  if (!graph.hasEdge(cfgEdge.id)) {
@@ -9080,15 +9733,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
9080
9733
 
9081
9734
  // src/extract/configs.ts
9082
9735
  init_cjs_shims();
9083
- var import_node_fs18 = require("fs");
9084
- var import_node_path30 = __toESM(require("path"), 1);
9085
- var import_types19 = require("@neat.is/types");
9736
+ var import_node_fs21 = require("fs");
9737
+ var import_node_path33 = __toESM(require("path"), 1);
9738
+ var import_types22 = require("@neat.is/types");
9086
9739
  async function walkConfigFiles(dir) {
9087
9740
  const out = [];
9088
9741
  async function walk9(current) {
9089
- const entries = await import_node_fs18.promises.readdir(current, { withFileTypes: true });
9742
+ const entries = await import_node_fs21.promises.readdir(current, { withFileTypes: true });
9090
9743
  for (const entry of entries) {
9091
- const full = import_node_path30.default.join(current, entry.name);
9744
+ const full = import_node_path33.default.join(current, entry.name);
9092
9745
  if (entry.isDirectory()) {
9093
9746
  if (IGNORED_DIRS.has(entry.name)) continue;
9094
9747
  if (await isPythonVenvDir(full)) continue;
@@ -9107,19 +9760,19 @@ async function addConfigNodes(graph, services, scanPath) {
9107
9760
  for (const service of services) {
9108
9761
  const configFiles = await walkConfigFiles(service.dir);
9109
9762
  for (const file of configFiles) {
9110
- const relPath = import_node_path30.default.relative(scanPath, file);
9763
+ const relPath = import_node_path33.default.relative(scanPath, file);
9111
9764
  const node = {
9112
- id: (0, import_types19.configId)(relPath),
9113
- type: import_types19.NodeType.ConfigNode,
9114
- name: import_node_path30.default.basename(file),
9765
+ id: (0, import_types22.configId)(relPath),
9766
+ type: import_types22.NodeType.ConfigNode,
9767
+ name: import_node_path33.default.basename(file),
9115
9768
  path: relPath,
9116
- fileType: isConfigFile(import_node_path30.default.basename(file)).fileType
9769
+ fileType: isConfigFile(import_node_path33.default.basename(file)).fileType
9117
9770
  };
9118
9771
  if (!graph.hasNode(node.id)) {
9119
9772
  graph.addNode(node.id, node);
9120
9773
  nodesAdded++;
9121
9774
  }
9122
- const relToService = toPosix(import_node_path30.default.relative(service.dir, file));
9775
+ const relToService = toPosix(import_node_path33.default.relative(service.dir, file));
9123
9776
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9124
9777
  graph,
9125
9778
  service.pkg.name,
@@ -9129,13 +9782,13 @@ async function addConfigNodes(graph, services, scanPath) {
9129
9782
  nodesAdded += fn;
9130
9783
  edgesAdded += fe;
9131
9784
  const edge = {
9132
- id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types19.EdgeType.CONFIGURED_BY),
9785
+ id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types22.EdgeType.CONFIGURED_BY),
9133
9786
  source: fileNodeId,
9134
9787
  target: node.id,
9135
- type: import_types19.EdgeType.CONFIGURED_BY,
9136
- provenance: import_types19.Provenance.EXTRACTED,
9137
- confidence: (0, import_types19.confidenceForExtracted)("structural"),
9138
- evidence: { file: relPath.split(import_node_path30.default.sep).join("/") }
9788
+ type: import_types22.EdgeType.CONFIGURED_BY,
9789
+ provenance: import_types22.Provenance.EXTRACTED,
9790
+ confidence: (0, import_types22.confidenceForExtracted)("structural"),
9791
+ evidence: { file: relPath.split(import_node_path33.default.sep).join("/") }
9139
9792
  };
9140
9793
  if (!graph.hasEdge(edge.id)) {
9141
9794
  graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
@@ -9148,9 +9801,9 @@ async function addConfigNodes(graph, services, scanPath) {
9148
9801
 
9149
9802
  // src/extract/proto.ts
9150
9803
  init_cjs_shims();
9151
- var import_node_fs19 = require("fs");
9152
- var import_node_path31 = __toESM(require("path"), 1);
9153
- var import_types20 = require("@neat.is/types");
9804
+ var import_node_fs22 = require("fs");
9805
+ var import_node_path34 = __toESM(require("path"), 1);
9806
+ var import_types23 = require("@neat.is/types");
9154
9807
  var PROTO_EXTENSION = ".proto";
9155
9808
  function packageOf(content) {
9156
9809
  const m = content.match(/^\s*package\s+([A-Za-z_][A-Za-z0-9_.]*)\s*;/m);
@@ -9189,14 +9842,14 @@ function grpcMethodsFromProto(content, fqPackage) {
9189
9842
  async function walkProtoFiles(dir) {
9190
9843
  const out = [];
9191
9844
  async function walk9(current) {
9192
- const entries = await import_node_fs19.promises.readdir(current, { withFileTypes: true }).catch(() => []);
9845
+ const entries = await import_node_fs22.promises.readdir(current, { withFileTypes: true }).catch(() => []);
9193
9846
  for (const entry of entries) {
9194
- const full = import_node_path31.default.join(current, entry.name);
9847
+ const full = import_node_path34.default.join(current, entry.name);
9195
9848
  if (entry.isDirectory()) {
9196
9849
  if (IGNORED_DIRS.has(entry.name)) continue;
9197
9850
  if (await isPythonVenvDir(full)) continue;
9198
9851
  await walk9(full);
9199
- } else if (entry.isFile() && import_node_path31.default.extname(entry.name) === PROTO_EXTENSION) {
9852
+ } else if (entry.isFile() && import_node_path34.default.extname(entry.name) === PROTO_EXTENSION) {
9200
9853
  out.push(full);
9201
9854
  }
9202
9855
  }
@@ -9211,10 +9864,10 @@ async function addGrpcMethods(graph, services) {
9211
9864
  const protoPaths = await walkProtoFiles(service.dir);
9212
9865
  for (const protoPath of protoPaths) {
9213
9866
  if (isTestPath(protoPath)) continue;
9214
- const relFile = toPosix(import_node_path31.default.relative(service.dir, protoPath));
9867
+ const relFile = toPosix(import_node_path34.default.relative(service.dir, protoPath));
9215
9868
  let content;
9216
9869
  try {
9217
- content = await import_node_fs19.promises.readFile(protoPath, "utf8");
9870
+ content = await import_node_fs22.promises.readFile(protoPath, "utf8");
9218
9871
  } catch (err) {
9219
9872
  recordExtractionError("proto extraction", protoPath, err);
9220
9873
  continue;
@@ -9228,11 +9881,11 @@ async function addGrpcMethods(graph, services) {
9228
9881
  }
9229
9882
  if (methods.length === 0) continue;
9230
9883
  for (const method of methods) {
9231
- const mid = (0, import_types20.grpcMethodId)(method.rpcService, method.rpcMethod);
9884
+ const mid = (0, import_types23.grpcMethodId)(method.rpcService, method.rpcMethod);
9232
9885
  if (!graph.hasNode(mid)) {
9233
9886
  const node = {
9234
9887
  id: mid,
9235
- type: import_types20.NodeType.GrpcMethodNode,
9888
+ type: import_types23.NodeType.GrpcMethodNode,
9236
9889
  name: `${method.rpcService}/${method.rpcMethod}`,
9237
9890
  rpcService: method.rpcService,
9238
9891
  rpcMethod: method.rpcMethod,
@@ -9243,15 +9896,15 @@ async function addGrpcMethods(graph, services) {
9243
9896
  graph.addNode(mid, node);
9244
9897
  nodesAdded++;
9245
9898
  }
9246
- const containsId = (0, import_types20.extractedEdgeId)(service.node.id, mid, import_types20.EdgeType.CONTAINS);
9899
+ const containsId = (0, import_types23.extractedEdgeId)(service.node.id, mid, import_types23.EdgeType.CONTAINS);
9247
9900
  if (!graph.hasEdge(containsId)) {
9248
9901
  const edge = {
9249
9902
  id: containsId,
9250
9903
  source: service.node.id,
9251
9904
  target: mid,
9252
- type: import_types20.EdgeType.CONTAINS,
9253
- provenance: import_types20.Provenance.EXTRACTED,
9254
- confidence: (0, import_types20.confidenceForExtracted)("structural"),
9905
+ type: import_types23.EdgeType.CONTAINS,
9906
+ provenance: import_types23.Provenance.EXTRACTED,
9907
+ confidence: (0, import_types23.confidenceForExtracted)("structural"),
9255
9908
  evidence: {
9256
9909
  file: relFile,
9257
9910
  line: method.line,
@@ -9269,16 +9922,16 @@ async function addGrpcMethods(graph, services) {
9269
9922
 
9270
9923
  // src/extract/calls/index.ts
9271
9924
  init_cjs_shims();
9272
- var import_types38 = require("@neat.is/types");
9925
+ var import_types41 = require("@neat.is/types");
9273
9926
 
9274
9927
  // src/extract/calls/http.ts
9275
9928
  init_cjs_shims();
9276
- var import_node_path32 = __toESM(require("path"), 1);
9929
+ var import_node_path35 = __toESM(require("path"), 1);
9277
9930
  var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
9278
9931
  var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
9279
9932
  var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
9280
- var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
9281
- var import_types21 = require("@neat.is/types");
9933
+ var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
9934
+ var import_types24 = require("@neat.is/types");
9282
9935
  var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
9283
9936
  var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
9284
9937
  function isInsideJsxExternalLink(node) {
@@ -9334,7 +9987,7 @@ var GRAMMAR_BY_EXT2 = {
9334
9987
  ".jsx": import_tree_sitter_javascript4.default,
9335
9988
  ".mjs": import_tree_sitter_javascript4.default,
9336
9989
  ".cjs": import_tree_sitter_javascript4.default,
9337
- ".py": import_tree_sitter_python3.default
9990
+ ".py": import_tree_sitter_python4.default
9338
9991
  };
9339
9992
  function parserForExt(ext, cache) {
9340
9993
  const grammar = GRAMMAR_BY_EXT2[ext] ?? import_tree_sitter_javascript4.default;
@@ -9356,7 +10009,7 @@ async function addHttpCallEdges(graph, services) {
9356
10009
  const seen = /* @__PURE__ */ new Set();
9357
10010
  for (const file of files) {
9358
10011
  if (isTestPath(file.path)) continue;
9359
- const parser = parserForExt(import_node_path32.default.extname(file.path), parserCache);
10012
+ const parser = parserForExt(import_node_path35.default.extname(file.path), parserCache);
9360
10013
  let sites;
9361
10014
  try {
9362
10015
  sites = callsFromSource(file.content, parser, knownHosts);
@@ -9365,14 +10018,14 @@ async function addHttpCallEdges(graph, services) {
9365
10018
  continue;
9366
10019
  }
9367
10020
  if (sites.length === 0) continue;
9368
- const relFile = toPosix(import_node_path32.default.relative(service.dir, file.path));
10021
+ const relFile = toPosix(import_node_path35.default.relative(service.dir, file.path));
9369
10022
  for (const site of sites) {
9370
10023
  const targetId = hostToNodeId.get(site.host);
9371
10024
  if (!targetId || targetId === service.node.id) continue;
9372
10025
  const dedupKey = `${relFile}|${targetId}`;
9373
10026
  if (seen.has(dedupKey)) continue;
9374
10027
  seen.add(dedupKey);
9375
- const confidence = (0, import_types21.confidenceForExtracted)("url-literal-service-target");
10028
+ const confidence = (0, import_types24.confidenceForExtracted)("url-literal-service-target");
9376
10029
  const ev = {
9377
10030
  file: relFile,
9378
10031
  line: site.line,
@@ -9386,25 +10039,25 @@ async function addHttpCallEdges(graph, services) {
9386
10039
  );
9387
10040
  nodesAdded += n;
9388
10041
  edgesAdded += e;
9389
- if (!(0, import_types21.passesExtractedFloor)(confidence)) {
10042
+ if (!(0, import_types24.passesExtractedFloor)(confidence)) {
9390
10043
  noteExtractedDropped({
9391
10044
  source: fileNodeId,
9392
10045
  target: targetId,
9393
- type: import_types21.EdgeType.CALLS,
10046
+ type: import_types24.EdgeType.CALLS,
9394
10047
  confidence,
9395
10048
  confidenceKind: "url-literal-service-target",
9396
10049
  evidence: ev
9397
10050
  });
9398
10051
  continue;
9399
10052
  }
9400
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types21.EdgeType.CALLS);
10053
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types24.EdgeType.CALLS);
9401
10054
  if (!graph.hasEdge(edgeId)) {
9402
10055
  const edge = {
9403
10056
  id: edgeId,
9404
10057
  source: fileNodeId,
9405
10058
  target: targetId,
9406
- type: import_types21.EdgeType.CALLS,
9407
- provenance: import_types21.Provenance.EXTRACTED,
10059
+ type: import_types24.EdgeType.CALLS,
10060
+ provenance: import_types24.Provenance.EXTRACTED,
9408
10061
  confidence,
9409
10062
  evidence: ev
9410
10063
  };
@@ -9419,10 +10072,10 @@ async function addHttpCallEdges(graph, services) {
9419
10072
 
9420
10073
  // src/extract/calls/route-match.ts
9421
10074
  init_cjs_shims();
9422
- var import_node_path33 = __toESM(require("path"), 1);
10075
+ var import_node_path36 = __toESM(require("path"), 1);
9423
10076
  var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
9424
10077
  var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
9425
- var import_types22 = require("@neat.is/types");
10078
+ var import_types25 = require("@neat.is/types");
9426
10079
  var PARSE_CHUNK5 = 16384;
9427
10080
  function parseSource5(parser, source) {
9428
10081
  return parser.parse(
@@ -9587,9 +10240,9 @@ function buildRouteIndex(graph) {
9587
10240
  const index = /* @__PURE__ */ new Map();
9588
10241
  graph.forEachNode((_id, attrs) => {
9589
10242
  const node = attrs;
9590
- if (node.type !== import_types22.NodeType.RouteNode) return;
10243
+ if (node.type !== import_types25.NodeType.RouteNode) return;
9591
10244
  const route = attrs;
9592
- const owner = (0, import_types22.serviceId)(route.service);
10245
+ const owner = (0, import_types25.serviceId)(route.service);
9593
10246
  const entry = {
9594
10247
  method: route.method.toUpperCase(),
9595
10248
  normalizedPath: normalizePathTemplate(route.pathTemplate),
@@ -9618,7 +10271,7 @@ async function addRouteCallEdges(graph, services) {
9618
10271
  const seen = /* @__PURE__ */ new Set();
9619
10272
  for (const file of files) {
9620
10273
  if (isTestPath(file.path)) continue;
9621
- if (!JS_CLIENT_EXTENSIONS.has(import_node_path33.default.extname(file.path))) continue;
10274
+ if (!JS_CLIENT_EXTENSIONS.has(import_node_path36.default.extname(file.path))) continue;
9622
10275
  let sites;
9623
10276
  try {
9624
10277
  sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
@@ -9627,7 +10280,7 @@ async function addRouteCallEdges(graph, services) {
9627
10280
  continue;
9628
10281
  }
9629
10282
  if (sites.length === 0) continue;
9630
- const relFile = toPosix(import_node_path33.default.relative(service.dir, file.path));
10283
+ const relFile = toPosix(import_node_path36.default.relative(service.dir, file.path));
9631
10284
  for (const site of sites) {
9632
10285
  const serverServiceId = hostToNodeId.get(site.host);
9633
10286
  if (!serverServiceId || serverServiceId === service.node.id) continue;
@@ -9647,7 +10300,7 @@ async function addRouteCallEdges(graph, services) {
9647
10300
  );
9648
10301
  nodesAdded += n;
9649
10302
  edgesAdded += e;
9650
- const confidence = (0, import_types22.confidenceForExtracted)("verified-call-site");
10303
+ const confidence = (0, import_types25.confidenceForExtracted)("verified-call-site");
9651
10304
  const ev = {
9652
10305
  file: relFile,
9653
10306
  line: site.line,
@@ -9655,25 +10308,25 @@ async function addRouteCallEdges(graph, services) {
9655
10308
  method: site.method ?? match.method,
9656
10309
  pathTemplate: site.pathTemplate
9657
10310
  };
9658
- if (!(0, import_types22.passesExtractedFloor)(confidence)) {
10311
+ if (!(0, import_types25.passesExtractedFloor)(confidence)) {
9659
10312
  noteExtractedDropped({
9660
10313
  source: fileNodeId,
9661
10314
  target: match.routeNodeId,
9662
- type: import_types22.EdgeType.CALLS,
10315
+ type: import_types25.EdgeType.CALLS,
9663
10316
  confidence,
9664
10317
  confidenceKind: "verified-call-site",
9665
10318
  evidence: ev
9666
10319
  });
9667
10320
  continue;
9668
10321
  }
9669
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types22.EdgeType.CALLS);
10322
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types25.EdgeType.CALLS);
9670
10323
  if (!graph.hasEdge(edgeId)) {
9671
10324
  const edge = {
9672
10325
  id: edgeId,
9673
10326
  source: fileNodeId,
9674
10327
  target: match.routeNodeId,
9675
- type: import_types22.EdgeType.CALLS,
9676
- provenance: import_types22.Provenance.EXTRACTED,
10328
+ type: import_types25.EdgeType.CALLS,
10329
+ provenance: import_types25.Provenance.EXTRACTED,
9677
10330
  confidence,
9678
10331
  evidence: ev
9679
10332
  };
@@ -9688,8 +10341,8 @@ async function addRouteCallEdges(graph, services) {
9688
10341
 
9689
10342
  // src/extract/calls/kafka.ts
9690
10343
  init_cjs_shims();
9691
- var import_node_path34 = __toESM(require("path"), 1);
9692
- var import_types23 = require("@neat.is/types");
10344
+ var import_node_path37 = __toESM(require("path"), 1);
10345
+ var import_types26 = require("@neat.is/types");
9693
10346
  var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
9694
10347
  var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
9695
10348
  function findAll(re, text) {
@@ -9710,7 +10363,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
9710
10363
  seen.add(key);
9711
10364
  const line = lineOf(file.content, topic);
9712
10365
  out.push({
9713
- infraId: (0, import_types23.infraId)("kafka-topic", topic),
10366
+ infraId: (0, import_types26.infraId)("kafka-topic", topic),
9714
10367
  name: topic,
9715
10368
  kind: "kafka-topic",
9716
10369
  edgeType,
@@ -9719,7 +10372,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
9719
10372
  // tier (ADR-066).
9720
10373
  confidenceKind: "verified-call-site",
9721
10374
  evidence: {
9722
- file: import_node_path34.default.relative(serviceDir, file.path),
10375
+ file: import_node_path37.default.relative(serviceDir, file.path),
9723
10376
  line,
9724
10377
  snippet: snippet(file.content, line)
9725
10378
  }
@@ -9732,8 +10385,8 @@ function kafkaEndpointsFromFile(file, serviceDir) {
9732
10385
 
9733
10386
  // src/extract/calls/redis.ts
9734
10387
  init_cjs_shims();
9735
- var import_node_path35 = __toESM(require("path"), 1);
9736
- var import_types24 = require("@neat.is/types");
10388
+ var import_node_path38 = __toESM(require("path"), 1);
10389
+ var import_types27 = require("@neat.is/types");
9737
10390
  var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
9738
10391
  function redisEndpointsFromFile(file, serviceDir) {
9739
10392
  const out = [];
@@ -9746,7 +10399,7 @@ function redisEndpointsFromFile(file, serviceDir) {
9746
10399
  seen.add(host);
9747
10400
  const line = lineOf(file.content, host);
9748
10401
  out.push({
9749
- infraId: (0, import_types24.infraId)("redis", host),
10402
+ infraId: (0, import_types27.infraId)("redis", host),
9750
10403
  name: host,
9751
10404
  kind: "redis",
9752
10405
  edgeType: "CALLS",
@@ -9755,7 +10408,7 @@ function redisEndpointsFromFile(file, serviceDir) {
9755
10408
  // support tier (ADR-066).
9756
10409
  confidenceKind: "url-with-structural-support",
9757
10410
  evidence: {
9758
- file: import_node_path35.default.relative(serviceDir, file.path),
10411
+ file: import_node_path38.default.relative(serviceDir, file.path),
9759
10412
  line,
9760
10413
  snippet: snippet(file.content, line)
9761
10414
  }
@@ -9766,8 +10419,8 @@ function redisEndpointsFromFile(file, serviceDir) {
9766
10419
 
9767
10420
  // src/extract/calls/aws.ts
9768
10421
  init_cjs_shims();
9769
- var import_node_path36 = __toESM(require("path"), 1);
9770
- var import_types25 = require("@neat.is/types");
10422
+ var import_node_path39 = __toESM(require("path"), 1);
10423
+ var import_types28 = require("@neat.is/types");
9771
10424
  var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
9772
10425
  var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
9773
10426
  function hasMarker(text, markers) {
@@ -9791,7 +10444,7 @@ function awsEndpointsFromFile(file, serviceDir) {
9791
10444
  seen.add(key);
9792
10445
  const line = lineOf(file.content, name);
9793
10446
  out.push({
9794
- infraId: (0, import_types25.infraId)(kind, name),
10447
+ infraId: (0, import_types28.infraId)(kind, name),
9795
10448
  name,
9796
10449
  kind,
9797
10450
  edgeType: "CALLS",
@@ -9800,7 +10453,7 @@ function awsEndpointsFromFile(file, serviceDir) {
9800
10453
  // (ADR-066).
9801
10454
  confidenceKind: "verified-call-site",
9802
10455
  evidence: {
9803
- file: import_node_path36.default.relative(serviceDir, file.path),
10456
+ file: import_node_path39.default.relative(serviceDir, file.path),
9804
10457
  line,
9805
10458
  snippet: snippet(file.content, line)
9806
10459
  }
@@ -9825,8 +10478,8 @@ function awsEndpointsFromFile(file, serviceDir) {
9825
10478
 
9826
10479
  // src/extract/calls/grpc.ts
9827
10480
  init_cjs_shims();
9828
- var import_node_path37 = __toESM(require("path"), 1);
9829
- var import_types26 = require("@neat.is/types");
10481
+ var import_node_path40 = __toESM(require("path"), 1);
10482
+ var import_types29 = require("@neat.is/types");
9830
10483
  var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
9831
10484
  var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
9832
10485
  var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
@@ -9875,7 +10528,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
9875
10528
  const { kind } = classified;
9876
10529
  const line = lineOf(file.content, m[0]);
9877
10530
  out.push({
9878
- infraId: (0, import_types26.infraId)(kind, name),
10531
+ infraId: (0, import_types29.infraId)(kind, name),
9879
10532
  name,
9880
10533
  kind,
9881
10534
  edgeType: "CALLS",
@@ -9884,7 +10537,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
9884
10537
  // tier (ADR-066).
9885
10538
  confidenceKind: "verified-call-site",
9886
10539
  evidence: {
9887
- file: import_node_path37.default.relative(serviceDir, file.path),
10540
+ file: import_node_path40.default.relative(serviceDir, file.path),
9888
10541
  line,
9889
10542
  snippet: snippet(file.content, line)
9890
10543
  }
@@ -9895,8 +10548,8 @@ function grpcEndpointsFromFile(file, serviceDir) {
9895
10548
 
9896
10549
  // src/extract/calls/supabase.ts
9897
10550
  init_cjs_shims();
9898
- var import_node_path38 = __toESM(require("path"), 1);
9899
- var import_types27 = require("@neat.is/types");
10551
+ var import_node_path41 = __toESM(require("path"), 1);
10552
+ var import_types30 = require("@neat.is/types");
9900
10553
  var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
9901
10554
  var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
9902
10555
  var SUPABASE_CLIENT_RE = /\b(createClient|createServerClient|createBrowserClient)\s*\(\s*(?:['"`]([^'"`]*)['"`])?/g;
@@ -9944,7 +10597,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
9944
10597
  seen.add(name);
9945
10598
  const line = lineOf(file.content, m[0]);
9946
10599
  out.push({
9947
- infraId: (0, import_types27.infraId)("supabase", name),
10600
+ infraId: (0, import_types30.infraId)("supabase", name),
9948
10601
  name,
9949
10602
  kind: "supabase",
9950
10603
  edgeType: "CALLS",
@@ -9954,7 +10607,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
9954
10607
  // tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
9955
10608
  confidenceKind: "verified-call-site",
9956
10609
  evidence: {
9957
- file: import_node_path38.default.relative(serviceDir, file.path),
10610
+ file: import_node_path41.default.relative(serviceDir, file.path),
9958
10611
  line,
9959
10612
  snippet: snippet(file.content, line)
9960
10613
  }
@@ -9975,13 +10628,13 @@ function supabaseEndpointsFromFile(file, serviceDir) {
9975
10628
  seen.add(key);
9976
10629
  const line = lineOf(file.content, am[0]);
9977
10630
  out.push({
9978
- infraId: (0, import_types27.infraId)(kind, resource),
10631
+ infraId: (0, import_types30.infraId)(kind, resource),
9979
10632
  name: resource,
9980
10633
  kind,
9981
10634
  edgeType: "CALLS",
9982
10635
  confidenceKind: "verified-call-site",
9983
10636
  evidence: {
9984
- file: import_node_path38.default.relative(serviceDir, file.path),
10637
+ file: import_node_path41.default.relative(serviceDir, file.path),
9985
10638
  line,
9986
10639
  snippet: snippet(file.content, line)
9987
10640
  }
@@ -9993,10 +10646,10 @@ function supabaseEndpointsFromFile(file, serviceDir) {
9993
10646
 
9994
10647
  // src/extract/calls/firestore.ts
9995
10648
  init_cjs_shims();
9996
- var import_node_path39 = __toESM(require("path"), 1);
10649
+ var import_node_path42 = __toESM(require("path"), 1);
9997
10650
  var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
9998
10651
  var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
9999
- var import_types28 = require("@neat.is/types");
10652
+ var import_types31 = require("@neat.is/types");
10000
10653
  var FIRESTORE_CLIENT_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase\/firestore['"`]/;
10001
10654
  var FIRESTORE_ADMIN_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase-admin(?:\/firestore)?['"`]/;
10002
10655
  function parserForExt2(ext) {
@@ -10164,7 +10817,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
10164
10817
  const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
10165
10818
  if (!hasClient && !hasAdmin) return [];
10166
10819
  const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
10167
- const tree = parseSource3(parserForExt2(import_node_path39.default.extname(file.path)), file.content);
10820
+ const tree = parseSource3(parserForExt2(import_node_path42.default.extname(file.path)), file.content);
10168
10821
  const clientVars = firestoreClientVars(tree.rootNode);
10169
10822
  const collLine = /* @__PURE__ */ new Map();
10170
10823
  const writes = /* @__PURE__ */ new Map();
@@ -10257,7 +10910,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
10257
10910
  }
10258
10911
  }
10259
10912
  out.push({
10260
- infraId: (0, import_types28.infraId)("firestore-collection", collPath),
10913
+ infraId: (0, import_types31.infraId)("firestore-collection", collPath),
10261
10914
  name: collPath,
10262
10915
  kind: "firestore-collection",
10263
10916
  edgeType: "CALLS",
@@ -10268,7 +10921,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
10268
10921
  ...columnSet.size > 0 ? { columns: [...columnSet] } : {},
10269
10922
  ...sdkWrites ? { sdkWrites } : {},
10270
10923
  evidence: {
10271
- file: import_node_path39.default.relative(serviceDir, file.path),
10924
+ file: import_node_path42.default.relative(serviceDir, file.path),
10272
10925
  line,
10273
10926
  snippet: snippet(file.content, line)
10274
10927
  }
@@ -10279,8 +10932,8 @@ function firestoreEndpointsFromFile(file, serviceDir) {
10279
10932
 
10280
10933
  // src/extract/calls/mongoose.ts
10281
10934
  init_cjs_shims();
10282
- var import_node_path40 = __toESM(require("path"), 1);
10283
- var import_types29 = require("@neat.is/types");
10935
+ var import_node_path43 = __toESM(require("path"), 1);
10936
+ var import_types32 = require("@neat.is/types");
10284
10937
  var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
10285
10938
  var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
10286
10939
  var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
@@ -10425,12 +11078,12 @@ function collectModelDefs(content, pluralizeOn) {
10425
11078
  function endpoint(r, file, serviceDir, matchText) {
10426
11079
  const line = lineOf(file.content, matchText);
10427
11080
  return {
10428
- infraId: (0, import_types29.infraId)(r.kind, r.name),
11081
+ infraId: (0, import_types32.infraId)(r.kind, r.name),
10429
11082
  name: r.name,
10430
11083
  kind: r.kind,
10431
11084
  edgeType: "CALLS",
10432
11085
  confidenceKind: "verified-call-site",
10433
- evidence: { file: import_node_path40.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
11086
+ evidence: { file: import_node_path43.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
10434
11087
  };
10435
11088
  }
10436
11089
  function mongooseEndpointsFromFile(file, serviceDir) {
@@ -10520,7 +11173,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
10520
11173
  const registry = /* @__PURE__ */ new Map();
10521
11174
  for (const f of mongooseFiles) {
10522
11175
  const fx = fileExportsOf(f.content, pluralizeOn);
10523
- if (fx) registry.set(toPosix(import_node_path40.default.relative(serviceDir, f.path)), fx);
11176
+ if (fx) registry.set(toPosix(import_node_path43.default.relative(serviceDir, f.path)), fx);
10524
11177
  }
10525
11178
  if (registry.size === 0) return [];
10526
11179
  const out = [];
@@ -10531,7 +11184,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
10531
11184
  const directColl = /* @__PURE__ */ new Map();
10532
11185
  const nsExports = /* @__PURE__ */ new Map();
10533
11186
  for (const b of bindings) {
10534
- const resolvedRel = await resolveJsImport(b.specifier, import_node_path40.default.dirname(f.path), serviceDir, null);
11187
+ const resolvedRel = await resolveJsImport(b.specifier, import_node_path43.default.dirname(f.path), serviceDir, null);
10535
11188
  if (!resolvedRel) continue;
10536
11189
  const fx = registry.get(resolvedRel);
10537
11190
  if (!fx) continue;
@@ -10575,15 +11228,15 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
10575
11228
 
10576
11229
  // src/extract/calls/sqlalchemy.ts
10577
11230
  init_cjs_shims();
10578
- var import_node_path41 = __toESM(require("path"), 1);
11231
+ var import_node_path44 = __toESM(require("path"), 1);
10579
11232
  var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
10580
- var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
10581
- var import_types30 = require("@neat.is/types");
11233
+ var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
11234
+ var import_types33 = require("@neat.is/types");
10582
11235
  var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
10583
11236
  var PARSE_CHUNK6 = 16384;
10584
11237
  function makePyParser3() {
10585
11238
  const p = new import_tree_sitter9.default();
10586
- p.setLanguage(import_tree_sitter_python4.default);
11239
+ p.setLanguage(import_tree_sitter_python5.default);
10587
11240
  return p;
10588
11241
  }
10589
11242
  function parseSource6(parser, source) {
@@ -10714,7 +11367,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
10714
11367
  childTable,
10715
11368
  parentTable,
10716
11369
  evidence: {
10717
- file: import_node_path41.default.relative(serviceDir, file.path),
11370
+ file: import_node_path44.default.relative(serviceDir, file.path),
10718
11371
  line,
10719
11372
  snippet: snippet(file.content, line)
10720
11373
  }
@@ -10732,14 +11385,14 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
10732
11385
  if (seen.has(name)) return;
10733
11386
  seen.add(name);
10734
11387
  out.push({
10735
- infraId: (0, import_types30.infraId)("sql-table", name),
11388
+ infraId: (0, import_types33.infraId)("sql-table", name),
10736
11389
  name,
10737
11390
  kind: "sql-table",
10738
11391
  edgeType: "CALLS",
10739
11392
  confidenceKind: "verified-call-site",
10740
11393
  ...columns && columns.length > 0 ? { columns } : {},
10741
11394
  evidence: {
10742
- file: import_node_path41.default.relative(serviceDir, file.path),
11395
+ file: import_node_path44.default.relative(serviceDir, file.path),
10743
11396
  line,
10744
11397
  snippet: snippet(file.content, line)
10745
11398
  }
@@ -10840,13 +11493,13 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
10840
11493
  if (seen.has(key)) continue;
10841
11494
  seen.add(key);
10842
11495
  out.push({
10843
- infraId: (0, import_types30.infraId)("sql-table", t),
11496
+ infraId: (0, import_types33.infraId)("sql-table", t),
10844
11497
  name: t,
10845
11498
  kind: "sql-table",
10846
11499
  edgeType: "CALLS",
10847
11500
  confidenceKind: "verified-call-site",
10848
11501
  evidence: {
10849
- file: import_node_path41.default.relative(serviceDir, file.path),
11502
+ file: import_node_path44.default.relative(serviceDir, file.path),
10850
11503
  line,
10851
11504
  snippet: snippet(file.content, line)
10852
11505
  }
@@ -10858,15 +11511,15 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
10858
11511
 
10859
11512
  // src/extract/calls/django-orm.ts
10860
11513
  init_cjs_shims();
10861
- var import_node_path42 = __toESM(require("path"), 1);
11514
+ var import_node_path45 = __toESM(require("path"), 1);
10862
11515
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
10863
- var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
10864
- var import_types31 = require("@neat.is/types");
11516
+ var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
11517
+ var import_types34 = require("@neat.is/types");
10865
11518
  var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
10866
11519
  var PARSE_CHUNK7 = 16384;
10867
11520
  function makePyParser4() {
10868
11521
  const p = new import_tree_sitter10.default();
10869
- p.setLanguage(import_tree_sitter_python5.default);
11522
+ p.setLanguage(import_tree_sitter_python6.default);
10870
11523
  return p;
10871
11524
  }
10872
11525
  function parseSource7(parser, source) {
@@ -10928,7 +11581,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
10928
11581
  const tree = parseSource7(makePyParser4(), file.content);
10929
11582
  const out = [];
10930
11583
  const seen = /* @__PURE__ */ new Set();
10931
- const defaultAppLabel = import_node_path42.default.basename(import_node_path42.default.dirname(file.path));
11584
+ const defaultAppLabel = import_node_path45.default.basename(import_node_path45.default.dirname(file.path));
10932
11585
  walk4(tree.rootNode, (node) => {
10933
11586
  if (node.type !== "class_definition") return;
10934
11587
  if (!extendsDjangoModel(node)) return;
@@ -10941,12 +11594,12 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
10941
11594
  seen.add(table);
10942
11595
  const line = node.startPosition.row + 1;
10943
11596
  out.push({
10944
- infraId: (0, import_types31.infraId)("sql-table", table),
11597
+ infraId: (0, import_types34.infraId)("sql-table", table),
10945
11598
  name: table,
10946
11599
  kind: "sql-table",
10947
11600
  edgeType: "CALLS",
10948
11601
  confidenceKind: "verified-call-site",
10949
- evidence: { file: import_node_path42.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
11602
+ evidence: { file: import_node_path45.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
10950
11603
  });
10951
11604
  });
10952
11605
  return out;
@@ -10954,10 +11607,10 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
10954
11607
 
10955
11608
  // src/extract/calls/drizzle.ts
10956
11609
  init_cjs_shims();
10957
- var import_node_path43 = __toESM(require("path"), 1);
11610
+ var import_node_path46 = __toESM(require("path"), 1);
10958
11611
  var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
10959
11612
  var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
10960
- var import_types32 = require("@neat.is/types");
11613
+ var import_types35 = require("@neat.is/types");
10961
11614
  var DRIZZLE_IMPORT_RE = /drizzle-orm/;
10962
11615
  var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
10963
11616
  function parserForExt3(ext) {
@@ -11032,7 +11685,7 @@ function columnsFromObject(obj) {
11032
11685
  }
11033
11686
  function drizzleEndpointsFromFile(file, serviceDir) {
11034
11687
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
11035
- const tree = parseSource3(parserForExt3(import_node_path43.default.extname(file.path)), file.content);
11688
+ const tree = parseSource3(parserForExt3(import_node_path46.default.extname(file.path)), file.content);
11036
11689
  const out = [];
11037
11690
  const seen = /* @__PURE__ */ new Set();
11038
11691
  const walk9 = (node) => {
@@ -11048,14 +11701,14 @@ function drizzleEndpointsFromFile(file, serviceDir) {
11048
11701
  const columns = columnsFromObject(obj);
11049
11702
  const line = node.startPosition.row + 1;
11050
11703
  out.push({
11051
- infraId: (0, import_types32.infraId)("sql-table", tableName),
11704
+ infraId: (0, import_types35.infraId)("sql-table", tableName),
11052
11705
  name: tableName,
11053
11706
  kind: "sql-table",
11054
11707
  edgeType: "CALLS",
11055
11708
  confidenceKind: "structural",
11056
11709
  columns,
11057
11710
  evidence: {
11058
- file: import_node_path43.default.relative(serviceDir, file.path),
11711
+ file: import_node_path46.default.relative(serviceDir, file.path),
11059
11712
  line,
11060
11713
  snippet: snippet(file.content, line)
11061
11714
  }
@@ -11121,7 +11774,7 @@ function referencesTargetVar(call) {
11121
11774
  }
11122
11775
  function drizzleForeignKeys(file, serviceDir) {
11123
11776
  if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
11124
- const tree = parseSource3(parserForExt3(import_node_path43.default.extname(file.path)), file.content);
11777
+ const tree = parseSource3(parserForExt3(import_node_path46.default.extname(file.path)), file.content);
11125
11778
  const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
11126
11779
  const out = [];
11127
11780
  const seen = /* @__PURE__ */ new Set();
@@ -11140,7 +11793,7 @@ function drizzleForeignKeys(file, serviceDir) {
11140
11793
  childTable: table.tableName,
11141
11794
  parentTable,
11142
11795
  evidence: {
11143
- file: import_node_path43.default.relative(serviceDir, file.path),
11796
+ file: import_node_path46.default.relative(serviceDir, file.path),
11144
11797
  line,
11145
11798
  snippet: snippet(file.content, line)
11146
11799
  }
@@ -11157,8 +11810,8 @@ function drizzleForeignKeys(file, serviceDir) {
11157
11810
 
11158
11811
  // src/extract/calls/prisma.ts
11159
11812
  init_cjs_shims();
11160
- var import_node_path44 = __toESM(require("path"), 1);
11161
- var import_types33 = require("@neat.is/types");
11813
+ var import_node_path47 = __toESM(require("path"), 1);
11814
+ var import_types36 = require("@neat.is/types");
11162
11815
  var SCALAR_TYPES = /* @__PURE__ */ new Set([
11163
11816
  "Int",
11164
11817
  "String",
@@ -11206,14 +11859,14 @@ function prismaColumnsFromSchema(file, serviceDir) {
11206
11859
  if (seenTable.has(b.tableName)) return;
11207
11860
  seenTable.add(b.tableName);
11208
11861
  out.push({
11209
- infraId: (0, import_types33.infraId)("sql-table", b.tableName),
11862
+ infraId: (0, import_types36.infraId)("sql-table", b.tableName),
11210
11863
  name: b.tableName,
11211
11864
  kind: "sql-table",
11212
11865
  edgeType: "CALLS",
11213
11866
  confidenceKind: "structural",
11214
11867
  columns: b.columns,
11215
11868
  evidence: {
11216
- file: import_node_path44.default.relative(serviceDir, file.path),
11869
+ file: import_node_path47.default.relative(serviceDir, file.path),
11217
11870
  line: b.startLine,
11218
11871
  snippet: snippet(content, b.startLine)
11219
11872
  }
@@ -11274,7 +11927,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
11274
11927
  }
11275
11928
  async function prismaColumnEndpoints(serviceDir) {
11276
11929
  const schemaPath = await findFirst(serviceDir, [
11277
- import_node_path44.default.join("prisma", "schema.prisma"),
11930
+ import_node_path47.default.join("prisma", "schema.prisma"),
11278
11931
  "schema.prisma"
11279
11932
  ]);
11280
11933
  if (!schemaPath) return [];
@@ -11349,7 +12002,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
11349
12002
  childTable: current.table,
11350
12003
  parentTable,
11351
12004
  evidence: {
11352
- file: import_node_path44.default.relative(serviceDir, file.path),
12005
+ file: import_node_path47.default.relative(serviceDir, file.path),
11353
12006
  line: lineNo,
11354
12007
  snippet: snippet(content, lineNo)
11355
12008
  }
@@ -11364,7 +12017,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
11364
12017
  }
11365
12018
  async function prismaForeignKeys(serviceDir) {
11366
12019
  const schemaPath = await findFirst(serviceDir, [
11367
- import_node_path44.default.join("prisma", "schema.prisma"),
12020
+ import_node_path47.default.join("prisma", "schema.prisma"),
11368
12021
  "schema.prisma"
11369
12022
  ]);
11370
12023
  if (!schemaPath) return [];
@@ -11375,15 +12028,15 @@ async function prismaForeignKeys(serviceDir) {
11375
12028
 
11376
12029
  // src/extract/calls/activerecord.ts
11377
12030
  init_cjs_shims();
11378
- var import_node_path45 = __toESM(require("path"), 1);
12031
+ var import_node_path48 = __toESM(require("path"), 1);
11379
12032
  var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
11380
- var import_tree_sitter_ruby2 = __toESM(require("tree-sitter-ruby"), 1);
11381
- var import_types34 = require("@neat.is/types");
12033
+ var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
12034
+ var import_types37 = require("@neat.is/types");
11382
12035
  var AR_SCHEMA_RE = /ActiveRecord::Schema/;
11383
12036
  var PARSE_CHUNK8 = 16384;
11384
12037
  function makeRubyParser2() {
11385
12038
  const p = new import_tree_sitter12.default();
11386
- p.setLanguage(import_tree_sitter_ruby2.default);
12039
+ p.setLanguage(import_tree_sitter_ruby3.default);
11387
12040
  return p;
11388
12041
  }
11389
12042
  function parseSource8(parser, source) {
@@ -11576,14 +12229,14 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
11576
12229
  if (!table || seen.has(table.name)) return;
11577
12230
  seen.add(table.name);
11578
12231
  out.push({
11579
- infraId: (0, import_types34.infraId)("sql-table", table.name),
12232
+ infraId: (0, import_types37.infraId)("sql-table", table.name),
11580
12233
  name: table.name,
11581
12234
  kind: "sql-table",
11582
12235
  edgeType: "CALLS",
11583
12236
  confidenceKind: "structural",
11584
12237
  ...table.columns.length > 0 ? { columns: table.columns } : {},
11585
12238
  evidence: {
11586
- file: import_node_path45.default.relative(serviceDir, file.path),
12239
+ file: import_node_path48.default.relative(serviceDir, file.path),
11587
12240
  line: table.line,
11588
12241
  snippet: snippet(file.content, table.line)
11589
12242
  }
@@ -11605,7 +12258,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
11605
12258
  childTable,
11606
12259
  parentTable,
11607
12260
  evidence: {
11608
- file: import_node_path45.default.relative(serviceDir, file.path),
12261
+ file: import_node_path48.default.relative(serviceDir, file.path),
11609
12262
  line,
11610
12263
  snippet: snippet(file.content, line)
11611
12264
  }
@@ -11682,13 +12335,13 @@ function railsModelEndpointsFromFile(file, serviceDir) {
11682
12335
  seen.add(table);
11683
12336
  const line = node.startPosition.row + 1;
11684
12337
  out.push({
11685
- infraId: (0, import_types34.infraId)("sql-table", table),
12338
+ infraId: (0, import_types37.infraId)("sql-table", table),
11686
12339
  name: table,
11687
12340
  kind: "sql-table",
11688
12341
  edgeType: "CALLS",
11689
12342
  confidenceKind: "verified-call-site",
11690
12343
  evidence: {
11691
- file: import_node_path45.default.relative(serviceDir, file.path),
12344
+ file: import_node_path48.default.relative(serviceDir, file.path),
11692
12345
  line,
11693
12346
  snippet: snippet(file.content, line)
11694
12347
  }
@@ -11725,7 +12378,7 @@ function railsModelForeignKeys(file, serviceDir) {
11725
12378
  childTable,
11726
12379
  parentTable,
11727
12380
  evidence: {
11728
- file: import_node_path45.default.relative(serviceDir, file.path),
12381
+ file: import_node_path48.default.relative(serviceDir, file.path),
11729
12382
  line,
11730
12383
  snippet: snippet(file.content, line)
11731
12384
  }
@@ -11737,15 +12390,15 @@ function railsModelForeignKeys(file, serviceDir) {
11737
12390
 
11738
12391
  // src/extract/calls/eloquent.ts
11739
12392
  init_cjs_shims();
11740
- var import_node_path46 = __toESM(require("path"), 1);
12393
+ var import_node_path49 = __toESM(require("path"), 1);
11741
12394
  var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
11742
- var import_tree_sitter_php2 = __toESM(require("tree-sitter-php"), 1);
11743
- var import_types35 = require("@neat.is/types");
12395
+ var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
12396
+ var import_types38 = require("@neat.is/types");
11744
12397
  var LARAVEL_SCHEMA_RE = /\bSchema::(create|createIfNotExists|table)\b/;
11745
12398
  var PARSE_CHUNK9 = 16384;
11746
12399
  function makePhpParser2() {
11747
12400
  const p = new import_tree_sitter13.default();
11748
- p.setLanguage(import_tree_sitter_php2.default.php_only);
12401
+ p.setLanguage(import_tree_sitter_php3.default.php_only);
11749
12402
  return p;
11750
12403
  }
11751
12404
  function parseSource9(parser, source) {
@@ -11987,14 +12640,14 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
11987
12640
  }
11988
12641
  }
11989
12642
  out.push({
11990
- infraId: (0, import_types35.infraId)("sql-table", bp.table),
12643
+ infraId: (0, import_types38.infraId)("sql-table", bp.table),
11991
12644
  name: bp.table,
11992
12645
  kind: "sql-table",
11993
12646
  edgeType: "CALLS",
11994
12647
  confidenceKind: "structural",
11995
12648
  ...columns.length > 0 ? { columns } : {},
11996
12649
  evidence: {
11997
- file: import_node_path46.default.relative(serviceDir, file.path),
12650
+ file: import_node_path49.default.relative(serviceDir, file.path),
11998
12651
  line: bp.line,
11999
12652
  snippet: snippet(file.content, bp.line)
12000
12653
  }
@@ -12016,7 +12669,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
12016
12669
  childTable,
12017
12670
  parentTable,
12018
12671
  evidence: {
12019
- file: import_node_path46.default.relative(serviceDir, file.path),
12672
+ file: import_node_path49.default.relative(serviceDir, file.path),
12020
12673
  line,
12021
12674
  snippet: snippet(file.content, line)
12022
12675
  }
@@ -12130,13 +12783,13 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
12130
12783
  seen.add(table);
12131
12784
  const line = node.startPosition.row + 1;
12132
12785
  out.push({
12133
- infraId: (0, import_types35.infraId)("sql-table", table),
12786
+ infraId: (0, import_types38.infraId)("sql-table", table),
12134
12787
  name: table,
12135
12788
  kind: "sql-table",
12136
12789
  edgeType: "CALLS",
12137
12790
  confidenceKind: "verified-call-site",
12138
12791
  evidence: {
12139
- file: import_node_path46.default.relative(serviceDir, file.path),
12792
+ file: import_node_path49.default.relative(serviceDir, file.path),
12140
12793
  line,
12141
12794
  snippet: snippet(file.content, line)
12142
12795
  }
@@ -12172,7 +12825,7 @@ function laravelModelForeignKeys(file, serviceDir) {
12172
12825
  childTable,
12173
12826
  parentTable,
12174
12827
  evidence: {
12175
- file: import_node_path46.default.relative(serviceDir, file.path),
12828
+ file: import_node_path49.default.relative(serviceDir, file.path),
12176
12829
  line,
12177
12830
  snippet: snippet(file.content, line)
12178
12831
  }
@@ -12184,10 +12837,10 @@ function laravelModelForeignKeys(file, serviceDir) {
12184
12837
 
12185
12838
  // src/extract/calls/go.ts
12186
12839
  init_cjs_shims();
12187
- var import_node_path49 = __toESM(require("path"), 1);
12840
+ var import_node_path52 = __toESM(require("path"), 1);
12188
12841
  var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
12189
- var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
12190
- var import_types36 = require("@neat.is/types");
12842
+ var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
12843
+ var import_types39 = require("@neat.is/types");
12191
12844
  init_otel();
12192
12845
  var PARSE_CHUNK10 = 16384;
12193
12846
  var DATABASE_SQL_METHODS = /* @__PURE__ */ new Set([
@@ -12216,7 +12869,7 @@ var DATABASE_SQL_IMPORT = "database/sql";
12216
12869
  var SQLX_IMPORT = "github.com/jmoiron/sqlx";
12217
12870
  function makeGoParser3() {
12218
12871
  const p = new import_tree_sitter14.default();
12219
- p.setLanguage(import_tree_sitter_go3.default);
12872
+ p.setLanguage(import_tree_sitter_go4.default);
12220
12873
  return p;
12221
12874
  }
12222
12875
  function parseSource10(parser, source) {
@@ -12259,7 +12912,7 @@ function firstStringLiteralArg(argsNode) {
12259
12912
  return null;
12260
12913
  }
12261
12914
  function goSqlEndpointsFromFile(file, serviceDir) {
12262
- if (import_node_path49.default.extname(file.path) !== ".go") return [];
12915
+ if (import_node_path52.default.extname(file.path) !== ".go") return [];
12263
12916
  if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
12264
12917
  const tree = parseSource10(makeGoParser3(), file.content);
12265
12918
  const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
@@ -12281,14 +12934,14 @@ function goSqlEndpointsFromFile(file, serviceDir) {
12281
12934
  const columns = columnsFromSqlStatement(sql);
12282
12935
  const line = node.startPosition.row + 1;
12283
12936
  out.push({
12284
- infraId: (0, import_types36.infraId)("sql-table", table),
12937
+ infraId: (0, import_types39.infraId)("sql-table", table),
12285
12938
  name: table,
12286
12939
  kind: "sql-table",
12287
12940
  edgeType: "CALLS",
12288
12941
  confidenceKind: "verified-call-site",
12289
12942
  ...columns.length > 0 ? { columns } : {},
12290
12943
  evidence: {
12291
- file: toPosix(import_node_path49.default.relative(serviceDir, file.path)),
12944
+ file: toPosix(import_node_path52.default.relative(serviceDir, file.path)),
12292
12945
  line,
12293
12946
  snippet: snippet(file.content, line)
12294
12947
  }
@@ -12299,15 +12952,15 @@ function goSqlEndpointsFromFile(file, serviceDir) {
12299
12952
 
12300
12953
  // src/extract/calls/gorm.ts
12301
12954
  init_cjs_shims();
12302
- var import_node_path50 = __toESM(require("path"), 1);
12955
+ var import_node_path53 = __toESM(require("path"), 1);
12303
12956
  var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
12304
- var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
12305
- var import_types37 = require("@neat.is/types");
12957
+ var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
12958
+ var import_types40 = require("@neat.is/types");
12306
12959
  var GORM_IMPORT_RE = /gorm\.io\/gorm/;
12307
12960
  var PARSE_CHUNK11 = 16384;
12308
12961
  function makeGoParser4() {
12309
12962
  const p = new import_tree_sitter15.default();
12310
- p.setLanguage(import_tree_sitter_go4.default);
12963
+ p.setLanguage(import_tree_sitter_go5.default);
12311
12964
  return p;
12312
12965
  }
12313
12966
  function parseSource11(parser, source) {
@@ -12732,7 +13385,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
12732
13385
  seen.delete(struct.name);
12733
13386
  }
12734
13387
  function gormEndpointsFromFile(file, serviceDir) {
12735
- if (import_node_path50.default.extname(file.path) !== ".go") return [];
13388
+ if (import_node_path53.default.extname(file.path) !== ".go") return [];
12736
13389
  if (!GORM_IMPORT_RE.test(file.content)) return [];
12737
13390
  const tree = parseSource11(makeGoParser4(), file.content);
12738
13391
  const { structs, models, tableFor } = analyze(tree);
@@ -12747,14 +13400,14 @@ function gormEndpointsFromFile(file, serviceDir) {
12747
13400
  const columns = [];
12748
13401
  collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
12749
13402
  out.push({
12750
- infraId: (0, import_types37.infraId)("sql-table", table),
13403
+ infraId: (0, import_types40.infraId)("sql-table", table),
12751
13404
  name: table,
12752
13405
  kind: "sql-table",
12753
13406
  edgeType: "CALLS",
12754
13407
  confidenceKind: "structural",
12755
13408
  ...columns.length > 0 ? { columns } : {},
12756
13409
  evidence: {
12757
- file: toPosix(import_node_path50.default.relative(serviceDir, file.path)),
13410
+ file: toPosix(import_node_path53.default.relative(serviceDir, file.path)),
12758
13411
  line: struct.line,
12759
13412
  snippet: snippet(file.content, struct.line)
12760
13413
  }
@@ -12763,7 +13416,7 @@ function gormEndpointsFromFile(file, serviceDir) {
12763
13416
  return out;
12764
13417
  }
12765
13418
  function gormForeignKeys(file, serviceDir) {
12766
- if (import_node_path50.default.extname(file.path) !== ".go") return [];
13419
+ if (import_node_path53.default.extname(file.path) !== ".go") return [];
12767
13420
  if (!GORM_IMPORT_RE.test(file.content)) return [];
12768
13421
  const tree = parseSource11(makeGoParser4(), file.content);
12769
13422
  const { structs, models, tableFor } = analyze(tree);
@@ -12778,7 +13431,7 @@ function gormForeignKeys(file, serviceDir) {
12778
13431
  childTable,
12779
13432
  parentTable,
12780
13433
  evidence: {
12781
- file: toPosix(import_node_path50.default.relative(serviceDir, file.path)),
13434
+ file: toPosix(import_node_path53.default.relative(serviceDir, file.path)),
12782
13435
  line,
12783
13436
  snippet: snippet(file.content, line)
12784
13437
  }
@@ -12817,11 +13470,11 @@ function gormForeignKeys(file, serviceDir) {
12817
13470
  function edgeTypeFromEndpoint(ep) {
12818
13471
  switch (ep.edgeType) {
12819
13472
  case "PUBLISHES_TO":
12820
- return import_types38.EdgeType.PUBLISHES_TO;
13473
+ return import_types41.EdgeType.PUBLISHES_TO;
12821
13474
  case "CONSUMES_FROM":
12822
- return import_types38.EdgeType.CONSUMES_FROM;
13475
+ return import_types41.EdgeType.CONSUMES_FROM;
12823
13476
  default:
12824
- return import_types38.EdgeType.CALLS;
13477
+ return import_types41.EdgeType.CALLS;
12825
13478
  }
12826
13479
  }
12827
13480
  function isAwsKind(kind) {
@@ -12881,7 +13534,7 @@ async function addExternalEndpointEdges(graph, services) {
12881
13534
  if (!graph.hasNode(ep.infraId)) {
12882
13535
  const node = {
12883
13536
  id: ep.infraId,
12884
- type: import_types38.NodeType.InfraNode,
13537
+ type: import_types41.NodeType.InfraNode,
12885
13538
  name: ep.name,
12886
13539
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
12887
13540
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -12894,21 +13547,21 @@ async function addExternalEndpointEdges(graph, services) {
12894
13547
  }
12895
13548
  if (ep.columns && ep.columns.length > 0) {
12896
13549
  const node = graph.getNodeAttributes(ep.infraId);
12897
- if (node.type === import_types38.NodeType.InfraNode) {
13550
+ if (node.type === import_types41.NodeType.InfraNode) {
12898
13551
  graph.replaceNodeAttributes(ep.infraId, {
12899
13552
  ...node,
12900
13553
  columns: foldColumns(
12901
13554
  node.columns,
12902
13555
  ep.columns,
12903
- import_types38.Provenance.EXTRACTED,
12904
- (0, import_types38.confidenceForExtracted)(ep.confidenceKind)
13556
+ import_types41.Provenance.EXTRACTED,
13557
+ (0, import_types41.confidenceForExtracted)(ep.confidenceKind)
12905
13558
  )
12906
13559
  });
12907
13560
  }
12908
13561
  }
12909
13562
  if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
12910
13563
  const node = graph.getNodeAttributes(ep.infraId);
12911
- if (node.type === import_types38.NodeType.InfraNode) {
13564
+ if (node.type === import_types41.NodeType.InfraNode) {
12912
13565
  graph.replaceNodeAttributes(ep.infraId, {
12913
13566
  ...node,
12914
13567
  columns: foldSdkWrites(node.columns, ep.sdkWrites)
@@ -12916,7 +13569,7 @@ async function addExternalEndpointEdges(graph, services) {
12916
13569
  }
12917
13570
  }
12918
13571
  const edgeType = edgeTypeFromEndpoint(ep);
12919
- const confidence = (0, import_types38.confidenceForExtracted)(ep.confidenceKind);
13572
+ const confidence = (0, import_types41.confidenceForExtracted)(ep.confidenceKind);
12920
13573
  const relFile = toPosix(ep.evidence.file);
12921
13574
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
12922
13575
  graph,
@@ -12926,7 +13579,7 @@ async function addExternalEndpointEdges(graph, services) {
12926
13579
  );
12927
13580
  nodesAdded += n;
12928
13581
  edgesAdded += e;
12929
- if (!(0, import_types38.passesExtractedFloor)(confidence)) {
13582
+ if (!(0, import_types41.passesExtractedFloor)(confidence)) {
12930
13583
  noteExtractedDropped({
12931
13584
  source: fileNodeId,
12932
13585
  target: ep.infraId,
@@ -12946,7 +13599,7 @@ async function addExternalEndpointEdges(graph, services) {
12946
13599
  source: fileNodeId,
12947
13600
  target: ep.infraId,
12948
13601
  type: edgeType,
12949
- provenance: import_types38.Provenance.EXTRACTED,
13602
+ provenance: import_types41.Provenance.EXTRACTED,
12950
13603
  confidence,
12951
13604
  evidence: ep.evidence
12952
13605
  };
@@ -12969,7 +13622,7 @@ async function addCallEdges(graph, services) {
12969
13622
 
12970
13623
  // src/extract/table-edges.ts
12971
13624
  init_cjs_shims();
12972
- var import_types39 = require("@neat.is/types");
13625
+ var import_types42 = require("@neat.is/types");
12973
13626
  async function addTableEdges(graph, services) {
12974
13627
  let nodesAdded = 0;
12975
13628
  let edgesAdded = 0;
@@ -12997,20 +13650,20 @@ async function addTableEdges(graph, services) {
12997
13650
  }
12998
13651
  refs.push(...modelRefs);
12999
13652
  for (const ref of refs) {
13000
- const childId = (0, import_types39.infraId)("sql-table", ref.childTable);
13001
- const parentId = (0, import_types39.infraId)("sql-table", ref.parentTable);
13653
+ const childId = (0, import_types42.infraId)("sql-table", ref.childTable);
13654
+ const parentId = (0, import_types42.infraId)("sql-table", ref.parentTable);
13002
13655
  if (childId === parentId) continue;
13003
13656
  nodesAdded += ensureTableNode(graph, childId, ref.childTable);
13004
13657
  nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
13005
- const edgeId = (0, import_types39.extractedEdgeId)(childId, parentId, import_types39.EdgeType.REFERENCES);
13658
+ const edgeId = (0, import_types42.extractedEdgeId)(childId, parentId, import_types42.EdgeType.REFERENCES);
13006
13659
  if (graph.hasEdge(edgeId)) continue;
13007
13660
  const edge = {
13008
13661
  id: edgeId,
13009
13662
  source: childId,
13010
13663
  target: parentId,
13011
- type: import_types39.EdgeType.REFERENCES,
13012
- provenance: import_types39.Provenance.EXTRACTED,
13013
- confidence: (0, import_types39.confidenceForExtracted)("structural"),
13664
+ type: import_types42.EdgeType.REFERENCES,
13665
+ provenance: import_types42.Provenance.EXTRACTED,
13666
+ confidence: (0, import_types42.confidenceForExtracted)("structural"),
13014
13667
  evidence: ref.evidence
13015
13668
  };
13016
13669
  graph.addEdgeWithKey(edgeId, childId, parentId, edge);
@@ -13023,7 +13676,7 @@ function ensureTableNode(graph, id, name) {
13023
13676
  if (graph.hasNode(id)) return 0;
13024
13677
  const node = {
13025
13678
  id,
13026
- type: import_types39.NodeType.InfraNode,
13679
+ type: import_types42.NodeType.InfraNode,
13027
13680
  name,
13028
13681
  provider: "self",
13029
13682
  kind: "sql-table"
@@ -13037,16 +13690,16 @@ init_cjs_shims();
13037
13690
 
13038
13691
  // src/extract/infra/docker-compose.ts
13039
13692
  init_cjs_shims();
13040
- var import_node_path51 = __toESM(require("path"), 1);
13041
- var import_types41 = require("@neat.is/types");
13693
+ var import_node_path54 = __toESM(require("path"), 1);
13694
+ var import_types44 = require("@neat.is/types");
13042
13695
 
13043
13696
  // src/extract/infra/shared.ts
13044
13697
  init_cjs_shims();
13045
- var import_types40 = require("@neat.is/types");
13698
+ var import_types43 = require("@neat.is/types");
13046
13699
  function makeInfraNode(kind, name, provider = "self", extras) {
13047
13700
  return {
13048
- id: (0, import_types40.infraId)(kind, name),
13049
- type: import_types40.NodeType.InfraNode,
13701
+ id: (0, import_types43.infraId)(kind, name),
13702
+ type: import_types43.NodeType.InfraNode,
13050
13703
  name,
13051
13704
  provider,
13052
13705
  kind,
@@ -13090,8 +13743,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
13090
13743
  source: anchorId,
13091
13744
  target: node.id,
13092
13745
  type: edgeType,
13093
- provenance: import_types40.Provenance.EXTRACTED,
13094
- confidence: (0, import_types40.confidenceForExtracted)("structural"),
13746
+ provenance: import_types43.Provenance.EXTRACTED,
13747
+ confidence: (0, import_types43.confidenceForExtracted)("structural"),
13095
13748
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
13096
13749
  };
13097
13750
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -13108,7 +13761,7 @@ function dependsOnList(value) {
13108
13761
  }
13109
13762
  function serviceNameToServiceNode(name, services) {
13110
13763
  for (const s of services) {
13111
- if (s.node.name === name || import_node_path51.default.basename(s.dir) === name) return s.node.id;
13764
+ if (s.node.name === name || import_node_path54.default.basename(s.dir) === name) return s.node.id;
13112
13765
  }
13113
13766
  return null;
13114
13767
  }
@@ -13117,7 +13770,7 @@ async function addComposeInfra(graph, scanPath, services) {
13117
13770
  let edgesAdded = 0;
13118
13771
  let composePath = null;
13119
13772
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
13120
- const abs = import_node_path51.default.join(scanPath, name);
13773
+ const abs = import_node_path54.default.join(scanPath, name);
13121
13774
  if (await exists2(abs)) {
13122
13775
  composePath = abs;
13123
13776
  break;
@@ -13130,13 +13783,13 @@ async function addComposeInfra(graph, scanPath, services) {
13130
13783
  } catch (err) {
13131
13784
  recordExtractionError(
13132
13785
  "infra docker-compose",
13133
- import_node_path51.default.relative(scanPath, composePath),
13786
+ import_node_path54.default.relative(scanPath, composePath),
13134
13787
  err
13135
13788
  );
13136
13789
  return { nodesAdded, edgesAdded };
13137
13790
  }
13138
13791
  if (!compose?.services) return { nodesAdded, edgesAdded };
13139
- const evidenceFile = import_node_path51.default.relative(scanPath, composePath).split(import_node_path51.default.sep).join("/");
13792
+ const evidenceFile = import_node_path54.default.relative(scanPath, composePath).split(import_node_path54.default.sep).join("/");
13140
13793
  const composeNameToNodeId = /* @__PURE__ */ new Map();
13141
13794
  for (const [composeName, svc] of Object.entries(compose.services)) {
13142
13795
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -13158,15 +13811,15 @@ async function addComposeInfra(graph, scanPath, services) {
13158
13811
  for (const dep of dependsOnList(svc.depends_on)) {
13159
13812
  const targetId = composeNameToNodeId.get(dep);
13160
13813
  if (!targetId) continue;
13161
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types41.EdgeType.DEPENDS_ON);
13814
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types44.EdgeType.DEPENDS_ON);
13162
13815
  if (graph.hasEdge(edgeId)) continue;
13163
13816
  const edge = {
13164
13817
  id: edgeId,
13165
13818
  source: sourceId,
13166
13819
  target: targetId,
13167
- type: import_types41.EdgeType.DEPENDS_ON,
13168
- provenance: import_types41.Provenance.EXTRACTED,
13169
- confidence: (0, import_types41.confidenceForExtracted)("structural"),
13820
+ type: import_types44.EdgeType.DEPENDS_ON,
13821
+ provenance: import_types44.Provenance.EXTRACTED,
13822
+ confidence: (0, import_types44.confidenceForExtracted)("structural"),
13170
13823
  evidence: { file: evidenceFile }
13171
13824
  };
13172
13825
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -13178,9 +13831,9 @@ async function addComposeInfra(graph, scanPath, services) {
13178
13831
 
13179
13832
  // src/extract/infra/dockerfile.ts
13180
13833
  init_cjs_shims();
13181
- var import_node_path52 = __toESM(require("path"), 1);
13182
- var import_node_fs20 = require("fs");
13183
- var import_types42 = require("@neat.is/types");
13834
+ var import_node_path55 = __toESM(require("path"), 1);
13835
+ var import_node_fs23 = require("fs");
13836
+ var import_types45 = require("@neat.is/types");
13184
13837
  function readDockerfile(content) {
13185
13838
  let image = null;
13186
13839
  const ports = [];
@@ -13209,15 +13862,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
13209
13862
  let nodesAdded = 0;
13210
13863
  let edgesAdded = 0;
13211
13864
  for (const service of services) {
13212
- const dockerfilePath = import_node_path52.default.join(service.dir, "Dockerfile");
13865
+ const dockerfilePath = import_node_path55.default.join(service.dir, "Dockerfile");
13213
13866
  if (!await exists2(dockerfilePath)) continue;
13214
13867
  let content;
13215
13868
  try {
13216
- content = await import_node_fs20.promises.readFile(dockerfilePath, "utf8");
13869
+ content = await import_node_fs23.promises.readFile(dockerfilePath, "utf8");
13217
13870
  } catch (err) {
13218
13871
  recordExtractionError(
13219
13872
  "infra dockerfile",
13220
- import_node_path52.default.relative(scanPath, dockerfilePath),
13873
+ import_node_path55.default.relative(scanPath, dockerfilePath),
13221
13874
  err
13222
13875
  );
13223
13876
  continue;
@@ -13229,8 +13882,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
13229
13882
  graph.addNode(node.id, node);
13230
13883
  nodesAdded++;
13231
13884
  }
13232
- const relDockerfile = toPosix(import_node_path52.default.relative(service.dir, dockerfilePath));
13233
- const evidenceFile = toPosix(import_node_path52.default.relative(scanPath, dockerfilePath));
13885
+ const relDockerfile = toPosix(import_node_path55.default.relative(service.dir, dockerfilePath));
13886
+ const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, dockerfilePath));
13234
13887
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
13235
13888
  graph,
13236
13889
  service.pkg.name,
@@ -13239,15 +13892,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
13239
13892
  );
13240
13893
  nodesAdded += fn;
13241
13894
  edgesAdded += fe;
13242
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types42.EdgeType.RUNS_ON);
13895
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types45.EdgeType.RUNS_ON);
13243
13896
  if (!graph.hasEdge(edgeId)) {
13244
13897
  const edge = {
13245
13898
  id: edgeId,
13246
13899
  source: fileNodeId,
13247
13900
  target: node.id,
13248
- type: import_types42.EdgeType.RUNS_ON,
13249
- provenance: import_types42.Provenance.EXTRACTED,
13250
- confidence: (0, import_types42.confidenceForExtracted)("structural"),
13901
+ type: import_types45.EdgeType.RUNS_ON,
13902
+ provenance: import_types45.Provenance.EXTRACTED,
13903
+ confidence: (0, import_types45.confidenceForExtracted)("structural"),
13251
13904
  evidence: {
13252
13905
  file: evidenceFile,
13253
13906
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -13262,15 +13915,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
13262
13915
  graph.addNode(portNode.id, portNode);
13263
13916
  nodesAdded++;
13264
13917
  }
13265
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types42.EdgeType.CONNECTS_TO);
13918
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types45.EdgeType.CONNECTS_TO);
13266
13919
  if (graph.hasEdge(portEdgeId)) continue;
13267
13920
  const portEdge = {
13268
13921
  id: portEdgeId,
13269
13922
  source: fileNodeId,
13270
13923
  target: portNode.id,
13271
- type: import_types42.EdgeType.CONNECTS_TO,
13272
- provenance: import_types42.Provenance.EXTRACTED,
13273
- confidence: (0, import_types42.confidenceForExtracted)("structural"),
13924
+ type: import_types45.EdgeType.CONNECTS_TO,
13925
+ provenance: import_types45.Provenance.EXTRACTED,
13926
+ confidence: (0, import_types45.confidenceForExtracted)("structural"),
13274
13927
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
13275
13928
  };
13276
13929
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -13282,23 +13935,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
13282
13935
 
13283
13936
  // src/extract/infra/terraform.ts
13284
13937
  init_cjs_shims();
13285
- var import_node_fs21 = require("fs");
13286
- var import_node_path53 = __toESM(require("path"), 1);
13287
- var import_types43 = require("@neat.is/types");
13938
+ var import_node_fs24 = require("fs");
13939
+ var import_node_path56 = __toESM(require("path"), 1);
13940
+ var import_types46 = require("@neat.is/types");
13288
13941
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
13289
13942
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
13290
13943
  async function walkTfFiles(start, depth = 0, max = 5) {
13291
13944
  if (depth > max) return [];
13292
13945
  const out = [];
13293
- const entries = await import_node_fs21.promises.readdir(start, { withFileTypes: true }).catch(() => []);
13946
+ const entries = await import_node_fs24.promises.readdir(start, { withFileTypes: true }).catch(() => []);
13294
13947
  for (const entry of entries) {
13295
13948
  if (entry.isDirectory()) {
13296
13949
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
13297
- const child = import_node_path53.default.join(start, entry.name);
13950
+ const child = import_node_path56.default.join(start, entry.name);
13298
13951
  if (await isPythonVenvDir(child)) continue;
13299
13952
  out.push(...await walkTfFiles(child, depth + 1, max));
13300
13953
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
13301
- out.push(import_node_path53.default.join(start, entry.name));
13954
+ out.push(import_node_path56.default.join(start, entry.name));
13302
13955
  }
13303
13956
  }
13304
13957
  return out;
@@ -13329,8 +13982,8 @@ async function addTerraformResources(graph, scanPath) {
13329
13982
  let edgesAdded = 0;
13330
13983
  const files = await walkTfFiles(scanPath);
13331
13984
  for (const file of files) {
13332
- const content = await import_node_fs21.promises.readFile(file, "utf8");
13333
- const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, file));
13985
+ const content = await import_node_fs24.promises.readFile(file, "utf8");
13986
+ const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, file));
13334
13987
  const resources = [];
13335
13988
  const byKey = /* @__PURE__ */ new Map();
13336
13989
  RESOURCE_RE.lastIndex = 0;
@@ -13365,16 +14018,16 @@ async function addTerraformResources(graph, scanPath) {
13365
14018
  if (!target) continue;
13366
14019
  if (seen.has(target.nodeId)) continue;
13367
14020
  seen.add(target.nodeId);
13368
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types43.EdgeType.DEPENDS_ON);
14021
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types46.EdgeType.DEPENDS_ON);
13369
14022
  if (graph.hasEdge(edgeId)) continue;
13370
14023
  const line = lineAt2(content, resource.bodyOffset + ref.index);
13371
14024
  const edge = {
13372
14025
  id: edgeId,
13373
14026
  source: resource.nodeId,
13374
14027
  target: target.nodeId,
13375
- type: import_types43.EdgeType.DEPENDS_ON,
13376
- provenance: import_types43.Provenance.EXTRACTED,
13377
- confidence: (0, import_types43.confidenceForExtracted)("structural"),
14028
+ type: import_types46.EdgeType.DEPENDS_ON,
14029
+ provenance: import_types46.Provenance.EXTRACTED,
14030
+ confidence: (0, import_types46.confidenceForExtracted)("structural"),
13378
14031
  evidence: { file: evidenceFile, line, snippet: key }
13379
14032
  };
13380
14033
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -13387,8 +14040,8 @@ async function addTerraformResources(graph, scanPath) {
13387
14040
 
13388
14041
  // src/extract/infra/k8s.ts
13389
14042
  init_cjs_shims();
13390
- var import_node_fs22 = require("fs");
13391
- var import_node_path54 = __toESM(require("path"), 1);
14043
+ var import_node_fs25 = require("fs");
14044
+ var import_node_path57 = __toESM(require("path"), 1);
13392
14045
  var import_yaml3 = require("yaml");
13393
14046
  var K8S_KIND_TO_INFRA_KIND = {
13394
14047
  Service: "k8s-service",
@@ -13402,15 +14055,15 @@ var K8S_KIND_TO_INFRA_KIND = {
13402
14055
  async function walkYamlFiles2(start, depth = 0, max = 5) {
13403
14056
  if (depth > max) return [];
13404
14057
  const out = [];
13405
- const entries = await import_node_fs22.promises.readdir(start, { withFileTypes: true }).catch(() => []);
14058
+ const entries = await import_node_fs25.promises.readdir(start, { withFileTypes: true }).catch(() => []);
13406
14059
  for (const entry of entries) {
13407
14060
  if (entry.isDirectory()) {
13408
14061
  if (IGNORED_DIRS.has(entry.name)) continue;
13409
- const child = import_node_path54.default.join(start, entry.name);
14062
+ const child = import_node_path57.default.join(start, entry.name);
13410
14063
  if (await isPythonVenvDir(child)) continue;
13411
14064
  out.push(...await walkYamlFiles2(child, depth + 1, max));
13412
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path54.default.extname(entry.name))) {
13413
- out.push(import_node_path54.default.join(start, entry.name));
14065
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path57.default.extname(entry.name))) {
14066
+ out.push(import_node_path57.default.join(start, entry.name));
13414
14067
  }
13415
14068
  }
13416
14069
  return out;
@@ -13419,7 +14072,7 @@ async function addK8sResources(graph, scanPath) {
13419
14072
  let nodesAdded = 0;
13420
14073
  const files = await walkYamlFiles2(scanPath);
13421
14074
  for (const file of files) {
13422
- const content = await import_node_fs22.promises.readFile(file, "utf8");
14075
+ const content = await import_node_fs25.promises.readFile(file, "utf8");
13423
14076
  let docs;
13424
14077
  try {
13425
14078
  docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
@@ -13443,16 +14096,16 @@ async function addK8sResources(graph, scanPath) {
13443
14096
 
13444
14097
  // src/extract/infra/cloudflare.ts
13445
14098
  init_cjs_shims();
13446
- var import_node_fs23 = require("fs");
13447
- var import_node_path55 = __toESM(require("path"), 1);
14099
+ var import_node_fs26 = require("fs");
14100
+ var import_node_path58 = __toESM(require("path"), 1);
13448
14101
  var import_smol_toml2 = require("smol-toml");
13449
- var import_types44 = require("@neat.is/types");
14102
+ var import_types47 = require("@neat.is/types");
13450
14103
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
13451
14104
  async function readWranglerConfig(dir) {
13452
14105
  for (const filename of WRANGLER_FILENAMES) {
13453
- const abs = import_node_path55.default.join(dir, filename);
14106
+ const abs = import_node_path58.default.join(dir, filename);
13454
14107
  if (!await exists2(abs)) continue;
13455
- const raw = await import_node_fs23.promises.readFile(abs, "utf8");
14108
+ const raw = await import_node_fs26.promises.readFile(abs, "utf8");
13456
14109
  const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
13457
14110
  return { config, relFile: filename, raw };
13458
14111
  }
@@ -13494,8 +14147,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
13494
14147
  source: anchorId,
13495
14148
  target: node.id,
13496
14149
  type: edgeType,
13497
- provenance: import_types44.Provenance.EXTRACTED,
13498
- confidence: (0, import_types44.confidenceForExtracted)("structural"),
14150
+ provenance: import_types47.Provenance.EXTRACTED,
14151
+ confidence: (0, import_types47.confidenceForExtracted)("structural"),
13499
14152
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
13500
14153
  };
13501
14154
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -13513,11 +14166,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13513
14166
  try {
13514
14167
  read = await readWranglerConfig(service.dir);
13515
14168
  } catch (err) {
13516
- recordExtractionError("infra cloudflare", import_node_path55.default.relative(scanPath, service.dir), err);
14169
+ recordExtractionError("infra cloudflare", import_node_path58.default.relative(scanPath, service.dir), err);
13517
14170
  continue;
13518
14171
  }
13519
14172
  if (!read || !read.config.name) continue;
13520
- const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, read.relFile)));
14173
+ const evidenceFile = toPosix(import_node_path58.default.relative(scanPath, import_node_path58.default.join(service.dir, read.relFile)));
13521
14174
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
13522
14175
  }
13523
14176
  for (const worker of discovered) {
@@ -13529,7 +14182,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13529
14182
  }
13530
14183
  let anchorId = service.node.id;
13531
14184
  if (config.main) {
13532
- const entryRelPath = toPosix(import_node_path55.default.normalize(config.main));
14185
+ const entryRelPath = toPosix(import_node_path58.default.normalize(config.main));
13533
14186
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
13534
14187
  graph,
13535
14188
  service.pkg.name,
@@ -13556,15 +14209,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13556
14209
  nodesAdded++;
13557
14210
  }
13558
14211
  if (runtimeNode.id !== anchorId) {
13559
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types44.EdgeType.RUNS_ON);
14212
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types47.EdgeType.RUNS_ON);
13560
14213
  if (!graph.hasEdge(runsOnId)) {
13561
14214
  const edge = {
13562
14215
  id: runsOnId,
13563
14216
  source: anchorId,
13564
14217
  target: runtimeNode.id,
13565
- type: import_types44.EdgeType.RUNS_ON,
13566
- provenance: import_types44.Provenance.EXTRACTED,
13567
- confidence: (0, import_types44.confidenceForExtracted)("structural"),
14218
+ type: import_types47.EdgeType.RUNS_ON,
14219
+ provenance: import_types47.Provenance.EXTRACTED,
14220
+ confidence: (0, import_types47.confidenceForExtracted)("structural"),
13568
14221
  evidence: {
13569
14222
  file: evidenceFile,
13570
14223
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -13578,7 +14231,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13578
14231
  const result = addResourceEdge(
13579
14232
  graph,
13580
14233
  anchorId,
13581
- import_types44.EdgeType.CONNECTS_TO,
14234
+ import_types47.EdgeType.CONNECTS_TO,
13582
14235
  "cloudflare-route",
13583
14236
  route,
13584
14237
  evidenceFile,
@@ -13602,7 +14255,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13602
14255
  const result = addResourceEdge(
13603
14256
  graph,
13604
14257
  anchorId,
13605
- import_types44.EdgeType.DEPENDS_ON,
14258
+ import_types47.EdgeType.DEPENDS_ON,
13606
14259
  group.kind,
13607
14260
  name,
13608
14261
  evidenceFile,
@@ -13616,7 +14269,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13616
14269
  const result = addResourceEdge(
13617
14270
  graph,
13618
14271
  anchorId,
13619
- import_types44.EdgeType.DEPENDS_ON,
14272
+ import_types47.EdgeType.DEPENDS_ON,
13620
14273
  "cloudflare-cron",
13621
14274
  cron,
13622
14275
  evidenceFile,
@@ -13629,7 +14282,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13629
14282
  const result = addResourceEdge(
13630
14283
  graph,
13631
14284
  anchorId,
13632
- import_types44.EdgeType.DEPENDS_ON,
14285
+ import_types47.EdgeType.DEPENDS_ON,
13633
14286
  "cloudflare-env-var",
13634
14287
  varName,
13635
14288
  evidenceFile,
@@ -13642,15 +14295,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13642
14295
  if (!svc.service) continue;
13643
14296
  const target = workerIndex.get(svc.service);
13644
14297
  if (target && target.anchorId !== anchorId) {
13645
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types44.EdgeType.CALLS);
14298
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types47.EdgeType.CALLS);
13646
14299
  if (!graph.hasEdge(edgeId)) {
13647
14300
  const edge = {
13648
14301
  id: edgeId,
13649
14302
  source: anchorId,
13650
14303
  target: target.anchorId,
13651
- type: import_types44.EdgeType.CALLS,
13652
- provenance: import_types44.Provenance.EXTRACTED,
13653
- confidence: (0, import_types44.confidenceForExtracted)("structural"),
14304
+ type: import_types47.EdgeType.CALLS,
14305
+ provenance: import_types47.Provenance.EXTRACTED,
14306
+ confidence: (0, import_types47.confidenceForExtracted)("structural"),
13654
14307
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
13655
14308
  };
13656
14309
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -13661,7 +14314,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13661
14314
  const result = addResourceEdge(
13662
14315
  graph,
13663
14316
  anchorId,
13664
- import_types44.EdgeType.DEPENDS_ON,
14317
+ import_types47.EdgeType.DEPENDS_ON,
13665
14318
  "cloudflare-service-binding",
13666
14319
  svc.service,
13667
14320
  evidenceFile,
@@ -13676,24 +14329,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
13676
14329
 
13677
14330
  // src/extract/infra/vercel.ts
13678
14331
  init_cjs_shims();
13679
- var import_node_fs24 = require("fs");
13680
- var import_node_path56 = __toESM(require("path"), 1);
13681
- var import_types45 = require("@neat.is/types");
14332
+ var import_node_fs27 = require("fs");
14333
+ var import_node_path59 = __toESM(require("path"), 1);
14334
+ var import_types48 = require("@neat.is/types");
13682
14335
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
13683
14336
  async function readVercelConfig(dir) {
13684
14337
  for (const filename of VERCEL_CONFIG_FILENAMES) {
13685
- const abs = import_node_path56.default.join(dir, filename);
14338
+ const abs = import_node_path59.default.join(dir, filename);
13686
14339
  if (!await exists2(abs)) continue;
13687
- const raw = await import_node_fs24.promises.readFile(abs, "utf8");
14340
+ const raw = await import_node_fs27.promises.readFile(abs, "utf8");
13688
14341
  const config = JSON.parse(maskCommentsInSource(raw));
13689
14342
  return { config, relFile: filename, raw };
13690
14343
  }
13691
14344
  return null;
13692
14345
  }
13693
14346
  async function readLinkedProjectName(dir) {
13694
- const abs = import_node_path56.default.join(dir, ".vercel", "project.json");
14347
+ const abs = import_node_path59.default.join(dir, ".vercel", "project.json");
13695
14348
  if (!await exists2(abs)) return void 0;
13696
- const parsed = JSON.parse(await import_node_fs24.promises.readFile(abs, "utf8"));
14349
+ const parsed = JSON.parse(await import_node_fs27.promises.readFile(abs, "utf8"));
13697
14350
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
13698
14351
  }
13699
14352
  function routeSource(route) {
@@ -13709,7 +14362,7 @@ async function addVercelServices(graph, services, scanPath) {
13709
14362
  read = await readVercelConfig(service.dir);
13710
14363
  projectName = await readLinkedProjectName(service.dir);
13711
14364
  } catch (err) {
13712
- recordExtractionError("infra vercel", import_node_path56.default.relative(scanPath, service.dir), err);
14365
+ recordExtractionError("infra vercel", import_node_path59.default.relative(scanPath, service.dir), err);
13713
14366
  continue;
13714
14367
  }
13715
14368
  if (!read && !projectName) continue;
@@ -13725,7 +14378,7 @@ async function addVercelServices(graph, services, scanPath) {
13725
14378
  const anchorId = service.node.id;
13726
14379
  if (!read) continue;
13727
14380
  const { config, relFile, raw } = read;
13728
- const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
14381
+ const evidenceFile = toPosix(import_node_path59.default.relative(scanPath, import_node_path59.default.join(service.dir, relFile)));
13729
14382
  const add = (edgeType, kind, name) => {
13730
14383
  if (!name) return;
13731
14384
  const result = emitPlatformResourceEdge(
@@ -13741,12 +14394,12 @@ async function addVercelServices(graph, services, scanPath) {
13741
14394
  nodesAdded += result.nodesAdded;
13742
14395
  edgesAdded += result.edgesAdded;
13743
14396
  };
13744
- add(import_types45.EdgeType.RUNS_ON, "vercel", "vercel");
13745
- for (const cron of config.crons ?? []) add(import_types45.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
13746
- for (const varName of Object.keys(config.env ?? {})) add(import_types45.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
13747
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types45.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
14397
+ add(import_types48.EdgeType.RUNS_ON, "vercel", "vercel");
14398
+ for (const cron of config.crons ?? []) add(import_types48.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
14399
+ for (const varName of Object.keys(config.env ?? {})) add(import_types48.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
14400
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types48.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
13748
14401
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
13749
- add(import_types45.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
14402
+ add(import_types48.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
13750
14403
  }
13751
14404
  }
13752
14405
  return { nodesAdded, edgesAdded };
@@ -13754,16 +14407,16 @@ async function addVercelServices(graph, services, scanPath) {
13754
14407
 
13755
14408
  // src/extract/infra/railway.ts
13756
14409
  init_cjs_shims();
13757
- var import_node_fs25 = require("fs");
13758
- var import_node_path57 = __toESM(require("path"), 1);
14410
+ var import_node_fs28 = require("fs");
14411
+ var import_node_path60 = __toESM(require("path"), 1);
13759
14412
  var import_smol_toml3 = require("smol-toml");
13760
- var import_types46 = require("@neat.is/types");
14413
+ var import_types49 = require("@neat.is/types");
13761
14414
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
13762
14415
  async function readRailwayConfig(dir) {
13763
14416
  for (const filename of RAILWAY_FILENAMES) {
13764
- const abs = import_node_path57.default.join(dir, filename);
14417
+ const abs = import_node_path60.default.join(dir, filename);
13765
14418
  if (!await exists2(abs)) continue;
13766
- const raw = await import_node_fs25.promises.readFile(abs, "utf8");
14419
+ const raw = await import_node_fs28.promises.readFile(abs, "utf8");
13767
14420
  const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
13768
14421
  return { config, relFile: filename, raw };
13769
14422
  }
@@ -13777,7 +14430,7 @@ async function addRailwayServices(graph, services, scanPath) {
13777
14430
  try {
13778
14431
  read = await readRailwayConfig(service.dir);
13779
14432
  } catch (err) {
13780
- recordExtractionError("infra railway", import_node_path57.default.relative(scanPath, service.dir), err);
14433
+ recordExtractionError("infra railway", import_node_path60.default.relative(scanPath, service.dir), err);
13781
14434
  continue;
13782
14435
  }
13783
14436
  if (!read) continue;
@@ -13787,7 +14440,7 @@ async function addRailwayServices(graph, services, scanPath) {
13787
14440
  }
13788
14441
  const anchorId = service.node.id;
13789
14442
  const { config, relFile, raw } = read;
13790
- const evidenceFile = toPosix(import_node_path57.default.relative(scanPath, import_node_path57.default.join(service.dir, relFile)));
14443
+ const evidenceFile = toPosix(import_node_path60.default.relative(scanPath, import_node_path60.default.join(service.dir, relFile)));
13791
14444
  const add = (edgeType, kind, name) => {
13792
14445
  if (!name) return;
13793
14446
  const result = emitPlatformResourceEdge(
@@ -13803,24 +14456,24 @@ async function addRailwayServices(graph, services, scanPath) {
13803
14456
  nodesAdded += result.nodesAdded;
13804
14457
  edgesAdded += result.edgesAdded;
13805
14458
  };
13806
- add(import_types46.EdgeType.RUNS_ON, "railway", "railway");
13807
- add(import_types46.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
13808
- add(import_types46.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
14459
+ add(import_types49.EdgeType.RUNS_ON, "railway", "railway");
14460
+ add(import_types49.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
14461
+ add(import_types49.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
13809
14462
  }
13810
14463
  return { nodesAdded, edgesAdded };
13811
14464
  }
13812
14465
 
13813
14466
  // src/extract/infra/supabase.ts
13814
14467
  init_cjs_shims();
13815
- var import_node_fs26 = require("fs");
13816
- var import_node_path58 = __toESM(require("path"), 1);
14468
+ var import_node_fs29 = require("fs");
14469
+ var import_node_path61 = __toESM(require("path"), 1);
13817
14470
  var import_smol_toml4 = require("smol-toml");
13818
- var import_types47 = require("@neat.is/types");
14471
+ var import_types50 = require("@neat.is/types");
13819
14472
  async function readSupabaseConfig(dir) {
13820
- const relFile = import_node_path58.default.join("supabase", "config.toml");
13821
- const abs = import_node_path58.default.join(dir, relFile);
14473
+ const relFile = import_node_path61.default.join("supabase", "config.toml");
14474
+ const abs = import_node_path61.default.join(dir, relFile);
13822
14475
  if (!await exists2(abs)) return null;
13823
- const raw = await import_node_fs26.promises.readFile(abs, "utf8");
14476
+ const raw = await import_node_fs29.promises.readFile(abs, "utf8");
13824
14477
  const config = (0, import_smol_toml4.parse)(raw);
13825
14478
  return { config, relFile, raw };
13826
14479
  }
@@ -13832,7 +14485,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
13832
14485
  try {
13833
14486
  read = await readSupabaseConfig(service.dir);
13834
14487
  } catch (err) {
13835
- recordExtractionError("infra supabase", import_node_path58.default.relative(scanPath, service.dir), err);
14488
+ recordExtractionError("infra supabase", import_node_path61.default.relative(scanPath, service.dir), err);
13836
14489
  continue;
13837
14490
  }
13838
14491
  if (!read) continue;
@@ -13847,7 +14500,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
13847
14500
  });
13848
14501
  }
13849
14502
  const anchorId = service.node.id;
13850
- const evidenceFile = toPosix(import_node_path58.default.relative(scanPath, import_node_path58.default.join(service.dir, relFile)));
14503
+ const evidenceFile = toPosix(import_node_path61.default.relative(scanPath, import_node_path61.default.join(service.dir, relFile)));
13851
14504
  const add = (edgeType, kind, name) => {
13852
14505
  if (!name) return;
13853
14506
  const result = emitPlatformResourceEdge(
@@ -13863,10 +14516,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
13863
14516
  nodesAdded += result.nodesAdded;
13864
14517
  edgesAdded += result.edgesAdded;
13865
14518
  };
13866
- add(import_types47.EdgeType.RUNS_ON, "supabase", "supabase");
13867
- for (const fn of Object.keys(config.functions ?? {})) add(import_types47.EdgeType.DEPENDS_ON, "supabase-function", fn);
13868
- if (config.storage) add(import_types47.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
13869
- if (config.auth) add(import_types47.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
14519
+ add(import_types50.EdgeType.RUNS_ON, "supabase", "supabase");
14520
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types50.EdgeType.DEPENDS_ON, "supabase-function", fn);
14521
+ if (config.storage) add(import_types50.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
14522
+ if (config.auth) add(import_types50.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
13870
14523
  }
13871
14524
  return { nodesAdded, edgesAdded };
13872
14525
  }
@@ -13889,10 +14542,10 @@ async function addInfra(graph, scanPath, services) {
13889
14542
 
13890
14543
  // src/extract/zod-shapes.ts
13891
14544
  init_cjs_shims();
13892
- var import_node_path59 = __toESM(require("path"), 1);
14545
+ var import_node_path62 = __toESM(require("path"), 1);
13893
14546
  var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
13894
14547
  var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
13895
- var import_types48 = require("@neat.is/types");
14548
+ var import_types51 = require("@neat.is/types");
13896
14549
  var ZOD_IMPORT_RE = /\bzod\b/;
13897
14550
  var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
13898
14551
  function parserForExt4(ext) {
@@ -13984,7 +14637,7 @@ function topLevelSchemas(root) {
13984
14637
  }
13985
14638
  function zodShapesFromFile(file, serviceDir) {
13986
14639
  if (!ZOD_IMPORT_RE.test(file.content)) return [];
13987
- const tree = parseSource3(parserForExt4(import_node_path59.default.extname(file.path)), file.content);
14640
+ const tree = parseSource3(parserForExt4(import_node_path62.default.extname(file.path)), file.content);
13988
14641
  const out = [];
13989
14642
  const seen = /* @__PURE__ */ new Set();
13990
14643
  for (const { name, call } of topLevelSchemas(tree.rootNode)) {
@@ -13998,11 +14651,11 @@ function zodShapesFromFile(file, serviceDir) {
13998
14651
  seen.add(name);
13999
14652
  const line = call.startPosition.row + 1;
14000
14653
  out.push({
14001
- infraId: (0, import_types48.infraId)("zod-schema", name),
14654
+ infraId: (0, import_types51.infraId)("zod-schema", name),
14002
14655
  name,
14003
14656
  fields,
14004
14657
  evidence: {
14005
- file: import_node_path59.default.relative(serviceDir, file.path),
14658
+ file: import_node_path62.default.relative(serviceDir, file.path),
14006
14659
  line,
14007
14660
  snippet: snippet(file.content, line)
14008
14661
  }
@@ -14033,7 +14686,7 @@ async function addZodShapes(graph, services) {
14033
14686
  if (!graph.hasNode(shape.infraId)) {
14034
14687
  const node = {
14035
14688
  id: shape.infraId,
14036
- type: import_types48.NodeType.InfraNode,
14689
+ type: import_types51.NodeType.InfraNode,
14037
14690
  name: shape.name,
14038
14691
  provider: "self",
14039
14692
  kind: "zod-schema"
@@ -14043,14 +14696,14 @@ async function addZodShapes(graph, services) {
14043
14696
  }
14044
14697
  if (shape.fields.length > 0) {
14045
14698
  const node = graph.getNodeAttributes(shape.infraId);
14046
- if (node.type === import_types48.NodeType.InfraNode) {
14699
+ if (node.type === import_types51.NodeType.InfraNode) {
14047
14700
  graph.replaceNodeAttributes(shape.infraId, {
14048
14701
  ...node,
14049
14702
  columns: foldColumns(
14050
14703
  node.columns,
14051
14704
  shape.fields,
14052
- import_types48.Provenance.EXTRACTED,
14053
- (0, import_types48.confidenceForExtracted)("structural")
14705
+ import_types51.Provenance.EXTRACTED,
14706
+ (0, import_types51.confidenceForExtracted)("structural")
14054
14707
  )
14055
14708
  });
14056
14709
  }
@@ -14064,15 +14717,15 @@ async function addZodShapes(graph, services) {
14064
14717
  );
14065
14718
  nodesAdded += n;
14066
14719
  edgesAdded += e;
14067
- const edgeId = (0, import_types48.extractedEdgeId)(fileNodeId, shape.infraId, import_types48.EdgeType.CONTAINS);
14720
+ const edgeId = (0, import_types51.extractedEdgeId)(fileNodeId, shape.infraId, import_types51.EdgeType.CONTAINS);
14068
14721
  if (!graph.hasEdge(edgeId)) {
14069
14722
  const edge = {
14070
14723
  id: edgeId,
14071
14724
  source: fileNodeId,
14072
14725
  target: shape.infraId,
14073
- type: import_types48.EdgeType.CONTAINS,
14074
- provenance: import_types48.Provenance.EXTRACTED,
14075
- confidence: (0, import_types48.confidenceForExtracted)("structural"),
14726
+ type: import_types51.EdgeType.CONTAINS,
14727
+ provenance: import_types51.Provenance.EXTRACTED,
14728
+ confidence: (0, import_types51.confidenceForExtracted)("structural"),
14076
14729
  evidence: shape.evidence
14077
14730
  };
14078
14731
  graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
@@ -14086,7 +14739,7 @@ async function addZodShapes(graph, services) {
14086
14739
 
14087
14740
  // src/extract/firestore-rules.ts
14088
14741
  init_cjs_shims();
14089
- var import_types49 = require("@neat.is/types");
14742
+ var import_types52 = require("@neat.is/types");
14090
14743
  var FIRESTORE_COLLECTION_KIND = "firestore-collection";
14091
14744
  var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
14092
14745
  function stripComments(src) {
@@ -14226,7 +14879,7 @@ async function addFirestoreRules(graph, services) {
14226
14879
  if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
14227
14880
  graph.forEachNode((id, attrs) => {
14228
14881
  const node = attrs;
14229
- if (node.type !== import_types49.NodeType.InfraNode) return;
14882
+ if (node.type !== import_types52.NodeType.InfraNode) return;
14230
14883
  if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
14231
14884
  const fields = guards.get(collectionKeyFromName(node.name));
14232
14885
  if (!fields || fields.size === 0) return;
@@ -14239,17 +14892,17 @@ async function addFirestoreRules(graph, services) {
14239
14892
  }
14240
14893
 
14241
14894
  // src/extract/index.ts
14242
- var import_node_path61 = __toESM(require("path"), 1);
14895
+ var import_node_path64 = __toESM(require("path"), 1);
14243
14896
 
14244
14897
  // src/extract/retire.ts
14245
14898
  init_cjs_shims();
14246
- var import_node_fs27 = require("fs");
14247
- var import_node_path60 = __toESM(require("path"), 1);
14248
- var import_types50 = require("@neat.is/types");
14899
+ var import_node_fs30 = require("fs");
14900
+ var import_node_path63 = __toESM(require("path"), 1);
14901
+ var import_types53 = require("@neat.is/types");
14249
14902
  function dropOrphanedFileNodes(graph) {
14250
14903
  const orphans = [];
14251
14904
  graph.forEachNode((id, attrs) => {
14252
- if (attrs.type !== import_types50.NodeType.FileNode) return;
14905
+ if (attrs.type !== import_types53.NodeType.FileNode) return;
14253
14906
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
14254
14907
  orphans.push(id);
14255
14908
  }
@@ -14262,14 +14915,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
14262
14915
  const bases = [scanPath, ...serviceDirs];
14263
14916
  graph.forEachEdge((id, attrs) => {
14264
14917
  const edge = attrs;
14265
- if (edge.provenance !== import_types50.Provenance.EXTRACTED) return;
14918
+ if (edge.provenance !== import_types53.Provenance.EXTRACTED) return;
14266
14919
  const evidenceFile = edge.evidence?.file;
14267
14920
  if (!evidenceFile) return;
14268
- if (import_node_path60.default.isAbsolute(evidenceFile)) {
14269
- if (!(0, import_node_fs27.existsSync)(evidenceFile)) toDrop.push(id);
14921
+ if (import_node_path63.default.isAbsolute(evidenceFile)) {
14922
+ if (!(0, import_node_fs30.existsSync)(evidenceFile)) toDrop.push(id);
14270
14923
  return;
14271
14924
  }
14272
- const found = bases.some((base) => (0, import_node_fs27.existsSync)(import_node_path60.default.join(base, evidenceFile)));
14925
+ const found = bases.some((base) => (0, import_node_fs30.existsSync)(import_node_path63.default.join(base, evidenceFile)));
14273
14926
  if (!found) toDrop.push(id);
14274
14927
  });
14275
14928
  for (const id of toDrop) graph.dropEdge(id);
@@ -14326,7 +14979,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
14326
14979
  }
14327
14980
  const droppedEntries = drainDroppedExtracted();
14328
14981
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
14329
- const rejectedPath = import_node_path61.default.join(import_node_path61.default.dirname(opts.errorsPath), "rejected.ndjson");
14982
+ const rejectedPath = import_node_path64.default.join(import_node_path64.default.dirname(opts.errorsPath), "rejected.ndjson");
14330
14983
  try {
14331
14984
  await writeRejectedExtracted(droppedEntries, rejectedPath);
14332
14985
  } catch (err) {
@@ -14360,7 +15013,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
14360
15013
 
14361
15014
  // src/diff.ts
14362
15015
  init_cjs_shims();
14363
- var import_node_fs28 = require("fs");
15016
+ var import_node_fs31 = require("fs");
14364
15017
  async function loadSnapshotForDiff(target) {
14365
15018
  if (/^https?:\/\//i.test(target)) {
14366
15019
  const res = await fetch(target);
@@ -14369,7 +15022,7 @@ async function loadSnapshotForDiff(target) {
14369
15022
  }
14370
15023
  return await res.json();
14371
15024
  }
14372
- const raw = await import_node_fs28.promises.readFile(target, "utf8");
15025
+ const raw = await import_node_fs31.promises.readFile(target, "utf8");
14373
15026
  return JSON.parse(raw);
14374
15027
  }
14375
15028
  function indexEntries(entries) {
@@ -14437,9 +15090,9 @@ function canonicalJson(value) {
14437
15090
 
14438
15091
  // src/persist.ts
14439
15092
  init_cjs_shims();
14440
- var import_node_fs29 = require("fs");
14441
- var import_node_path62 = __toESM(require("path"), 1);
14442
- var import_types51 = require("@neat.is/types");
15093
+ var import_node_fs32 = require("fs");
15094
+ var import_node_path65 = __toESM(require("path"), 1);
15095
+ var import_types54 = require("@neat.is/types");
14443
15096
  var SCHEMA_VERSION = 7;
14444
15097
  function migrateV1ToV2(payload) {
14445
15098
  const nodes = payload.graph.nodes;
@@ -14463,7 +15116,7 @@ function migrateV5ToV6(payload) {
14463
15116
  if (Array.isArray(nodes)) {
14464
15117
  for (const node of nodes) {
14465
15118
  const attrs = node.attributes;
14466
- if (!attrs || attrs.type !== import_types51.NodeType.InfraNode) continue;
15119
+ if (!attrs || attrs.type !== import_types54.NodeType.InfraNode) continue;
14467
15120
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
14468
15121
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
14469
15122
  }
@@ -14479,12 +15132,12 @@ function migrateV2ToV3(payload) {
14479
15132
  for (const edge of edges) {
14480
15133
  const attrs = edge.attributes;
14481
15134
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
14482
- attrs.provenance = import_types51.Provenance.OBSERVED;
15135
+ attrs.provenance = import_types54.Provenance.OBSERVED;
14483
15136
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
14484
15137
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
14485
15138
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
14486
15139
  if (type && source && target) {
14487
- const newId = (0, import_types51.observedEdgeId)(source, target, type);
15140
+ const newId = (0, import_types54.observedEdgeId)(source, target, type);
14488
15141
  attrs.id = newId;
14489
15142
  if (edge.key) edge.key = newId;
14490
15143
  }
@@ -14493,7 +15146,7 @@ function migrateV2ToV3(payload) {
14493
15146
  return { ...payload, schemaVersion: 3 };
14494
15147
  }
14495
15148
  async function ensureDir(filePath) {
14496
- await import_node_fs29.promises.mkdir(import_node_path62.default.dirname(filePath), { recursive: true });
15149
+ await import_node_fs32.promises.mkdir(import_node_path65.default.dirname(filePath), { recursive: true });
14497
15150
  }
14498
15151
  async function saveGraphToDisk(graph, outPath) {
14499
15152
  await ensureDir(outPath);
@@ -14503,13 +15156,13 @@ async function saveGraphToDisk(graph, outPath) {
14503
15156
  graph: graph.export()
14504
15157
  };
14505
15158
  const tmp = `${outPath}.tmp`;
14506
- await import_node_fs29.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
14507
- await import_node_fs29.promises.rename(tmp, outPath);
15159
+ await import_node_fs32.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
15160
+ await import_node_fs32.promises.rename(tmp, outPath);
14508
15161
  }
14509
15162
  async function loadGraphFromDisk(graph, outPath) {
14510
15163
  let raw;
14511
15164
  try {
14512
- raw = await import_node_fs29.promises.readFile(outPath, "utf8");
15165
+ raw = await import_node_fs32.promises.readFile(outPath, "utf8");
14513
15166
  } catch (err) {
14514
15167
  if (err.code === "ENOENT") return;
14515
15168
  throw err;
@@ -14583,23 +15236,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
14583
15236
 
14584
15237
  // src/projects.ts
14585
15238
  init_cjs_shims();
14586
- var import_node_path63 = __toESM(require("path"), 1);
15239
+ var import_node_path66 = __toESM(require("path"), 1);
14587
15240
  function pathsForProject(project, baseDir) {
14588
15241
  if (project === DEFAULT_PROJECT) {
14589
15242
  return {
14590
- snapshotPath: import_node_path63.default.join(baseDir, "graph.json"),
14591
- errorsPath: import_node_path63.default.join(baseDir, "errors.ndjson"),
14592
- staleEventsPath: import_node_path63.default.join(baseDir, "stale-events.ndjson"),
14593
- embeddingsCachePath: import_node_path63.default.join(baseDir, "embeddings.json"),
14594
- policyViolationsPath: import_node_path63.default.join(baseDir, "policy-violations.ndjson")
15243
+ snapshotPath: import_node_path66.default.join(baseDir, "graph.json"),
15244
+ errorsPath: import_node_path66.default.join(baseDir, "errors.ndjson"),
15245
+ staleEventsPath: import_node_path66.default.join(baseDir, "stale-events.ndjson"),
15246
+ embeddingsCachePath: import_node_path66.default.join(baseDir, "embeddings.json"),
15247
+ policyViolationsPath: import_node_path66.default.join(baseDir, "policy-violations.ndjson")
14595
15248
  };
14596
15249
  }
14597
15250
  return {
14598
- snapshotPath: import_node_path63.default.join(baseDir, `${project}.json`),
14599
- errorsPath: import_node_path63.default.join(baseDir, `errors.${project}.ndjson`),
14600
- staleEventsPath: import_node_path63.default.join(baseDir, `stale-events.${project}.ndjson`),
14601
- embeddingsCachePath: import_node_path63.default.join(baseDir, `embeddings.${project}.json`),
14602
- policyViolationsPath: import_node_path63.default.join(baseDir, `policy-violations.${project}.ndjson`)
15251
+ snapshotPath: import_node_path66.default.join(baseDir, `${project}.json`),
15252
+ errorsPath: import_node_path66.default.join(baseDir, `errors.${project}.ndjson`),
15253
+ staleEventsPath: import_node_path66.default.join(baseDir, `stale-events.${project}.ndjson`),
15254
+ embeddingsCachePath: import_node_path66.default.join(baseDir, `embeddings.${project}.json`),
15255
+ policyViolationsPath: import_node_path66.default.join(baseDir, `policy-violations.${project}.ndjson`)
14603
15256
  };
14604
15257
  }
14605
15258
  var Projects = class {
@@ -14639,20 +15292,20 @@ function parseExtraProjects(raw) {
14639
15292
 
14640
15293
  // src/registry.ts
14641
15294
  init_cjs_shims();
14642
- var import_node_fs30 = require("fs");
15295
+ var import_node_fs33 = require("fs");
14643
15296
  var import_node_os3 = __toESM(require("os"), 1);
14644
- var import_node_path64 = __toESM(require("path"), 1);
14645
- var import_types52 = require("@neat.is/types");
15297
+ var import_node_path67 = __toESM(require("path"), 1);
15298
+ var import_types55 = require("@neat.is/types");
14646
15299
  function neatHome() {
14647
15300
  const override = process.env.NEAT_HOME;
14648
- if (override && override.length > 0) return import_node_path64.default.resolve(override);
14649
- return import_node_path64.default.join(import_node_os3.default.homedir(), ".neat");
15301
+ if (override && override.length > 0) return import_node_path67.default.resolve(override);
15302
+ return import_node_path67.default.join(import_node_os3.default.homedir(), ".neat");
14650
15303
  }
14651
15304
  function registryPath() {
14652
- return import_node_path64.default.join(neatHome(), "projects.json");
15305
+ return import_node_path67.default.join(neatHome(), "projects.json");
14653
15306
  }
14654
15307
  function daemonsDir() {
14655
- return import_node_path64.default.join(neatHome(), "daemons");
15308
+ return import_node_path67.default.join(neatHome(), "daemons");
14656
15309
  }
14657
15310
  function isFiniteInt(v) {
14658
15311
  return typeof v === "number" && Number.isFinite(v);
@@ -14685,7 +15338,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
14685
15338
  const dir = daemonsDir();
14686
15339
  let names;
14687
15340
  try {
14688
- names = await import_node_fs30.promises.readdir(dir);
15341
+ names = await import_node_fs33.promises.readdir(dir);
14689
15342
  } catch (err) {
14690
15343
  if (err.code === "ENOENT") return [];
14691
15344
  throw err;
@@ -14693,10 +15346,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
14693
15346
  const out = [];
14694
15347
  for (const name of names) {
14695
15348
  if (!name.endsWith(".json")) continue;
14696
- const file = import_node_path64.default.join(dir, name);
15349
+ const file = import_node_path67.default.join(dir, name);
14697
15350
  let raw;
14698
15351
  try {
14699
- raw = await import_node_fs30.promises.readFile(file, "utf8");
15352
+ raw = await import_node_fs33.promises.readFile(file, "utf8");
14700
15353
  } catch {
14701
15354
  continue;
14702
15355
  }
@@ -14724,7 +15377,7 @@ async function readRegistry() {
14724
15377
  const file = registryPath();
14725
15378
  let raw;
14726
15379
  try {
14727
- raw = await import_node_fs30.promises.readFile(file, "utf8");
15380
+ raw = await import_node_fs33.promises.readFile(file, "utf8");
14728
15381
  } catch (err) {
14729
15382
  if (err.code === "ENOENT") {
14730
15383
  return { version: 1, projects: [] };
@@ -14732,7 +15385,7 @@ async function readRegistry() {
14732
15385
  throw err;
14733
15386
  }
14734
15387
  const parsed = JSON.parse(raw);
14735
- return import_types52.RegistryFileSchema.parse(parsed);
15388
+ return import_types55.RegistryFileSchema.parse(parsed);
14736
15389
  }
14737
15390
  async function getProject(name) {
14738
15391
  const reg = await readRegistry();
@@ -14807,8 +15460,8 @@ init_auth();
14807
15460
  // src/connectors-config.ts
14808
15461
  init_cjs_shims();
14809
15462
  var import_node_os4 = __toESM(require("os"), 1);
14810
- var import_node_path65 = __toESM(require("path"), 1);
14811
- var import_node_fs31 = require("fs");
15463
+ var import_node_path68 = __toESM(require("path"), 1);
15464
+ var import_node_fs34 = require("fs");
14812
15465
  var CONNECTORS_CONFIG_VERSION = 1;
14813
15466
  var EnvRefUnsetError = class extends Error {
14814
15467
  ref;
@@ -14822,17 +15475,17 @@ var EnvRefUnsetError = class extends Error {
14822
15475
  };
14823
15476
  function neatHome2() {
14824
15477
  const override = process.env.NEAT_HOME;
14825
- if (override && override.length > 0) return import_node_path65.default.resolve(override);
14826
- return import_node_path65.default.join(import_node_os4.default.homedir(), ".neat");
15478
+ if (override && override.length > 0) return import_node_path68.default.resolve(override);
15479
+ return import_node_path68.default.join(import_node_os4.default.homedir(), ".neat");
14827
15480
  }
14828
15481
  function connectorsConfigPath(home = neatHome2()) {
14829
- return import_node_path65.default.join(home, "connectors.json");
15482
+ return import_node_path68.default.join(home, "connectors.json");
14830
15483
  }
14831
15484
  var MODE_MASK_LOOSER_THAN_0600 = 63;
14832
15485
  async function warnIfModeLooserThan0600(file) {
14833
15486
  if (process.platform === "win32") return;
14834
15487
  try {
14835
- const stat = await import_node_fs31.promises.stat(file);
15488
+ const stat = await import_node_fs34.promises.stat(file);
14836
15489
  if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
14837
15490
  const mode = (stat.mode & 511).toString(8).padStart(3, "0");
14838
15491
  console.warn(
@@ -14846,7 +15499,7 @@ async function readConnectorsConfig(home = neatHome2()) {
14846
15499
  const file = connectorsConfigPath(home);
14847
15500
  let raw;
14848
15501
  try {
14849
- raw = await import_node_fs31.promises.readFile(file, "utf8");
15502
+ raw = await import_node_fs34.promises.readFile(file, "utf8");
14850
15503
  } catch (err) {
14851
15504
  if (err.code === "ENOENT") {
14852
15505
  return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
@@ -15013,15 +15666,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
15013
15666
 
15014
15667
  // src/connectors/index.ts
15015
15668
  init_cjs_shims();
15016
- var import_types53 = require("@neat.is/types");
15669
+ var import_types56 = require("@neat.is/types");
15017
15670
  var NO_ENV = "unknown";
15018
15671
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
15019
15672
  if (!graph.hasNode(targetNodeId)) return void 0;
15020
15673
  const sites = [];
15021
15674
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
15022
15675
  const edge = graph.getEdgeAttributes(edgeId);
15023
- if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
15024
- const parsed = (0, import_types53.parseFileId)(edge.source);
15676
+ if (edge.provenance !== import_types56.Provenance.EXTRACTED) continue;
15677
+ const parsed = (0, import_types56.parseFileId)(edge.source);
15025
15678
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
15026
15679
  const site = { relPath: edge.evidence.file };
15027
15680
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -15032,7 +15685,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
15032
15685
  function routeCallSiteFor(graph, targetNodeId) {
15033
15686
  if (!graph.hasNode(targetNodeId)) return void 0;
15034
15687
  const attrs = graph.getNodeAttributes(targetNodeId);
15035
- if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
15688
+ if (attrs.type !== import_types56.NodeType.RouteNode || !attrs.path) return void 0;
15036
15689
  const site = { relPath: attrs.path };
15037
15690
  if (attrs.line !== void 0) site.line = attrs.line;
15038
15691
  return site;
@@ -15489,10 +16142,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
15489
16142
  // src/connectors/supabase/map.ts
15490
16143
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
15491
16144
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
15492
- function targetFromRestPath(path68) {
15493
- const rpcMatch = REST_RPC_PATH_RE.exec(path68);
16145
+ function targetFromRestPath(path71) {
16146
+ const rpcMatch = REST_RPC_PATH_RE.exec(path71);
15494
16147
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
15495
- const tableMatch = REST_TABLE_PATH_RE.exec(path68);
16148
+ const tableMatch = REST_TABLE_PATH_RE.exec(path71);
15496
16149
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
15497
16150
  return null;
15498
16151
  }
@@ -15603,23 +16256,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
15603
16256
 
15604
16257
  // src/connectors/supabase/resolve.ts
15605
16258
  init_cjs_shims();
15606
- var import_types55 = require("@neat.is/types");
16259
+ var import_types58 = require("@neat.is/types");
15607
16260
  function createSupabaseResolveTarget(graph, config) {
15608
16261
  return (signal, _ctx) => {
15609
16262
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
15610
16263
  return null;
15611
16264
  }
15612
- const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
16265
+ const subResourceId = (0, import_types58.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
15613
16266
  if (graph.hasNode(subResourceId)) {
15614
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
16267
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types58.EdgeType.CALLS };
15615
16268
  }
15616
- const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
16269
+ const bareResourceId = (0, import_types58.infraId)(signal.targetKind, signal.targetName);
15617
16270
  if (graph.hasNode(bareResourceId)) {
15618
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
16271
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types58.EdgeType.CALLS };
15619
16272
  }
15620
- const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
16273
+ const projectLevelId = (0, import_types58.infraId)("supabase", config.nodeRef);
15621
16274
  if (graph.hasNode(projectLevelId)) {
15622
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
16275
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types58.EdgeType.CALLS };
15623
16276
  }
15624
16277
  return null;
15625
16278
  };
@@ -15712,7 +16365,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
15712
16365
 
15713
16366
  // src/connectors/railway/index.ts
15714
16367
  init_cjs_shims();
15715
- var import_types59 = require("@neat.is/types");
16368
+ var import_types62 = require("@neat.is/types");
15716
16369
 
15717
16370
  // src/connectors/railway/client.ts
15718
16371
  init_cjs_shims();
@@ -15863,7 +16516,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
15863
16516
  const out = [];
15864
16517
  graph.forEachNode((_id, attrs) => {
15865
16518
  const node = attrs;
15866
- if (node.type !== import_types59.NodeType.RouteNode) return;
16519
+ if (node.type !== import_types62.NodeType.RouteNode) return;
15867
16520
  const route = attrs;
15868
16521
  if (route.service !== serviceName) return;
15869
16522
  out.push({
@@ -15967,12 +16620,12 @@ function createRailwayResolveTarget(config) {
15967
16620
  const serviceName = config.serviceNameById[config.serviceId];
15968
16621
  if (!serviceName) return null;
15969
16622
  if (signal.targetKind === ROUTE_TARGET_KIND) {
15970
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
16623
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types62.EdgeType.CALLS };
15971
16624
  }
15972
16625
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
15973
16626
  const peerName = config.serviceNameById[signal.targetName];
15974
16627
  if (!peerName) return null;
15975
- return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
16628
+ return { targetNodeId: (0, import_types62.serviceId)(peerName), serviceName, edgeType: import_types62.EdgeType.CONNECTS_TO };
15976
16629
  }
15977
16630
  return null;
15978
16631
  };
@@ -16096,9 +16749,9 @@ function parseFirebaseTargetName(targetName) {
16096
16749
  const secondSep = rest.indexOf(FIELD_SEP);
16097
16750
  if (secondSep === -1) return null;
16098
16751
  const method = rest.slice(0, secondSep);
16099
- const path68 = rest.slice(secondSep + 1);
16100
- if (!resourceName || !method || !path68) return null;
16101
- return { resourceName, method, path: path68 };
16752
+ const path71 = rest.slice(secondSep + 1);
16753
+ if (!resourceName || !method || !path71) return null;
16754
+ return { resourceName, method, path: path71 };
16102
16755
  }
16103
16756
  function resourceNameFor(type, labels) {
16104
16757
  if (!labels) return null;
@@ -16136,14 +16789,14 @@ function mapLogEntryToSignal(entry) {
16136
16789
  if (!req) return null;
16137
16790
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
16138
16791
  const method = req.requestMethod.toUpperCase();
16139
- const path68 = pathFromRequestUrl(req.requestUrl);
16140
- if (path68 === null) return null;
16792
+ const path71 = pathFromRequestUrl(req.requestUrl);
16793
+ if (path71 === null) return null;
16141
16794
  const timestamp = entry.timestamp;
16142
16795
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
16143
16796
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
16144
16797
  return {
16145
16798
  targetKind: resourceType,
16146
- targetName: packFirebaseTargetName({ resourceName, method, path: path68 }),
16799
+ targetName: packFirebaseTargetName({ resourceName, method, path: path71 }),
16147
16800
  callCount: 1,
16148
16801
  errorCount: isError ? 1 : 0,
16149
16802
  lastObservedIso: timestamp
@@ -16160,7 +16813,7 @@ function mapLogEntriesToSignals(entries) {
16160
16813
 
16161
16814
  // src/connectors/firebase/resolve.ts
16162
16815
  init_cjs_shims();
16163
- var import_types60 = require("@neat.is/types");
16816
+ var import_types63 = require("@neat.is/types");
16164
16817
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
16165
16818
  switch (resourceType) {
16166
16819
  case "cloud_function":
@@ -16175,7 +16828,7 @@ function routeEntriesFor(graph, serviceName) {
16175
16828
  const entries = [];
16176
16829
  graph.forEachNode((_id, attrs) => {
16177
16830
  const node = attrs;
16178
- if (node.type !== import_types60.NodeType.RouteNode) return;
16831
+ if (node.type !== import_types63.NodeType.RouteNode) return;
16179
16832
  const route = attrs;
16180
16833
  if (route.service !== serviceName) return;
16181
16834
  entries.push({
@@ -16207,7 +16860,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
16207
16860
  return {
16208
16861
  targetNodeId: match.routeNodeId,
16209
16862
  serviceName,
16210
- edgeType: import_types60.EdgeType.CALLS
16863
+ edgeType: import_types63.EdgeType.CALLS
16211
16864
  };
16212
16865
  };
16213
16866
  }
@@ -16234,7 +16887,7 @@ init_cjs_shims();
16234
16887
 
16235
16888
  // src/connectors/cloudflare/connector.ts
16236
16889
  init_cjs_shims();
16237
- var import_types62 = require("@neat.is/types");
16890
+ var import_types65 = require("@neat.is/types");
16238
16891
 
16239
16892
  // src/connectors/cloudflare/client.ts
16240
16893
  init_cjs_shims();
@@ -16350,7 +17003,7 @@ function mapEventToSignal(event) {
16350
17003
  if (Number.isNaN(observedAt.getTime())) return null;
16351
17004
  const statusCode = metadata?.statusCode;
16352
17005
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
16353
- const path68 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
17006
+ const path71 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
16354
17007
  return {
16355
17008
  targetKind: CLOUDFLARE_TARGET_KIND,
16356
17009
  targetName: scriptName,
@@ -16358,7 +17011,7 @@ function mapEventToSignal(event) {
16358
17011
  errorCount: isError ? 1 : 0,
16359
17012
  lastObservedIso: observedAt.toISOString(),
16360
17013
  method,
16361
- ...path68 ? { path: path68 } : {},
17014
+ ...path71 ? { path: path71 } : {},
16362
17015
  ...typeof statusCode === "number" ? { statusCode } : {},
16363
17016
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
16364
17017
  };
@@ -16398,19 +17051,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
16398
17051
  graph.forEachNode((id, attrs) => {
16399
17052
  if (found) return;
16400
17053
  const a = attrs;
16401
- if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
17054
+ if (a.type === import_types65.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
16402
17055
  found = id;
16403
17056
  }
16404
17057
  });
16405
17058
  return found;
16406
17059
  }
16407
- function findMatchingRouteNode(graph, serviceName, method, path68) {
16408
- const normalizedPath = normalizePathTemplate(path68);
17060
+ function findMatchingRouteNode(graph, serviceName, method, path71) {
17061
+ const normalizedPath = normalizePathTemplate(path71);
16409
17062
  let found = null;
16410
17063
  graph.forEachNode((id, attrs) => {
16411
17064
  if (found) return;
16412
17065
  const a = attrs;
16413
- if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
17066
+ if (a.type !== import_types65.NodeType.RouteNode || a.service !== serviceName) return;
16414
17067
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
16415
17068
  const routeMethod = (a.method ?? "").toUpperCase();
16416
17069
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -16422,18 +17075,18 @@ function createCloudflareResolveTarget(config, graph) {
16422
17075
  return (signal) => {
16423
17076
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
16424
17077
  const scriptName = signal.targetName;
16425
- const { method, path: path68 } = signal;
17078
+ const { method, path: path71 } = signal;
16426
17079
  const resolveRouteGrain = (serviceName, wholeFileId) => {
16427
- if (!method || !path68) return wholeFileId;
16428
- return findMatchingRouteNode(graph, serviceName, method, path68) ?? wholeFileId;
17080
+ if (!method || !path71) return wholeFileId;
17081
+ return findMatchingRouteNode(graph, serviceName, method, path71) ?? wholeFileId;
16429
17082
  };
16430
17083
  const mapping = config.workers?.[scriptName];
16431
17084
  if (mapping) {
16432
- const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
17085
+ const wholeFileId = (0, import_types65.fileId)(mapping.service, mapping.entryFile);
16433
17086
  return {
16434
17087
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
16435
17088
  serviceName: mapping.service,
16436
- edgeType: import_types62.EdgeType.CALLS
17089
+ edgeType: import_types65.EdgeType.CALLS
16437
17090
  };
16438
17091
  }
16439
17092
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -16442,13 +17095,13 @@ function createCloudflareResolveTarget(config, graph) {
16442
17095
  return {
16443
17096
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
16444
17097
  serviceName: fileNode.service,
16445
- edgeType: import_types62.EdgeType.CALLS
17098
+ edgeType: import_types65.EdgeType.CALLS
16446
17099
  };
16447
17100
  }
16448
17101
  return {
16449
- targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
17102
+ targetNodeId: (0, import_types65.infraId)("cloudflare-worker", scriptName),
16450
17103
  serviceName: scriptName,
16451
- edgeType: import_types62.EdgeType.CALLS,
17104
+ edgeType: import_types65.EdgeType.CALLS,
16452
17105
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
16453
17106
  };
16454
17107
  };
@@ -16644,14 +17297,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
16644
17297
 
16645
17298
  // src/connectors/neon/resolve.ts
16646
17299
  init_cjs_shims();
16647
- var import_types66 = require("@neat.is/types");
17300
+ var import_types69 = require("@neat.is/types");
16648
17301
  function createNeonResolveTarget(config) {
16649
17302
  return (signal) => {
16650
17303
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
16651
17304
  return {
16652
- targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
17305
+ targetNodeId: (0, import_types69.infraId)("sql-table", signal.targetName),
16653
17306
  serviceName: config.serviceName,
16654
- edgeType: import_types66.EdgeType.CALLS,
17307
+ edgeType: import_types69.EdgeType.CALLS,
16655
17308
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
16656
17309
  };
16657
17310
  };
@@ -16777,9 +17430,9 @@ function parseCloudRunTargetName(targetName) {
16777
17430
  const secondSep = rest.indexOf(FIELD_SEP2);
16778
17431
  if (secondSep === -1) return null;
16779
17432
  const method = rest.slice(0, secondSep);
16780
- const path68 = rest.slice(secondSep + 1);
16781
- if (!serviceName || !method || !path68) return null;
16782
- return { serviceName, method, path: path68 };
17433
+ const path71 = rest.slice(secondSep + 1);
17434
+ if (!serviceName || !method || !path71) return null;
17435
+ return { serviceName, method, path: path71 };
16783
17436
  }
16784
17437
 
16785
17438
  // src/connectors/cloud-run/map.ts
@@ -16808,14 +17461,14 @@ function mapLogEntryToSignal2(entry) {
16808
17461
  if (!req) return null;
16809
17462
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
16810
17463
  const method = req.requestMethod.toUpperCase();
16811
- const path68 = pathFromRequestUrl2(req.requestUrl);
16812
- if (path68 === null) return null;
17464
+ const path71 = pathFromRequestUrl2(req.requestUrl);
17465
+ if (path71 === null) return null;
16813
17466
  const timestamp = entry.timestamp;
16814
17467
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
16815
17468
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
16816
17469
  return {
16817
17470
  targetKind: CLOUD_RUN_TARGET_KIND,
16818
- targetName: packCloudRunTargetName({ serviceName, method, path: path68 }),
17471
+ targetName: packCloudRunTargetName({ serviceName, method, path: path71 }),
16819
17472
  callCount: 1,
16820
17473
  errorCount: isError ? 1 : 0,
16821
17474
  lastObservedIso: timestamp
@@ -16832,14 +17485,14 @@ function mapLogEntriesToSignals2(entries) {
16832
17485
 
16833
17486
  // src/connectors/cloud-run/resolve.ts
16834
17487
  init_cjs_shims();
16835
- var import_types70 = require("@neat.is/types");
17488
+ var import_types73 = require("@neat.is/types");
16836
17489
  var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
16837
17490
  function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
16838
17491
  let found = null;
16839
17492
  graph.forEachNode((_id, attrs) => {
16840
17493
  if (found) return;
16841
17494
  const node = attrs;
16842
- if (node.type !== import_types70.NodeType.RouteNode) return;
17495
+ if (node.type !== import_types73.NodeType.RouteNode) return;
16843
17496
  const route = attrs;
16844
17497
  if (route.service !== serviceName || !route.pathTemplate) return;
16845
17498
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -16854,23 +17507,23 @@ function createCloudRunResolveTarget(graph, config) {
16854
17507
  if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
16855
17508
  const identity = parseCloudRunTargetName(signal.targetName);
16856
17509
  if (!identity) return null;
16857
- const { serviceName: gcpServiceName, method, path: path68 } = identity;
17510
+ const { serviceName: gcpServiceName, method, path: path71 } = identity;
16858
17511
  const mappedService = config.serviceMap?.[gcpServiceName];
16859
17512
  if (mappedService) {
16860
17513
  const routeNodeId = findMatchingRouteNode2(
16861
17514
  graph,
16862
17515
  mappedService,
16863
17516
  method,
16864
- normalizePathTemplate(path68)
17517
+ normalizePathTemplate(path71)
16865
17518
  );
16866
17519
  if (routeNodeId) {
16867
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
17520
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types73.EdgeType.CALLS };
16868
17521
  }
16869
17522
  }
16870
17523
  return {
16871
- targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
17524
+ targetNodeId: (0, import_types73.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
16872
17525
  serviceName: mappedService ?? gcpServiceName,
16873
- edgeType: import_types70.EdgeType.CALLS,
17526
+ edgeType: import_types73.EdgeType.CALLS,
16874
17527
  ensureInfraNode: {
16875
17528
  kind: CLOUD_RUN_SERVICE_INFRA_KIND,
16876
17529
  name: gcpServiceName,
@@ -16911,7 +17564,7 @@ function createCloudRunConnector(graph, config = {}) {
16911
17564
 
16912
17565
  // src/connectors/render/index.ts
16913
17566
  init_cjs_shims();
16914
- var import_types73 = require("@neat.is/types");
17567
+ var import_types76 = require("@neat.is/types");
16915
17568
 
16916
17569
  // src/connectors/render/types.ts
16917
17570
  init_cjs_shims();
@@ -16989,7 +17642,7 @@ function buildRenderRouteIndex(graph, serviceName) {
16989
17642
  const out = [];
16990
17643
  graph.forEachNode((_id, attrs) => {
16991
17644
  const node = attrs;
16992
- if (node.type !== import_types73.NodeType.RouteNode) return;
17645
+ if (node.type !== import_types76.NodeType.RouteNode) return;
16993
17646
  const route = attrs;
16994
17647
  if (route.service !== serviceName) return;
16995
17648
  out.push({
@@ -17074,7 +17727,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
17074
17727
  function createRenderResolveTarget(config) {
17075
17728
  return (signal) => {
17076
17729
  if (signal.targetKind === ROUTE_TARGET_KIND2) {
17077
- return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
17730
+ return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types76.EdgeType.CALLS };
17078
17731
  }
17079
17732
  return null;
17080
17733
  };
@@ -17212,21 +17865,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
17212
17865
 
17213
17866
  // src/connectors/planetscale/resolve.ts
17214
17867
  init_cjs_shims();
17215
- var import_types77 = require("@neat.is/types");
17868
+ var import_types80 = require("@neat.is/types");
17216
17869
  var PLANETSCALE_DATABASE_KIND = "planetscale-database";
17217
17870
  function createPlanetscaleResolveTarget(graph, config) {
17218
17871
  const databaseName = `${config.organization}/${config.database}`;
17219
17872
  return (signal, _ctx) => {
17220
17873
  if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
17221
- const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
17874
+ const tableId = (0, import_types80.infraId)("sql-table", signal.targetName);
17222
17875
  if (graph.hasNode(tableId)) {
17223
- return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
17876
+ return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types80.EdgeType.CALLS };
17224
17877
  }
17225
- const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
17878
+ const providerId = (0, import_types80.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
17226
17879
  return {
17227
17880
  targetNodeId: providerId,
17228
17881
  serviceName: config.serviceName,
17229
- edgeType: import_types77.EdgeType.CALLS,
17882
+ edgeType: import_types80.EdgeType.CALLS,
17230
17883
  ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
17231
17884
  };
17232
17885
  };
@@ -17491,7 +18144,7 @@ function mapBuildsToSignals(builds, serviceName) {
17491
18144
 
17492
18145
  // src/connectors/eas/resolve.ts
17493
18146
  init_cjs_shims();
17494
- var import_types82 = require("@neat.is/types");
18147
+ var import_types85 = require("@neat.is/types");
17495
18148
  var NO_ENV2 = "unknown";
17496
18149
  var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
17497
18150
  var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
@@ -17507,8 +18160,8 @@ function configBasenamesForPhase(phase) {
17507
18160
  function configNodeService(graph, configNodeId) {
17508
18161
  for (const edgeId of graph.inboundEdges(configNodeId)) {
17509
18162
  const edge = graph.getEdgeAttributes(edgeId);
17510
- if (edge.type !== import_types82.EdgeType.CONFIGURED_BY) continue;
17511
- const parsed = (0, import_types82.parseFileId)(edge.source);
18163
+ if (edge.type !== import_types85.EdgeType.CONFIGURED_BY) continue;
18164
+ const parsed = (0, import_types85.parseFileId)(edge.source);
17512
18165
  if (parsed) return parsed.service;
17513
18166
  }
17514
18167
  return null;
@@ -17519,7 +18172,7 @@ function findConfigNode(graph, basenames, serviceName) {
17519
18172
  graph.forEachNode((id, attrs) => {
17520
18173
  if (scoped) return;
17521
18174
  const node = attrs;
17522
- if (node.type !== import_types82.NodeType.ConfigNode) return;
18175
+ if (node.type !== import_types85.NodeType.ConfigNode) return;
17523
18176
  if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
17524
18177
  if (anyMatch === null) anyMatch = id;
17525
18178
  if (configNodeService(graph, id) === serviceName) scoped = id;
@@ -17536,13 +18189,13 @@ function createEasResolveTarget(graph) {
17536
18189
  if (basenames.length > 0) {
17537
18190
  const configNodeId = findConfigNode(graph, basenames, serviceName);
17538
18191
  if (configNodeId) {
17539
- return { targetNodeId: configNodeId, serviceName, edgeType: import_types82.EdgeType.CALLS };
18192
+ return { targetNodeId: configNodeId, serviceName, edgeType: import_types85.EdgeType.CALLS };
17540
18193
  }
17541
18194
  }
17542
18195
  return {
17543
18196
  targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
17544
18197
  serviceName,
17545
- edgeType: import_types82.EdgeType.CALLS
18198
+ edgeType: import_types85.EdgeType.CALLS
17546
18199
  };
17547
18200
  };
17548
18201
  }
@@ -18221,11 +18874,11 @@ function registerRoutes(scope, ctx) {
18221
18874
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
18222
18875
  const parsed = [];
18223
18876
  for (const c of candidates) {
18224
- const r = import_types85.DivergenceTypeSchema.safeParse(c);
18877
+ const r = import_types88.DivergenceTypeSchema.safeParse(c);
18225
18878
  if (!r.success) {
18226
18879
  return reply.code(400).send({
18227
18880
  error: `unknown divergence type "${c}"`,
18228
- allowed: import_types85.DivergenceTypeSchema.options
18881
+ allowed: import_types88.DivergenceTypeSchema.options
18229
18882
  });
18230
18883
  }
18231
18884
  parsed.push(r.data);
@@ -18567,7 +19220,7 @@ function registerRoutes(scope, ctx) {
18567
19220
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
18568
19221
  let violations = await log.readAll();
18569
19222
  if (req.query.severity) {
18570
- const sev = import_types85.PolicySeveritySchema.safeParse(req.query.severity);
19223
+ const sev = import_types88.PolicySeveritySchema.safeParse(req.query.severity);
18571
19224
  if (!sev.success) {
18572
19225
  return reply.code(400).send({
18573
19226
  error: "invalid severity",
@@ -18606,7 +19259,7 @@ function registerRoutes(scope, ctx) {
18606
19259
  scope.post("/policies/check", async (req, reply) => {
18607
19260
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
18608
19261
  if (!proj) return;
18609
- const parsed = import_types85.PoliciesCheckBodySchema.safeParse(req.body ?? {});
19262
+ const parsed = import_types88.PoliciesCheckBodySchema.safeParse(req.body ?? {});
18610
19263
  if (!parsed.success) {
18611
19264
  return reply.code(400).send({
18612
19265
  error: "invalid /policies/check body",
@@ -18927,8 +19580,8 @@ init_otel_grpc();
18927
19580
 
18928
19581
  // src/search.ts
18929
19582
  init_cjs_shims();
18930
- var import_node_fs32 = require("fs");
18931
- var import_node_path66 = __toESM(require("path"), 1);
19583
+ var import_node_fs35 = require("fs");
19584
+ var import_node_path69 = __toESM(require("path"), 1);
18932
19585
  var import_node_crypto4 = require("crypto");
18933
19586
  var DEFAULT_LIMIT = 10;
18934
19587
  var NOMIC_DIM = 768;
@@ -19082,7 +19735,7 @@ async function pickEmbedder() {
19082
19735
  }
19083
19736
  async function readCache(cachePath) {
19084
19737
  try {
19085
- const raw = await import_node_fs32.promises.readFile(cachePath, "utf8");
19738
+ const raw = await import_node_fs35.promises.readFile(cachePath, "utf8");
19086
19739
  const parsed = JSON.parse(raw);
19087
19740
  if (parsed.version !== 1) return null;
19088
19741
  return parsed;
@@ -19091,8 +19744,8 @@ async function readCache(cachePath) {
19091
19744
  }
19092
19745
  }
19093
19746
  async function writeCache(cachePath, cache) {
19094
- await import_node_fs32.promises.mkdir(import_node_path66.default.dirname(cachePath), { recursive: true });
19095
- await import_node_fs32.promises.writeFile(cachePath, JSON.stringify(cache));
19747
+ await import_node_fs35.promises.mkdir(import_node_path69.default.dirname(cachePath), { recursive: true });
19748
+ await import_node_fs35.promises.writeFile(cachePath, JSON.stringify(cache));
19096
19749
  }
19097
19750
  var VectorIndex = class {
19098
19751
  constructor(embedder, cachePath) {
@@ -19306,14 +19959,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
19306
19959
  async function main() {
19307
19960
  const baseDirEnv = process.env.NEAT_OUT_DIR;
19308
19961
  const legacyOutPath = process.env.NEAT_OUT_PATH;
19309
- const baseDir = baseDirEnv ? import_node_path67.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path67.default.resolve(import_node_path67.default.dirname(legacyOutPath)) : import_node_path67.default.resolve("./neat-out");
19310
- const defaultScanPath = import_node_path67.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
19962
+ const baseDir = baseDirEnv ? import_node_path70.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path70.default.resolve(import_node_path70.default.dirname(legacyOutPath)) : import_node_path70.default.resolve("./neat-out");
19963
+ const defaultScanPath = import_node_path70.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
19311
19964
  const registry = new Projects();
19312
19965
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
19313
19966
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
19314
19967
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
19315
19968
  const projectScan = process.env[envKey];
19316
- await bootProject(registry, name, projectScan ? import_node_path67.default.resolve(projectScan) : void 0, baseDir);
19969
+ await bootProject(registry, name, projectScan ? import_node_path70.default.resolve(projectScan) : void 0, baseDir);
19317
19970
  }
19318
19971
  const host = process.env.HOST ?? "0.0.0.0";
19319
19972
  const port = Number(process.env.PORT ?? 8080);