@neat.is/core 0.10.6-dev.20261009 → 0.10.6

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/neatd.cjs CHANGED
@@ -2882,7 +2882,7 @@ var PolicyViolationsLog = class {
2882
2882
  };
2883
2883
 
2884
2884
  // src/ingest.ts
2885
- var import_types8 = require("@neat.is/types");
2885
+ var import_types9 = require("@neat.is/types");
2886
2886
 
2887
2887
  // src/extract/routes.ts
2888
2888
  init_cjs_shims();
@@ -5642,9 +5642,101 @@ async function addRoutes(graph, services) {
5642
5642
  return { nodesAdded, edgesAdded };
5643
5643
  }
5644
5644
 
5645
- // src/columns.ts
5645
+ // src/extract/source-baseline.ts
5646
5646
  init_cjs_shims();
5647
5647
  var import_types7 = require("@neat.is/types");
5648
+ var states = /* @__PURE__ */ new WeakMap();
5649
+ var REPOSITORY = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
5650
+ function validCommit(commit, repository) {
5651
+ return !!commit && commit.repository === repository && /^[0-9a-f]{40}$/.test(commit.sha);
5652
+ }
5653
+ function stateOf(graph) {
5654
+ let state = states.get(graph);
5655
+ if (!state) {
5656
+ state = { repos: /* @__PURE__ */ new Map(), active: /* @__PURE__ */ new Set(), conflicted: /* @__PURE__ */ new Set() };
5657
+ states.set(graph, state);
5658
+ }
5659
+ return state;
5660
+ }
5661
+ function setEntry(state, repository, baseline, generation = /* @__PURE__ */ Symbol()) {
5662
+ state.repos.set(repository, {
5663
+ baseline,
5664
+ generation,
5665
+ services: state.repos.get(repository)?.services ?? /* @__PURE__ */ new Set()
5666
+ });
5667
+ }
5668
+ function readSourceBaselines(graph) {
5669
+ const state = states.get(graph);
5670
+ if (!state) return [];
5671
+ return [...state.repos.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([, entry2]) => ({ ...entry2.baseline }));
5672
+ }
5673
+ function invalidateSourceBaseline(graph, repository, status2 = "unavailable") {
5674
+ if (repository !== void 0) {
5675
+ if (REPOSITORY.test(repository)) setEntry(stateOf(graph), repository, { status: status2, repository });
5676
+ return;
5677
+ }
5678
+ const state = states.get(graph);
5679
+ if (!state) return;
5680
+ for (const generation of state.active) state.conflicted.add(generation);
5681
+ for (const name of state.repos.keys()) {
5682
+ setEntry(state, name, { status: "unavailable", repository: name });
5683
+ }
5684
+ }
5685
+ function retainSourceBaselines(graph, repositories) {
5686
+ const state = states.get(graph);
5687
+ if (!state) return;
5688
+ const keep = new Set(repositories);
5689
+ for (const name of [...state.repos.keys()]) if (!keep.has(name)) state.repos.delete(name);
5690
+ }
5691
+ function beginSourceExtraction(graph, source, commit) {
5692
+ const generation = /* @__PURE__ */ Symbol();
5693
+ const state = stateOf(graph);
5694
+ if (source === void 0) {
5695
+ invalidateSourceBaseline(graph);
5696
+ state.active.add(generation);
5697
+ return generation;
5698
+ }
5699
+ state.active.add(generation);
5700
+ if (!REPOSITORY.test(source)) return generation;
5701
+ setEntry(
5702
+ state,
5703
+ source,
5704
+ validCommit(commit, source) ? { status: "syncing", repository: source } : { status: "unavailable", repository: source },
5705
+ generation
5706
+ );
5707
+ return generation;
5708
+ }
5709
+ function servicesOf(graph, repository) {
5710
+ const services = /* @__PURE__ */ new Set();
5711
+ graph.forEachNode((_id, attrs) => {
5712
+ const node = attrs;
5713
+ if (node.type === import_types7.NodeType.FileNode && node.source === repository && node.service) {
5714
+ services.add(node.service);
5715
+ }
5716
+ });
5717
+ return services;
5718
+ }
5719
+ function finishSourceExtraction(graph, generation, source, commit, result) {
5720
+ const state = states.get(graph);
5721
+ if (!state) return;
5722
+ state.active.delete(generation);
5723
+ const conflicted = state.conflicted.delete(generation);
5724
+ if (source === void 0 || !REPOSITORY.test(source)) return;
5725
+ const entry2 = state.repos.get(source);
5726
+ if (!entry2 || entry2.generation !== generation) return;
5727
+ entry2.services = servicesOf(graph, source);
5728
+ let shared = false;
5729
+ for (const [name, other] of state.repos) {
5730
+ if (name === source || ![...entry2.services].some((s) => other.services.has(s))) continue;
5731
+ shared = true;
5732
+ setEntry(state, name, { status: "unavailable", repository: name }, other.generation);
5733
+ }
5734
+ entry2.baseline = !conflicted && !shared && validCommit(commit, source) && result.extractionErrors === 0 && result.skippedFiles === 0 ? { status: "ready", repository: source, sha: commit.sha } : { status: "unavailable", repository: source };
5735
+ }
5736
+
5737
+ // src/columns.ts
5738
+ init_cjs_shims();
5739
+ var import_types8 = require("@neat.is/types");
5648
5740
  var OBSERVED_COLUMN_CONFIDENCE = 0.9;
5649
5741
  function normalizeProvenances(provenances) {
5650
5742
  return [...new Set(provenances)].sort();
@@ -5687,10 +5779,10 @@ function foldSdkWrites(existing, writes) {
5687
5779
  return out;
5688
5780
  }
5689
5781
  function columnIsDeclared(col) {
5690
- return col.provenances.includes(import_types7.Provenance.EXTRACTED);
5782
+ return col.provenances.includes(import_types8.Provenance.EXTRACTED);
5691
5783
  }
5692
5784
  function columnIsObserved(col) {
5693
- return col.provenances.includes(import_types7.Provenance.OBSERVED);
5785
+ return col.provenances.includes(import_types8.Provenance.OBSERVED);
5694
5786
  }
5695
5787
 
5696
5788
  // src/latency-digest.ts
@@ -6154,11 +6246,11 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
6154
6246
  };
6155
6247
  }
6156
6248
  function reconcileObservedRelPath(graph, serviceName, relPath) {
6157
- if (graph.hasNode((0, import_types8.fileId)(serviceName, relPath))) return relPath;
6249
+ if (graph.hasNode((0, import_types9.fileId)(serviceName, relPath))) return relPath;
6158
6250
  let best = null;
6159
6251
  graph.forEachNode((_id, attrs) => {
6160
6252
  const a = attrs;
6161
- if (a.type !== import_types8.NodeType.FileNode || a.service !== serviceName) return;
6253
+ if (a.type !== import_types9.NodeType.FileNode || a.service !== serviceName) return;
6162
6254
  if (a.discoveredVia === "otel") return;
6163
6255
  const p = a.path;
6164
6256
  if (!p) return;
@@ -6170,14 +6262,14 @@ function reconcileObservedRelPath(graph, serviceName, relPath) {
6170
6262
  }
6171
6263
  function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
6172
6264
  const svcAttrs = graph.hasNode(serviceNodeId) ? graph.getNodeAttributes(serviceNodeId) : void 0;
6173
- const canonicalService = svcAttrs && svcAttrs.type === import_types8.NodeType.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
6265
+ const canonicalService = svcAttrs && svcAttrs.type === import_types9.NodeType.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
6174
6266
  const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath);
6175
- const fileNodeId = (0, import_types8.fileId)(canonicalService, relPath);
6267
+ const fileNodeId = (0, import_types9.fileId)(canonicalService, relPath);
6176
6268
  if (!graph.hasNode(fileNodeId)) {
6177
6269
  const language = languageForExt(relPath);
6178
6270
  const node = {
6179
6271
  id: fileNodeId,
6180
- type: import_types8.NodeType.FileNode,
6272
+ type: import_types9.NodeType.FileNode,
6181
6273
  service: canonicalService,
6182
6274
  path: relPath,
6183
6275
  ...language ? { language } : {},
@@ -6186,14 +6278,14 @@ function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
6186
6278
  };
6187
6279
  graph.addNode(fileNodeId, node);
6188
6280
  }
6189
- const containsId = makeObservedEdgeId(import_types8.EdgeType.CONTAINS, serviceNodeId, fileNodeId);
6281
+ const containsId = makeObservedEdgeId(import_types9.EdgeType.CONTAINS, serviceNodeId, fileNodeId);
6190
6282
  if (!graph.hasEdge(containsId)) {
6191
6283
  const edge = {
6192
6284
  id: containsId,
6193
6285
  source: serviceNodeId,
6194
6286
  target: fileNodeId,
6195
- type: import_types8.EdgeType.CONTAINS,
6196
- provenance: import_types8.Provenance.OBSERVED
6287
+ type: import_types9.EdgeType.CONTAINS,
6288
+ provenance: import_types9.Provenance.OBSERVED
6197
6289
  };
6198
6290
  graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge);
6199
6291
  }
@@ -6217,11 +6309,11 @@ function pickContainingSymbol(candidates, fn) {
6217
6309
  return [...candidates].sort(bySpan)[0].id;
6218
6310
  }
6219
6311
  function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line) {
6220
- const sid = (0, import_types8.symbolId)(service, relPath, fn);
6312
+ const sid = (0, import_types9.symbolId)(service, relPath, fn);
6221
6313
  if (!graph.hasNode(sid)) {
6222
6314
  const node = {
6223
6315
  id: sid,
6224
- type: import_types8.NodeType.SymbolNode,
6316
+ type: import_types9.NodeType.SymbolNode,
6225
6317
  kind: "function",
6226
6318
  qualname: fn,
6227
6319
  span: { startLine: line, endLine: line },
@@ -6231,14 +6323,14 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
6231
6323
  };
6232
6324
  graph.addNode(sid, node);
6233
6325
  }
6234
- const containsId = makeObservedEdgeId(import_types8.EdgeType.CONTAINS, fileNodeId, sid);
6326
+ const containsId = makeObservedEdgeId(import_types9.EdgeType.CONTAINS, fileNodeId, sid);
6235
6327
  if (!graph.hasEdge(containsId)) {
6236
6328
  const edge = {
6237
6329
  id: containsId,
6238
6330
  source: fileNodeId,
6239
6331
  target: sid,
6240
- type: import_types8.EdgeType.CONTAINS,
6241
- provenance: import_types8.Provenance.OBSERVED
6332
+ type: import_types9.EdgeType.CONTAINS,
6333
+ provenance: import_types9.Provenance.OBSERVED
6242
6334
  };
6243
6335
  graph.addEdgeWithKey(containsId, fileNodeId, sid, edge);
6244
6336
  }
@@ -6250,9 +6342,9 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint
6250
6342
  let sawSymbol = false;
6251
6343
  const candidates = [];
6252
6344
  graph.forEachOutboundEdge(fileNodeId, (_edge, edgeAttrs, _source, target) => {
6253
- if (edgeAttrs.type !== import_types8.EdgeType.CONTAINS) return;
6345
+ if (edgeAttrs.type !== import_types9.EdgeType.CONTAINS) return;
6254
6346
  const t = graph.getNodeAttributes(target);
6255
- if (t.type !== import_types8.NodeType.SymbolNode) return;
6347
+ if (t.type !== import_types9.NodeType.SymbolNode) return;
6256
6348
  sawSymbol = true;
6257
6349
  if (line >= t.span.startLine && line <= t.span.endLine) {
6258
6350
  candidates.push({ id: target, symbol: t });
@@ -6265,17 +6357,17 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint
6265
6357
  return fileNodeId;
6266
6358
  }
6267
6359
  function makeObservedEdgeId(type, source, target) {
6268
- return (0, import_types8.observedEdgeId)(source, target, type);
6360
+ return (0, import_types9.observedEdgeId)(source, target, type);
6269
6361
  }
6270
6362
  function makeInferredEdgeId(type, source, target) {
6271
- return (0, import_types8.inferredEdgeId)(source, target, type);
6363
+ return (0, import_types9.inferredEdgeId)(source, target, type);
6272
6364
  }
6273
6365
  var INFERRED_CONFIDENCE = 0.6;
6274
6366
  var STITCH_MAX_DEPTH = 2;
6275
6367
  var STITCH_EDGE_TYPES = /* @__PURE__ */ new Set([
6276
- import_types8.EdgeType.CALLS,
6277
- import_types8.EdgeType.CONNECTS_TO,
6278
- import_types8.EdgeType.DEPENDS_ON
6368
+ import_types9.EdgeType.CALLS,
6369
+ import_types9.EdgeType.CONNECTS_TO,
6370
+ import_types9.EdgeType.DEPENDS_ON
6279
6371
  ]);
6280
6372
  var WIRE_SPAN_KIND_CLIENT = 3;
6281
6373
  var WIRE_SPAN_KIND_PRODUCER = 4;
@@ -6291,11 +6383,11 @@ function spanServesGraphqlOperation(kind) {
6291
6383
  return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
6292
6384
  }
6293
6385
  function ensureGraphqlOperationNode(graph, serviceName, operationType, operationName) {
6294
- const id = (0, import_types8.graphqlOperationId)(serviceName, operationType, operationName);
6386
+ const id = (0, import_types9.graphqlOperationId)(serviceName, operationType, operationName);
6295
6387
  if (graph.hasNode(id)) return id;
6296
6388
  const node = {
6297
6389
  id,
6298
- type: import_types8.NodeType.GraphQLOperationNode,
6390
+ type: import_types9.NodeType.GraphQLOperationNode,
6299
6391
  name: operationName,
6300
6392
  service: serviceName,
6301
6393
  operationType: operationType.toLowerCase(),
@@ -6309,11 +6401,11 @@ function spanServesGrpcMethod(kind) {
6309
6401
  return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
6310
6402
  }
6311
6403
  function ensureGrpcMethodNode(graph, rpcService, rpcMethod) {
6312
- const id = (0, import_types8.grpcMethodId)(rpcService, rpcMethod);
6404
+ const id = (0, import_types9.grpcMethodId)(rpcService, rpcMethod);
6313
6405
  if (graph.hasNode(id)) return id;
6314
6406
  const node = {
6315
6407
  id,
6316
- type: import_types8.NodeType.GrpcMethodNode,
6408
+ type: import_types9.NodeType.GrpcMethodNode,
6317
6409
  name: `${rpcService}/${rpcMethod}`,
6318
6410
  rpcService,
6319
6411
  rpcMethod,
@@ -6326,11 +6418,11 @@ function spanServesWebsocketChannel(kind) {
6326
6418
  return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
6327
6419
  }
6328
6420
  function ensureWebsocketChannelNode(graph, serviceName, channel) {
6329
- const id = (0, import_types8.websocketChannelId)(serviceName, channel);
6421
+ const id = (0, import_types9.websocketChannelId)(serviceName, channel);
6330
6422
  if (graph.hasNode(id)) return id;
6331
6423
  const node = {
6332
6424
  id,
6333
- type: import_types8.NodeType.WebSocketChannelNode,
6425
+ type: import_types9.NodeType.WebSocketChannelNode,
6334
6426
  name: channel,
6335
6427
  service: serviceName,
6336
6428
  channel,
@@ -6343,11 +6435,11 @@ function messagingDestinationKind(system) {
6343
6435
  return `${system}-topic`;
6344
6436
  }
6345
6437
  function ensureMessagingDestinationNode(graph, system, destination) {
6346
- const id = (0, import_types8.infraId)(messagingDestinationKind(system), destination);
6438
+ const id = (0, import_types9.infraId)(messagingDestinationKind(system), destination);
6347
6439
  if (graph.hasNode(id)) return id;
6348
6440
  const node = {
6349
6441
  id,
6350
- type: import_types8.NodeType.InfraNode,
6442
+ type: import_types9.NodeType.InfraNode,
6351
6443
  name: destination,
6352
6444
  provider: "self",
6353
6445
  kind: messagingDestinationKind(system)
@@ -6391,9 +6483,9 @@ function lookupParentSpan(traceId, parentSpanId, now) {
6391
6483
  };
6392
6484
  }
6393
6485
  function resolveServiceId(graph, host, env) {
6394
- const envTagged = (0, import_types8.serviceId)(host, env);
6486
+ const envTagged = (0, import_types9.serviceId)(host, env);
6395
6487
  if (graph.hasNode(envTagged)) return envTagged;
6396
- const envLess = (0, import_types8.serviceId)(host);
6488
+ const envLess = (0, import_types9.serviceId)(host);
6397
6489
  if (envLess !== envTagged && graph.hasNode(envLess)) return envLess;
6398
6490
  let sameEnv = null;
6399
6491
  let envLessMatch = null;
@@ -6401,7 +6493,7 @@ function resolveServiceId(graph, host, env) {
6401
6493
  graph.forEachNode((id, attrs) => {
6402
6494
  if (sameEnv) return;
6403
6495
  const a = attrs;
6404
- if (a.type !== import_types8.NodeType.ServiceNode) return;
6496
+ if (a.type !== import_types9.NodeType.ServiceNode) return;
6405
6497
  const matchesByName = a.name === host;
6406
6498
  const matchesByAlias = a.aliases ? a.aliases.includes(host) : false;
6407
6499
  if (!matchesByName && !matchesByAlias) return;
@@ -6416,14 +6508,14 @@ function resolveServiceId(graph, host, env) {
6416
6508
  return sameEnv ?? envLessMatch ?? anyMatch;
6417
6509
  }
6418
6510
  function frontierIdFor(host) {
6419
- return (0, import_types8.frontierId)(host);
6511
+ return (0, import_types9.frontierId)(host);
6420
6512
  }
6421
6513
  function resolveFusedServiceId(graph, serviceName, env) {
6422
- const id = (0, import_types8.serviceId)(serviceName, env);
6514
+ const id = (0, import_types9.serviceId)(serviceName, env);
6423
6515
  if (graph.hasNode(id)) return id;
6424
6516
  const wanted = serviceName.toLowerCase();
6425
6517
  const extractedId = graph.findNode((_nid, attrs) => {
6426
- if (attrs.type !== import_types8.NodeType.ServiceNode) return false;
6518
+ if (attrs.type !== import_types9.NodeType.ServiceNode) return false;
6427
6519
  const svc = attrs;
6428
6520
  if (svc.discoveredVia === "otel") return false;
6429
6521
  return typeof svc.name === "string" && svc.name.toLowerCase() === wanted;
@@ -6435,7 +6527,7 @@ function ensureServiceNode(graph, serviceName, env) {
6435
6527
  if (graph.hasNode(resolved)) return resolved;
6436
6528
  const node = {
6437
6529
  id: resolved,
6438
- type: import_types8.NodeType.ServiceNode,
6530
+ type: import_types9.NodeType.ServiceNode,
6439
6531
  name: serviceName,
6440
6532
  language: "unknown",
6441
6533
  discoveredVia: "otel",
@@ -6445,11 +6537,11 @@ function ensureServiceNode(graph, serviceName, env) {
6445
6537
  return resolved;
6446
6538
  }
6447
6539
  function ensureInfraNode(graph, kind, name, provider) {
6448
- const id = (0, import_types8.infraId)(kind, name);
6540
+ const id = (0, import_types9.infraId)(kind, name);
6449
6541
  if (graph.hasNode(id)) return id;
6450
6542
  const node = {
6451
6543
  id,
6452
- type: import_types8.NodeType.InfraNode,
6544
+ type: import_types9.NodeType.InfraNode,
6453
6545
  name,
6454
6546
  provider,
6455
6547
  kind
@@ -6461,7 +6553,7 @@ var COLUMN_BEARING_INFRA_KINDS = /* @__PURE__ */ new Set(["sql-table", "supabase
6461
6553
  function mergeColumnsAt(graph, tableNodeId, columns, provenance, confidence) {
6462
6554
  if (!columns || columns.length === 0 || !graph.hasNode(tableNodeId)) return;
6463
6555
  const node = graph.getNodeAttributes(tableNodeId);
6464
- if (node.type !== import_types8.NodeType.InfraNode || !node.kind || !COLUMN_BEARING_INFRA_KINDS.has(node.kind)) {
6556
+ if (node.type !== import_types9.NodeType.InfraNode || !node.kind || !COLUMN_BEARING_INFRA_KINDS.has(node.kind)) {
6465
6557
  return;
6466
6558
  }
6467
6559
  graph.replaceNodeAttributes(tableNodeId, {
@@ -6470,7 +6562,7 @@ function mergeColumnsAt(graph, tableNodeId, columns, provenance, confidence) {
6470
6562
  });
6471
6563
  }
6472
6564
  function mergeObservedColumns(graph, tableNodeId, columns) {
6473
- mergeColumnsAt(graph, tableNodeId, columns, import_types8.Provenance.OBSERVED, OBSERVED_COLUMN_CONFIDENCE);
6565
+ mergeColumnsAt(graph, tableNodeId, columns, import_types9.Provenance.OBSERVED, OBSERVED_COLUMN_CONFIDENCE);
6474
6566
  }
6475
6567
  function mergeObservedDeployState(graph, serviceNodeId, state) {
6476
6568
  if (!graph.hasNode(serviceNodeId)) return;
@@ -6481,11 +6573,11 @@ function mergeObservedDeployState(graph, serviceNodeId, state) {
6481
6573
  graph.mergeNodeAttributes(serviceNodeId, attrs);
6482
6574
  }
6483
6575
  function ensureDatabaseNode(graph, host, engine) {
6484
- const id = (0, import_types8.databaseId)(host);
6576
+ const id = (0, import_types9.databaseId)(host);
6485
6577
  if (graph.hasNode(id)) return id;
6486
6578
  const node = {
6487
6579
  id,
6488
- type: import_types8.NodeType.DatabaseNode,
6580
+ type: import_types9.NodeType.DatabaseNode,
6489
6581
  name: host,
6490
6582
  engine,
6491
6583
  engineVersion: "unknown",
@@ -6497,11 +6589,11 @@ function ensureDatabaseNode(graph, host, engine) {
6497
6589
  return id;
6498
6590
  }
6499
6591
  function ensureLocalDatabaseNode(graph, serviceName, name, engine) {
6500
- const id = (0, import_types8.localDatabaseId)(serviceName, name);
6592
+ const id = (0, import_types9.localDatabaseId)(serviceName, name);
6501
6593
  if (graph.hasNode(id)) return id;
6502
6594
  const node = {
6503
6595
  id,
6504
- type: import_types8.NodeType.DatabaseNode,
6596
+ type: import_types9.NodeType.DatabaseNode,
6505
6597
  name,
6506
6598
  engine,
6507
6599
  engineVersion: "unknown",
@@ -6516,17 +6608,17 @@ function findDeclaredDatabaseForService(graph, serviceNodeId, engine) {
6516
6608
  const sources = [serviceNodeId];
6517
6609
  for (const edgeId of graph.outboundEdges(serviceNodeId)) {
6518
6610
  const e = graph.getEdgeAttributes(edgeId);
6519
- if (e.type === import_types8.EdgeType.CONTAINS) sources.push(e.target);
6611
+ if (e.type === import_types9.EdgeType.CONTAINS) sources.push(e.target);
6520
6612
  }
6521
6613
  const matches = /* @__PURE__ */ new Set();
6522
6614
  for (const src of sources) {
6523
6615
  if (!graph.hasNode(src)) continue;
6524
6616
  for (const edgeId of graph.outboundEdges(src)) {
6525
6617
  const edge = graph.getEdgeAttributes(edgeId);
6526
- if (edge.type !== import_types8.EdgeType.CONNECTS_TO || edge.provenance !== import_types8.Provenance.EXTRACTED) continue;
6618
+ if (edge.type !== import_types9.EdgeType.CONNECTS_TO || edge.provenance !== import_types9.Provenance.EXTRACTED) continue;
6527
6619
  if (!graph.hasNode(edge.target)) continue;
6528
6620
  const target = graph.getNodeAttributes(edge.target);
6529
- if (target.type !== import_types8.NodeType.DatabaseNode || target.engine !== engine) continue;
6621
+ if (target.type !== import_types9.NodeType.DatabaseNode || target.engine !== engine) continue;
6530
6622
  matches.add(edge.target);
6531
6623
  }
6532
6624
  }
@@ -6541,7 +6633,7 @@ function ensureFrontierNode(graph, host, ts) {
6541
6633
  }
6542
6634
  const node = {
6543
6635
  id,
6544
- type: import_types8.NodeType.FrontierNode,
6636
+ type: import_types9.NodeType.FrontierNode,
6545
6637
  name: host,
6546
6638
  host,
6547
6639
  firstObserved: ts,
@@ -6594,11 +6686,11 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
6594
6686
  };
6595
6687
  const updated = {
6596
6688
  ...existing,
6597
- provenance: import_types8.Provenance.OBSERVED,
6689
+ provenance: import_types9.Provenance.OBSERVED,
6598
6690
  lastObserved: ts,
6599
6691
  callCount: newSpanCount,
6600
6692
  signal: newSignal,
6601
- confidence: (0, import_types8.confidenceForObservedSignal)(newSignal),
6693
+ confidence: (0, import_types9.confidenceForObservedSignal)(newSignal),
6602
6694
  grain
6603
6695
  // backfills legacy edges that predate ADR-142
6604
6696
  };
@@ -6621,8 +6713,8 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
6621
6713
  source,
6622
6714
  target,
6623
6715
  type,
6624
- provenance: import_types8.Provenance.OBSERVED,
6625
- confidence: (0, import_types8.confidenceForObservedSignal)(signal),
6716
+ provenance: import_types9.Provenance.OBSERVED,
6717
+ confidence: (0, import_types9.confidenceForObservedSignal)(signal),
6626
6718
  lastObserved: ts,
6627
6719
  callCount: 1,
6628
6720
  signal,
@@ -6644,9 +6736,9 @@ function stitchTrace(graph, sourceServiceId, ts) {
6644
6736
  const outbound = graph.outboundEdges(nodeId);
6645
6737
  for (const edgeId of outbound) {
6646
6738
  const edge = graph.getEdgeAttributes(edgeId);
6647
- if (edge.provenance !== import_types8.Provenance.EXTRACTED) continue;
6739
+ if (edge.provenance !== import_types9.Provenance.EXTRACTED) continue;
6648
6740
  if (!STITCH_EDGE_TYPES.has(edge.type)) continue;
6649
- if (graph.hasEdge((0, import_types8.observedEdgeId)(edge.source, edge.target, edge.type))) continue;
6741
+ if (graph.hasEdge((0, import_types9.observedEdgeId)(edge.source, edge.target, edge.type))) continue;
6650
6742
  upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts);
6651
6743
  if (!visited.has(edge.target)) {
6652
6744
  visited.add(edge.target);
@@ -6668,7 +6760,7 @@ function upsertInferredEdge(graph, type, source, target, ts) {
6668
6760
  source,
6669
6761
  target,
6670
6762
  type,
6671
- provenance: import_types8.Provenance.INFERRED,
6763
+ provenance: import_types9.Provenance.INFERRED,
6672
6764
  confidence: INFERRED_CONFIDENCE,
6673
6765
  lastObserved: ts
6674
6766
  };
@@ -6682,7 +6774,7 @@ function emitIncidentEvent(project, ev) {
6682
6774
  incidentId: ev.id,
6683
6775
  affectedNode: ev.affectedNode,
6684
6776
  service: ev.service,
6685
- incidentKind: (0, import_types8.incidentKindOf)(ev),
6777
+ incidentKind: (0, import_types9.incidentKindOf)(ev),
6686
6778
  at: ev.timestamp
6687
6779
  }
6688
6780
  });
@@ -6711,7 +6803,7 @@ function landIncidentCallSite(span, callSite, trusted, graph) {
6711
6803
  const canonicalService = serviceNodeName(graph, span) ?? span.service;
6712
6804
  const recovered = !trusted;
6713
6805
  if (graph) {
6714
- const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
6806
+ const fusedFileId = (0, import_types9.fileId)(canonicalService, relPath);
6715
6807
  if (graph.hasNode(fusedFileId)) {
6716
6808
  const node = landObservedSymbol(
6717
6809
  graph,
@@ -6731,7 +6823,7 @@ function landIncidentCallSite(span, callSite, trusted, graph) {
6731
6823
  }
6732
6824
  if (recovered) return null;
6733
6825
  }
6734
- return { affectedNode: (0, import_types8.fileId)(span.service, relPath) };
6826
+ return { affectedNode: (0, import_types9.fileId)(span.service, relPath) };
6735
6827
  }
6736
6828
  function serviceNodeName(graph, span) {
6737
6829
  if (!graph) return void 0;
@@ -6748,7 +6840,7 @@ function stacktraceCallSite(span, serviceNode, scanPath) {
6748
6840
  return { relPath, line: frame.line, ...frame.fn ? { fn: frame.fn } : {} };
6749
6841
  }
6750
6842
  function incidentLocus(span, graph, scanPath) {
6751
- const sid = graph ? resolveFusedServiceId(graph, span.service, span.env) : (0, import_types8.serviceId)(span.service, span.env);
6843
+ const sid = graph ? resolveFusedServiceId(graph, span.service, span.env) : (0, import_types9.serviceId)(span.service, span.env);
6752
6844
  const serviceNode = graph && graph.hasNode(sid) ? graph.getNodeAttributes(sid) : void 0;
6753
6845
  const callSite = callSiteFromSpan(span, serviceNode, scanPath);
6754
6846
  if (callSite) {
@@ -6939,7 +7031,7 @@ function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
6939
7031
  graph.forEachNode((id, attrs) => {
6940
7032
  if (found) return;
6941
7033
  const a = attrs;
6942
- if (a.type !== import_types8.NodeType.RouteNode || a.service !== serviceName) return;
7034
+ if (a.type !== import_types9.NodeType.RouteNode || a.service !== serviceName) return;
6943
7035
  if (m && a.method !== "ALL" && a.method !== m) return;
6944
7036
  if (normalizePathTemplate(a.pathTemplate) === target) found = id;
6945
7037
  });
@@ -6972,7 +7064,7 @@ async function handleSpan(ctx, span) {
6972
7064
  let targetId;
6973
7065
  if (host) {
6974
7066
  ensureDatabaseNode(ctx.graph, host, span.dbSystem);
6975
- targetId = (0, import_types8.databaseId)(host);
7067
+ targetId = (0, import_types9.databaseId)(host);
6976
7068
  } else {
6977
7069
  const declared = findDeclaredDatabaseForService(ctx.graph, sourceId, span.dbSystem);
6978
7070
  if (declared) {
@@ -6989,7 +7081,7 @@ async function handleSpan(ctx, span) {
6989
7081
  }
6990
7082
  const result = upsertObservedEdge(
6991
7083
  ctx.graph,
6992
- import_types8.EdgeType.CONNECTS_TO,
7084
+ import_types9.EdgeType.CONNECTS_TO,
6993
7085
  observedSource(),
6994
7086
  targetId,
6995
7087
  ts,
@@ -7003,7 +7095,7 @@ async function handleSpan(ctx, span) {
7003
7095
  const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
7004
7096
  upsertObservedEdge(
7005
7097
  ctx.graph,
7006
- import_types8.EdgeType.CALLS,
7098
+ import_types9.EdgeType.CALLS,
7007
7099
  observedSource(),
7008
7100
  collectionId,
7009
7101
  ts,
@@ -7017,7 +7109,7 @@ async function handleSpan(ctx, span) {
7017
7109
  const tableId = ensureInfraNode(ctx.graph, "sql-table", span.dbTable, "self");
7018
7110
  upsertObservedEdge(
7019
7111
  ctx.graph,
7020
- import_types8.EdgeType.CALLS,
7112
+ import_types9.EdgeType.CALLS,
7021
7113
  observedSource(),
7022
7114
  tableId,
7023
7115
  ts,
@@ -7035,7 +7127,7 @@ async function handleSpan(ctx, span) {
7035
7127
  span.messagingSystem,
7036
7128
  span.messagingDestination
7037
7129
  );
7038
- const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ? import_types8.EdgeType.CONSUMES_FROM : import_types8.EdgeType.PUBLISHES_TO;
7130
+ const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ? import_types9.EdgeType.CONSUMES_FROM : import_types9.EdgeType.PUBLISHES_TO;
7039
7131
  const result = upsertObservedEdge(
7040
7132
  ctx.graph,
7041
7133
  edgeType,
@@ -7057,7 +7149,7 @@ async function handleSpan(ctx, span) {
7057
7149
  );
7058
7150
  const result = upsertObservedEdge(
7059
7151
  ctx.graph,
7060
- import_types8.EdgeType.CONTAINS,
7152
+ import_types9.EdgeType.CONTAINS,
7061
7153
  observedSource(),
7062
7154
  targetId,
7063
7155
  ts,
@@ -7071,7 +7163,7 @@ async function handleSpan(ctx, span) {
7071
7163
  const targetId = ensureGrpcMethodNode(ctx.graph, span.rpcService, span.rpcMethod);
7072
7164
  const result = upsertObservedEdge(
7073
7165
  ctx.graph,
7074
- import_types8.EdgeType.CONTAINS,
7166
+ import_types9.EdgeType.CONTAINS,
7075
7167
  observedSource(),
7076
7168
  targetId,
7077
7169
  ts,
@@ -7089,7 +7181,7 @@ async function handleSpan(ctx, span) {
7089
7181
  );
7090
7182
  const result = upsertObservedEdge(
7091
7183
  ctx.graph,
7092
- import_types8.EdgeType.CONNECTS_TO,
7184
+ import_types9.EdgeType.CONNECTS_TO,
7093
7185
  observedSource(),
7094
7186
  targetId,
7095
7187
  ts,
@@ -7107,7 +7199,7 @@ async function handleSpan(ctx, span) {
7107
7199
  if (targetId && targetId !== sourceId) {
7108
7200
  upsertObservedEdge(
7109
7201
  ctx.graph,
7110
- import_types8.EdgeType.CALLS,
7202
+ import_types9.EdgeType.CALLS,
7111
7203
  observedSource(),
7112
7204
  targetId,
7113
7205
  ts,
@@ -7122,7 +7214,7 @@ async function handleSpan(ctx, span) {
7122
7214
  const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts);
7123
7215
  upsertObservedEdge(
7124
7216
  ctx.graph,
7125
- import_types8.EdgeType.CALLS,
7217
+ import_types9.EdgeType.CALLS,
7126
7218
  observedSource(),
7127
7219
  frontierNodeId,
7128
7220
  ts,
@@ -7150,7 +7242,7 @@ async function handleSpan(ctx, span) {
7150
7242
  } : void 0;
7151
7243
  upsertObservedEdge(
7152
7244
  ctx.graph,
7153
- import_types8.EdgeType.CALLS,
7245
+ import_types9.EdgeType.CALLS,
7154
7246
  fallbackSource,
7155
7247
  sourceId,
7156
7248
  ts,
@@ -7172,7 +7264,7 @@ async function handleSpan(ctx, span) {
7172
7264
  );
7173
7265
  if (routeNodeId) {
7174
7266
  const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
7175
- upsertObservedEdge(ctx.graph, import_types8.EdgeType.CONTAINS, (0, import_types8.serviceId)(routeSvc), routeNodeId, ts, isError, void 0, durationMs, errorDetail);
7267
+ upsertObservedEdge(ctx.graph, import_types9.EdgeType.CONTAINS, (0, import_types9.serviceId)(routeSvc), routeNodeId, ts, isError, void 0, durationMs, errorDetail);
7176
7268
  }
7177
7269
  }
7178
7270
  if (span.statusCode === 2) {
@@ -7202,7 +7294,7 @@ function promoteFrontierNodes(graph, opts = {}) {
7202
7294
  const aliasIndex = /* @__PURE__ */ new Map();
7203
7295
  graph.forEachNode((id, attrs) => {
7204
7296
  const a = attrs;
7205
- if (a.type !== import_types8.NodeType.ServiceNode) return;
7297
+ if (a.type !== import_types9.NodeType.ServiceNode) return;
7206
7298
  aliasIndex.set(a.name, id);
7207
7299
  if (a.aliases) {
7208
7300
  for (const alias of a.aliases) aliasIndex.set(alias, id);
@@ -7211,7 +7303,7 @@ function promoteFrontierNodes(graph, opts = {}) {
7211
7303
  const toPromote = [];
7212
7304
  graph.forEachNode((id, attrs) => {
7213
7305
  const a = attrs;
7214
- if (a.type !== import_types8.NodeType.FrontierNode) return;
7306
+ if (a.type !== import_types9.NodeType.FrontierNode) return;
7215
7307
  const target = aliasIndex.get(a.host);
7216
7308
  if (!target) return;
7217
7309
  if (target === id) return;
@@ -7233,15 +7325,15 @@ function promoteFrontierNodes(graph, opts = {}) {
7233
7325
  }
7234
7326
  function stageFrontierEdge(graph, source, target, type) {
7235
7327
  if (!graph.hasNode(source) || !graph.hasNode(target)) return false;
7236
- if (graph.hasEdge((0, import_types8.observedEdgeId)(source, target, type))) return false;
7237
- const key = (0, import_types8.frontierEdgeId)(source, target, type);
7328
+ if (graph.hasEdge((0, import_types9.observedEdgeId)(source, target, type))) return false;
7329
+ const key = (0, import_types9.frontierEdgeId)(source, target, type);
7238
7330
  if (graph.hasEdge(key)) return false;
7239
7331
  graph.addEdgeWithKey(key, source, target, {
7240
7332
  id: key,
7241
7333
  source,
7242
7334
  target,
7243
7335
  type,
7244
- provenance: import_types8.Provenance.FRONTIER
7336
+ provenance: import_types9.Provenance.FRONTIER
7245
7337
  });
7246
7338
  return true;
7247
7339
  }
@@ -7249,8 +7341,8 @@ function promoteFrontierEdges(graph) {
7249
7341
  const graduated = [];
7250
7342
  graph.forEachEdge((edgeId, attrs) => {
7251
7343
  const e = attrs;
7252
- if (e.provenance !== import_types8.Provenance.FRONTIER) return;
7253
- if (graph.hasEdge((0, import_types8.observedEdgeId)(e.source, e.target, e.type))) {
7344
+ if (e.provenance !== import_types9.Provenance.FRONTIER) return;
7345
+ if (graph.hasEdge((0, import_types9.observedEdgeId)(e.source, e.target, e.type))) {
7254
7346
  graduated.push(edgeId);
7255
7347
  }
7256
7348
  });
@@ -7271,7 +7363,7 @@ function rewireFrontierEdges(graph, frontierId2, serviceId17) {
7271
7363
  }
7272
7364
  function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
7273
7365
  graph.dropEdge(oldEdgeId);
7274
- const newId = edge.provenance === import_types8.Provenance.OBSERVED ? (0, import_types8.observedEdgeId)(newSource, newTarget, edge.type) : edge.provenance === import_types8.Provenance.INFERRED ? (0, import_types8.inferredEdgeId)(newSource, newTarget, edge.type) : (0, import_types8.extractedEdgeId)(newSource, newTarget, edge.type);
7366
+ const newId = edge.provenance === import_types9.Provenance.OBSERVED ? (0, import_types9.observedEdgeId)(newSource, newTarget, edge.type) : edge.provenance === import_types9.Provenance.INFERRED ? (0, import_types9.inferredEdgeId)(newSource, newTarget, edge.type) : (0, import_types9.extractedEdgeId)(newSource, newTarget, edge.type);
7275
7367
  if (graph.hasEdge(newId)) {
7276
7368
  const existing = graph.getEdgeAttributes(newId);
7277
7369
  const merged = {
@@ -7302,12 +7394,12 @@ async function markStaleEdges(graph, options = {}) {
7302
7394
  const project = options.project ?? DEFAULT_PROJECT;
7303
7395
  graph.forEachEdge((id, attrs) => {
7304
7396
  const e = attrs;
7305
- if (e.provenance !== import_types8.Provenance.OBSERVED) return;
7397
+ if (e.provenance !== import_types9.Provenance.OBSERVED) return;
7306
7398
  if (!e.lastObserved) return;
7307
7399
  const threshold = thresholdForEdgeType(e.type, thresholds);
7308
7400
  const age = now - new Date(e.lastObserved).getTime();
7309
7401
  if (age > threshold) {
7310
- const updated = { ...e, provenance: import_types8.Provenance.STALE, confidence: 0.3 };
7402
+ const updated = { ...e, provenance: import_types9.Provenance.STALE, confidence: 0.3 };
7311
7403
  graph.replaceEdgeAttributes(id, updated);
7312
7404
  events.push({
7313
7405
  edgeId: id,
@@ -7324,8 +7416,8 @@ async function markStaleEdges(graph, options = {}) {
7324
7416
  project,
7325
7417
  payload: {
7326
7418
  edgeId: id,
7327
- from: import_types8.Provenance.OBSERVED,
7328
- to: import_types8.Provenance.STALE
7419
+ from: import_types9.Provenance.OBSERVED,
7420
+ to: import_types9.Provenance.STALE
7329
7421
  }
7330
7422
  });
7331
7423
  }
@@ -7473,6 +7565,7 @@ function describeZodIssues(error) {
7473
7565
  return error.issues.map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
7474
7566
  }
7475
7567
  function mergeSnapshot(graph, snapshot) {
7568
+ invalidateSourceBaseline(graph);
7476
7569
  const exported = snapshot.graph;
7477
7570
  const incomingNodes = Array.isArray(exported.nodes) ? exported.nodes : [];
7478
7571
  const incomingEdges = Array.isArray(exported.edges) ? exported.edges : [];
@@ -7481,7 +7574,7 @@ function mergeSnapshot(graph, snapshot) {
7481
7574
  const validEdges = [];
7482
7575
  for (const node of incomingNodes) {
7483
7576
  if (node.attributes === void 0) continue;
7484
- const parsed = import_types8.GraphNodeSchema.safeParse(node.attributes);
7577
+ const parsed = import_types9.GraphNodeSchema.safeParse(node.attributes);
7485
7578
  if (!parsed.success) {
7486
7579
  issues.push(`node "${node.key}": ${describeZodIssues(parsed.error)}`);
7487
7580
  continue;
@@ -7490,7 +7583,7 @@ function mergeSnapshot(graph, snapshot) {
7490
7583
  }
7491
7584
  for (const edge of incomingEdges) {
7492
7585
  if (edge.attributes === void 0) continue;
7493
- const parsed = import_types8.GraphEdgeSchema.safeParse(edge.attributes);
7586
+ const parsed = import_types9.GraphEdgeSchema.safeParse(edge.attributes);
7494
7587
  if (!parsed.success) {
7495
7588
  const label = edge.key ?? `${edge.source}->${edge.target}`;
7496
7589
  issues.push(`edge "${label}": ${describeZodIssues(parsed.error)}`);
@@ -7524,7 +7617,7 @@ var import_node_fs20 = require("fs");
7524
7617
  var import_node_path22 = __toESM(require("path"), 1);
7525
7618
  var import_ignore2 = __toESM(require("ignore"), 1);
7526
7619
  var import_minimatch2 = require("minimatch");
7527
- var import_types18 = require("@neat.is/types");
7620
+ var import_types19 = require("@neat.is/types");
7528
7621
 
7529
7622
  // src/extract/python.ts
7530
7623
  init_cjs_shims();
@@ -7597,7 +7690,7 @@ function pythonToPackage(service) {
7597
7690
  init_cjs_shims();
7598
7691
  var import_node_fs11 = require("fs");
7599
7692
  var import_node_path12 = __toESM(require("path"), 1);
7600
- var import_types9 = require("@neat.is/types");
7693
+ var import_types10 = require("@neat.is/types");
7601
7694
  function parseGoMod(source) {
7602
7695
  const module2 = source.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
7603
7696
  if (!module2) return null;
@@ -7633,8 +7726,8 @@ async function discoverGoService(scanPath, dir) {
7633
7726
  const pkg = { name, dependencies: mod.dependencies };
7634
7727
  const framework = goFramework(mod.dependencies);
7635
7728
  const node = {
7636
- id: (0, import_types9.serviceId)(name),
7637
- type: import_types9.NodeType.ServiceNode,
7729
+ id: (0, import_types10.serviceId)(name),
7730
+ type: import_types10.NodeType.ServiceNode,
7638
7731
  name,
7639
7732
  language: "go",
7640
7733
  dependencies: mod.dependencies,
@@ -7648,7 +7741,7 @@ async function discoverGoService(scanPath, dir) {
7648
7741
  init_cjs_shims();
7649
7742
  var import_node_fs12 = require("fs");
7650
7743
  var import_node_path13 = __toESM(require("path"), 1);
7651
- var import_types10 = require("@neat.is/types");
7744
+ var import_types11 = require("@neat.is/types");
7652
7745
  function parseGemfile(source) {
7653
7746
  const dependencies = {};
7654
7747
  for (const raw of source.split(/\r?\n/)) {
@@ -7672,8 +7765,8 @@ async function discoverRubyService(scanPath, dir) {
7672
7765
  const name = import_node_path13.default.basename(dir);
7673
7766
  const pkg = { name, dependencies: gemfile.dependencies };
7674
7767
  const node = {
7675
- id: (0, import_types10.serviceId)(name),
7676
- type: import_types10.NodeType.ServiceNode,
7768
+ id: (0, import_types11.serviceId)(name),
7769
+ type: import_types11.NodeType.ServiceNode,
7677
7770
  name,
7678
7771
  language: "ruby",
7679
7772
  dependencies: gemfile.dependencies,
@@ -7686,7 +7779,7 @@ async function discoverRubyService(scanPath, dir) {
7686
7779
  // src/extract/php.ts
7687
7780
  init_cjs_shims();
7688
7781
  var import_node_path14 = __toESM(require("path"), 1);
7689
- var import_types11 = require("@neat.is/types");
7782
+ var import_types12 = require("@neat.is/types");
7690
7783
  function parseComposerJson(composer) {
7691
7784
  return {
7692
7785
  dependencies: {
@@ -7706,8 +7799,8 @@ async function discoverPhpService(scanPath, dir) {
7706
7799
  const name = import_node_path14.default.basename(dir);
7707
7800
  const pkg = { name, dependencies };
7708
7801
  const node = {
7709
- id: (0, import_types11.serviceId)(name),
7710
- type: import_types11.NodeType.ServiceNode,
7802
+ id: (0, import_types12.serviceId)(name),
7803
+ type: import_types12.NodeType.ServiceNode,
7711
7804
  name,
7712
7805
  language: "php",
7713
7806
  dependencies,
@@ -7721,7 +7814,7 @@ async function discoverPhpService(scanPath, dir) {
7721
7814
  init_cjs_shims();
7722
7815
  var import_node_fs13 = require("fs");
7723
7816
  var import_node_path15 = __toESM(require("path"), 1);
7724
- var import_types12 = require("@neat.is/types");
7817
+ var import_types13 = require("@neat.is/types");
7725
7818
  var CSHARP_PROJECT_EXTS = /* @__PURE__ */ new Set([".csproj", ".sln"]);
7726
7819
  async function projectFiles(dir) {
7727
7820
  const entries = await import_node_fs13.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
@@ -7768,8 +7861,8 @@ async function discoverCsharpService(scanPath, dir) {
7768
7861
  }
7769
7862
  const pkg = { name, dependencies };
7770
7863
  const node = {
7771
- id: (0, import_types12.serviceId)(name),
7772
- type: import_types12.NodeType.ServiceNode,
7864
+ id: (0, import_types13.serviceId)(name),
7865
+ type: import_types13.NodeType.ServiceNode,
7773
7866
  name,
7774
7867
  language: "csharp",
7775
7868
  dependencies,
@@ -7784,7 +7877,7 @@ async function discoverCsharpService(scanPath, dir) {
7784
7877
  init_cjs_shims();
7785
7878
  var import_node_fs14 = require("fs");
7786
7879
  var import_node_path16 = __toESM(require("path"), 1);
7787
- var import_types13 = require("@neat.is/types");
7880
+ var import_types14 = require("@neat.is/types");
7788
7881
  var JAVA_MANIFESTS = ["pom.xml", "build.gradle", "build.gradle.kts"];
7789
7882
  async function hasJavaManifest(dir) {
7790
7883
  for (const manifest of JAVA_MANIFESTS) {
@@ -7839,8 +7932,8 @@ async function discoverJavaService(scanPath, dir) {
7839
7932
  const dependencies = manifest.dependencies;
7840
7933
  const pkg = { name, dependencies };
7841
7934
  const node = {
7842
- id: (0, import_types13.serviceId)(name),
7843
- type: import_types13.NodeType.ServiceNode,
7935
+ id: (0, import_types14.serviceId)(name),
7936
+ type: import_types14.NodeType.ServiceNode,
7844
7937
  name,
7845
7938
  language: "java",
7846
7939
  dependencies,
@@ -7853,7 +7946,7 @@ async function discoverJavaService(scanPath, dir) {
7853
7946
  init_cjs_shims();
7854
7947
  var import_node_fs15 = require("fs");
7855
7948
  var import_node_path17 = __toESM(require("path"), 1);
7856
- var import_types14 = require("@neat.is/types");
7949
+ var import_types15 = require("@neat.is/types");
7857
7950
  var KOTLIN_SOURCE_EXT = ".kt";
7858
7951
  var JAVA_SOURCE_EXT = ".java";
7859
7952
  var SOURCE_PROBE_MAX_DEPTH = 8;
@@ -7904,8 +7997,8 @@ async function discoverKotlinService(scanPath, dir) {
7904
7997
  const dependencies = manifest.dependencies;
7905
7998
  const pkg = { name, dependencies };
7906
7999
  const node = {
7907
- id: (0, import_types14.serviceId)(name),
7908
- type: import_types14.NodeType.ServiceNode,
8000
+ id: (0, import_types15.serviceId)(name),
8001
+ type: import_types15.NodeType.ServiceNode,
7909
8002
  name,
7910
8003
  language: "kotlin",
7911
8004
  dependencies,
@@ -7919,7 +8012,7 @@ init_cjs_shims();
7919
8012
  var import_node_fs16 = require("fs");
7920
8013
  var import_node_path18 = __toESM(require("path"), 1);
7921
8014
  var import_smol_toml2 = require("smol-toml");
7922
- var import_types15 = require("@neat.is/types");
8015
+ var import_types16 = require("@neat.is/types");
7923
8016
  var CARGO_MANIFEST = "Cargo.toml";
7924
8017
  async function hasRustManifest(dir) {
7925
8018
  return exists(import_node_path18.default.join(dir, CARGO_MANIFEST));
@@ -7954,8 +8047,8 @@ async function discoverRustService(scanPath, dir) {
7954
8047
  const dependencies = manifest.dependencies;
7955
8048
  const pkg = { name, dependencies };
7956
8049
  const node = {
7957
- id: (0, import_types15.serviceId)(name),
7958
- type: import_types15.NodeType.ServiceNode,
8050
+ id: (0, import_types16.serviceId)(name),
8051
+ type: import_types16.NodeType.ServiceNode,
7959
8052
  name,
7960
8053
  language: "rust",
7961
8054
  dependencies,
@@ -7968,7 +8061,7 @@ async function discoverRustService(scanPath, dir) {
7968
8061
  init_cjs_shims();
7969
8062
  var import_node_fs17 = require("fs");
7970
8063
  var import_node_path19 = __toESM(require("path"), 1);
7971
- var import_types16 = require("@neat.is/types");
8064
+ var import_types17 = require("@neat.is/types");
7972
8065
  var CMAKE_MANIFEST = "CMakeLists.txt";
7973
8066
  async function hasCppManifest(dir) {
7974
8067
  return exists(import_node_path19.default.join(dir, CMAKE_MANIFEST));
@@ -7986,8 +8079,8 @@ async function discoverCppService(scanPath, dir) {
7986
8079
  const dependencies = {};
7987
8080
  const pkg = { name, dependencies };
7988
8081
  const node = {
7989
- id: (0, import_types16.serviceId)(name),
7990
- type: import_types16.NodeType.ServiceNode,
8082
+ id: (0, import_types17.serviceId)(name),
8083
+ type: import_types17.NodeType.ServiceNode,
7991
8084
  name,
7992
8085
  language: "cpp",
7993
8086
  dependencies,
@@ -8000,7 +8093,7 @@ async function discoverCppService(scanPath, dir) {
8000
8093
  init_cjs_shims();
8001
8094
  var import_node_fs18 = require("fs");
8002
8095
  var import_node_path20 = __toESM(require("path"), 1);
8003
- var import_types17 = require("@neat.is/types");
8096
+ var import_types18 = require("@neat.is/types");
8004
8097
  function languageForSourceExt(ext) {
8005
8098
  switch (ext) {
8006
8099
  case ".py":
@@ -8086,8 +8179,8 @@ async function discoverDockerfileService(scanPath, dir) {
8086
8179
  const name = import_node_path20.default.basename(dir);
8087
8180
  const pkg = { name, dependencies: {} };
8088
8181
  const node = {
8089
- id: (0, import_types17.serviceId)(name),
8090
- type: import_types17.NodeType.ServiceNode,
8182
+ id: (0, import_types18.serviceId)(name),
8183
+ type: import_types18.NodeType.ServiceNode,
8091
8184
  name,
8092
8185
  language,
8093
8186
  dependencies: {},
@@ -8281,8 +8374,8 @@ async function discoverNodeService(scanPath, dir) {
8281
8374
  const framework = detectJsFramework(pkg);
8282
8375
  const language = await detectJsServiceLanguage(dir, pkg);
8283
8376
  const node = {
8284
- id: (0, import_types18.serviceId)(pkg.name),
8285
- type: import_types18.NodeType.ServiceNode,
8377
+ id: (0, import_types19.serviceId)(pkg.name),
8378
+ type: import_types19.NodeType.ServiceNode,
8286
8379
  name: pkg.name,
8287
8380
  language,
8288
8381
  version: pkg.version,
@@ -8298,8 +8391,8 @@ async function discoverPyService(scanPath, dir) {
8298
8391
  if (!py) return null;
8299
8392
  const pkg = pythonToPackage(py);
8300
8393
  const node = {
8301
- id: (0, import_types18.serviceId)(py.name),
8302
- type: import_types18.NodeType.ServiceNode,
8394
+ id: (0, import_types19.serviceId)(py.name),
8395
+ type: import_types19.NodeType.ServiceNode,
8303
8396
  name: py.name,
8304
8397
  language: "python",
8305
8398
  version: py.version,
@@ -8418,7 +8511,7 @@ init_cjs_shims();
8418
8511
  var import_node_path23 = __toESM(require("path"), 1);
8419
8512
  var import_node_fs21 = require("fs");
8420
8513
  var import_yaml2 = require("yaml");
8421
- var import_types19 = require("@neat.is/types");
8514
+ var import_types20 = require("@neat.is/types");
8422
8515
  var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
8423
8516
  "Service",
8424
8517
  "Deployment",
@@ -8428,7 +8521,7 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
8428
8521
  function addAliases(graph, serviceId17, candidates) {
8429
8522
  if (!graph.hasNode(serviceId17)) return;
8430
8523
  const node = graph.getNodeAttributes(serviceId17);
8431
- if (node.type !== import_types19.NodeType.ServiceNode) return;
8524
+ if (node.type !== import_types20.NodeType.ServiceNode) return;
8432
8525
  const set = new Set(node.aliases ?? []);
8433
8526
  for (const c of candidates) {
8434
8527
  if (!c) continue;
@@ -8618,7 +8711,7 @@ var import_tree_sitter_java = __toESM(require("tree-sitter-java"), 1);
8618
8711
  var import_tree_sitter_kotlin = __toESM(require("tree-sitter-kotlin"), 1);
8619
8712
  var import_tree_sitter_rust2 = __toESM(require("tree-sitter-rust"), 1);
8620
8713
  var import_tree_sitter_cpp = __toESM(require("tree-sitter-cpp"), 1);
8621
- var import_types20 = require("@neat.is/types");
8714
+ var import_types21 = require("@neat.is/types");
8622
8715
  var PARSE_CHUNK3 = 16384;
8623
8716
  var GRAMMAR_BY_EXT = {
8624
8717
  ".ts": import_tree_sitter_typescript.default.typescript,
@@ -8671,7 +8764,9 @@ function collectSymbolDefs(root) {
8671
8764
  kind,
8672
8765
  qualname,
8673
8766
  startLine: node.startPosition.row + 1,
8674
- endLine: node.endPosition.row + 1
8767
+ endLine: node.endPosition.row + 1,
8768
+ startIndex: node.startIndex,
8769
+ endIndex: node.endIndex
8675
8770
  });
8676
8771
  };
8677
8772
  const visit = (node, classCtx) => {
@@ -8730,7 +8825,9 @@ function collectPythonSymbolDefs(root) {
8730
8825
  kind,
8731
8826
  qualname,
8732
8827
  startLine: node.startPosition.row + 1,
8733
- endLine: node.endPosition.row + 1
8828
+ endLine: node.endPosition.row + 1,
8829
+ startIndex: node.startIndex,
8830
+ endIndex: node.endIndex
8734
8831
  });
8735
8832
  };
8736
8833
  const visit = (node, classCtx) => {
@@ -8803,7 +8900,9 @@ function collectGoSymbolDefs(root) {
8803
8900
  kind,
8804
8901
  qualname,
8805
8902
  startLine: node.startPosition.row + 1,
8806
- endLine: node.endPosition.row + 1
8903
+ endLine: node.endPosition.row + 1,
8904
+ startIndex: node.startIndex,
8905
+ endIndex: node.endIndex
8807
8906
  });
8808
8907
  };
8809
8908
  const visit = (node) => {
@@ -8837,7 +8936,9 @@ function collectRubySymbolDefs(root) {
8837
8936
  kind,
8838
8937
  qualname,
8839
8938
  startLine: node.startPosition.row + 1,
8840
- endLine: node.endPosition.row + 1
8939
+ endLine: node.endPosition.row + 1,
8940
+ startIndex: node.startIndex,
8941
+ endIndex: node.endIndex
8841
8942
  });
8842
8943
  };
8843
8944
  const nameText = (node) => node.childForFieldName("name")?.text.replace(/::/g, ".");
@@ -8888,7 +8989,9 @@ function collectPhpSymbolDefs(root) {
8888
8989
  kind,
8889
8990
  qualname,
8890
8991
  startLine: node.startPosition.row + 1,
8891
- endLine: node.endPosition.row + 1
8992
+ endLine: node.endPosition.row + 1,
8993
+ startIndex: node.startIndex,
8994
+ endIndex: node.endIndex
8892
8995
  });
8893
8996
  };
8894
8997
  const dot = (s) => s.replace(/\\/g, ".").replace(/::/g, ".").replace(/^\.+/, "");
@@ -8954,7 +9057,9 @@ function collectCsharpSymbolDefs(root) {
8954
9057
  kind,
8955
9058
  qualname,
8956
9059
  startLine: node.startPosition.row + 1,
8957
- endLine: node.endPosition.row + 1
9060
+ endLine: node.endPosition.row + 1,
9061
+ startIndex: node.startIndex,
9062
+ endIndex: node.endIndex
8958
9063
  });
8959
9064
  };
8960
9065
  const join2 = (prefix, name) => prefix ? `${prefix}.${name}` : name;
@@ -9016,7 +9121,9 @@ function collectJavaSymbolDefs(root) {
9016
9121
  kind,
9017
9122
  qualname,
9018
9123
  startLine: node.startPosition.row + 1,
9019
- endLine: node.endPosition.row + 1
9124
+ endLine: node.endPosition.row + 1,
9125
+ startIndex: node.startIndex,
9126
+ endIndex: node.endIndex
9020
9127
  });
9021
9128
  };
9022
9129
  const join2 = (prefix, name) => prefix ? `${prefix}.${name}` : name;
@@ -9073,7 +9180,9 @@ function collectKotlinSymbolDefs(root) {
9073
9180
  kind,
9074
9181
  qualname,
9075
9182
  startLine: node.startPosition.row + 1,
9076
- endLine: node.endPosition.row + 1
9183
+ endLine: node.endPosition.row + 1,
9184
+ startIndex: node.startIndex,
9185
+ endIndex: node.endIndex
9077
9186
  });
9078
9187
  };
9079
9188
  const join2 = (prefix, name) => prefix ? `${prefix}.${name}` : name;
@@ -9143,7 +9252,9 @@ function collectRustSymbolDefs(root) {
9143
9252
  kind,
9144
9253
  qualname,
9145
9254
  startLine: node.startPosition.row + 1,
9146
- endLine: node.endPosition.row + 1
9255
+ endLine: node.endPosition.row + 1,
9256
+ startIndex: node.startIndex,
9257
+ endIndex: node.endIndex
9147
9258
  });
9148
9259
  };
9149
9260
  const join2 = (prefix, name) => prefix ? `${prefix}::${name}` : name;
@@ -9211,7 +9322,9 @@ function collectCppSymbolDefs(root) {
9211
9322
  kind,
9212
9323
  qualname,
9213
9324
  startLine: node.startPosition.row + 1,
9214
- endLine: node.endPosition.row + 1
9325
+ endLine: node.endPosition.row + 1,
9326
+ startIndex: node.startIndex,
9327
+ endIndex: node.endIndex
9215
9328
  });
9216
9329
  };
9217
9330
  const join2 = (prefix, name) => prefix ? `${prefix}::${name}` : name;
@@ -9339,6 +9452,22 @@ function disambiguate(defs) {
9339
9452
  return { def, disambiguator: ordinal };
9340
9453
  });
9341
9454
  }
9455
+ function utf8Offsets(content, defs) {
9456
+ if (content.includes("\uFFFD")) return /* @__PURE__ */ new Map();
9457
+ const indices = [...new Set(defs.flatMap(({ startIndex, endIndex }) => [startIndex, endIndex]))].sort(
9458
+ (a, b) => a - b
9459
+ );
9460
+ const offsets = /* @__PURE__ */ new Map();
9461
+ let cursor = 0;
9462
+ let bytes = 0;
9463
+ for (const index of indices) {
9464
+ if (index < cursor || index > content.length) return /* @__PURE__ */ new Map();
9465
+ bytes += Buffer.byteLength(content.slice(cursor, index), "utf8");
9466
+ offsets.set(index, bytes);
9467
+ cursor = index;
9468
+ }
9469
+ return offsets;
9470
+ }
9342
9471
  async function addSymbols(graph, services) {
9343
9472
  const parsers = /* @__PURE__ */ new Map();
9344
9473
  const parserForExt5 = (ext) => {
@@ -9362,47 +9491,59 @@ async function addSymbols(graph, services) {
9362
9491
  if (!parser) continue;
9363
9492
  const relPath = toPosix(import_node_path25.default.relative(service.dir, file.path));
9364
9493
  let defs;
9494
+ let completeParse;
9365
9495
  try {
9366
9496
  const tree = parseSource3(parser, file.content);
9367
9497
  defs = collectSymbolDefsForExt(ext, tree.rootNode);
9498
+ completeParse = !tree.rootNode.hasError;
9368
9499
  } catch (err) {
9369
9500
  recordExtractionError("symbol extraction", file.path, err);
9370
9501
  continue;
9371
9502
  }
9372
9503
  if (defs.length === 0) continue;
9373
- const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9374
- graph,
9375
- service.pkg.name,
9376
- service.node.id,
9377
- relPath
9378
- );
9504
+ const offsets = completeParse ? utf8Offsets(file.content, defs) : /* @__PURE__ */ new Map();
9505
+ const {
9506
+ fileNodeId,
9507
+ nodesAdded: fn,
9508
+ edgesAdded: fe
9509
+ } = ensureFileNode(graph, service.pkg.name, service.node.id, relPath);
9379
9510
  nodesAdded += fn;
9380
9511
  edgesAdded += fe;
9381
9512
  for (const { def, disambiguator } of disambiguate(defs)) {
9382
- const sid = (0, import_types20.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
9513
+ const sid = (0, import_types21.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
9514
+ const startByte = offsets.get(def.startIndex);
9515
+ const endByte = offsets.get(def.endIndex);
9516
+ const precise = startByte !== void 0 && endByte !== void 0 && endByte > startByte ? { startByte, endByte } : {};
9517
+ const node = {
9518
+ id: sid,
9519
+ type: import_types21.NodeType.SymbolNode,
9520
+ kind: def.kind,
9521
+ qualname: def.qualname,
9522
+ span: { startLine: def.startLine, endLine: def.endLine, ...precise },
9523
+ service: service.pkg.name,
9524
+ relPath,
9525
+ discoveredVia: "static"
9526
+ };
9383
9527
  if (!graph.hasNode(sid)) {
9384
- const node = {
9385
- id: sid,
9386
- type: import_types20.NodeType.SymbolNode,
9387
- kind: def.kind,
9388
- qualname: def.qualname,
9389
- span: { startLine: def.startLine, endLine: def.endLine },
9390
- service: service.pkg.name,
9391
- relPath,
9392
- discoveredVia: "static"
9393
- };
9394
9528
  graph.addNode(sid, node);
9395
9529
  nodesAdded++;
9530
+ } else {
9531
+ const previous = graph.getNodeAttributes(sid);
9532
+ const discoveredVia = previous.discoveredVia === "otel" || previous.discoveredVia === "merged" ? "merged" : "static";
9533
+ const moved = previous.span.startLine !== node.span.startLine || previous.span.endLine !== node.span.endLine || previous.span.startByte !== node.span.startByte || previous.span.endByte !== node.span.endByte;
9534
+ if (moved || previous.kind !== node.kind || previous.qualname !== node.qualname || previous.discoveredVia !== discoveredVia || previous.service !== node.service || previous.relPath !== node.relPath) {
9535
+ graph.replaceNodeAttributes(sid, { ...previous, ...node, discoveredVia });
9536
+ }
9396
9537
  }
9397
- const containsId = (0, import_types20.extractedEdgeId)(fileNodeId, sid, import_types20.EdgeType.CONTAINS);
9538
+ const containsId = (0, import_types21.extractedEdgeId)(fileNodeId, sid, import_types21.EdgeType.CONTAINS);
9398
9539
  if (!graph.hasEdge(containsId)) {
9399
9540
  const edge = {
9400
9541
  id: containsId,
9401
9542
  source: fileNodeId,
9402
9543
  target: sid,
9403
- type: import_types20.EdgeType.CONTAINS,
9404
- provenance: import_types20.Provenance.EXTRACTED,
9405
- confidence: (0, import_types20.confidenceForExtracted)("structural"),
9544
+ type: import_types21.EdgeType.CONTAINS,
9545
+ provenance: import_types21.Provenance.EXTRACTED,
9546
+ confidence: (0, import_types21.confidenceForExtracted)("structural"),
9406
9547
  evidence: {
9407
9548
  file: relPath,
9408
9549
  line: def.startLine,
@@ -9422,7 +9563,7 @@ async function addSymbols(graph, services) {
9422
9563
  init_cjs_shims();
9423
9564
  var import_node_path26 = __toESM(require("path"), 1);
9424
9565
  var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
9425
- var import_types21 = require("@neat.is/types");
9566
+ var import_types22 = require("@neat.is/types");
9426
9567
  function extendsInfo(classHeritage) {
9427
9568
  for (let i = 0; i < classHeritage.namedChildCount; i++) {
9428
9569
  const child = classHeritage.namedChild(i);
@@ -9540,7 +9681,7 @@ async function addSymbolEdges(graph, services) {
9540
9681
  }
9541
9682
  const disambiguated = disambiguate(collectSymbolDefs(root));
9542
9683
  const locals = disambiguated.map(({ def, disambiguator }) => ({
9543
- sid: (0, import_types21.symbolId)(serviceName, relPath, def.qualname, disambiguator),
9684
+ sid: (0, import_types22.symbolId)(serviceName, relPath, def.qualname, disambiguator),
9544
9685
  qualname: def.qualname,
9545
9686
  kind: def.kind,
9546
9687
  startLine: def.startLine,
@@ -9569,10 +9710,10 @@ async function addSymbolEdges(graph, services) {
9569
9710
  if (local) return local.kind === wantKind ? local.sid : null;
9570
9711
  const imp = resolvedImports.get(name);
9571
9712
  if (imp) {
9572
- const candidate = (0, import_types21.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
9713
+ const candidate = (0, import_types22.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
9573
9714
  if (graph.hasNode(candidate)) {
9574
9715
  const node = graph.getNodeAttributes(candidate);
9575
- if (node.type === import_types21.NodeType.SymbolNode && node.kind === wantKind) return candidate;
9716
+ if (node.type === import_types22.NodeType.SymbolNode && node.kind === wantKind) return candidate;
9576
9717
  }
9577
9718
  }
9578
9719
  return null;
@@ -9599,7 +9740,7 @@ async function addSymbolEdges(graph, services) {
9599
9740
  sourceSid: self.sid,
9600
9741
  targetName: ext.name,
9601
9742
  wantKind: "class",
9602
- edgeType: import_types21.EdgeType.INHERITS,
9743
+ edgeType: import_types22.EdgeType.INHERITS,
9603
9744
  line: ext.line
9604
9745
  });
9605
9746
  }
@@ -9608,7 +9749,7 @@ async function addSymbolEdges(graph, services) {
9608
9749
  sourceSid: self.sid,
9609
9750
  targetName: impl.name,
9610
9751
  wantKind: "class",
9611
- edgeType: import_types21.EdgeType.IMPLEMENTS,
9752
+ edgeType: import_types22.EdgeType.IMPLEMENTS,
9612
9753
  line: impl.line
9613
9754
  });
9614
9755
  }
@@ -9624,7 +9765,7 @@ async function addSymbolEdges(graph, services) {
9624
9765
  sourceSid: caller.sid,
9625
9766
  targetName: fn.text,
9626
9767
  wantKind: "function",
9627
- edgeType: import_types21.EdgeType.CALLS,
9768
+ edgeType: import_types22.EdgeType.CALLS,
9628
9769
  line
9629
9770
  });
9630
9771
  }
@@ -9640,15 +9781,15 @@ async function addSymbolEdges(graph, services) {
9640
9781
  const targetSid = resolveTarget(req2.targetName, req2.wantKind);
9641
9782
  if (!targetSid) continue;
9642
9783
  if (targetSid === req2.sourceSid) continue;
9643
- const edgeId = (0, import_types21.extractedEdgeId)(req2.sourceSid, targetSid, req2.edgeType);
9784
+ const edgeId = (0, import_types22.extractedEdgeId)(req2.sourceSid, targetSid, req2.edgeType);
9644
9785
  if (graph.hasEdge(edgeId)) continue;
9645
9786
  const edge = {
9646
9787
  id: edgeId,
9647
9788
  source: req2.sourceSid,
9648
9789
  target: targetSid,
9649
9790
  type: req2.edgeType,
9650
- provenance: import_types21.Provenance.EXTRACTED,
9651
- confidence: (0, import_types21.confidenceForExtracted)("structural"),
9791
+ provenance: import_types22.Provenance.EXTRACTED,
9792
+ confidence: (0, import_types22.confidenceForExtracted)("structural"),
9652
9793
  evidence: {
9653
9794
  file: relPath,
9654
9795
  line: req2.line,
@@ -9667,7 +9808,7 @@ async function addSymbolEdges(graph, services) {
9667
9808
  init_cjs_shims();
9668
9809
  var import_node_path27 = __toESM(require("path"), 1);
9669
9810
  var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
9670
- var import_types22 = require("@neat.is/types");
9811
+ var import_types23 = require("@neat.is/types");
9671
9812
  function stringLiteralText2(node) {
9672
9813
  for (let i = 0; i < node.childCount; i++) {
9673
9814
  const child = node.child(i);
@@ -9837,11 +9978,11 @@ async function addServerActions(graph, services) {
9837
9978
  nodesAdded += fn;
9838
9979
  edgesAdded += fe;
9839
9980
  for (const action of actions) {
9840
- const aid = (0, import_types22.serverActionId)(service.pkg.name, relPath, action.exportName);
9981
+ const aid = (0, import_types23.serverActionId)(service.pkg.name, relPath, action.exportName);
9841
9982
  if (!graph.hasNode(aid)) {
9842
9983
  const node = {
9843
9984
  id: aid,
9844
- type: import_types22.NodeType.ServerActionNode,
9985
+ type: import_types23.NodeType.ServerActionNode,
9845
9986
  name: action.exportName,
9846
9987
  service: service.pkg.name,
9847
9988
  module: relPath,
@@ -9853,15 +9994,15 @@ async function addServerActions(graph, services) {
9853
9994
  graph.addNode(aid, node);
9854
9995
  nodesAdded++;
9855
9996
  }
9856
- const containsId = (0, import_types22.extractedEdgeId)(fileNodeId, aid, import_types22.EdgeType.CONTAINS);
9997
+ const containsId = (0, import_types23.extractedEdgeId)(fileNodeId, aid, import_types23.EdgeType.CONTAINS);
9857
9998
  if (!graph.hasEdge(containsId)) {
9858
9999
  const edge = {
9859
10000
  id: containsId,
9860
10001
  source: fileNodeId,
9861
10002
  target: aid,
9862
- type: import_types22.EdgeType.CONTAINS,
9863
- provenance: import_types22.Provenance.EXTRACTED,
9864
- confidence: (0, import_types22.confidenceForExtracted)("structural"),
10003
+ type: import_types23.EdgeType.CONTAINS,
10004
+ provenance: import_types23.Provenance.EXTRACTED,
10005
+ confidence: (0, import_types23.confidenceForExtracted)("structural"),
9865
10006
  evidence: {
9866
10007
  file: relPath,
9867
10008
  line: action.line,
@@ -9891,7 +10032,7 @@ async function addServerActions(graph, services) {
9891
10032
  for (const [local, binding] of bindings) {
9892
10033
  const target = await resolveJsImport(binding.specifier, fileDir, service.dir, tsPaths);
9893
10034
  if (!target) continue;
9894
- const aid = (0, import_types22.serverActionId)(service.pkg.name, target, binding.importedName);
10035
+ const aid = (0, import_types23.serverActionId)(service.pkg.name, target, binding.importedName);
9895
10036
  if (graph.hasNode(aid)) actionBindings.set(local, aid);
9896
10037
  }
9897
10038
  if (actionBindings.size === 0) continue;
@@ -9906,15 +10047,15 @@ async function addServerActions(graph, services) {
9906
10047
  nodesAdded += ensured.nodesAdded;
9907
10048
  edgesAdded += ensured.edgesAdded;
9908
10049
  }
9909
- const callsId = (0, import_types22.extractedEdgeId)(clientFileId, aid, import_types22.EdgeType.CALLS);
10050
+ const callsId = (0, import_types23.extractedEdgeId)(clientFileId, aid, import_types23.EdgeType.CALLS);
9910
10051
  if (graph.hasEdge(callsId)) continue;
9911
10052
  const edge = {
9912
10053
  id: callsId,
9913
10054
  source: clientFileId,
9914
10055
  target: aid,
9915
- type: import_types22.EdgeType.CALLS,
9916
- provenance: import_types22.Provenance.EXTRACTED,
9917
- confidence: (0, import_types22.confidenceForExtracted)("structural"),
10056
+ type: import_types23.EdgeType.CALLS,
10057
+ provenance: import_types23.Provenance.EXTRACTED,
10058
+ confidence: (0, import_types23.confidenceForExtracted)("structural"),
9918
10059
  evidence: {
9919
10060
  file: relPath,
9920
10061
  line,
@@ -9932,7 +10073,7 @@ async function addServerActions(graph, services) {
9932
10073
  // src/extract/databases/index.ts
9933
10074
  init_cjs_shims();
9934
10075
  var import_node_path36 = __toESM(require("path"), 1);
9935
- var import_types23 = require("@neat.is/types");
10076
+ var import_types24 = require("@neat.is/types");
9936
10077
 
9937
10078
  // src/extract/databases/db-config-yaml.ts
9938
10079
  init_cjs_shims();
@@ -10591,8 +10732,8 @@ function compatibleDriversFor(engine) {
10591
10732
  }
10592
10733
  function toDatabaseNode(config) {
10593
10734
  return {
10594
- id: (0, import_types23.databaseId)(config.host),
10595
- type: import_types23.NodeType.DatabaseNode,
10735
+ id: (0, import_types24.databaseId)(config.host),
10736
+ type: import_types24.NodeType.DatabaseNode,
10596
10737
  name: config.database || config.host,
10597
10738
  engine: config.engine,
10598
10739
  engineVersion: config.engineVersion,
@@ -10733,12 +10874,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
10733
10874
  edgesAdded += fe;
10734
10875
  const evidenceFile = toPosix(import_node_path36.default.relative(scanPath, config.sourceFile));
10735
10876
  const edge = {
10736
- id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types23.EdgeType.CONNECTS_TO),
10877
+ id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types24.EdgeType.CONNECTS_TO),
10737
10878
  source: fileNodeId,
10738
10879
  target: dbNode.id,
10739
- type: import_types23.EdgeType.CONNECTS_TO,
10740
- provenance: import_types23.Provenance.EXTRACTED,
10741
- confidence: (0, import_types23.confidenceForExtracted)("structural"),
10880
+ type: import_types24.EdgeType.CONNECTS_TO,
10881
+ provenance: import_types24.Provenance.EXTRACTED,
10882
+ confidence: (0, import_types24.confidenceForExtracted)("structural"),
10742
10883
  // Carry how the host was recovered (ADR-213) so the divergence ranker
10743
10884
  // can tell a real declared store from a hardcoded fault-injection /
10744
10885
  // flag-gated probe. Only set when the parser distinguished the two.
@@ -10753,11 +10894,11 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
10753
10894
  const primary = allConfigs[0];
10754
10895
  service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
10755
10896
  const relPath = import_node_path36.default.relative(scanPath, primary.sourceFile);
10756
- const cfgId = (0, import_types23.configId)(relPath);
10897
+ const cfgId = (0, import_types24.configId)(relPath);
10757
10898
  if (!graph.hasNode(cfgId)) {
10758
10899
  const cfgNode = {
10759
10900
  id: cfgId,
10760
- type: import_types23.NodeType.ConfigNode,
10901
+ type: import_types24.NodeType.ConfigNode,
10761
10902
  name: import_node_path36.default.basename(primary.sourceFile),
10762
10903
  path: relPath,
10763
10904
  fileType: isConfigFile(import_node_path36.default.basename(primary.sourceFile)).fileType || "config"
@@ -10766,12 +10907,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
10766
10907
  nodesAdded++;
10767
10908
  }
10768
10909
  const cfgEdge = {
10769
- id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types23.EdgeType.CONFIGURED_BY),
10910
+ id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types24.EdgeType.CONFIGURED_BY),
10770
10911
  source: service.node.id,
10771
10912
  target: cfgId,
10772
- type: import_types23.EdgeType.CONFIGURED_BY,
10773
- provenance: import_types23.Provenance.EXTRACTED,
10774
- confidence: (0, import_types23.confidenceForExtracted)("structural"),
10913
+ type: import_types24.EdgeType.CONFIGURED_BY,
10914
+ provenance: import_types24.Provenance.EXTRACTED,
10915
+ confidence: (0, import_types24.confidenceForExtracted)("structural"),
10775
10916
  evidence: { file: toPosix(relPath) }
10776
10917
  };
10777
10918
  if (!graph.hasEdge(cfgEdge.id)) {
@@ -10803,7 +10944,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
10803
10944
  init_cjs_shims();
10804
10945
  var import_node_fs25 = require("fs");
10805
10946
  var import_node_path37 = __toESM(require("path"), 1);
10806
- var import_types24 = require("@neat.is/types");
10947
+ var import_types25 = require("@neat.is/types");
10807
10948
  async function walkConfigFiles(dir, excludeDirs = []) {
10808
10949
  const excluded = new Set(excludeDirs.map((d) => import_node_path37.default.resolve(d)));
10809
10950
  const out = [];
@@ -10832,8 +10973,8 @@ async function addConfigNodes(graph, services, scanPath) {
10832
10973
  for (const file of configFiles) {
10833
10974
  const relPath = import_node_path37.default.relative(scanPath, file);
10834
10975
  const node = {
10835
- id: (0, import_types24.configId)(relPath),
10836
- type: import_types24.NodeType.ConfigNode,
10976
+ id: (0, import_types25.configId)(relPath),
10977
+ type: import_types25.NodeType.ConfigNode,
10837
10978
  name: import_node_path37.default.basename(file),
10838
10979
  path: relPath,
10839
10980
  fileType: isConfigFile(import_node_path37.default.basename(file)).fileType
@@ -10852,12 +10993,12 @@ async function addConfigNodes(graph, services, scanPath) {
10852
10993
  nodesAdded += fn;
10853
10994
  edgesAdded += fe;
10854
10995
  const edge = {
10855
- id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types24.EdgeType.CONFIGURED_BY),
10996
+ id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types25.EdgeType.CONFIGURED_BY),
10856
10997
  source: fileNodeId,
10857
10998
  target: node.id,
10858
- type: import_types24.EdgeType.CONFIGURED_BY,
10859
- provenance: import_types24.Provenance.EXTRACTED,
10860
- confidence: (0, import_types24.confidenceForExtracted)("structural"),
10999
+ type: import_types25.EdgeType.CONFIGURED_BY,
11000
+ provenance: import_types25.Provenance.EXTRACTED,
11001
+ confidence: (0, import_types25.confidenceForExtracted)("structural"),
10861
11002
  evidence: { file: relPath.split(import_node_path37.default.sep).join("/") }
10862
11003
  };
10863
11004
  if (!graph.hasEdge(edge.id)) {
@@ -10873,7 +11014,7 @@ async function addConfigNodes(graph, services, scanPath) {
10873
11014
  init_cjs_shims();
10874
11015
  var import_node_fs26 = require("fs");
10875
11016
  var import_node_path38 = __toESM(require("path"), 1);
10876
- var import_types25 = require("@neat.is/types");
11017
+ var import_types26 = require("@neat.is/types");
10877
11018
  var PROTO_EXTENSION = ".proto";
10878
11019
  function packageOf(content) {
10879
11020
  const m = content.match(/^\s*package\s+([A-Za-z_][A-Za-z0-9_.]*)\s*;/m);
@@ -10953,11 +11094,11 @@ async function addGrpcMethods(graph, services) {
10953
11094
  }
10954
11095
  if (methods.length === 0) continue;
10955
11096
  for (const method of methods) {
10956
- const mid = (0, import_types25.grpcMethodId)(method.rpcService, method.rpcMethod);
11097
+ const mid = (0, import_types26.grpcMethodId)(method.rpcService, method.rpcMethod);
10957
11098
  if (!graph.hasNode(mid)) {
10958
11099
  const node = {
10959
11100
  id: mid,
10960
- type: import_types25.NodeType.GrpcMethodNode,
11101
+ type: import_types26.NodeType.GrpcMethodNode,
10961
11102
  name: `${method.rpcService}/${method.rpcMethod}`,
10962
11103
  rpcService: method.rpcService,
10963
11104
  rpcMethod: method.rpcMethod,
@@ -10968,15 +11109,15 @@ async function addGrpcMethods(graph, services) {
10968
11109
  graph.addNode(mid, node);
10969
11110
  nodesAdded++;
10970
11111
  }
10971
- const containsId = (0, import_types25.extractedEdgeId)(service.node.id, mid, import_types25.EdgeType.CONTAINS);
11112
+ const containsId = (0, import_types26.extractedEdgeId)(service.node.id, mid, import_types26.EdgeType.CONTAINS);
10972
11113
  if (!graph.hasEdge(containsId)) {
10973
11114
  const edge = {
10974
11115
  id: containsId,
10975
11116
  source: service.node.id,
10976
11117
  target: mid,
10977
- type: import_types25.EdgeType.CONTAINS,
10978
- provenance: import_types25.Provenance.EXTRACTED,
10979
- confidence: (0, import_types25.confidenceForExtracted)("structural"),
11118
+ type: import_types26.EdgeType.CONTAINS,
11119
+ provenance: import_types26.Provenance.EXTRACTED,
11120
+ confidence: (0, import_types26.confidenceForExtracted)("structural"),
10980
11121
  evidence: {
10981
11122
  file: relFile,
10982
11123
  line: method.line,
@@ -10994,7 +11135,7 @@ async function addGrpcMethods(graph, services) {
10994
11135
 
10995
11136
  // src/extract/calls/index.ts
10996
11137
  init_cjs_shims();
10997
- var import_types45 = require("@neat.is/types");
11138
+ var import_types46 = require("@neat.is/types");
10998
11139
 
10999
11140
  // src/extract/calls/http.ts
11000
11141
  init_cjs_shims();
@@ -11003,7 +11144,7 @@ var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
11003
11144
  var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
11004
11145
  var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
11005
11146
  var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
11006
- var import_types26 = require("@neat.is/types");
11147
+ var import_types27 = require("@neat.is/types");
11007
11148
  var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
11008
11149
  var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
11009
11150
  function isInsideJsxExternalLink(node) {
@@ -11097,7 +11238,7 @@ async function addHttpCallEdges(graph, services) {
11097
11238
  const dedupKey = `${relFile}|${targetId}`;
11098
11239
  if (seen.has(dedupKey)) continue;
11099
11240
  seen.add(dedupKey);
11100
- const confidence = (0, import_types26.confidenceForExtracted)("url-literal-service-target");
11241
+ const confidence = (0, import_types27.confidenceForExtracted)("url-literal-service-target");
11101
11242
  const ev = {
11102
11243
  file: relFile,
11103
11244
  line: site.line,
@@ -11111,25 +11252,25 @@ async function addHttpCallEdges(graph, services) {
11111
11252
  );
11112
11253
  nodesAdded += n;
11113
11254
  edgesAdded += e;
11114
- if (!(0, import_types26.passesExtractedFloor)(confidence)) {
11255
+ if (!(0, import_types27.passesExtractedFloor)(confidence)) {
11115
11256
  noteExtractedDropped({
11116
11257
  source: fileNodeId,
11117
11258
  target: targetId,
11118
- type: import_types26.EdgeType.CALLS,
11259
+ type: import_types27.EdgeType.CALLS,
11119
11260
  confidence,
11120
11261
  confidenceKind: "url-literal-service-target",
11121
11262
  evidence: ev
11122
11263
  });
11123
11264
  continue;
11124
11265
  }
11125
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types26.EdgeType.CALLS);
11266
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types27.EdgeType.CALLS);
11126
11267
  if (!graph.hasEdge(edgeId)) {
11127
11268
  const edge = {
11128
11269
  id: edgeId,
11129
11270
  source: fileNodeId,
11130
11271
  target: targetId,
11131
- type: import_types26.EdgeType.CALLS,
11132
- provenance: import_types26.Provenance.EXTRACTED,
11272
+ type: import_types27.EdgeType.CALLS,
11273
+ provenance: import_types27.Provenance.EXTRACTED,
11133
11274
  confidence,
11134
11275
  evidence: ev
11135
11276
  };
@@ -11147,7 +11288,7 @@ init_cjs_shims();
11147
11288
  var import_node_path40 = __toESM(require("path"), 1);
11148
11289
  var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
11149
11290
  var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
11150
- var import_types27 = require("@neat.is/types");
11291
+ var import_types28 = require("@neat.is/types");
11151
11292
  var PARSE_CHUNK5 = 16384;
11152
11293
  function parseSource5(parser, source) {
11153
11294
  return parser.parse(
@@ -11391,9 +11532,9 @@ function buildRouteIndex(graph) {
11391
11532
  const index = /* @__PURE__ */ new Map();
11392
11533
  graph.forEachNode((_id, attrs) => {
11393
11534
  const node = attrs;
11394
- if (node.type !== import_types27.NodeType.RouteNode) return;
11535
+ if (node.type !== import_types28.NodeType.RouteNode) return;
11395
11536
  const route = attrs;
11396
- const owner = (0, import_types27.serviceId)(route.service);
11537
+ const owner = (0, import_types28.serviceId)(route.service);
11397
11538
  const entry2 = {
11398
11539
  method: route.method.toUpperCase(),
11399
11540
  normalizedPath: normalizePathTemplate(route.pathTemplate),
@@ -11448,8 +11589,8 @@ async function addRouteCallEdges(graph, services) {
11448
11589
  noteExtractedDropped({
11449
11590
  source: fileNodeId2,
11450
11591
  target: "route:unresolved",
11451
- type: import_types27.EdgeType.CALLS,
11452
- confidence: (0, import_types27.confidenceForExtracted)("reconstructed-approximate"),
11592
+ type: import_types28.EdgeType.CALLS,
11593
+ confidence: (0, import_types28.confidenceForExtracted)("reconstructed-approximate"),
11453
11594
  confidenceKind: "reconstructed-approximate",
11454
11595
  evidence: {
11455
11596
  file: relFile,
@@ -11482,7 +11623,7 @@ async function addRouteCallEdges(graph, services) {
11482
11623
  edgesAdded += e;
11483
11624
  const anchored = pathHasLiteralAnchor(site.pathTemplate);
11484
11625
  const confidenceKind = site.approximate && !anchored ? "reconstructed-approximate" : "verified-call-site";
11485
- const confidence = (0, import_types27.confidenceForExtracted)(confidenceKind);
11626
+ const confidence = (0, import_types28.confidenceForExtracted)(confidenceKind);
11486
11627
  const ev = {
11487
11628
  file: relFile,
11488
11629
  line: site.line,
@@ -11491,25 +11632,25 @@ async function addRouteCallEdges(graph, services) {
11491
11632
  pathTemplate: site.pathTemplate,
11492
11633
  ...confidenceKind === "reconstructed-approximate" ? { approximate: true, reason: site.reason } : {}
11493
11634
  };
11494
- if (!(0, import_types27.passesExtractedFloor)(confidence)) {
11635
+ if (!(0, import_types28.passesExtractedFloor)(confidence)) {
11495
11636
  noteExtractedDropped({
11496
11637
  source: fileNodeId,
11497
11638
  target: match.routeNodeId,
11498
- type: import_types27.EdgeType.CALLS,
11639
+ type: import_types28.EdgeType.CALLS,
11499
11640
  confidence,
11500
11641
  confidenceKind,
11501
11642
  evidence: ev
11502
11643
  });
11503
11644
  continue;
11504
11645
  }
11505
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types27.EdgeType.CALLS);
11646
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types28.EdgeType.CALLS);
11506
11647
  if (!graph.hasEdge(edgeId)) {
11507
11648
  const edge = {
11508
11649
  id: edgeId,
11509
11650
  source: fileNodeId,
11510
11651
  target: match.routeNodeId,
11511
- type: import_types27.EdgeType.CALLS,
11512
- provenance: import_types27.Provenance.EXTRACTED,
11652
+ type: import_types28.EdgeType.CALLS,
11653
+ provenance: import_types28.Provenance.EXTRACTED,
11513
11654
  confidence,
11514
11655
  evidence: ev
11515
11656
  };
@@ -11525,7 +11666,7 @@ async function addRouteCallEdges(graph, services) {
11525
11666
  // src/extract/calls/kafka.ts
11526
11667
  init_cjs_shims();
11527
11668
  var import_node_path41 = __toESM(require("path"), 1);
11528
- var import_types28 = require("@neat.is/types");
11669
+ var import_types29 = require("@neat.is/types");
11529
11670
  var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
11530
11671
  var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
11531
11672
  var SARAMA_IMPORT_RE = /"[^"]*\/sarama"/;
@@ -11602,7 +11743,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
11602
11743
  seen.add(key);
11603
11744
  const line = anchor !== void 0 ? file.content.slice(0, anchor).split("\n").length : lineOf(file.content, topic);
11604
11745
  out.push({
11605
- infraId: (0, import_types28.infraId)("kafka-topic", topic),
11746
+ infraId: (0, import_types29.infraId)("kafka-topic", topic),
11606
11747
  name: topic,
11607
11748
  kind: "kafka-topic",
11608
11749
  edgeType,
@@ -11630,7 +11771,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
11630
11771
  // src/extract/calls/redis.ts
11631
11772
  init_cjs_shims();
11632
11773
  var import_node_path42 = __toESM(require("path"), 1);
11633
- var import_types29 = require("@neat.is/types");
11774
+ var import_types30 = require("@neat.is/types");
11634
11775
  var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
11635
11776
  function redisEndpointsFromFile(file, serviceDir) {
11636
11777
  const out = [];
@@ -11643,7 +11784,7 @@ function redisEndpointsFromFile(file, serviceDir) {
11643
11784
  seen.add(host);
11644
11785
  const line = lineOf(file.content, host);
11645
11786
  out.push({
11646
- infraId: (0, import_types29.infraId)("redis", host),
11787
+ infraId: (0, import_types30.infraId)("redis", host),
11647
11788
  name: host,
11648
11789
  kind: "redis",
11649
11790
  edgeType: "CALLS",
@@ -11664,7 +11805,7 @@ function redisEndpointsFromFile(file, serviceDir) {
11664
11805
  // src/extract/calls/aws.ts
11665
11806
  init_cjs_shims();
11666
11807
  var import_node_path43 = __toESM(require("path"), 1);
11667
- var import_types30 = require("@neat.is/types");
11808
+ var import_types31 = require("@neat.is/types");
11668
11809
  var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
11669
11810
  var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
11670
11811
  function hasMarker(text, markers) {
@@ -11688,7 +11829,7 @@ function awsEndpointsFromFile(file, serviceDir) {
11688
11829
  seen.add(key);
11689
11830
  const line = lineOf(file.content, name);
11690
11831
  out.push({
11691
- infraId: (0, import_types30.infraId)(kind, name),
11832
+ infraId: (0, import_types31.infraId)(kind, name),
11692
11833
  name,
11693
11834
  kind,
11694
11835
  edgeType: "CALLS",
@@ -11723,7 +11864,7 @@ function awsEndpointsFromFile(file, serviceDir) {
11723
11864
  // src/extract/calls/grpc.ts
11724
11865
  init_cjs_shims();
11725
11866
  var import_node_path44 = __toESM(require("path"), 1);
11726
- var import_types31 = require("@neat.is/types");
11867
+ var import_types32 = require("@neat.is/types");
11727
11868
  var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
11728
11869
  var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
11729
11870
  var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
@@ -11772,7 +11913,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
11772
11913
  const { kind } = classified;
11773
11914
  const line = lineOf(file.content, m[0]);
11774
11915
  out.push({
11775
- infraId: (0, import_types31.infraId)(kind, name),
11916
+ infraId: (0, import_types32.infraId)(kind, name),
11776
11917
  name,
11777
11918
  kind,
11778
11919
  edgeType: "CALLS",
@@ -11793,7 +11934,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
11793
11934
  // src/extract/calls/supabase.ts
11794
11935
  init_cjs_shims();
11795
11936
  var import_node_path45 = __toESM(require("path"), 1);
11796
- var import_types32 = require("@neat.is/types");
11937
+ var import_types33 = require("@neat.is/types");
11797
11938
  var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
11798
11939
  var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
11799
11940
  var SUPABASE_CLIENT_RE = /\b(createClient|createServerClient|createBrowserClient)\s*\(\s*(?:['"`]([^'"`]*)['"`])?/g;
@@ -11841,7 +11982,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
11841
11982
  seen.add(name);
11842
11983
  const line = lineOf(file.content, m[0]);
11843
11984
  out.push({
11844
- infraId: (0, import_types32.infraId)("supabase", name),
11985
+ infraId: (0, import_types33.infraId)("supabase", name),
11845
11986
  name,
11846
11987
  kind: "supabase",
11847
11988
  edgeType: "CALLS",
@@ -11872,7 +12013,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
11872
12013
  seen.add(key);
11873
12014
  const line = lineOf(file.content, am[0]);
11874
12015
  out.push({
11875
- infraId: (0, import_types32.infraId)(kind, resource),
12016
+ infraId: (0, import_types33.infraId)(kind, resource),
11876
12017
  name: resource,
11877
12018
  kind,
11878
12019
  edgeType: "CALLS",
@@ -11893,7 +12034,7 @@ init_cjs_shims();
11893
12034
  var import_node_path46 = __toESM(require("path"), 1);
11894
12035
  var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
11895
12036
  var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
11896
- var import_types33 = require("@neat.is/types");
12037
+ var import_types34 = require("@neat.is/types");
11897
12038
  var FIRESTORE_CLIENT_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase\/firestore['"`]/;
11898
12039
  var FIRESTORE_ADMIN_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])firebase-admin(?:\/firestore)?['"`]/;
11899
12040
  function parserForExt2(ext) {
@@ -12157,7 +12298,7 @@ function firestoreEndpointsFromFile(file, serviceDir, imported) {
12157
12298
  }
12158
12299
  }
12159
12300
  out.push({
12160
- infraId: (0, import_types33.infraId)("firestore-collection", collPath),
12301
+ infraId: (0, import_types34.infraId)("firestore-collection", collPath),
12161
12302
  name: collPath,
12162
12303
  kind: "firestore-collection",
12163
12304
  edgeType: "CALLS",
@@ -12273,7 +12414,7 @@ async function firestoreCrossFileEndpoints(files, serviceDir) {
12273
12414
  // src/extract/calls/mongoose.ts
12274
12415
  init_cjs_shims();
12275
12416
  var import_node_path47 = __toESM(require("path"), 1);
12276
- var import_types34 = require("@neat.is/types");
12417
+ var import_types35 = require("@neat.is/types");
12277
12418
  var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
12278
12419
  var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
12279
12420
  var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
@@ -12418,7 +12559,7 @@ function collectModelDefs(content, pluralizeOn) {
12418
12559
  function endpoint(r, file, serviceDir, matchText) {
12419
12560
  const line = lineOf(file.content, matchText);
12420
12561
  return {
12421
- infraId: (0, import_types34.infraId)(r.kind, r.name),
12562
+ infraId: (0, import_types35.infraId)(r.kind, r.name),
12422
12563
  name: r.name,
12423
12564
  kind: r.kind,
12424
12565
  edgeType: "CALLS",
@@ -12571,7 +12712,7 @@ init_cjs_shims();
12571
12712
  var import_node_path48 = __toESM(require("path"), 1);
12572
12713
  var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
12573
12714
  var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
12574
- var import_types35 = require("@neat.is/types");
12715
+ var import_types36 = require("@neat.is/types");
12575
12716
  var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
12576
12717
  var PARSE_CHUNK6 = 16384;
12577
12718
  function makePyParser3() {
@@ -12725,7 +12866,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
12725
12866
  if (seen.has(name)) return;
12726
12867
  seen.add(name);
12727
12868
  out.push({
12728
- infraId: (0, import_types35.infraId)("sql-table", name),
12869
+ infraId: (0, import_types36.infraId)("sql-table", name),
12729
12870
  name,
12730
12871
  kind: "sql-table",
12731
12872
  edgeType: "CALLS",
@@ -12833,7 +12974,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
12833
12974
  if (seen.has(key)) continue;
12834
12975
  seen.add(key);
12835
12976
  out.push({
12836
- infraId: (0, import_types35.infraId)("sql-table", t),
12977
+ infraId: (0, import_types36.infraId)("sql-table", t),
12837
12978
  name: t,
12838
12979
  kind: "sql-table",
12839
12980
  edgeType: "CALLS",
@@ -12854,7 +12995,7 @@ init_cjs_shims();
12854
12995
  var import_node_path49 = __toESM(require("path"), 1);
12855
12996
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
12856
12997
  var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
12857
- var import_types36 = require("@neat.is/types");
12998
+ var import_types37 = require("@neat.is/types");
12858
12999
  var SOCKET_IMPORT_RE = /(?:^|\n)\s*(?:import\s+socket\b|from\s+socket\s+import\b)/;
12859
13000
  var PARSE_CHUNK7 = 16384;
12860
13001
  function makePyParser4() {
@@ -12920,7 +13061,7 @@ function socketEndpointsFromFile(file, serviceDir) {
12920
13061
  seen.add(name);
12921
13062
  const line = node.startPosition.row + 1;
12922
13063
  out.push({
12923
- infraId: (0, import_types36.infraId)("socket", name),
13064
+ infraId: (0, import_types37.infraId)("socket", name),
12924
13065
  name,
12925
13066
  kind: "socket",
12926
13067
  edgeType: "CALLS",
@@ -12941,7 +13082,7 @@ init_cjs_shims();
12941
13082
  var import_node_path50 = __toESM(require("path"), 1);
12942
13083
  var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
12943
13084
  var import_tree_sitter_python7 = __toESM(require("tree-sitter-python"), 1);
12944
- var import_types37 = require("@neat.is/types");
13085
+ var import_types38 = require("@neat.is/types");
12945
13086
  var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
12946
13087
  var PARSE_CHUNK8 = 16384;
12947
13088
  function makePyParser5() {
@@ -13021,7 +13162,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
13021
13162
  seen.add(table);
13022
13163
  const line = node.startPosition.row + 1;
13023
13164
  out.push({
13024
- infraId: (0, import_types37.infraId)("sql-table", table),
13165
+ infraId: (0, import_types38.infraId)("sql-table", table),
13025
13166
  name: table,
13026
13167
  kind: "sql-table",
13027
13168
  edgeType: "CALLS",
@@ -13037,7 +13178,7 @@ init_cjs_shims();
13037
13178
  var import_node_path51 = __toESM(require("path"), 1);
13038
13179
  var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
13039
13180
  var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
13040
- var import_types38 = require("@neat.is/types");
13181
+ var import_types39 = require("@neat.is/types");
13041
13182
  var DRIZZLE_IMPORT_RE = /drizzle-orm/;
13042
13183
  var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
13043
13184
  function parserForExt3(ext) {
@@ -13128,7 +13269,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
13128
13269
  const columns = columnsFromObject(obj);
13129
13270
  const line = node.startPosition.row + 1;
13130
13271
  out.push({
13131
- infraId: (0, import_types38.infraId)("sql-table", tableName),
13272
+ infraId: (0, import_types39.infraId)("sql-table", tableName),
13132
13273
  name: tableName,
13133
13274
  kind: "sql-table",
13134
13275
  edgeType: "CALLS",
@@ -13238,7 +13379,7 @@ function drizzleForeignKeys(file, serviceDir) {
13238
13379
  // src/extract/calls/prisma.ts
13239
13380
  init_cjs_shims();
13240
13381
  var import_node_path52 = __toESM(require("path"), 1);
13241
- var import_types39 = require("@neat.is/types");
13382
+ var import_types40 = require("@neat.is/types");
13242
13383
  var SCALAR_TYPES = /* @__PURE__ */ new Set([
13243
13384
  "Int",
13244
13385
  "String",
@@ -13286,7 +13427,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
13286
13427
  if (seenTable.has(b.tableName)) return;
13287
13428
  seenTable.add(b.tableName);
13288
13429
  out.push({
13289
- infraId: (0, import_types39.infraId)("sql-table", b.tableName),
13430
+ infraId: (0, import_types40.infraId)("sql-table", b.tableName),
13290
13431
  name: b.tableName,
13291
13432
  kind: "sql-table",
13292
13433
  edgeType: "CALLS",
@@ -13458,7 +13599,7 @@ init_cjs_shims();
13458
13599
  var import_node_path53 = __toESM(require("path"), 1);
13459
13600
  var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
13460
13601
  var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
13461
- var import_types40 = require("@neat.is/types");
13602
+ var import_types41 = require("@neat.is/types");
13462
13603
  var AR_SCHEMA_RE = /ActiveRecord::Schema/;
13463
13604
  var PARSE_CHUNK9 = 16384;
13464
13605
  function makeRubyParser2() {
@@ -13656,7 +13797,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
13656
13797
  if (!table || seen.has(table.name)) return;
13657
13798
  seen.add(table.name);
13658
13799
  out.push({
13659
- infraId: (0, import_types40.infraId)("sql-table", table.name),
13800
+ infraId: (0, import_types41.infraId)("sql-table", table.name),
13660
13801
  name: table.name,
13661
13802
  kind: "sql-table",
13662
13803
  edgeType: "CALLS",
@@ -13762,7 +13903,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
13762
13903
  seen.add(table);
13763
13904
  const line = node.startPosition.row + 1;
13764
13905
  out.push({
13765
- infraId: (0, import_types40.infraId)("sql-table", table),
13906
+ infraId: (0, import_types41.infraId)("sql-table", table),
13766
13907
  name: table,
13767
13908
  kind: "sql-table",
13768
13909
  edgeType: "CALLS",
@@ -13820,7 +13961,7 @@ init_cjs_shims();
13820
13961
  var import_node_path54 = __toESM(require("path"), 1);
13821
13962
  var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
13822
13963
  var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
13823
- var import_types41 = require("@neat.is/types");
13964
+ var import_types42 = require("@neat.is/types");
13824
13965
  var LARAVEL_SCHEMA_RE = /\bSchema::(create|createIfNotExists|table)\b/;
13825
13966
  var PARSE_CHUNK10 = 16384;
13826
13967
  function makePhpParser2() {
@@ -14067,7 +14208,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
14067
14208
  }
14068
14209
  }
14069
14210
  out.push({
14070
- infraId: (0, import_types41.infraId)("sql-table", bp.table),
14211
+ infraId: (0, import_types42.infraId)("sql-table", bp.table),
14071
14212
  name: bp.table,
14072
14213
  kind: "sql-table",
14073
14214
  edgeType: "CALLS",
@@ -14210,7 +14351,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
14210
14351
  seen.add(table);
14211
14352
  const line = node.startPosition.row + 1;
14212
14353
  out.push({
14213
- infraId: (0, import_types41.infraId)("sql-table", table),
14354
+ infraId: (0, import_types42.infraId)("sql-table", table),
14214
14355
  name: table,
14215
14356
  kind: "sql-table",
14216
14357
  edgeType: "CALLS",
@@ -14267,7 +14408,7 @@ init_cjs_shims();
14267
14408
  var import_node_path57 = __toESM(require("path"), 1);
14268
14409
  var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
14269
14410
  var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
14270
- var import_types42 = require("@neat.is/types");
14411
+ var import_types43 = require("@neat.is/types");
14271
14412
  init_otel();
14272
14413
  var PARSE_CHUNK11 = 16384;
14273
14414
  var DATABASE_SQL_METHODS = /* @__PURE__ */ new Set([
@@ -14361,7 +14502,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
14361
14502
  const columns = columnsFromSqlStatement(sql);
14362
14503
  const line = node.startPosition.row + 1;
14363
14504
  out.push({
14364
- infraId: (0, import_types42.infraId)("sql-table", table),
14505
+ infraId: (0, import_types43.infraId)("sql-table", table),
14365
14506
  name: table,
14366
14507
  kind: "sql-table",
14367
14508
  edgeType: "CALLS",
@@ -14382,7 +14523,7 @@ init_cjs_shims();
14382
14523
  var import_node_path58 = __toESM(require("path"), 1);
14383
14524
  var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
14384
14525
  var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
14385
- var import_types43 = require("@neat.is/types");
14526
+ var import_types44 = require("@neat.is/types");
14386
14527
  var GORM_IMPORT_RE = /gorm\.io\/gorm/;
14387
14528
  var PARSE_CHUNK12 = 16384;
14388
14529
  function makeGoParser4() {
@@ -14827,7 +14968,7 @@ function gormEndpointsFromFile(file, serviceDir) {
14827
14968
  const columns = [];
14828
14969
  collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
14829
14970
  out.push({
14830
- infraId: (0, import_types43.infraId)("sql-table", table),
14971
+ infraId: (0, import_types44.infraId)("sql-table", table),
14831
14972
  name: table,
14832
14973
  kind: "sql-table",
14833
14974
  edgeType: "CALLS",
@@ -14898,7 +15039,7 @@ init_cjs_shims();
14898
15039
  var import_node_path59 = __toESM(require("path"), 1);
14899
15040
  var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
14900
15041
  var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
14901
- var import_types44 = require("@neat.is/types");
15042
+ var import_types45 = require("@neat.is/types");
14902
15043
  var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
14903
15044
  var PARSE_CHUNK13 = 16384;
14904
15045
  function makeCsParser() {
@@ -14983,7 +15124,7 @@ function efcoreEndpointsFromFile(file, serviceDir) {
14983
15124
  if (!name || seen.has(name)) return;
14984
15125
  seen.add(name);
14985
15126
  out.push({
14986
- infraId: (0, import_types44.infraId)("sql-table", name),
15127
+ infraId: (0, import_types45.infraId)("sql-table", name),
14987
15128
  name,
14988
15129
  kind: "sql-table",
14989
15130
  edgeType: "CALLS",
@@ -15013,11 +15154,11 @@ function efcoreEndpointsFromFile(file, serviceDir) {
15013
15154
  function edgeTypeFromEndpoint(ep) {
15014
15155
  switch (ep.edgeType) {
15015
15156
  case "PUBLISHES_TO":
15016
- return import_types45.EdgeType.PUBLISHES_TO;
15157
+ return import_types46.EdgeType.PUBLISHES_TO;
15017
15158
  case "CONSUMES_FROM":
15018
- return import_types45.EdgeType.CONSUMES_FROM;
15159
+ return import_types46.EdgeType.CONSUMES_FROM;
15019
15160
  default:
15020
- return import_types45.EdgeType.CALLS;
15161
+ return import_types46.EdgeType.CALLS;
15021
15162
  }
15022
15163
  }
15023
15164
  function isAwsKind(kind) {
@@ -15088,7 +15229,7 @@ async function addExternalEndpointEdges(graph, services) {
15088
15229
  if (!graph.hasNode(ep.infraId)) {
15089
15230
  const node = {
15090
15231
  id: ep.infraId,
15091
- type: import_types45.NodeType.InfraNode,
15232
+ type: import_types46.NodeType.InfraNode,
15092
15233
  name: ep.name,
15093
15234
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
15094
15235
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -15101,21 +15242,21 @@ async function addExternalEndpointEdges(graph, services) {
15101
15242
  }
15102
15243
  if (ep.columns && ep.columns.length > 0) {
15103
15244
  const node = graph.getNodeAttributes(ep.infraId);
15104
- if (node.type === import_types45.NodeType.InfraNode) {
15245
+ if (node.type === import_types46.NodeType.InfraNode) {
15105
15246
  graph.replaceNodeAttributes(ep.infraId, {
15106
15247
  ...node,
15107
15248
  columns: foldColumns(
15108
15249
  node.columns,
15109
15250
  ep.columns,
15110
- import_types45.Provenance.EXTRACTED,
15111
- (0, import_types45.confidenceForExtracted)(ep.confidenceKind)
15251
+ import_types46.Provenance.EXTRACTED,
15252
+ (0, import_types46.confidenceForExtracted)(ep.confidenceKind)
15112
15253
  )
15113
15254
  });
15114
15255
  }
15115
15256
  }
15116
15257
  if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
15117
15258
  const node = graph.getNodeAttributes(ep.infraId);
15118
- if (node.type === import_types45.NodeType.InfraNode) {
15259
+ if (node.type === import_types46.NodeType.InfraNode) {
15119
15260
  graph.replaceNodeAttributes(ep.infraId, {
15120
15261
  ...node,
15121
15262
  columns: foldSdkWrites(node.columns, ep.sdkWrites)
@@ -15123,7 +15264,7 @@ async function addExternalEndpointEdges(graph, services) {
15123
15264
  }
15124
15265
  }
15125
15266
  const edgeType = edgeTypeFromEndpoint(ep);
15126
- const confidence = (0, import_types45.confidenceForExtracted)(ep.confidenceKind);
15267
+ const confidence = (0, import_types46.confidenceForExtracted)(ep.confidenceKind);
15127
15268
  const relFile = toPosix(ep.evidence.file);
15128
15269
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
15129
15270
  graph,
@@ -15133,7 +15274,7 @@ async function addExternalEndpointEdges(graph, services) {
15133
15274
  );
15134
15275
  nodesAdded += n;
15135
15276
  edgesAdded += e;
15136
- if (!(0, import_types45.passesExtractedFloor)(confidence)) {
15277
+ if (!(0, import_types46.passesExtractedFloor)(confidence)) {
15137
15278
  noteExtractedDropped({
15138
15279
  source: fileNodeId,
15139
15280
  target: ep.infraId,
@@ -15153,7 +15294,7 @@ async function addExternalEndpointEdges(graph, services) {
15153
15294
  source: fileNodeId,
15154
15295
  target: ep.infraId,
15155
15296
  type: edgeType,
15156
- provenance: import_types45.Provenance.EXTRACTED,
15297
+ provenance: import_types46.Provenance.EXTRACTED,
15157
15298
  confidence,
15158
15299
  evidence: ep.evidence
15159
15300
  };
@@ -15176,7 +15317,7 @@ async function addCallEdges(graph, services) {
15176
15317
 
15177
15318
  // src/extract/table-edges.ts
15178
15319
  init_cjs_shims();
15179
- var import_types46 = require("@neat.is/types");
15320
+ var import_types47 = require("@neat.is/types");
15180
15321
  async function addTableEdges(graph, services) {
15181
15322
  let nodesAdded = 0;
15182
15323
  let edgesAdded = 0;
@@ -15204,20 +15345,20 @@ async function addTableEdges(graph, services) {
15204
15345
  }
15205
15346
  refs.push(...modelRefs);
15206
15347
  for (const ref of refs) {
15207
- const childId = (0, import_types46.infraId)("sql-table", ref.childTable);
15208
- const parentId = (0, import_types46.infraId)("sql-table", ref.parentTable);
15348
+ const childId = (0, import_types47.infraId)("sql-table", ref.childTable);
15349
+ const parentId = (0, import_types47.infraId)("sql-table", ref.parentTable);
15209
15350
  if (childId === parentId) continue;
15210
15351
  nodesAdded += ensureTableNode(graph, childId, ref.childTable);
15211
15352
  nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
15212
- const edgeId = (0, import_types46.extractedEdgeId)(childId, parentId, import_types46.EdgeType.REFERENCES);
15353
+ const edgeId = (0, import_types47.extractedEdgeId)(childId, parentId, import_types47.EdgeType.REFERENCES);
15213
15354
  if (graph.hasEdge(edgeId)) continue;
15214
15355
  const edge = {
15215
15356
  id: edgeId,
15216
15357
  source: childId,
15217
15358
  target: parentId,
15218
- type: import_types46.EdgeType.REFERENCES,
15219
- provenance: import_types46.Provenance.EXTRACTED,
15220
- confidence: (0, import_types46.confidenceForExtracted)("structural"),
15359
+ type: import_types47.EdgeType.REFERENCES,
15360
+ provenance: import_types47.Provenance.EXTRACTED,
15361
+ confidence: (0, import_types47.confidenceForExtracted)("structural"),
15221
15362
  evidence: ref.evidence
15222
15363
  };
15223
15364
  graph.addEdgeWithKey(edgeId, childId, parentId, edge);
@@ -15230,7 +15371,7 @@ function ensureTableNode(graph, id, name) {
15230
15371
  if (graph.hasNode(id)) return 0;
15231
15372
  const node = {
15232
15373
  id,
15233
- type: import_types46.NodeType.InfraNode,
15374
+ type: import_types47.NodeType.InfraNode,
15234
15375
  name,
15235
15376
  provider: "self",
15236
15377
  kind: "sql-table"
@@ -15245,15 +15386,15 @@ init_cjs_shims();
15245
15386
  // src/extract/infra/docker-compose.ts
15246
15387
  init_cjs_shims();
15247
15388
  var import_node_path60 = __toESM(require("path"), 1);
15248
- var import_types48 = require("@neat.is/types");
15389
+ var import_types49 = require("@neat.is/types");
15249
15390
 
15250
15391
  // src/extract/infra/shared.ts
15251
15392
  init_cjs_shims();
15252
- var import_types47 = require("@neat.is/types");
15393
+ var import_types48 = require("@neat.is/types");
15253
15394
  function makeInfraNode(kind, name, provider = "self", extras) {
15254
15395
  return {
15255
- id: (0, import_types47.infraId)(kind, name),
15256
- type: import_types47.NodeType.InfraNode,
15396
+ id: (0, import_types48.infraId)(kind, name),
15397
+ type: import_types48.NodeType.InfraNode,
15257
15398
  name,
15258
15399
  provider,
15259
15400
  kind,
@@ -15297,8 +15438,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
15297
15438
  source: anchorId,
15298
15439
  target: node.id,
15299
15440
  type: edgeType,
15300
- provenance: import_types47.Provenance.EXTRACTED,
15301
- confidence: (0, import_types47.confidenceForExtracted)("structural"),
15441
+ provenance: import_types48.Provenance.EXTRACTED,
15442
+ confidence: (0, import_types48.confidenceForExtracted)("structural"),
15302
15443
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
15303
15444
  };
15304
15445
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -15365,15 +15506,15 @@ async function addComposeInfra(graph, scanPath, services) {
15365
15506
  for (const dep of dependsOnList(svc.depends_on)) {
15366
15507
  const targetId = composeNameToNodeId.get(dep);
15367
15508
  if (!targetId) continue;
15368
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types48.EdgeType.DEPENDS_ON);
15509
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types49.EdgeType.DEPENDS_ON);
15369
15510
  if (graph.hasEdge(edgeId)) continue;
15370
15511
  const edge = {
15371
15512
  id: edgeId,
15372
15513
  source: sourceId,
15373
15514
  target: targetId,
15374
- type: import_types48.EdgeType.DEPENDS_ON,
15375
- provenance: import_types48.Provenance.EXTRACTED,
15376
- confidence: (0, import_types48.confidenceForExtracted)("structural"),
15515
+ type: import_types49.EdgeType.DEPENDS_ON,
15516
+ provenance: import_types49.Provenance.EXTRACTED,
15517
+ confidence: (0, import_types49.confidenceForExtracted)("structural"),
15377
15518
  evidence: { file: evidenceFile }
15378
15519
  };
15379
15520
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -15387,7 +15528,7 @@ async function addComposeInfra(graph, scanPath, services) {
15387
15528
  init_cjs_shims();
15388
15529
  var import_node_path61 = __toESM(require("path"), 1);
15389
15530
  var import_node_fs27 = require("fs");
15390
- var import_types49 = require("@neat.is/types");
15531
+ var import_types50 = require("@neat.is/types");
15391
15532
  function readDockerfile(content) {
15392
15533
  let image = null;
15393
15534
  const ports = [];
@@ -15446,15 +15587,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
15446
15587
  );
15447
15588
  nodesAdded += fn;
15448
15589
  edgesAdded += fe;
15449
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types49.EdgeType.RUNS_ON);
15590
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types50.EdgeType.RUNS_ON);
15450
15591
  if (!graph.hasEdge(edgeId)) {
15451
15592
  const edge = {
15452
15593
  id: edgeId,
15453
15594
  source: fileNodeId,
15454
15595
  target: node.id,
15455
- type: import_types49.EdgeType.RUNS_ON,
15456
- provenance: import_types49.Provenance.EXTRACTED,
15457
- confidence: (0, import_types49.confidenceForExtracted)("structural"),
15596
+ type: import_types50.EdgeType.RUNS_ON,
15597
+ provenance: import_types50.Provenance.EXTRACTED,
15598
+ confidence: (0, import_types50.confidenceForExtracted)("structural"),
15458
15599
  evidence: {
15459
15600
  file: evidenceFile,
15460
15601
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -15469,15 +15610,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
15469
15610
  graph.addNode(portNode.id, portNode);
15470
15611
  nodesAdded++;
15471
15612
  }
15472
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types49.EdgeType.CONNECTS_TO);
15613
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types50.EdgeType.CONNECTS_TO);
15473
15614
  if (graph.hasEdge(portEdgeId)) continue;
15474
15615
  const portEdge = {
15475
15616
  id: portEdgeId,
15476
15617
  source: fileNodeId,
15477
15618
  target: portNode.id,
15478
- type: import_types49.EdgeType.CONNECTS_TO,
15479
- provenance: import_types49.Provenance.EXTRACTED,
15480
- confidence: (0, import_types49.confidenceForExtracted)("structural"),
15619
+ type: import_types50.EdgeType.CONNECTS_TO,
15620
+ provenance: import_types50.Provenance.EXTRACTED,
15621
+ confidence: (0, import_types50.confidenceForExtracted)("structural"),
15481
15622
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
15482
15623
  };
15483
15624
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -15491,7 +15632,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
15491
15632
  init_cjs_shims();
15492
15633
  var import_node_fs28 = require("fs");
15493
15634
  var import_node_path62 = __toESM(require("path"), 1);
15494
- var import_types50 = require("@neat.is/types");
15635
+ var import_types51 = require("@neat.is/types");
15495
15636
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
15496
15637
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
15497
15638
  async function walkTfFiles(start, depth = 0, max = 5) {
@@ -15572,16 +15713,16 @@ async function addTerraformResources(graph, scanPath) {
15572
15713
  if (!target) continue;
15573
15714
  if (seen.has(target.nodeId)) continue;
15574
15715
  seen.add(target.nodeId);
15575
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types50.EdgeType.DEPENDS_ON);
15716
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types51.EdgeType.DEPENDS_ON);
15576
15717
  if (graph.hasEdge(edgeId)) continue;
15577
15718
  const line = lineAt2(content, resource.bodyOffset + ref.index);
15578
15719
  const edge = {
15579
15720
  id: edgeId,
15580
15721
  source: resource.nodeId,
15581
15722
  target: target.nodeId,
15582
- type: import_types50.EdgeType.DEPENDS_ON,
15583
- provenance: import_types50.Provenance.EXTRACTED,
15584
- confidence: (0, import_types50.confidenceForExtracted)("structural"),
15723
+ type: import_types51.EdgeType.DEPENDS_ON,
15724
+ provenance: import_types51.Provenance.EXTRACTED,
15725
+ confidence: (0, import_types51.confidenceForExtracted)("structural"),
15585
15726
  evidence: { file: evidenceFile, line, snippet: key }
15586
15727
  };
15587
15728
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -15597,7 +15738,7 @@ init_cjs_shims();
15597
15738
  var import_node_fs29 = require("fs");
15598
15739
  var import_node_path63 = __toESM(require("path"), 1);
15599
15740
  var import_yaml3 = require("yaml");
15600
- var import_types51 = require("@neat.is/types");
15741
+ var import_types52 = require("@neat.is/types");
15601
15742
  var K8S_KIND_TO_INFRA_KIND = {
15602
15743
  Service: "k8s-service",
15603
15744
  Deployment: "k8s-deployment",
@@ -15657,7 +15798,7 @@ async function addK8sResources(graph, scanPath) {
15657
15798
  nodesAdded++;
15658
15799
  }
15659
15800
  if (isWorkload) {
15660
- const svcId = (0, import_types51.serviceId)(name);
15801
+ const svcId = (0, import_types52.serviceId)(name);
15661
15802
  if (graph.hasNode(svcId)) {
15662
15803
  const svc = graph.getNodeAttributes(svcId);
15663
15804
  graph.replaceNodeAttributes(svcId, {
@@ -15669,7 +15810,7 @@ async function addK8sResources(graph, scanPath) {
15669
15810
  edgesAdded += emitPlatformResourceEdge(
15670
15811
  graph,
15671
15812
  svcId,
15672
- import_types51.EdgeType.RUNS_ON,
15813
+ import_types52.EdgeType.RUNS_ON,
15673
15814
  infraKind,
15674
15815
  name,
15675
15816
  "kubernetes",
@@ -15688,7 +15829,7 @@ init_cjs_shims();
15688
15829
  var import_node_fs30 = require("fs");
15689
15830
  var import_node_path64 = __toESM(require("path"), 1);
15690
15831
  var import_smol_toml3 = require("smol-toml");
15691
- var import_types52 = require("@neat.is/types");
15832
+ var import_types53 = require("@neat.is/types");
15692
15833
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
15693
15834
  async function readWranglerConfig(dir) {
15694
15835
  for (const filename of WRANGLER_FILENAMES) {
@@ -15736,8 +15877,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
15736
15877
  source: anchorId,
15737
15878
  target: node.id,
15738
15879
  type: edgeType,
15739
- provenance: import_types52.Provenance.EXTRACTED,
15740
- confidence: (0, import_types52.confidenceForExtracted)("structural"),
15880
+ provenance: import_types53.Provenance.EXTRACTED,
15881
+ confidence: (0, import_types53.confidenceForExtracted)("structural"),
15741
15882
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
15742
15883
  };
15743
15884
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -15798,15 +15939,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15798
15939
  nodesAdded++;
15799
15940
  }
15800
15941
  if (runtimeNode.id !== anchorId) {
15801
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types52.EdgeType.RUNS_ON);
15942
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types53.EdgeType.RUNS_ON);
15802
15943
  if (!graph.hasEdge(runsOnId)) {
15803
15944
  const edge = {
15804
15945
  id: runsOnId,
15805
15946
  source: anchorId,
15806
15947
  target: runtimeNode.id,
15807
- type: import_types52.EdgeType.RUNS_ON,
15808
- provenance: import_types52.Provenance.EXTRACTED,
15809
- confidence: (0, import_types52.confidenceForExtracted)("structural"),
15948
+ type: import_types53.EdgeType.RUNS_ON,
15949
+ provenance: import_types53.Provenance.EXTRACTED,
15950
+ confidence: (0, import_types53.confidenceForExtracted)("structural"),
15810
15951
  evidence: {
15811
15952
  file: evidenceFile,
15812
15953
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -15820,7 +15961,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15820
15961
  const result = addResourceEdge(
15821
15962
  graph,
15822
15963
  anchorId,
15823
- import_types52.EdgeType.CONNECTS_TO,
15964
+ import_types53.EdgeType.CONNECTS_TO,
15824
15965
  "cloudflare-route",
15825
15966
  route,
15826
15967
  evidenceFile,
@@ -15844,7 +15985,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15844
15985
  const result = addResourceEdge(
15845
15986
  graph,
15846
15987
  anchorId,
15847
- import_types52.EdgeType.DEPENDS_ON,
15988
+ import_types53.EdgeType.DEPENDS_ON,
15848
15989
  group.kind,
15849
15990
  name,
15850
15991
  evidenceFile,
@@ -15858,7 +15999,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15858
15999
  const result = addResourceEdge(
15859
16000
  graph,
15860
16001
  anchorId,
15861
- import_types52.EdgeType.DEPENDS_ON,
16002
+ import_types53.EdgeType.DEPENDS_ON,
15862
16003
  "cloudflare-cron",
15863
16004
  cron,
15864
16005
  evidenceFile,
@@ -15871,7 +16012,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15871
16012
  const result = addResourceEdge(
15872
16013
  graph,
15873
16014
  anchorId,
15874
- import_types52.EdgeType.DEPENDS_ON,
16015
+ import_types53.EdgeType.DEPENDS_ON,
15875
16016
  "cloudflare-env-var",
15876
16017
  varName,
15877
16018
  evidenceFile,
@@ -15884,15 +16025,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15884
16025
  if (!svc.service) continue;
15885
16026
  const target = workerIndex.get(svc.service);
15886
16027
  if (target && target.anchorId !== anchorId) {
15887
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types52.EdgeType.CALLS);
16028
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types53.EdgeType.CALLS);
15888
16029
  if (!graph.hasEdge(edgeId)) {
15889
16030
  const edge = {
15890
16031
  id: edgeId,
15891
16032
  source: anchorId,
15892
16033
  target: target.anchorId,
15893
- type: import_types52.EdgeType.CALLS,
15894
- provenance: import_types52.Provenance.EXTRACTED,
15895
- confidence: (0, import_types52.confidenceForExtracted)("structural"),
16034
+ type: import_types53.EdgeType.CALLS,
16035
+ provenance: import_types53.Provenance.EXTRACTED,
16036
+ confidence: (0, import_types53.confidenceForExtracted)("structural"),
15896
16037
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
15897
16038
  };
15898
16039
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -15903,7 +16044,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15903
16044
  const result = addResourceEdge(
15904
16045
  graph,
15905
16046
  anchorId,
15906
- import_types52.EdgeType.DEPENDS_ON,
16047
+ import_types53.EdgeType.DEPENDS_ON,
15907
16048
  "cloudflare-service-binding",
15908
16049
  svc.service,
15909
16050
  evidenceFile,
@@ -15920,7 +16061,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
15920
16061
  init_cjs_shims();
15921
16062
  var import_node_fs31 = require("fs");
15922
16063
  var import_node_path65 = __toESM(require("path"), 1);
15923
- var import_types53 = require("@neat.is/types");
16064
+ var import_types54 = require("@neat.is/types");
15924
16065
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
15925
16066
  async function readVercelConfig(dir) {
15926
16067
  for (const filename of VERCEL_CONFIG_FILENAMES) {
@@ -15983,12 +16124,12 @@ async function addVercelServices(graph, services, scanPath) {
15983
16124
  nodesAdded += result.nodesAdded;
15984
16125
  edgesAdded += result.edgesAdded;
15985
16126
  };
15986
- add(import_types53.EdgeType.RUNS_ON, "vercel", "vercel");
15987
- for (const cron of config.crons ?? []) add(import_types53.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
15988
- for (const varName of Object.keys(config.env ?? {})) add(import_types53.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
15989
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types53.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
16127
+ add(import_types54.EdgeType.RUNS_ON, "vercel", "vercel");
16128
+ for (const cron of config.crons ?? []) add(import_types54.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
16129
+ for (const varName of Object.keys(config.env ?? {})) add(import_types54.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
16130
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types54.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
15990
16131
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
15991
- add(import_types53.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
16132
+ add(import_types54.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
15992
16133
  }
15993
16134
  }
15994
16135
  return { nodesAdded, edgesAdded };
@@ -15999,7 +16140,7 @@ init_cjs_shims();
15999
16140
  var import_node_fs32 = require("fs");
16000
16141
  var import_node_path66 = __toESM(require("path"), 1);
16001
16142
  var import_smol_toml4 = require("smol-toml");
16002
- var import_types54 = require("@neat.is/types");
16143
+ var import_types55 = require("@neat.is/types");
16003
16144
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
16004
16145
  async function readRailwayConfig(dir) {
16005
16146
  for (const filename of RAILWAY_FILENAMES) {
@@ -16045,9 +16186,9 @@ async function addRailwayServices(graph, services, scanPath) {
16045
16186
  nodesAdded += result.nodesAdded;
16046
16187
  edgesAdded += result.edgesAdded;
16047
16188
  };
16048
- add(import_types54.EdgeType.RUNS_ON, "railway", "railway");
16049
- add(import_types54.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
16050
- add(import_types54.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
16189
+ add(import_types55.EdgeType.RUNS_ON, "railway", "railway");
16190
+ add(import_types55.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
16191
+ add(import_types55.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
16051
16192
  }
16052
16193
  return { nodesAdded, edgesAdded };
16053
16194
  }
@@ -16057,7 +16198,7 @@ init_cjs_shims();
16057
16198
  var import_node_fs33 = require("fs");
16058
16199
  var import_node_path67 = __toESM(require("path"), 1);
16059
16200
  var import_smol_toml5 = require("smol-toml");
16060
- var import_types55 = require("@neat.is/types");
16201
+ var import_types56 = require("@neat.is/types");
16061
16202
  async function readSupabaseConfig(dir) {
16062
16203
  const relFile = import_node_path67.default.join("supabase", "config.toml");
16063
16204
  const abs = import_node_path67.default.join(dir, relFile);
@@ -16105,10 +16246,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
16105
16246
  nodesAdded += result.nodesAdded;
16106
16247
  edgesAdded += result.edgesAdded;
16107
16248
  };
16108
- add(import_types55.EdgeType.RUNS_ON, "supabase", "supabase");
16109
- for (const fn of Object.keys(config.functions ?? {})) add(import_types55.EdgeType.DEPENDS_ON, "supabase-function", fn);
16110
- if (config.storage) add(import_types55.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
16111
- if (config.auth) add(import_types55.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
16249
+ add(import_types56.EdgeType.RUNS_ON, "supabase", "supabase");
16250
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types56.EdgeType.DEPENDS_ON, "supabase-function", fn);
16251
+ if (config.storage) add(import_types56.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
16252
+ if (config.auth) add(import_types56.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
16112
16253
  }
16113
16254
  return { nodesAdded, edgesAdded };
16114
16255
  }
@@ -16134,7 +16275,7 @@ init_cjs_shims();
16134
16275
  var import_node_path68 = __toESM(require("path"), 1);
16135
16276
  var import_tree_sitter18 = __toESM(require("tree-sitter"), 1);
16136
16277
  var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
16137
- var import_types56 = require("@neat.is/types");
16278
+ var import_types57 = require("@neat.is/types");
16138
16279
  var ZOD_IMPORT_RE = /\bzod\b/;
16139
16280
  var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
16140
16281
  function parserForExt4(ext) {
@@ -16240,7 +16381,7 @@ function zodShapesFromFile(file, serviceDir) {
16240
16381
  seen.add(name);
16241
16382
  const line = call.startPosition.row + 1;
16242
16383
  out.push({
16243
- infraId: (0, import_types56.infraId)("zod-schema", name),
16384
+ infraId: (0, import_types57.infraId)("zod-schema", name),
16244
16385
  name,
16245
16386
  fields,
16246
16387
  evidence: {
@@ -16275,7 +16416,7 @@ async function addZodShapes(graph, services) {
16275
16416
  if (!graph.hasNode(shape.infraId)) {
16276
16417
  const node = {
16277
16418
  id: shape.infraId,
16278
- type: import_types56.NodeType.InfraNode,
16419
+ type: import_types57.NodeType.InfraNode,
16279
16420
  name: shape.name,
16280
16421
  provider: "self",
16281
16422
  kind: "zod-schema"
@@ -16285,14 +16426,14 @@ async function addZodShapes(graph, services) {
16285
16426
  }
16286
16427
  if (shape.fields.length > 0) {
16287
16428
  const node = graph.getNodeAttributes(shape.infraId);
16288
- if (node.type === import_types56.NodeType.InfraNode) {
16429
+ if (node.type === import_types57.NodeType.InfraNode) {
16289
16430
  graph.replaceNodeAttributes(shape.infraId, {
16290
16431
  ...node,
16291
16432
  columns: foldColumns(
16292
16433
  node.columns,
16293
16434
  shape.fields,
16294
- import_types56.Provenance.EXTRACTED,
16295
- (0, import_types56.confidenceForExtracted)("structural")
16435
+ import_types57.Provenance.EXTRACTED,
16436
+ (0, import_types57.confidenceForExtracted)("structural")
16296
16437
  )
16297
16438
  });
16298
16439
  }
@@ -16306,15 +16447,15 @@ async function addZodShapes(graph, services) {
16306
16447
  );
16307
16448
  nodesAdded += n;
16308
16449
  edgesAdded += e;
16309
- const edgeId = (0, import_types56.extractedEdgeId)(fileNodeId, shape.infraId, import_types56.EdgeType.CONTAINS);
16450
+ const edgeId = (0, import_types57.extractedEdgeId)(fileNodeId, shape.infraId, import_types57.EdgeType.CONTAINS);
16310
16451
  if (!graph.hasEdge(edgeId)) {
16311
16452
  const edge = {
16312
16453
  id: edgeId,
16313
16454
  source: fileNodeId,
16314
16455
  target: shape.infraId,
16315
- type: import_types56.EdgeType.CONTAINS,
16316
- provenance: import_types56.Provenance.EXTRACTED,
16317
- confidence: (0, import_types56.confidenceForExtracted)("structural"),
16456
+ type: import_types57.EdgeType.CONTAINS,
16457
+ provenance: import_types57.Provenance.EXTRACTED,
16458
+ confidence: (0, import_types57.confidenceForExtracted)("structural"),
16318
16459
  evidence: shape.evidence
16319
16460
  };
16320
16461
  graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
@@ -16328,7 +16469,7 @@ async function addZodShapes(graph, services) {
16328
16469
 
16329
16470
  // src/extract/firestore-rules.ts
16330
16471
  init_cjs_shims();
16331
- var import_types57 = require("@neat.is/types");
16472
+ var import_types58 = require("@neat.is/types");
16332
16473
  var FIRESTORE_COLLECTION_KIND = "firestore-collection";
16333
16474
  var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
16334
16475
  function stripComments(src) {
@@ -16499,7 +16640,7 @@ async function addFirestoreRules(graph, services) {
16499
16640
  if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
16500
16641
  graph.forEachNode((id, attrs) => {
16501
16642
  const node = attrs;
16502
- if (node.type !== import_types57.NodeType.InfraNode) return;
16643
+ if (node.type !== import_types58.NodeType.InfraNode) return;
16503
16644
  if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
16504
16645
  const fields = guards.get(collectionKeyFromName(node.name));
16505
16646
  if (!fields || fields.size === 0) return;
@@ -16518,12 +16659,12 @@ var import_node_path70 = __toESM(require("path"), 1);
16518
16659
  init_cjs_shims();
16519
16660
  var import_node_fs34 = require("fs");
16520
16661
  var import_node_path69 = __toESM(require("path"), 1);
16521
- var import_types58 = require("@neat.is/types");
16662
+ var import_types59 = require("@neat.is/types");
16522
16663
  function dropOrphanedFileNodes(graph, source) {
16523
16664
  const orphans = [];
16524
16665
  graph.forEachNode((id, attrs) => {
16525
16666
  const node = attrs;
16526
- if (node.type !== import_types58.NodeType.FileNode) return;
16667
+ if (node.type !== import_types59.NodeType.FileNode) return;
16527
16668
  if (source && node.source !== source) return;
16528
16669
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
16529
16670
  orphans.push(id);
@@ -16537,7 +16678,7 @@ function outOfScope(graph, edge, source) {
16537
16678
  for (const endpoint2 of [edge.source, edge.target]) {
16538
16679
  if (!graph.hasNode(endpoint2)) continue;
16539
16680
  const node = graph.getNodeAttributes(endpoint2);
16540
- if (node.type !== import_types58.NodeType.FileNode) continue;
16681
+ if (node.type !== import_types59.NodeType.FileNode) continue;
16541
16682
  return node.source !== source;
16542
16683
  }
16543
16684
  return false;
@@ -16547,7 +16688,7 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = [], so
16547
16688
  const bases = [scanPath, ...serviceDirs];
16548
16689
  graph.forEachEdge((id, attrs) => {
16549
16690
  const edge = attrs;
16550
- if (edge.provenance !== import_types58.Provenance.EXTRACTED) return;
16691
+ if (edge.provenance !== import_types59.Provenance.EXTRACTED) return;
16551
16692
  if (outOfScope(graph, edge, source)) return;
16552
16693
  const evidenceFile = edge.evidence?.file;
16553
16694
  if (!evidenceFile) return;
@@ -16566,7 +16707,23 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = [], so
16566
16707
  // src/extract/index.ts
16567
16708
  var passQueue = Promise.resolve();
16568
16709
  function extractFromDirectory(graph, scanPath, opts = {}) {
16569
- const pass = passQueue.then(() => runExtractionPass(graph, scanPath, opts));
16710
+ invalidateSourceBaseline(graph, opts.source, "syncing");
16711
+ const pass = passQueue.then(async () => {
16712
+ const sourceGeneration = beginSourceExtraction(graph, opts.source, opts.sourceCommit);
16713
+ let result;
16714
+ try {
16715
+ result = await runExtractionPass(graph, scanPath, opts);
16716
+ return result;
16717
+ } finally {
16718
+ finishSourceExtraction(
16719
+ graph,
16720
+ sourceGeneration,
16721
+ opts.source,
16722
+ opts.sourceCommit,
16723
+ result ?? { extractionErrors: 1, skippedFiles: 0 }
16724
+ );
16725
+ }
16726
+ });
16570
16727
  passQueue = pass.catch(() => {
16571
16728
  });
16572
16729
  return pass;
@@ -16662,7 +16819,7 @@ async function runExtractionPass(graph, scanPath, opts) {
16662
16819
  init_cjs_shims();
16663
16820
  var import_node_fs35 = require("fs");
16664
16821
  var import_node_path71 = __toESM(require("path"), 1);
16665
- var import_types59 = require("@neat.is/types");
16822
+ var import_types60 = require("@neat.is/types");
16666
16823
  var SCHEMA_VERSION = 7;
16667
16824
  function migrateV1ToV2(payload) {
16668
16825
  const nodes = payload.graph.nodes;
@@ -16686,7 +16843,7 @@ function migrateV5ToV6(payload) {
16686
16843
  if (Array.isArray(nodes)) {
16687
16844
  for (const node of nodes) {
16688
16845
  const attrs = node.attributes;
16689
- if (!attrs || attrs.type !== import_types59.NodeType.InfraNode) continue;
16846
+ if (!attrs || attrs.type !== import_types60.NodeType.InfraNode) continue;
16690
16847
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
16691
16848
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
16692
16849
  }
@@ -16702,12 +16859,12 @@ function migrateV2ToV3(payload) {
16702
16859
  for (const edge of edges) {
16703
16860
  const attrs = edge.attributes;
16704
16861
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
16705
- attrs.provenance = import_types59.Provenance.OBSERVED;
16862
+ attrs.provenance = import_types60.Provenance.OBSERVED;
16706
16863
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
16707
16864
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
16708
16865
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
16709
16866
  if (type && source && target) {
16710
- const newId = (0, import_types59.observedEdgeId)(source, target, type);
16867
+ const newId = (0, import_types60.observedEdgeId)(source, target, type);
16711
16868
  attrs.id = newId;
16712
16869
  if (edge.key) edge.key = newId;
16713
16870
  }
@@ -16914,7 +17071,7 @@ init_cjs_shims();
16914
17071
  var import_fastify2 = __toESM(require("fastify"), 1);
16915
17072
  var import_node_crypto6 = require("crypto");
16916
17073
  var import_cors = __toESM(require("@fastify/cors"), 1);
16917
- var import_types103 = require("@neat.is/types");
17074
+ var import_types104 = require("@neat.is/types");
16918
17075
 
16919
17076
  // src/extend/index.ts
16920
17077
  init_cjs_shims();
@@ -17261,39 +17418,39 @@ async function rollbackExtension(ctx, args) {
17261
17418
 
17262
17419
  // src/divergences.ts
17263
17420
  init_cjs_shims();
17264
- var import_types60 = require("@neat.is/types");
17421
+ var import_types61 = require("@neat.is/types");
17265
17422
  function bucketKey(source, target, type) {
17266
17423
  return `${type}|${source}|${target}`;
17267
17424
  }
17268
17425
  function bucketSourceFor(graph, edge) {
17269
- if (edge.type !== import_types60.EdgeType.CONNECTS_TO) return edge.source;
17270
- const parsed = (0, import_types60.parseFileId)(edge.source);
17426
+ if (edge.type !== import_types61.EdgeType.CONNECTS_TO) return edge.source;
17427
+ const parsed = (0, import_types61.parseFileId)(edge.source);
17271
17428
  if (!parsed || !graph.hasNode(edge.target)) return edge.source;
17272
17429
  const target = graph.getNodeAttributes(edge.target);
17273
- if (target.type !== import_types60.NodeType.DatabaseNode) return edge.source;
17274
- return (0, import_types60.serviceId)(parsed.service);
17430
+ if (target.type !== import_types61.NodeType.DatabaseNode) return edge.source;
17431
+ return (0, import_types61.serviceId)(parsed.service);
17275
17432
  }
17276
17433
  function bucketEdges(graph) {
17277
17434
  const buckets2 = /* @__PURE__ */ new Map();
17278
17435
  graph.forEachEdge((id, attrs) => {
17279
17436
  const e = attrs;
17280
- const parsed = (0, import_types60.parseEdgeId)(id);
17437
+ const parsed = (0, import_types61.parseEdgeId)(id);
17281
17438
  const provenance = parsed?.provenance ?? e.provenance;
17282
17439
  const source = bucketSourceFor(graph, e);
17283
17440
  const key = bucketKey(source, e.target, e.type);
17284
17441
  const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
17285
17442
  switch (provenance) {
17286
- case import_types60.Provenance.EXTRACTED:
17443
+ case import_types61.Provenance.EXTRACTED:
17287
17444
  cur.extracted = e;
17288
17445
  break;
17289
- case import_types60.Provenance.OBSERVED:
17446
+ case import_types61.Provenance.OBSERVED:
17290
17447
  cur.observed = e;
17291
17448
  break;
17292
- case import_types60.Provenance.INFERRED:
17449
+ case import_types61.Provenance.INFERRED:
17293
17450
  cur.inferred = e;
17294
17451
  break;
17295
17452
  default:
17296
- if (e.provenance === import_types60.Provenance.STALE) cur.stale = e;
17453
+ if (e.provenance === import_types61.Provenance.STALE) cur.stale = e;
17297
17454
  }
17298
17455
  buckets2.set(key, cur);
17299
17456
  });
@@ -17302,22 +17459,22 @@ function bucketEdges(graph) {
17302
17459
  function nodeIsFrontier(graph, nodeId) {
17303
17460
  if (!graph.hasNode(nodeId)) return false;
17304
17461
  const attrs = graph.getNodeAttributes(nodeId);
17305
- return attrs.type === import_types60.NodeType.FrontierNode;
17462
+ return attrs.type === import_types61.NodeType.FrontierNode;
17306
17463
  }
17307
17464
  function nodeIsWebsocketChannel(graph, nodeId) {
17308
17465
  if (!graph.hasNode(nodeId)) return false;
17309
17466
  const attrs = graph.getNodeAttributes(nodeId);
17310
- return attrs.type === import_types60.NodeType.WebSocketChannelNode;
17467
+ return attrs.type === import_types61.NodeType.WebSocketChannelNode;
17311
17468
  }
17312
17469
  function nodeIsServerAction(graph, nodeId) {
17313
17470
  if (!graph.hasNode(nodeId)) return false;
17314
17471
  const attrs = graph.getNodeAttributes(nodeId);
17315
- return attrs.type === import_types60.NodeType.ServerActionNode;
17472
+ return attrs.type === import_types61.NodeType.ServerActionNode;
17316
17473
  }
17317
17474
  function nodeIsSymbol(graph, nodeId) {
17318
17475
  if (!graph.hasNode(nodeId)) return false;
17319
17476
  const attrs = graph.getNodeAttributes(nodeId);
17320
- return attrs.type === import_types60.NodeType.SymbolNode;
17477
+ return attrs.type === import_types61.NodeType.SymbolNode;
17321
17478
  }
17322
17479
  function clampConfidence(n) {
17323
17480
  if (!Number.isFinite(n)) return 0;
@@ -17337,14 +17494,14 @@ function gradedConfidence(edge) {
17337
17494
  return clampConfidence(confidenceForEdge(edge));
17338
17495
  }
17339
17496
  var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
17340
- import_types60.EdgeType.CALLS,
17341
- import_types60.EdgeType.CONNECTS_TO,
17342
- import_types60.EdgeType.PUBLISHES_TO,
17343
- import_types60.EdgeType.CONSUMES_FROM
17497
+ import_types61.EdgeType.CALLS,
17498
+ import_types61.EdgeType.CONNECTS_TO,
17499
+ import_types61.EdgeType.PUBLISHES_TO,
17500
+ import_types61.EdgeType.CONSUMES_FROM
17344
17501
  ]);
17345
17502
  function detectMissingDivergences(graph, bucket) {
17346
17503
  const out = [];
17347
- if (bucket.type === import_types60.EdgeType.CONTAINS) return out;
17504
+ if (bucket.type === import_types61.EdgeType.CONTAINS) return out;
17348
17505
  if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
17349
17506
  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
17350
17507
  if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
@@ -17386,7 +17543,7 @@ function declaredHostFor(svc) {
17386
17543
  function hasExtractedConfiguredBy(graph, svcId) {
17387
17544
  for (const edgeId of graph.outboundEdges(svcId)) {
17388
17545
  const e = graph.getEdgeAttributes(edgeId);
17389
- if (e.type === import_types60.EdgeType.CONFIGURED_BY && e.provenance === import_types60.Provenance.EXTRACTED) {
17546
+ if (e.type === import_types61.EdgeType.CONFIGURED_BY && e.provenance === import_types61.Provenance.EXTRACTED) {
17390
17547
  return true;
17391
17548
  }
17392
17549
  }
@@ -17399,10 +17556,10 @@ function detectHostMismatch(graph, svcId, svc) {
17399
17556
  const out = [];
17400
17557
  for (const edgeId of graph.outboundEdges(svcId)) {
17401
17558
  const edge = graph.getEdgeAttributes(edgeId);
17402
- if (edge.type !== import_types60.EdgeType.CONNECTS_TO) continue;
17403
- if (edge.provenance !== import_types60.Provenance.OBSERVED) continue;
17559
+ if (edge.type !== import_types61.EdgeType.CONNECTS_TO) continue;
17560
+ if (edge.provenance !== import_types61.Provenance.OBSERVED) continue;
17404
17561
  const target = graph.getNodeAttributes(edge.target);
17405
- if (target.type !== import_types60.NodeType.DatabaseNode) continue;
17562
+ if (target.type !== import_types61.NodeType.DatabaseNode) continue;
17406
17563
  const observedHost = target.host?.trim();
17407
17564
  if (!observedHost) continue;
17408
17565
  if (observedHost === declaredHost) continue;
@@ -17424,10 +17581,10 @@ function detectCompatDivergences(graph, svcId, svc) {
17424
17581
  const deps = svc.dependencies ?? {};
17425
17582
  for (const edgeId of graph.outboundEdges(svcId)) {
17426
17583
  const edge = graph.getEdgeAttributes(edgeId);
17427
- if (edge.type !== import_types60.EdgeType.CONNECTS_TO) continue;
17428
- if (edge.provenance !== import_types60.Provenance.OBSERVED) continue;
17584
+ if (edge.type !== import_types61.EdgeType.CONNECTS_TO) continue;
17585
+ if (edge.provenance !== import_types61.Provenance.OBSERVED) continue;
17429
17586
  const target = graph.getNodeAttributes(edge.target);
17430
- if (target.type !== import_types60.NodeType.DatabaseNode) continue;
17587
+ if (target.type !== import_types61.NodeType.DatabaseNode) continue;
17431
17588
  for (const pair of compatPairs()) {
17432
17589
  if (pair.engine !== target.engine) continue;
17433
17590
  const declared = deps[pair.driver];
@@ -17590,11 +17747,11 @@ function symbolLocus(graph, ev) {
17590
17747
  const location = filepath ? `${filepath}${lineno !== void 0 ? `:${lineno}` : ""}` : void 0;
17591
17748
  const affected = ev.affectedNode;
17592
17749
  const affectedInGraph = affected.length > 0 && graph.hasNode(affected);
17593
- const affectedIsCode = affectedInGraph && ((0, import_types60.parseSymbolId)(affected) !== null || (0, import_types60.parseFileId)(affected) !== null);
17750
+ const affectedIsCode = affectedInGraph && ((0, import_types61.parseSymbolId)(affected) !== null || (0, import_types61.parseFileId)(affected) !== null);
17594
17751
  if (affectedIsCode) return { node: affected, ...location ? { location } : {} };
17595
17752
  if (!location) return null;
17596
17753
  if (affectedInGraph) return { node: affected, location };
17597
- const svc = (0, import_types60.serviceId)(ev.service);
17754
+ const svc = (0, import_types61.serviceId)(ev.service);
17598
17755
  if (graph.hasNode(svc)) return { node: svc, location };
17599
17756
  return null;
17600
17757
  }
@@ -17637,7 +17794,7 @@ function detectSymbolMismatches(graph, incidents) {
17637
17794
  mismatchKind: g.kind,
17638
17795
  ...g.symbol ? { symbol: g.symbol } : {},
17639
17796
  ...g.location ? { location: g.location } : {},
17640
- provenance: import_types60.Provenance.INFERRED,
17797
+ provenance: import_types61.Provenance.INFERRED,
17641
17798
  incidentId: g.latest.id,
17642
17799
  errorMessage: g.latest.errorMessage,
17643
17800
  incidentCount: g.count,
@@ -17654,7 +17811,7 @@ var OBSERVED_FAILING_CONFIDENCE = 0.6;
17654
17811
  function detectObservedFailingEdge(graph, bucket) {
17655
17812
  if (!bucket.extracted || !bucket.observed) return [];
17656
17813
  if (!OBSERVABLE_EDGE_TYPES.has(bucket.type)) return [];
17657
- if (bucket.observed.provenance !== import_types60.Provenance.OBSERVED) return [];
17814
+ if (bucket.observed.provenance !== import_types61.Provenance.OBSERVED) return [];
17658
17815
  const signal = bucket.observed.signal;
17659
17816
  if (!signal) return [];
17660
17817
  const { spanCount, errorCount } = signal;
@@ -17668,7 +17825,7 @@ function detectObservedFailingEdge(graph, bucket) {
17668
17825
  source: bucket.source,
17669
17826
  target: bucket.target,
17670
17827
  failureKind: "error-rate",
17671
- provenance: import_types60.Provenance.INFERRED,
17828
+ provenance: import_types61.Provenance.INFERRED,
17672
17829
  edgeType: bucket.type,
17673
17830
  observed: bucket.observed,
17674
17831
  spanCount,
@@ -17773,7 +17930,7 @@ function detectObservedFailingIncidents(graph, incidents) {
17773
17930
  source: g.node,
17774
17931
  target: g.node,
17775
17932
  failureKind: g.kind,
17776
- provenance: import_types60.Provenance.INFERRED,
17933
+ provenance: import_types61.Provenance.INFERRED,
17777
17934
  ...g.location ? { location: g.location } : {},
17778
17935
  incidentId: g.latest.id,
17779
17936
  errorMessage: g.latest.errorMessage,
@@ -17792,24 +17949,24 @@ function involvesNode(d, nodeId) {
17792
17949
  function datastoreEverObserved(graph, nodeId) {
17793
17950
  if (!graph.hasNode(nodeId)) return false;
17794
17951
  const n = graph.getNodeAttributes(nodeId);
17795
- if (n.type === import_types60.NodeType.DatabaseNode) {
17952
+ if (n.type === import_types61.NodeType.DatabaseNode) {
17796
17953
  const via = n.discoveredVia;
17797
17954
  if (via === "otel" || via === "merged") return true;
17798
17955
  }
17799
17956
  for (const edgeId of graph.inboundEdges(nodeId)) {
17800
17957
  const e = graph.getEdgeAttributes(edgeId);
17801
- if (e.provenance === import_types60.Provenance.OBSERVED || e.provenance === import_types60.Provenance.STALE) return true;
17958
+ if (e.provenance === import_types61.Provenance.OBSERVED || e.provenance === import_types61.Provenance.STALE) return true;
17802
17959
  }
17803
17960
  return false;
17804
17961
  }
17805
17962
  function serviceHasObservedSameEngineStore(graph, buckets2, serviceId17, engine, excludeTarget) {
17806
17963
  for (const bucket of buckets2.values()) {
17807
- if (bucket.type !== import_types60.EdgeType.CONNECTS_TO) continue;
17964
+ if (bucket.type !== import_types61.EdgeType.CONNECTS_TO) continue;
17808
17965
  if (bucket.source !== serviceId17) continue;
17809
17966
  if (bucket.target === excludeTarget) continue;
17810
17967
  if (!graph.hasNode(bucket.target)) continue;
17811
17968
  const target = graph.getNodeAttributes(bucket.target);
17812
- if (target.type !== import_types60.NodeType.DatabaseNode) continue;
17969
+ if (target.type !== import_types61.NodeType.DatabaseNode) continue;
17813
17970
  if (target.engine !== engine) continue;
17814
17971
  if (bucket.observed || datastoreEverObserved(graph, bucket.target)) return true;
17815
17972
  }
@@ -17819,10 +17976,10 @@ var DEAD_CODE_PROBE_CONFIDENCE = 0.1;
17819
17976
  function dampenDeadCodeProbes(graph, buckets2, all) {
17820
17977
  return all.map((d) => {
17821
17978
  if (d.type !== "missing-observed") return d;
17822
- if (!d.extracted || d.edgeType !== import_types60.EdgeType.CONNECTS_TO) return d;
17979
+ if (!d.extracted || d.edgeType !== import_types61.EdgeType.CONNECTS_TO) return d;
17823
17980
  if (!graph.hasNode(d.target)) return d;
17824
17981
  const target = graph.getNodeAttributes(d.target);
17825
- if (target.type !== import_types60.NodeType.DatabaseNode) return d;
17982
+ if (target.type !== import_types61.NodeType.DatabaseNode) return d;
17826
17983
  if (d.extracted.evidence?.hostSource !== "literal") return d;
17827
17984
  if (datastoreEverObserved(graph, d.target)) return d;
17828
17985
  const engine = target.engine;
@@ -17842,7 +17999,7 @@ function suppressHostMismatchHalves(all) {
17842
17999
  for (const d of all) {
17843
18000
  if (d.type !== "host-mismatch") continue;
17844
18001
  observedHalf.add(`${d.source}->${d.target}`);
17845
- declaredHalf.add((0, import_types60.databaseId)(d.extractedHost));
18002
+ declaredHalf.add((0, import_types61.databaseId)(d.extractedHost));
17846
18003
  }
17847
18004
  if (observedHalf.size === 0) return all;
17848
18005
  return all.filter((d) => {
@@ -17862,14 +18019,14 @@ function computeDivergences(graph, opts = {}) {
17862
18019
  }
17863
18020
  graph.forEachNode((nodeId, attrs) => {
17864
18021
  const n = attrs;
17865
- if (n.type === import_types60.NodeType.ServiceNode) {
18022
+ if (n.type === import_types61.NodeType.ServiceNode) {
17866
18023
  const svc = n;
17867
18024
  for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
17868
18025
  for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
17869
18026
  for (const d of detectDeployDivergence(svc)) all.push(d);
17870
18027
  return;
17871
18028
  }
17872
- if (n.type === import_types60.NodeType.InfraNode && n.kind === "sql-table") {
18029
+ if (n.type === import_types61.NodeType.InfraNode && n.kind === "sql-table") {
17873
18030
  for (const d of detectColumnDrift(n)) all.push(d);
17874
18031
  }
17875
18032
  });
@@ -17934,7 +18091,7 @@ function computeDivergences(graph, opts = {}) {
17934
18091
  const bloc = "location" in b && b.location ? b.location : "";
17935
18092
  return aloc.localeCompare(bloc);
17936
18093
  });
17937
- return import_types60.DivergenceResultSchema.parse({
18094
+ return import_types61.DivergenceResultSchema.parse({
17938
18095
  divergences: filtered,
17939
18096
  totalAffected: filtered.length,
17940
18097
  computedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -17988,7 +18145,7 @@ function queryLogEntries(opts) {
17988
18145
 
17989
18146
  // src/goodybag.ts
17990
18147
  init_cjs_shims();
17991
- var import_types61 = require("@neat.is/types");
18148
+ var import_types62 = require("@neat.is/types");
17992
18149
  var CODE_FILEPATH_ATTR2 = "code.filepath";
17993
18150
  var CODE_LINENO_ATTR2 = "code.lineno";
17994
18151
  var BLAST_NEAREST_LIMIT = 5;
@@ -18014,7 +18171,7 @@ function locusOf(graph, ev) {
18014
18171
  ...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
18015
18172
  ...symbol ? { symbol } : {},
18016
18173
  service: node?.service ?? ev.service,
18017
- provenance: import_types61.Provenance.OBSERVED
18174
+ provenance: import_types62.Provenance.OBSERVED
18018
18175
  };
18019
18176
  }
18020
18177
  function locusFromNode(graph, nodeId) {
@@ -18030,7 +18187,7 @@ function locusFromNode(graph, nodeId) {
18030
18187
  ...typeof end === "number" ? { lineEnd: end } : {},
18031
18188
  ...n.qualname ? { symbol: shortLabel(graph, nodeId) } : {},
18032
18189
  ...n.service ? { service: n.service } : {},
18033
- provenance: import_types61.Provenance.INFERRED
18190
+ provenance: import_types62.Provenance.INFERRED
18034
18191
  };
18035
18192
  }
18036
18193
  function promoteCauseLocus(graph, causeNode, incidents) {
@@ -18039,7 +18196,7 @@ function promoteCauseLocus(graph, causeNode, incidents) {
18039
18196
  );
18040
18197
  if (native) {
18041
18198
  const l = locusOf(graph, native);
18042
- if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance: import_types61.Provenance.INFERRED };
18199
+ if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance: import_types62.Provenance.INFERRED };
18043
18200
  }
18044
18201
  return locusFromNode(graph, causeNode);
18045
18202
  }
@@ -18088,7 +18245,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
18088
18245
  const chain = (rc.traversalPath ?? []).map((node, i) => ({
18089
18246
  node,
18090
18247
  grain: grainOf2(graph, node),
18091
- provenance: provs[i] ?? provs[provs.length - 1] ?? import_types61.Provenance.INFERRED
18248
+ provenance: provs[i] ?? provs[provs.length - 1] ?? import_types62.Provenance.INFERRED
18092
18249
  }));
18093
18250
  rootCause = {
18094
18251
  node: rc.rootCauseNode,
@@ -18119,7 +18276,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
18119
18276
  kind: "incident",
18120
18277
  id: errorEvent.id,
18121
18278
  at: errorEvent.timestamp,
18122
- incidentKind: (0, import_types61.incidentKindOf)(errorEvent),
18279
+ incidentKind: (0, import_types62.incidentKindOf)(errorEvent),
18123
18280
  service: errorEvent.service,
18124
18281
  affectedNode: affected,
18125
18282
  message: errorEvent.errorMessage,
@@ -18137,7 +18294,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
18137
18294
  headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
18138
18295
  };
18139
18296
  card.grade = gradeIncidentCard(card);
18140
- return import_types61.IncidentCardSchema.parse(card);
18297
+ return import_types62.IncidentCardSchema.parse(card);
18141
18298
  }
18142
18299
  var GRADE_PRIORS_VERSION = "sniper-architecture-priors-2026-10-08";
18143
18300
  var GRADE_WEIGHTS = {
@@ -18244,7 +18401,7 @@ function gradeIncidentCard(card) {
18244
18401
 
18245
18402
  // src/ask.ts
18246
18403
  init_cjs_shims();
18247
- var import_types62 = require("@neat.is/types");
18404
+ var import_types63 = require("@neat.is/types");
18248
18405
  var DEFAULT_MAX_NODES = 3;
18249
18406
  var MAX_FACTS_PER_SECTION = 6;
18250
18407
  var INTENT_RULES = [
@@ -18480,11 +18637,11 @@ function idBody(id) {
18480
18637
  return colon >= 0 ? id.slice(colon + 1) : id;
18481
18638
  }
18482
18639
  var TYPE_NOUNS = [
18483
- { nouns: ["database", "db", "table"], type: import_types62.NodeType.DatabaseNode },
18484
- { nouns: ["service", "api", "backend"], type: import_types62.NodeType.ServiceNode },
18485
- { nouns: ["route", "endpoint"], type: import_types62.NodeType.RouteNode },
18486
- { nouns: ["file"], type: import_types62.NodeType.FileNode },
18487
- { nouns: ["config"], type: import_types62.NodeType.ConfigNode }
18640
+ { nouns: ["database", "db", "table"], type: import_types63.NodeType.DatabaseNode },
18641
+ { nouns: ["service", "api", "backend"], type: import_types63.NodeType.ServiceNode },
18642
+ { nouns: ["route", "endpoint"], type: import_types63.NodeType.RouteNode },
18643
+ { nouns: ["file"], type: import_types63.NodeType.FileNode },
18644
+ { nouns: ["config"], type: import_types63.NodeType.ConfigNode }
18488
18645
  ];
18489
18646
  var EMBED_MIN_SCORE = 0.35;
18490
18647
  async function resolveEntities(graph, question, searchIndex, maxNodes) {
@@ -18498,7 +18655,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
18498
18655
  };
18499
18656
  graph.forEachNode((id, attrs) => {
18500
18657
  const node = attrs;
18501
- if (node.type === import_types62.NodeType.FrontierNode) return;
18658
+ if (node.type === import_types63.NodeType.FrontierNode) return;
18502
18659
  const name = nodeName(node);
18503
18660
  const body = idBody(id);
18504
18661
  const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
@@ -18517,7 +18674,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
18517
18674
  const res = await searchIndex.search(question, 10);
18518
18675
  if (res.provider !== "substring") {
18519
18676
  for (const m of res.matches) {
18520
- if (m.node.type === import_types62.NodeType.FrontierNode) continue;
18677
+ if (m.node.type === import_types63.NodeType.FrontierNode) continue;
18521
18678
  if (!graph.hasNode(m.node.id)) continue;
18522
18679
  const already = best.get(m.node.id);
18523
18680
  if (!already && m.score < EMBED_MIN_SCORE) continue;
@@ -18577,7 +18734,7 @@ function edgeSignalNote(e) {
18577
18734
  function buildRootCauseSection(graph, node, incidents, now) {
18578
18735
  const result = getRootCause(graph, node, void 0, incidents, { now });
18579
18736
  if (!result) return null;
18580
- const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types62.Provenance.OBSERVED;
18737
+ const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types63.Provenance.OBSERVED;
18581
18738
  const facts = [
18582
18739
  {
18583
18740
  text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
@@ -18627,7 +18784,7 @@ function buildObservedSection(graph, node) {
18627
18784
  if (result.observed && result.inboundObservedCount > 0) {
18628
18785
  facts.push({
18629
18786
  text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
18630
- provenance: import_types62.Provenance.OBSERVED
18787
+ provenance: import_types63.Provenance.OBSERVED
18631
18788
  });
18632
18789
  } else {
18633
18790
  return null;
@@ -18650,10 +18807,10 @@ function buildBlastSection(graph, node) {
18650
18807
  }
18651
18808
  function buildDatabaseCallersSection(graph, node) {
18652
18809
  const callers = getBlastRadius(graph, node).affectedNodes.filter((item) => {
18653
- if (graph.getNodeAttributes(item.nodeId).type !== import_types62.NodeType.ServiceNode) return false;
18810
+ if (graph.getNodeAttributes(item.nodeId).type !== import_types63.NodeType.ServiceNode) return false;
18654
18811
  return item.path.slice(1, -1).every((id) => {
18655
18812
  const type = graph.getNodeAttributes(id).type;
18656
- return type === import_types62.NodeType.FileNode || type === import_types62.NodeType.SymbolNode;
18813
+ return type === import_types63.NodeType.FileNode || type === import_types63.NodeType.SymbolNode;
18657
18814
  });
18658
18815
  });
18659
18816
  return {
@@ -18672,7 +18829,7 @@ function buildIncidentsSection(node, incidents) {
18672
18829
  const facts = ordered.map((ev) => ({
18673
18830
  text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
18674
18831
  // ErrorEvents are observation records — OBSERVED by definition.
18675
- provenance: import_types62.Provenance.OBSERVED
18832
+ provenance: import_types63.Provenance.OBSERVED
18676
18833
  }));
18677
18834
  return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
18678
18835
  }
@@ -18695,8 +18852,8 @@ function runtimeEdgeState(graph) {
18695
18852
  let observed = false;
18696
18853
  let stale = false;
18697
18854
  graph.forEachEdge((_id, attrs) => {
18698
- if (attrs.provenance === import_types62.Provenance.OBSERVED) observed = true;
18699
- if (attrs.provenance === import_types62.Provenance.STALE) stale = true;
18855
+ if (attrs.provenance === import_types63.Provenance.OBSERVED) observed = true;
18856
+ if (attrs.provenance === import_types63.Provenance.STALE) stale = true;
18700
18857
  });
18701
18858
  return { observed, stale };
18702
18859
  }
@@ -18764,7 +18921,7 @@ function buildGlobalIncidentsSection(incidents) {
18764
18921
  }
18765
18922
  const byKey = /* @__PURE__ */ new Map();
18766
18923
  for (const ev of incidents) {
18767
- const key = ev.affectedNode || (0, import_types62.serviceId)(ev.service);
18924
+ const key = ev.affectedNode || (0, import_types63.serviceId)(ev.service);
18768
18925
  const cur = byKey.get(key);
18769
18926
  if (!cur) {
18770
18927
  byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
@@ -18779,7 +18936,7 @@ function buildGlobalIncidentsSection(incidents) {
18779
18936
  const rows = [...byKey.values()].sort((a, b) => b.count - a.count || b.latest.localeCompare(a.latest) || a.key.localeCompare(b.key)).slice(0, MAX_FACTS_PER_SECTION);
18780
18937
  const facts = rows.map((r) => ({
18781
18938
  text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
18782
- provenance: import_types62.Provenance.OBSERVED
18939
+ provenance: import_types63.Provenance.OBSERVED
18783
18940
  }));
18784
18941
  return {
18785
18942
  heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
@@ -18792,7 +18949,7 @@ function buildOverviewSections(graph, incidents) {
18792
18949
  graph.forEachNode((_id, attrs) => {
18793
18950
  const node = attrs;
18794
18951
  nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
18795
- if (node.type === import_types62.NodeType.ServiceNode) services.push(node.id);
18952
+ if (node.type === import_types63.NodeType.ServiceNode) services.push(node.id);
18796
18953
  });
18797
18954
  const edgeByProv = /* @__PURE__ */ new Map();
18798
18955
  graph.forEachEdge((_id, attrs) => {
@@ -18804,10 +18961,10 @@ function buildOverviewSections(graph, incidents) {
18804
18961
  const shapeFacts = [
18805
18962
  { text: `${graph.order} nodes, ${graph.size} edges` },
18806
18963
  {
18807
- text: `${count(import_types62.NodeType.ServiceNode)} services, ${count(import_types62.NodeType.FileNode)} files, ${count(import_types62.NodeType.SymbolNode)} symbols, ${count(import_types62.NodeType.DatabaseNode)} databases`
18964
+ text: `${count(import_types63.NodeType.ServiceNode)} services, ${count(import_types63.NodeType.FileNode)} files, ${count(import_types63.NodeType.SymbolNode)} symbols, ${count(import_types63.NodeType.DatabaseNode)} databases`
18808
18965
  }
18809
18966
  ];
18810
- for (const p of [import_types62.Provenance.EXTRACTED, import_types62.Provenance.OBSERVED, import_types62.Provenance.INFERRED, import_types62.Provenance.STALE]) {
18967
+ for (const p of [import_types63.Provenance.EXTRACTED, import_types63.Provenance.OBSERVED, import_types63.Provenance.INFERRED, import_types63.Provenance.STALE]) {
18811
18968
  const n = edgeByProv.get(p) ?? 0;
18812
18969
  if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
18813
18970
  }
@@ -18824,7 +18981,7 @@ function buildOverviewSections(graph, incidents) {
18824
18981
  if (incidents && incidents.length > 0) {
18825
18982
  const incCount = /* @__PURE__ */ new Map();
18826
18983
  for (const ev of incidents) {
18827
- const key = ev.affectedNode || (0, import_types62.serviceId)(ev.service);
18984
+ const key = ev.affectedNode || (0, import_types63.serviceId)(ev.service);
18828
18985
  incCount.set(key, (incCount.get(key) ?? 0) + 1);
18829
18986
  }
18830
18987
  const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
@@ -18832,7 +18989,7 @@ function buildOverviewSections(graph, incidents) {
18832
18989
  heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
18833
18990
  facts: top.map(([k, n]) => ({
18834
18991
  text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
18835
- provenance: import_types62.Provenance.OBSERVED
18992
+ provenance: import_types63.Provenance.OBSERVED
18836
18993
  }))
18837
18994
  });
18838
18995
  }
@@ -18963,7 +19120,7 @@ async function askGraph(graph, question, opts = {}) {
18963
19120
  let scope;
18964
19121
  if (primary) {
18965
19122
  scope = "node";
18966
- const callersQuestion = intent === "dependencies" && graph.getNodeAttributes(primary).type === import_types62.NodeType.DatabaseNode && /\b(?:which|what)\s+services?\s+(?:talks?\s+to|connects?\s+to|uses?|hits?|calls?|reads?\s+from|writes?\s+to)\b/i.test(question);
19123
+ const callersQuestion = intent === "dependencies" && graph.getNodeAttributes(primary).type === import_types63.NodeType.DatabaseNode && /\b(?:which|what)\s+services?\s+(?:talks?\s+to|connects?\s+to|uses?|hits?|calls?|reads?\s+from|writes?\s+to)\b/i.test(question);
18967
19124
  if (callersQuestion) sections.push(buildDatabaseCallersSection(graph, primary));
18968
19125
  for (const kind of SECTION_ORDER[intent]) {
18969
19126
  if (callersQuestion && kind === "blast") continue;
@@ -18981,7 +19138,7 @@ async function askGraph(graph, question, opts = {}) {
18981
19138
  const provSet = /* @__PURE__ */ new Set();
18982
19139
  for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
18983
19140
  const confidence = sections[0]?.facts[0]?.confidence;
18984
- return import_types62.AskResultSchema.parse({
19141
+ return import_types63.AskResultSchema.parse({
18985
19142
  question,
18986
19143
  intent,
18987
19144
  matched,
@@ -19076,7 +19233,7 @@ init_cjs_shims();
19076
19233
  var import_node_fs39 = require("fs");
19077
19234
  var import_node_os3 = __toESM(require("os"), 1);
19078
19235
  var import_node_path75 = __toESM(require("path"), 1);
19079
- var import_types63 = require("@neat.is/types");
19236
+ var import_types64 = require("@neat.is/types");
19080
19237
  var LOCK_TIMEOUT_MS = 5e3;
19081
19238
  var LOCK_RETRY_MS = 50;
19082
19239
  function neatHome() {
@@ -19294,10 +19451,10 @@ async function readRegistry() {
19294
19451
  throw err;
19295
19452
  }
19296
19453
  const parsed = JSON.parse(raw);
19297
- return import_types63.RegistryFileSchema.parse(parsed);
19454
+ return import_types64.RegistryFileSchema.parse(parsed);
19298
19455
  }
19299
19456
  async function writeRegistry(reg) {
19300
- const validated = import_types63.RegistryFileSchema.parse(reg);
19457
+ const validated = import_types64.RegistryFileSchema.parse(reg);
19301
19458
  await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
19302
19459
  }
19303
19460
  var RegistryError = class extends Error {
@@ -19396,11 +19553,11 @@ async function pruneRegistry(opts = {}) {
19396
19553
  init_cjs_shims();
19397
19554
  var import_node_fs40 = require("fs");
19398
19555
  var import_zod = require("zod");
19399
- var import_types64 = require("@neat.is/types");
19556
+ var import_types65 = require("@neat.is/types");
19400
19557
  var SSE_HEARTBEAT_MS = 3e4;
19401
19558
  var SSE_BACKPRESSURE_CAP = 1e3;
19402
19559
  var INCIDENT_TRIGGER_STREAM_SCOPE = "incident-only-v1";
19403
- var IncidentTriggerSchema = import_types64.IncidentEventPayloadSchema.extend({
19560
+ var IncidentTriggerSchema = import_types65.IncidentEventPayloadSchema.extend({
19404
19561
  incidentId: import_zod.z.string().regex(/^[A-Za-z0-9:_-]{1,100}$/),
19405
19562
  affectedNode: import_zod.z.string().min(1).max(512),
19406
19563
  service: import_zod.z.string().min(1).max(256),
@@ -19428,12 +19585,12 @@ function loadIncidentReplay(errorsPath, cursor) {
19428
19585
  if (!isExtractionFailure(row)) throw new Error("incident replay unavailable");
19429
19586
  continue;
19430
19587
  }
19431
- const event = import_types64.ErrorEventSchema.parse(row);
19588
+ const event = import_types65.ErrorEventSchema.parse(row);
19432
19589
  const trigger = IncidentTriggerSchema.parse({
19433
19590
  incidentId: event.id,
19434
19591
  affectedNode: event.affectedNode,
19435
19592
  service: event.service,
19436
- incidentKind: (0, import_types64.incidentKindOf)(event),
19593
+ incidentKind: (0, import_types65.incidentKindOf)(event),
19437
19594
  at: event.timestamp
19438
19595
  });
19439
19596
  const prior = seen.get(trigger.incidentId), encoded = JSON.stringify(trigger);
@@ -19808,7 +19965,7 @@ function renderVerdict({
19808
19965
  }
19809
19966
 
19810
19967
  // src/pr-verdict.ts
19811
- var import_types65 = require("@neat.is/types");
19968
+ var import_types66 = require("@neat.is/types");
19812
19969
 
19813
19970
  // src/connectors/hosted-repos.ts
19814
19971
  init_cjs_shims();
@@ -19869,6 +20026,7 @@ var defaultCloneRepo = async (cloneUrl, ref, destDir) => {
19869
20026
  });
19870
20027
  try {
19871
20028
  await Promise.race([clone, timeout]);
20029
+ return await git.resolveRef({ fs: fs44, dir: destDir, ref: "HEAD" });
19872
20030
  } finally {
19873
20031
  if (timer) clearTimeout(timer);
19874
20032
  }
@@ -19920,6 +20078,19 @@ function scrubCloneToken(s) {
19920
20078
  function needsSync(r) {
19921
20079
  return r.syncStatus === void 0 || r.syncStatus === "syncing";
19922
20080
  }
20081
+ function validRepoRow(row) {
20082
+ if (!row || typeof row !== "object") return false;
20083
+ const r = row;
20084
+ if (typeof r.owner !== "string" || typeof r.name !== "string" || typeof r.cloneUrl !== "string") return false;
20085
+ if (!/^[A-Za-z0-9_.-]+$/.test(r.owner) || !/^[A-Za-z0-9_.-]+$/.test(r.name)) return false;
20086
+ if (r.syncStatus !== void 0 && !["syncing", "synced", "failed"].includes(r.syncStatus)) return false;
20087
+ try {
20088
+ const url = new URL(r.cloneUrl);
20089
+ return url.protocol === "https:" && url.hostname === "github.com" && !url.port && !url.search && !url.hash && url.pathname === `/${r.owner}/${r.name}.git`;
20090
+ } catch {
20091
+ return false;
20092
+ }
20093
+ }
19923
20094
  async function syncOneRepo(r, input) {
19924
20095
  const { deps, graph } = input;
19925
20096
  const cloneRepo = input.cloneRepo ?? defaultCloneRepo;
@@ -19928,20 +20099,30 @@ async function syncOneRepo(r, input) {
19928
20099
  const tmpRoot = input.tmpRoot ?? import_node_os4.default.tmpdir();
19929
20100
  let dir;
19930
20101
  try {
20102
+ invalidateSourceBaseline(graph, label, "syncing");
19931
20103
  dir = await (0, import_promises.mkdtemp)(import_node_path76.default.join(tmpRoot, "neat-repo-"));
19932
20104
  await cpPostStatus(deps, r.owner, r.name, { syncStatus: "syncing", detail: "cloning" }).catch(() => {
19933
20105
  });
19934
- await cloneRepo(r.cloneUrl, r.defaultBranch, dir);
19935
- const extracted = await extract(graph, dir, { source: label });
20106
+ const sha = await cloneRepo(r.cloneUrl, r.defaultBranch, dir);
20107
+ const extracted = await extract(graph, dir, {
20108
+ source: label,
20109
+ ...typeof sha === "string" ? { sourceCommit: { repository: label, sha } } : {}
20110
+ });
20111
+ input.onExtracted?.(label);
20112
+ const errors = extracted?.extractionErrors ?? 0;
20113
+ const skipped = extracted?.skippedFiles ?? 0;
20114
+ const incomplete = errors > 0 || skipped > 0;
20115
+ if (incomplete) invalidateSourceBaseline(graph, label);
19936
20116
  const nodes = extracted?.nodesAdded ?? 0;
19937
20117
  const edges = extracted?.edgesAdded ?? 0;
19938
20118
  await cpPostStatus(deps, r.owner, r.name, {
19939
20119
  syncStatus: "synced",
19940
- detail: `extracted ${nodes} node${nodes === 1 ? "" : "s"}, ${edges} edge${edges === 1 ? "" : "s"}`,
20120
+ detail: `extracted ${nodes} node${nodes === 1 ? "" : "s"}, ${edges} edge${edges === 1 ? "" : "s"}` + (incomplete ? ` (incomplete: ${errors} errors, ${skipped} skipped files)` : ""),
19941
20121
  lastSyncAt: new Date(input.now?.() ?? Date.now()).toISOString()
19942
20122
  });
19943
20123
  return true;
19944
20124
  } catch (err) {
20125
+ invalidateSourceBaseline(graph, label);
19945
20126
  input.onError?.(label, err);
19946
20127
  await cpPostStatus(deps, r.owner, r.name, {
19947
20128
  syncStatus: "failed",
@@ -19960,13 +20141,30 @@ async function runRepoSyncPassCounted(input) {
19960
20141
  try {
19961
20142
  repos = await cpGet(`/internal/projects/${input.deps.projectId}/repos`, input.deps);
19962
20143
  } catch (err) {
20144
+ invalidateSourceBaseline(input.graph);
19963
20145
  input.onSkip?.("(all)", `control plane repo list unreadable \u2014 ${err.message}`);
19964
20146
  return counts;
19965
20147
  }
19966
- if (!Array.isArray(repos)) return counts;
20148
+ if (!Array.isArray(repos)) {
20149
+ invalidateSourceBaseline(input.graph);
20150
+ return counts;
20151
+ }
19967
20152
  counts.listed = true;
19968
- for (const r of repos) {
19969
- if (!input.forceResync && !needsSync(r)) continue;
20153
+ const validRepos = repos.filter(validRepoRow);
20154
+ const invalidCount = repos.length - validRepos.length;
20155
+ if (invalidCount) {
20156
+ counts.failed += invalidCount;
20157
+ for (let index = 0; index < invalidCount; index++) {
20158
+ input.onSkip?.("(invalid)", "control plane repo row invalid");
20159
+ }
20160
+ }
20161
+ retainSourceBaselines(input.graph, validRepos.map((r) => `${r.owner}/${r.name}`));
20162
+ for (const r of validRepos) {
20163
+ if (r.syncStatus === "failed") invalidateSourceBaseline(input.graph, `${r.owner}/${r.name}`);
20164
+ }
20165
+ for (const r of validRepos) {
20166
+ const forced = typeof input.forceResync === "function" ? input.forceResync(`${r.owner}/${r.name}`) : input.forceResync === true;
20167
+ if (!forced && !needsSync(r)) continue;
19970
20168
  if (await syncOneRepo(r, input)) counts.synced++;
19971
20169
  else counts.failed++;
19972
20170
  }
@@ -19979,14 +20177,20 @@ async function startRepoSync(input) {
19979
20177
  let inFlight = null;
19980
20178
  let again = false;
19981
20179
  let lastPass;
19982
- let bootResyncDone = false;
20180
+ const bootExtracted = /* @__PURE__ */ new Set();
19983
20181
  const run = async () => {
19984
20182
  try {
19985
20183
  do {
19986
20184
  again = false;
19987
20185
  const startedAt = new Date(now()).toISOString();
19988
- const counts = await runRepoSyncPassCounted({ ...input, forceResync: !bootResyncDone });
19989
- if (counts.listed) bootResyncDone = true;
20186
+ const counts = await runRepoSyncPassCounted({
20187
+ ...input,
20188
+ forceResync: (repo) => !bootExtracted.has(repo),
20189
+ onExtracted: (repo) => {
20190
+ bootExtracted.add(repo);
20191
+ input.onExtracted?.(repo);
20192
+ }
20193
+ });
19990
20194
  lastPass = { ...counts, startedAt, finishedAt: new Date(now()).toISOString() };
19991
20195
  } while (again && !stopped);
19992
20196
  } finally {
@@ -20055,7 +20259,7 @@ var PrVerdictError = class extends Error {
20055
20259
  details;
20056
20260
  };
20057
20261
  function parsePrVerdictRequest(body) {
20058
- const parsed = import_types65.PrVerdictBodySchema.safeParse(body);
20262
+ const parsed = import_types66.PrVerdictBodySchema.safeParse(body);
20059
20263
  if (!parsed.success) {
20060
20264
  throw new PrVerdictError("invalid pr-verdict body", 400, void 0, parsed.error.issues);
20061
20265
  }
@@ -20404,15 +20608,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
20404
20608
 
20405
20609
  // src/connectors/index.ts
20406
20610
  init_cjs_shims();
20407
- var import_types66 = require("@neat.is/types");
20611
+ var import_types67 = require("@neat.is/types");
20408
20612
  var NO_ENV = "unknown";
20409
20613
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
20410
20614
  if (!graph.hasNode(targetNodeId)) return void 0;
20411
20615
  const sites = [];
20412
20616
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
20413
20617
  const edge = graph.getEdgeAttributes(edgeId);
20414
- if (edge.provenance !== import_types66.Provenance.EXTRACTED) continue;
20415
- const parsed = (0, import_types66.parseFileId)(edge.source);
20618
+ if (edge.provenance !== import_types67.Provenance.EXTRACTED) continue;
20619
+ const parsed = (0, import_types67.parseFileId)(edge.source);
20416
20620
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
20417
20621
  const site = { relPath: edge.evidence.file };
20418
20622
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -20423,7 +20627,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
20423
20627
  function routeCallSiteFor(graph, targetNodeId) {
20424
20628
  if (!graph.hasNode(targetNodeId)) return void 0;
20425
20629
  const attrs = graph.getNodeAttributes(targetNodeId);
20426
- if (attrs.type !== import_types66.NodeType.RouteNode || !attrs.path) return void 0;
20630
+ if (attrs.type !== import_types67.NodeType.RouteNode || !attrs.path) return void 0;
20427
20631
  const site = { relPath: attrs.path };
20428
20632
  if (attrs.line !== void 0) site.line = attrs.line;
20429
20633
  return site;
@@ -21147,23 +21351,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
21147
21351
 
21148
21352
  // src/connectors/supabase/resolve.ts
21149
21353
  init_cjs_shims();
21150
- var import_types68 = require("@neat.is/types");
21354
+ var import_types69 = require("@neat.is/types");
21151
21355
  function createSupabaseResolveTarget(graph, config) {
21152
21356
  return (signal, _ctx) => {
21153
21357
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
21154
21358
  return null;
21155
21359
  }
21156
- const subResourceId = (0, import_types68.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
21360
+ const subResourceId = (0, import_types69.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
21157
21361
  if (graph.hasNode(subResourceId)) {
21158
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
21362
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types69.EdgeType.CALLS };
21159
21363
  }
21160
- const bareResourceId = (0, import_types68.infraId)(signal.targetKind, signal.targetName);
21364
+ const bareResourceId = (0, import_types69.infraId)(signal.targetKind, signal.targetName);
21161
21365
  if (graph.hasNode(bareResourceId)) {
21162
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
21366
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types69.EdgeType.CALLS };
21163
21367
  }
21164
- const projectLevelId = (0, import_types68.infraId)("supabase", config.nodeRef);
21368
+ const projectLevelId = (0, import_types69.infraId)("supabase", config.nodeRef);
21165
21369
  if (graph.hasNode(projectLevelId)) {
21166
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types68.EdgeType.CALLS };
21370
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types69.EdgeType.CALLS };
21167
21371
  }
21168
21372
  return null;
21169
21373
  };
@@ -21256,7 +21460,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
21256
21460
 
21257
21461
  // src/connectors/railway/index.ts
21258
21462
  init_cjs_shims();
21259
- var import_types72 = require("@neat.is/types");
21463
+ var import_types73 = require("@neat.is/types");
21260
21464
 
21261
21465
  // src/connectors/railway/client.ts
21262
21466
  init_cjs_shims();
@@ -21407,7 +21611,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
21407
21611
  const out = [];
21408
21612
  graph.forEachNode((_id, attrs) => {
21409
21613
  const node = attrs;
21410
- if (node.type !== import_types72.NodeType.RouteNode) return;
21614
+ if (node.type !== import_types73.NodeType.RouteNode) return;
21411
21615
  const route = attrs;
21412
21616
  if (route.service !== serviceName) return;
21413
21617
  out.push({
@@ -21511,12 +21715,12 @@ function createRailwayResolveTarget(config) {
21511
21715
  const serviceName = config.serviceNameById[config.serviceId];
21512
21716
  if (!serviceName) return null;
21513
21717
  if (signal.targetKind === ROUTE_TARGET_KIND) {
21514
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types72.EdgeType.CALLS };
21718
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types73.EdgeType.CALLS };
21515
21719
  }
21516
21720
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
21517
21721
  const peerName = config.serviceNameById[signal.targetName];
21518
21722
  if (!peerName) return null;
21519
- return { targetNodeId: (0, import_types72.serviceId)(peerName), serviceName, edgeType: import_types72.EdgeType.CONNECTS_TO };
21723
+ return { targetNodeId: (0, import_types73.serviceId)(peerName), serviceName, edgeType: import_types73.EdgeType.CONNECTS_TO };
21520
21724
  }
21521
21725
  return null;
21522
21726
  };
@@ -21704,11 +21908,11 @@ function mapLogEntriesToSignals(entries) {
21704
21908
 
21705
21909
  // src/connectors/firebase/resolve.ts
21706
21910
  init_cjs_shims();
21707
- var import_types74 = require("@neat.is/types");
21911
+ var import_types75 = require("@neat.is/types");
21708
21912
 
21709
21913
  // src/connectors/infer-service.ts
21710
21914
  init_cjs_shims();
21711
- var import_types73 = require("@neat.is/types");
21915
+ var import_types74 = require("@neat.is/types");
21712
21916
  function normalizeName(name) {
21713
21917
  return name.toLowerCase().replace(/[^a-z0-9]/g, "");
21714
21918
  }
@@ -21719,11 +21923,11 @@ function inferServiceName(graph, resourceName, method, path84) {
21719
21923
  const owners = /* @__PURE__ */ new Set();
21720
21924
  graph.forEachNode((_id, attrs) => {
21721
21925
  const node = attrs;
21722
- if (node.type === import_types73.NodeType.ServiceNode && typeof node.name === "string") {
21926
+ if (node.type === import_types74.NodeType.ServiceNode && typeof node.name === "string") {
21723
21927
  services.push(node.name);
21724
21928
  return;
21725
21929
  }
21726
- if (node.type !== import_types73.NodeType.RouteNode) return;
21930
+ if (node.type !== import_types74.NodeType.RouteNode) return;
21727
21931
  const route = attrs;
21728
21932
  if (!route.pathTemplate || normalizePathTemplate(route.pathTemplate) !== wantedPath) return;
21729
21933
  const routeMethod = route.method.toUpperCase();
@@ -21750,7 +21954,7 @@ function routeEntriesFor(graph, serviceName) {
21750
21954
  const entries = [];
21751
21955
  graph.forEachNode((_id, attrs) => {
21752
21956
  const node = attrs;
21753
- if (node.type !== import_types74.NodeType.RouteNode) return;
21957
+ if (node.type !== import_types75.NodeType.RouteNode) return;
21754
21958
  const route = attrs;
21755
21959
  if (route.service !== serviceName) return;
21756
21960
  entries.push({
@@ -21782,7 +21986,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
21782
21986
  return {
21783
21987
  targetNodeId: match.routeNodeId,
21784
21988
  serviceName,
21785
- edgeType: import_types74.EdgeType.CALLS
21989
+ edgeType: import_types75.EdgeType.CALLS
21786
21990
  };
21787
21991
  };
21788
21992
  }
@@ -21815,7 +22019,7 @@ init_cjs_shims();
21815
22019
 
21816
22020
  // src/connectors/cloudflare/connector.ts
21817
22021
  init_cjs_shims();
21818
- var import_types76 = require("@neat.is/types");
22022
+ var import_types77 = require("@neat.is/types");
21819
22023
 
21820
22024
  // src/connectors/cloudflare/client.ts
21821
22025
  init_cjs_shims();
@@ -21979,7 +22183,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
21979
22183
  graph.forEachNode((id, attrs) => {
21980
22184
  if (found) return;
21981
22185
  const a = attrs;
21982
- if (a.type === import_types76.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
22186
+ if (a.type === import_types77.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
21983
22187
  found = id;
21984
22188
  }
21985
22189
  });
@@ -21991,7 +22195,7 @@ function findMatchingRouteNode(graph, serviceName, method, path84) {
21991
22195
  graph.forEachNode((id, attrs) => {
21992
22196
  if (found) return;
21993
22197
  const a = attrs;
21994
- if (a.type !== import_types76.NodeType.RouteNode || a.service !== serviceName) return;
22198
+ if (a.type !== import_types77.NodeType.RouteNode || a.service !== serviceName) return;
21995
22199
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
21996
22200
  const routeMethod = (a.method ?? "").toUpperCase();
21997
22201
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -22010,11 +22214,11 @@ function createCloudflareResolveTarget(config, graph) {
22010
22214
  };
22011
22215
  const mapping = config.workers?.[scriptName];
22012
22216
  if (mapping) {
22013
- const wholeFileId = (0, import_types76.fileId)(mapping.service, mapping.entryFile);
22217
+ const wholeFileId = (0, import_types77.fileId)(mapping.service, mapping.entryFile);
22014
22218
  return {
22015
22219
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
22016
22220
  serviceName: mapping.service,
22017
- edgeType: import_types76.EdgeType.CALLS
22221
+ edgeType: import_types77.EdgeType.CALLS
22018
22222
  };
22019
22223
  }
22020
22224
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -22023,13 +22227,13 @@ function createCloudflareResolveTarget(config, graph) {
22023
22227
  return {
22024
22228
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
22025
22229
  serviceName: fileNode.service,
22026
- edgeType: import_types76.EdgeType.CALLS
22230
+ edgeType: import_types77.EdgeType.CALLS
22027
22231
  };
22028
22232
  }
22029
22233
  return {
22030
- targetNodeId: (0, import_types76.infraId)("cloudflare-worker", scriptName),
22234
+ targetNodeId: (0, import_types77.infraId)("cloudflare-worker", scriptName),
22031
22235
  serviceName: scriptName,
22032
- edgeType: import_types76.EdgeType.CALLS,
22236
+ edgeType: import_types77.EdgeType.CALLS,
22033
22237
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
22034
22238
  };
22035
22239
  };
@@ -22225,14 +22429,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
22225
22429
 
22226
22430
  // src/connectors/neon/resolve.ts
22227
22431
  init_cjs_shims();
22228
- var import_types80 = require("@neat.is/types");
22432
+ var import_types81 = require("@neat.is/types");
22229
22433
  function createNeonResolveTarget(config) {
22230
22434
  return (signal) => {
22231
22435
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
22232
22436
  return {
22233
- targetNodeId: (0, import_types80.infraId)("sql-table", signal.targetName),
22437
+ targetNodeId: (0, import_types81.infraId)("sql-table", signal.targetName),
22234
22438
  serviceName: config.serviceName,
22235
- edgeType: import_types80.EdgeType.CALLS,
22439
+ edgeType: import_types81.EdgeType.CALLS,
22236
22440
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
22237
22441
  };
22238
22442
  };
@@ -22413,14 +22617,14 @@ function mapLogEntriesToSignals2(entries) {
22413
22617
 
22414
22618
  // src/connectors/cloud-run/resolve.ts
22415
22619
  init_cjs_shims();
22416
- var import_types84 = require("@neat.is/types");
22620
+ var import_types85 = require("@neat.is/types");
22417
22621
  var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
22418
22622
  function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
22419
22623
  let found = null;
22420
22624
  graph.forEachNode((_id, attrs) => {
22421
22625
  if (found) return;
22422
22626
  const node = attrs;
22423
- if (node.type !== import_types84.NodeType.RouteNode) return;
22627
+ if (node.type !== import_types85.NodeType.RouteNode) return;
22424
22628
  const route = attrs;
22425
22629
  if (route.service !== serviceName || !route.pathTemplate) return;
22426
22630
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -22445,13 +22649,13 @@ function createCloudRunResolveTarget(graph, config) {
22445
22649
  normalizePathTemplate(path84)
22446
22650
  );
22447
22651
  if (routeNodeId) {
22448
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types84.EdgeType.CALLS };
22652
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types85.EdgeType.CALLS };
22449
22653
  }
22450
22654
  }
22451
22655
  return {
22452
- targetNodeId: (0, import_types84.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
22656
+ targetNodeId: (0, import_types85.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
22453
22657
  serviceName: mappedService ?? gcpServiceName,
22454
- edgeType: import_types84.EdgeType.CALLS,
22658
+ edgeType: import_types85.EdgeType.CALLS,
22455
22659
  ensureInfraNode: {
22456
22660
  kind: CLOUD_RUN_SERVICE_INFRA_KIND,
22457
22661
  name: gcpServiceName,
@@ -22633,14 +22837,14 @@ function mapLogEntriesToSignals3(entries) {
22633
22837
 
22634
22838
  // src/connectors/gcp-lb/resolve.ts
22635
22839
  init_cjs_shims();
22636
- var import_types88 = require("@neat.is/types");
22840
+ var import_types89 = require("@neat.is/types");
22637
22841
  var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
22638
22842
  function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
22639
22843
  let found = null;
22640
22844
  graph.forEachNode((_id, attrs) => {
22641
22845
  if (found) return;
22642
22846
  const node = attrs;
22643
- if (node.type !== import_types88.NodeType.RouteNode) return;
22847
+ if (node.type !== import_types89.NodeType.RouteNode) return;
22644
22848
  const route = attrs;
22645
22849
  if (route.service !== serviceName || !route.pathTemplate) return;
22646
22850
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -22665,13 +22869,13 @@ function createGcpLbResolveTarget(graph, config) {
22665
22869
  normalizePathTemplate(path84)
22666
22870
  );
22667
22871
  if (routeNodeId) {
22668
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types88.EdgeType.CALLS };
22872
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types89.EdgeType.CALLS };
22669
22873
  }
22670
22874
  }
22671
22875
  return {
22672
- targetNodeId: (0, import_types88.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
22876
+ targetNodeId: (0, import_types89.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
22673
22877
  serviceName: mappedService ?? backendServiceName,
22674
- edgeType: import_types88.EdgeType.CALLS,
22878
+ edgeType: import_types89.EdgeType.CALLS,
22675
22879
  ensureInfraNode: {
22676
22880
  kind: GCP_LB_BACKEND_INFRA_KIND,
22677
22881
  name: backendServiceName,
@@ -22712,7 +22916,7 @@ function createGcpLbConnector(graph, config = {}) {
22712
22916
 
22713
22917
  // src/connectors/render/index.ts
22714
22918
  init_cjs_shims();
22715
- var import_types91 = require("@neat.is/types");
22919
+ var import_types92 = require("@neat.is/types");
22716
22920
 
22717
22921
  // src/connectors/render/types.ts
22718
22922
  init_cjs_shims();
@@ -22790,7 +22994,7 @@ function buildRenderRouteIndex(graph, serviceName) {
22790
22994
  const out = [];
22791
22995
  graph.forEachNode((_id, attrs) => {
22792
22996
  const node = attrs;
22793
- if (node.type !== import_types91.NodeType.RouteNode) return;
22997
+ if (node.type !== import_types92.NodeType.RouteNode) return;
22794
22998
  const route = attrs;
22795
22999
  if (route.service !== serviceName) return;
22796
23000
  out.push({
@@ -22875,7 +23079,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
22875
23079
  function createRenderResolveTarget(config) {
22876
23080
  return (signal) => {
22877
23081
  if (signal.targetKind === ROUTE_TARGET_KIND2) {
22878
- return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types91.EdgeType.CALLS };
23082
+ return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types92.EdgeType.CALLS };
22879
23083
  }
22880
23084
  return null;
22881
23085
  };
@@ -23013,21 +23217,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
23013
23217
 
23014
23218
  // src/connectors/planetscale/resolve.ts
23015
23219
  init_cjs_shims();
23016
- var import_types95 = require("@neat.is/types");
23220
+ var import_types96 = require("@neat.is/types");
23017
23221
  var PLANETSCALE_DATABASE_KIND = "planetscale-database";
23018
23222
  function createPlanetscaleResolveTarget(graph, config) {
23019
23223
  const databaseName = `${config.organization}/${config.database}`;
23020
23224
  return (signal, _ctx) => {
23021
23225
  if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
23022
- const tableId = (0, import_types95.infraId)("sql-table", signal.targetName);
23226
+ const tableId = (0, import_types96.infraId)("sql-table", signal.targetName);
23023
23227
  if (graph.hasNode(tableId)) {
23024
- return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types95.EdgeType.CALLS };
23228
+ return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types96.EdgeType.CALLS };
23025
23229
  }
23026
- const providerId = (0, import_types95.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
23230
+ const providerId = (0, import_types96.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
23027
23231
  return {
23028
23232
  targetNodeId: providerId,
23029
23233
  serviceName: config.serviceName,
23030
- edgeType: import_types95.EdgeType.CALLS,
23234
+ edgeType: import_types96.EdgeType.CALLS,
23031
23235
  ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
23032
23236
  };
23033
23237
  };
@@ -23292,7 +23496,7 @@ function mapBuildsToSignals(builds, serviceName) {
23292
23496
 
23293
23497
  // src/connectors/eas/resolve.ts
23294
23498
  init_cjs_shims();
23295
- var import_types100 = require("@neat.is/types");
23499
+ var import_types101 = require("@neat.is/types");
23296
23500
  var NO_ENV2 = "unknown";
23297
23501
  var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
23298
23502
  var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
@@ -23308,8 +23512,8 @@ function configBasenamesForPhase(phase) {
23308
23512
  function configNodeService(graph, configNodeId) {
23309
23513
  for (const edgeId of graph.inboundEdges(configNodeId)) {
23310
23514
  const edge = graph.getEdgeAttributes(edgeId);
23311
- if (edge.type !== import_types100.EdgeType.CONFIGURED_BY) continue;
23312
- const parsed = (0, import_types100.parseFileId)(edge.source);
23515
+ if (edge.type !== import_types101.EdgeType.CONFIGURED_BY) continue;
23516
+ const parsed = (0, import_types101.parseFileId)(edge.source);
23313
23517
  if (parsed) return parsed.service;
23314
23518
  }
23315
23519
  return null;
@@ -23320,7 +23524,7 @@ function findConfigNode(graph, basenames, serviceName) {
23320
23524
  graph.forEachNode((id, attrs) => {
23321
23525
  if (scoped) return;
23322
23526
  const node = attrs;
23323
- if (node.type !== import_types100.NodeType.ConfigNode) return;
23527
+ if (node.type !== import_types101.NodeType.ConfigNode) return;
23324
23528
  if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
23325
23529
  if (anyMatch === null) anyMatch = id;
23326
23530
  if (configNodeService(graph, id) === serviceName) scoped = id;
@@ -23337,13 +23541,13 @@ function createEasResolveTarget(graph) {
23337
23541
  if (basenames.length > 0) {
23338
23542
  const configNodeId = findConfigNode(graph, basenames, serviceName);
23339
23543
  if (configNodeId) {
23340
- return { targetNodeId: configNodeId, serviceName, edgeType: import_types100.EdgeType.CALLS };
23544
+ return { targetNodeId: configNodeId, serviceName, edgeType: import_types101.EdgeType.CALLS };
23341
23545
  }
23342
23546
  }
23343
23547
  return {
23344
23548
  targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
23345
23549
  serviceName,
23346
- edgeType: import_types100.EdgeType.CALLS
23550
+ edgeType: import_types101.EdgeType.CALLS
23347
23551
  };
23348
23552
  };
23349
23553
  }
@@ -23978,7 +24182,7 @@ function serializeGraph(graph) {
23978
24182
  graph.forEachEdge((_id, attrs) => {
23979
24183
  edges.push(attrs);
23980
24184
  });
23981
- return { nodes, edges };
24185
+ return { nodes, edges, sourceBaselines: readSourceBaselines(graph) };
23982
24186
  }
23983
24187
  function projectFromReq(req2, singleProject, registry) {
23984
24188
  const params = req2.params;
@@ -24161,11 +24365,11 @@ function registerRoutes(scope, ctx) {
24161
24365
  const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
24162
24366
  const parsed = [];
24163
24367
  for (const c of candidates) {
24164
- const r = import_types103.DivergenceTypeSchema.safeParse(c);
24368
+ const r = import_types104.DivergenceTypeSchema.safeParse(c);
24165
24369
  if (!r.success) {
24166
24370
  return reply.code(400).send({
24167
24371
  error: `unknown divergence type "${c}"`,
24168
- allowed: import_types103.DivergenceTypeSchema.options
24372
+ allowed: import_types104.DivergenceTypeSchema.options
24169
24373
  });
24170
24374
  }
24171
24375
  parsed.push(r.data);
@@ -24602,7 +24806,7 @@ function registerRoutes(scope, ctx) {
24602
24806
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
24603
24807
  let violations = await log.readAll();
24604
24808
  if (req2.query.severity) {
24605
- const sev = import_types103.PolicySeveritySchema.safeParse(req2.query.severity);
24809
+ const sev = import_types104.PolicySeveritySchema.safeParse(req2.query.severity);
24606
24810
  if (!sev.success) {
24607
24811
  return reply.code(400).send({
24608
24812
  error: "invalid severity",
@@ -24641,7 +24845,7 @@ function registerRoutes(scope, ctx) {
24641
24845
  scope.post("/policies/check", async (req2, reply) => {
24642
24846
  const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
24643
24847
  if (!proj) return;
24644
- const parsed = import_types103.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
24848
+ const parsed = import_types104.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
24645
24849
  if (!parsed.success) {
24646
24850
  return reply.code(400).send({
24647
24851
  error: "invalid /policies/check body",
@@ -25002,7 +25206,7 @@ init_otel();
25002
25206
 
25003
25207
  // src/hang-sensor.ts
25004
25208
  init_cjs_shims();
25005
- var import_types104 = require("@neat.is/types");
25209
+ var import_types105 = require("@neat.is/types");
25006
25210
  var RECONCILE_INCIDENT_LIMIT = 500;
25007
25211
  function stageHangSurfaces(graph, incidents) {
25008
25212
  const boundaries = /* @__PURE__ */ new Set();
@@ -25015,7 +25219,7 @@ function stageHangSurfaces(graph, incidents) {
25015
25219
  if (!isBoundaryTimeoutSymptom(ctx)) continue;
25016
25220
  const hop = resolveHangHop(graph, boundary, incidents);
25017
25221
  if (!hop) continue;
25018
- if (stageFrontierEdge(graph, hop.source, hop.target, import_types104.EdgeType.CALLS)) staged++;
25222
+ if (stageFrontierEdge(graph, hop.source, hop.target, import_types105.EdgeType.CALLS)) staged++;
25019
25223
  }
25020
25224
  return staged;
25021
25225
  }
@@ -25377,12 +25581,22 @@ init_cjs_shims();
25377
25581
  // src/connectors/kubernetes/client.ts
25378
25582
  init_cjs_shims();
25379
25583
  var import_node_https = require("https");
25584
+ var K8S_RATE_LIMIT = { capacity: 120, refillMs: 1e3 };
25380
25585
  function deploymentsPath(namespace) {
25381
25586
  return `/apis/apps/v1/namespaces/${namespace}/deployments`;
25382
25587
  }
25383
25588
  function podsPath(namespace) {
25384
25589
  return `/api/v1/namespaces/${namespace}/pods`;
25385
25590
  }
25591
+ function podLogPath(namespace, podName, opts = {}) {
25592
+ const params = new URLSearchParams();
25593
+ if (opts.container) params.set("container", opts.container);
25594
+ if (typeof opts.tailLines === "number" && Number.isFinite(opts.tailLines)) params.set("tailLines", String(Math.trunc(opts.tailLines)));
25595
+ if (typeof opts.limitBytes === "number" && Number.isFinite(opts.limitBytes)) params.set("limitBytes", String(Math.trunc(opts.limitBytes)));
25596
+ if (opts.previous) params.set("previous", "true");
25597
+ const qs = params.toString();
25598
+ return `${podsPath(namespace)}/${podName}/log${qs ? `?${qs}` : ""}`;
25599
+ }
25386
25600
  function makeK8sFetchImpl(transport) {
25387
25601
  const agent = new import_node_https.Agent({
25388
25602
  ...transport.ca ? { ca: transport.ca } : {},
@@ -25433,7 +25647,7 @@ async function listResource(transport, namespace, path84, opts = {}) {
25433
25647
  { method: "GET", headers: { ...transport.token ? bearerAuthHeader(transport.token) : {}, Accept: "application/json" } },
25434
25648
  // accountKey: the (cluster, namespace) pair — an identifier, safe to log, the
25435
25649
  // rate-limit bucket for one namespace on one cluster (ADR-131).
25436
- { provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, fetchImpl }
25650
+ { provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, rateLimit: K8S_RATE_LIMIT, fetchImpl }
25437
25651
  );
25438
25652
  if (!res.ok) {
25439
25653
  throw new Error(`kubernetes ${path84} failed: ${res.status} ${res.statusText}`);
@@ -25454,6 +25668,37 @@ async function fetchDeployments(transport, namespace, opts = {}) {
25454
25668
  async function fetchPods(transport, namespace, opts = {}) {
25455
25669
  return listResource(transport, namespace, podsPath(namespace), opts);
25456
25670
  }
25671
+ async function fetchPodLog(transport, namespace, podName, opts = {}) {
25672
+ const base = opts.apiUrl ?? transport.server;
25673
+ const path84 = podLogPath(namespace, podName, {
25674
+ ...opts.container ? { container: opts.container } : {},
25675
+ ...opts.tailLines !== void 0 ? { tailLines: opts.tailLines } : {},
25676
+ ...opts.limitBytes !== void 0 ? { limitBytes: opts.limitBytes } : {},
25677
+ ...opts.previous ? { previous: true } : {}
25678
+ });
25679
+ const url = `${base.replace(/\/$/, "")}${path84}`;
25680
+ const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport);
25681
+ try {
25682
+ const res = await junctionFetch(
25683
+ url,
25684
+ { method: "GET", headers: { ...transport.token ? bearerAuthHeader(transport.token) : {}, Accept: "text/plain" } },
25685
+ { provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, rateLimit: K8S_RATE_LIMIT, fetchImpl }
25686
+ );
25687
+ if (!res.ok) return void 0;
25688
+ return await res.text();
25689
+ } catch {
25690
+ return void 0;
25691
+ }
25692
+ }
25693
+ function hasLogContent(text) {
25694
+ return typeof text === "string" && text.trim().length > 0;
25695
+ }
25696
+ async function fetchPodProcessLog(transport, namespace, podName, opts = {}) {
25697
+ const previous = await fetchPodLog(transport, namespace, podName, { ...opts, previous: true });
25698
+ if (hasLogContent(previous)) return previous;
25699
+ const current = await fetchPodLog(transport, namespace, podName, { ...opts, previous: false });
25700
+ return hasLogContent(current) ? current : void 0;
25701
+ }
25457
25702
 
25458
25703
  // src/connectors/kubernetes/kubeconfig.ts
25459
25704
  init_cjs_shims();
@@ -25561,6 +25806,123 @@ function parseK8sTargetName(targetName) {
25561
25806
  return { serviceName, fault };
25562
25807
  }
25563
25808
 
25809
+ // src/connectors/kubernetes/process-context.ts
25810
+ init_cjs_shims();
25811
+ var DEFAULT_MAX_LOG_LINES = 50;
25812
+ var DEFAULT_MAX_LOG_BYTES2 = 2 * 1024;
25813
+ var DEFAULT_MAX_ENTRIES = 64;
25814
+ var DEFAULT_MAX_VALUE_CHARS = 512;
25815
+ var REDACTED = "***REDACTED***";
25816
+ var SECRET_KEY_RE = /TOKEN|SECRET|KEY|PASSW(?:OR)?D|PWD|(?:^|[^A-Z])PASS(?:$|[^A-Z])|CREDENTIAL|(?:^|[^A-Z])AUTH|PRIVATE|DSN|COOKIE|SESSION|SALT|SIGNATURE|CERT|CONN(?:ECTION)?_?STR/i;
25817
+ function isSecretKey(name) {
25818
+ return SECRET_KEY_RE.test(name);
25819
+ }
25820
+ var PRIVATE_KEY_BLOCK_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g;
25821
+ var PRIVATE_KEY_TAIL_RE = /(?:^[A-Za-z0-9+/=]{32,}\r?\n)+-----END [A-Z ]*PRIVATE KEY-----/gm;
25822
+ var URL_USERINFO_RE = /([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^\s/@]*)@/g;
25823
+ var SECRET_PAIR_RE = /((?:^|[\s?&;,{("'])[A-Za-z0-9_.-]*?(?:passw(?:or)?d|pwd|(?<![a-z])pass(?![a-z])|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?key|credentials?|(?<![a-z])auth(?![a-z])|(?<![a-z])dsn(?![a-z]))[A-Za-z0-9_.-]*["']?\s*[=:]\s*["']?)([^\s&;,"'})]+)/gi;
25824
+ var AUTH_SCHEME_RE = /\b(Bearer|Basic|Token)\s+[A-Za-z0-9._~+/=-]{8,}/g;
25825
+ var KNOWN_TOKEN_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}|\bAKIA[0-9A-Z]{16}\b|\bgh[pousr]_[A-Za-z0-9]{20,}|\bgithub_pat_[A-Za-z0-9_]{20,}|\bsk_(?:live|test)_[A-Za-z0-9]{10,}|\bxox[abprs]-[A-Za-z0-9-]{10,}|\bglpat-[A-Za-z0-9_-]{16,}|\bAIza[0-9A-Za-z_-]{30,}|\bneat_pat_[A-Za-z0-9_-]{16,}/g;
25826
+ function redactText(text) {
25827
+ return text.replace(PRIVATE_KEY_BLOCK_RE, REDACTED).replace(PRIVATE_KEY_TAIL_RE, REDACTED).replace(URL_USERINFO_RE, (_m, scheme, userinfo) => {
25828
+ const colon = userinfo.indexOf(":");
25829
+ return colon > 0 ? `${scheme}${userinfo.slice(0, colon)}:${REDACTED}@` : `${scheme}${REDACTED}@`;
25830
+ }).replace(SECRET_PAIR_RE, (_m, key) => `${key}${REDACTED}`).replace(AUTH_SCHEME_RE, (_m, scheme) => `${scheme} ${REDACTED}`).replace(KNOWN_TOKEN_RE, REDACTED);
25831
+ }
25832
+ function redactValue(name, value) {
25833
+ if (isSecretKey(name)) return REDACTED;
25834
+ return redactText(value);
25835
+ }
25836
+ function redactArg(arg) {
25837
+ const eq = /^(--?)?([A-Za-z0-9_.-]+)=([\s\S]*)$/.exec(arg);
25838
+ if (eq && isSecretKey(eq[2])) {
25839
+ return `${eq[1] ?? ""}${eq[2]}=${REDACTED}`;
25840
+ }
25841
+ return redactText(arg);
25842
+ }
25843
+ function isSecretFlag(arg) {
25844
+ const m = /^--?([A-Za-z0-9_.-]+)$/.exec(arg);
25845
+ return m !== null && isSecretKey(m[1]);
25846
+ }
25847
+ function capValue(s, max = DEFAULT_MAX_VALUE_CHARS) {
25848
+ return s.length > max ? `${s.slice(0, max)}\u2026` : s;
25849
+ }
25850
+ function describeEnvVar(ev) {
25851
+ const name = typeof ev.name === "string" ? ev.name : "";
25852
+ if (name.length === 0) return void 0;
25853
+ if (typeof ev.value === "string") {
25854
+ return `${name}=${capValue(redactValue(name, ev.value))}`;
25855
+ }
25856
+ const from = ev.valueFrom;
25857
+ if (from) {
25858
+ if (from.secretKeyRef) {
25859
+ const ref = typeof from.secretKeyRef.name === "string" && from.secretKeyRef.name.length > 0 ? from.secretKeyRef.name : "<unnamed>";
25860
+ return `${name}=<from secret ${ref}>`;
25861
+ }
25862
+ if (from.configMapKeyRef) {
25863
+ const ref = typeof from.configMapKeyRef.name === "string" && from.configMapKeyRef.name.length > 0 ? from.configMapKeyRef.name : "<unnamed>";
25864
+ const key = typeof from.configMapKeyRef.key === "string" && from.configMapKeyRef.key.length > 0 ? ` key ${from.configMapKeyRef.key}` : "";
25865
+ return `${name}=<from configMap ${ref}${key}>`;
25866
+ }
25867
+ if (from.fieldRef && typeof from.fieldRef.fieldPath === "string" && from.fieldRef.fieldPath.length > 0) {
25868
+ return `${name}=<from field ${from.fieldRef.fieldPath}>`;
25869
+ }
25870
+ if (from.resourceFieldRef && typeof from.resourceFieldRef.resource === "string" && from.resourceFieldRef.resource.length > 0) {
25871
+ return `${name}=<from resource ${from.resourceFieldRef.resource}>`;
25872
+ }
25873
+ return `${name}=<from reference>`;
25874
+ }
25875
+ return `${name}=`;
25876
+ }
25877
+ function buildContainerEnv(container) {
25878
+ const out = [];
25879
+ for (const ev of container.env ?? []) {
25880
+ const d = describeEnvVar(ev);
25881
+ if (d !== void 0) out.push(d);
25882
+ if (out.length >= DEFAULT_MAX_ENTRIES) break;
25883
+ }
25884
+ return out;
25885
+ }
25886
+ function buildContainerArgs(container) {
25887
+ const raw = [];
25888
+ for (const c of container.command ?? []) if (typeof c === "string") raw.push(c);
25889
+ for (const a of container.args ?? []) if (typeof a === "string") raw.push(a);
25890
+ const out = [];
25891
+ for (let i = 0; i < raw.length && out.length < DEFAULT_MAX_ENTRIES; i++) {
25892
+ const arg = raw[i];
25893
+ out.push(capValue(redactArg(arg)));
25894
+ const next = raw[i + 1];
25895
+ if (isSecretFlag(arg) && next !== void 0 && !next.startsWith("-") && out.length < DEFAULT_MAX_ENTRIES) {
25896
+ out.push(REDACTED);
25897
+ i++;
25898
+ }
25899
+ }
25900
+ return out;
25901
+ }
25902
+ function capProcessLog(text, maxLines = DEFAULT_MAX_LOG_LINES, maxBytes = DEFAULT_MAX_LOG_BYTES2) {
25903
+ const trimmed = text.replace(/\s+$/, "");
25904
+ if (trimmed.length === 0) return "";
25905
+ const lines = trimmed.split("\n");
25906
+ const tail = lines.length > maxLines ? lines.slice(lines.length - maxLines) : lines;
25907
+ let out = tail.join("\n");
25908
+ if (out.length > maxBytes) out = out.slice(out.length - maxBytes);
25909
+ return out;
25910
+ }
25911
+ function buildProcessContext(input) {
25912
+ const out = {};
25913
+ if (typeof input.log === "string") {
25914
+ const capped = capProcessLog(redactText(input.log));
25915
+ if (capped.length > 0) out.processLog = capped;
25916
+ }
25917
+ if (input.container) {
25918
+ const args = buildContainerArgs(input.container);
25919
+ if (args.length > 0) out.containerArgs = args;
25920
+ const env = buildContainerEnv(input.container);
25921
+ if (env.length > 0) out.containerEnv = env;
25922
+ }
25923
+ return out;
25924
+ }
25925
+
25564
25926
  // src/connectors/kubernetes/map.ts
25565
25927
  function serviceNameFor(deployment, config) {
25566
25928
  const name = deployment.metadata?.name ?? "";
@@ -25578,6 +25940,9 @@ function podsForDeployment(deployment, pods) {
25578
25940
  function nowIso2() {
25579
25941
  return (/* @__PURE__ */ new Date()).toISOString();
25580
25942
  }
25943
+ function podLogKey(podName, container) {
25944
+ return container ? `${podName}\0${container}` : podName;
25945
+ }
25581
25946
  function podLevelFault(deployment, pods) {
25582
25947
  const name = deployment.metadata?.name ?? "";
25583
25948
  const owned = podsForDeployment(deployment, pods);
@@ -25595,7 +25960,9 @@ function podLevelFault(deployment, pods) {
25595
25960
  fault: "image-pull",
25596
25961
  message: `Deployment ${name} cannot pull image ${image} (${reason})`,
25597
25962
  timestamp: pod.status?.startTime ?? nowIso2(),
25598
- attributes: attrs
25963
+ attributes: attrs,
25964
+ pod,
25965
+ ...typeof cs.name === "string" && cs.name.length > 0 ? { container: cs.name } : {}
25599
25966
  };
25600
25967
  }
25601
25968
  if (reason === CRASH_LOOP_REASON && !crash) crash = { cs, pod };
@@ -25617,11 +25984,47 @@ function podLevelFault(deployment, pods) {
25617
25984
  fault: "crash-loop",
25618
25985
  message: `Deployment ${name} is crashlooping (restarts: ${restarts}); ${detail}`,
25619
25986
  timestamp: term?.finishedAt ?? pod.status?.startTime ?? nowIso2(),
25620
- attributes: attrs
25987
+ attributes: attrs,
25988
+ pod,
25989
+ ...typeof cs.name === "string" && cs.name.length > 0 ? { container: cs.name } : {}
25621
25990
  };
25622
25991
  }
25623
25992
  return null;
25624
25993
  }
25994
+ function faultedContainer(finding) {
25995
+ const containers = finding.pod?.spec?.containers;
25996
+ if (!Array.isArray(containers) || containers.length === 0) return void 0;
25997
+ if (finding.container) {
25998
+ const named2 = containers.find((c) => c.name === finding.container);
25999
+ if (named2) return named2;
26000
+ }
26001
+ return containers.length === 1 ? containers[0] : void 0;
26002
+ }
26003
+ function mergeProcessContext(finding, logs) {
26004
+ const container = faultedContainer(finding);
26005
+ const podName = finding.pod?.metadata?.name;
26006
+ const log = logs && podName ? logs.get(podLogKey(podName, finding.container)) : void 0;
26007
+ if (!container && log === void 0) return;
26008
+ const ctx = buildProcessContext({
26009
+ ...log !== void 0 ? { log } : {},
26010
+ ...container ? { container } : {}
26011
+ });
26012
+ if (ctx.processLog !== void 0) finding.attributes["k8s.processLog"] = ctx.processLog;
26013
+ if (ctx.containerArgs !== void 0) finding.attributes["k8s.containerArgs"] = ctx.containerArgs;
26014
+ if (ctx.containerEnv !== void 0) finding.attributes["k8s.containerEnv"] = ctx.containerEnv;
26015
+ }
26016
+ function faultedPods(deployments, pods, config) {
26017
+ const out = [];
26018
+ const expectedZero = config.expectedZero ? new Set(config.expectedZero) : void 0;
26019
+ for (const deployment of deployments) {
26020
+ const finding = classifyDeployment(deployment, pods, expectedZero);
26021
+ if (!finding || finding.fault !== "crash-loop") continue;
26022
+ const podName = finding.pod?.metadata?.name;
26023
+ if (typeof podName !== "string" || podName.length === 0) continue;
26024
+ out.push({ podName, ...finding.container ? { container: finding.container } : {} });
26025
+ }
26026
+ return out;
26027
+ }
25625
26028
  function classifyDeployment(deployment, pods, expectedZero) {
25626
26029
  const name = deployment.metadata?.name ?? "";
25627
26030
  const desired = typeof deployment.spec?.replicas === "number" ? deployment.spec.replicas : 1;
@@ -25649,12 +26052,13 @@ function classifyDeployment(deployment, pods, expectedZero) {
25649
26052
  attributes: { "k8s.desiredReplicas": desired, "k8s.readyReplicas": ready }
25650
26053
  };
25651
26054
  }
25652
- function mapDeploymentToSignal(deployment, pods, config) {
26055
+ function mapDeploymentToSignal(deployment, pods, config, logs) {
25653
26056
  const name = deployment.metadata?.name;
25654
26057
  if (typeof name !== "string" || name.length === 0) return null;
25655
26058
  const expectedZero = config.expectedZero ? new Set(config.expectedZero) : void 0;
25656
26059
  const finding = classifyDeployment(deployment, pods, expectedZero);
25657
26060
  if (!finding) return null;
26061
+ mergeProcessContext(finding, logs);
25658
26062
  const serviceName = serviceNameFor(deployment, config);
25659
26063
  const namespace = deployment.metadata?.namespace ?? config.namespace;
25660
26064
  const attributes = {
@@ -25707,12 +26111,12 @@ function deployStateSignal(deployment, pods, config) {
25707
26111
  deployState: observedDeployState(deployment, pods)
25708
26112
  };
25709
26113
  }
25710
- function mapWorkloadsToSignals(deployments, pods, config) {
26114
+ function mapWorkloadsToSignals(deployments, pods, config, logs) {
25711
26115
  const out = [];
25712
26116
  for (const deployment of deployments) {
25713
26117
  const deployState = deployStateSignal(deployment, pods, config);
25714
26118
  if (deployState) out.push(deployState);
25715
- const incident = mapDeploymentToSignal(deployment, pods, config);
26119
+ const incident = mapDeploymentToSignal(deployment, pods, config, logs);
25716
26120
  if (incident) out.push(incident);
25717
26121
  }
25718
26122
  return out;
@@ -25720,7 +26124,7 @@ function mapWorkloadsToSignals(deployments, pods, config) {
25720
26124
 
25721
26125
  // src/connectors/kubernetes/resolve.ts
25722
26126
  init_cjs_shims();
25723
- var import_types106 = require("@neat.is/types");
26127
+ var import_types107 = require("@neat.is/types");
25724
26128
  var NO_ENV3 = "unknown";
25725
26129
  function createK8sResolveTarget(graph) {
25726
26130
  return (signal) => {
@@ -25731,7 +26135,7 @@ function createK8sResolveTarget(graph) {
25731
26135
  return {
25732
26136
  targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV3),
25733
26137
  serviceName,
25734
- edgeType: import_types106.EdgeType.CALLS
26138
+ edgeType: import_types107.EdgeType.CALLS
25735
26139
  };
25736
26140
  };
25737
26141
  }
@@ -25811,6 +26215,8 @@ async function startK8sSubstratePolling(input) {
25811
26215
  }
25812
26216
 
25813
26217
  // src/connectors/kubernetes/index.ts
26218
+ var PROCESS_LOG_TAIL_LINES = 200;
26219
+ var PROCESS_LOG_LIMIT_BYTES = 64 * 1024;
25814
26220
  var KubernetesConnector = class {
25815
26221
  constructor(config, fetchImpl) {
25816
26222
  this.config = config;
@@ -25831,7 +26237,24 @@ var KubernetesConnector = class {
25831
26237
  fetchDeployments(transport, namespace, opts),
25832
26238
  fetchPods(transport, namespace, opts)
25833
26239
  ]);
25834
- return mapWorkloadsToSignals(deployments, pods, this.config);
26240
+ const logs = await this.fetchFaultedPodLogs(transport, namespace, deployments, pods, opts);
26241
+ return mapWorkloadsToSignals(deployments, pods, this.config, logs);
26242
+ }
26243
+ async fetchFaultedPodLogs(transport, namespace, deployments, pods, opts) {
26244
+ const logs = /* @__PURE__ */ new Map();
26245
+ const targets = faultedPods(deployments, pods, this.config);
26246
+ await Promise.all(
26247
+ targets.map(async (t) => {
26248
+ const text = await fetchPodProcessLog(transport, namespace, t.podName, {
26249
+ ...t.container ? { container: t.container } : {},
26250
+ tailLines: PROCESS_LOG_TAIL_LINES,
26251
+ limitBytes: PROCESS_LOG_LIMIT_BYTES,
26252
+ ...opts
26253
+ });
26254
+ if (typeof text === "string" && text.length > 0) logs.set(podLogKey(t.podName, t.container), text);
26255
+ })
26256
+ );
26257
+ return logs;
25835
26258
  }
25836
26259
  };
25837
26260
  function createKubernetesConnector(graph, config, fetchImpl) {
@@ -25866,7 +26289,7 @@ function unroutedErrorsPath(neatHome4) {
25866
26289
  }
25867
26290
 
25868
26291
  // src/daemon.ts
25869
- var import_types109 = require("@neat.is/types");
26292
+ var import_types110 = require("@neat.is/types");
25870
26293
  function daemonJsonPath(scanPath) {
25871
26294
  return import_node_path82.default.join(scanPath, "neat-out", "daemon.json");
25872
26295
  }
@@ -26017,7 +26440,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
26017
26440
  if (!serviceName) return true;
26018
26441
  if (serviceNameMatchesProject(serviceName, project)) return true;
26019
26442
  return graph.someNode(
26020
- (_id, attrs) => attrs.type === import_types109.NodeType.ServiceNode && attrs.name === serviceName
26443
+ (_id, attrs) => attrs.type === import_types110.NodeType.ServiceNode && attrs.name === serviceName
26021
26444
  );
26022
26445
  }
26023
26446
  async function bootstrapProject(entry2, connectors = [], neatHome4) {