@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260710

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.
@@ -456,19 +456,19 @@ function confidenceFromMix(edges, now = Date.now()) {
456
456
  function longestIncomingWalk(graph, start, maxDepth) {
457
457
  let best = { path: [start], edges: [] };
458
458
  const visited = /* @__PURE__ */ new Set([start]);
459
- function step(node, path42, edges) {
460
- if (path42.length > best.path.length) {
461
- best = { path: [...path42], edges: [...edges] };
459
+ function step(node, path43, edges) {
460
+ if (path43.length > best.path.length) {
461
+ best = { path: [...path43], edges: [...edges] };
462
462
  }
463
- if (path42.length - 1 >= maxDepth) return;
463
+ if (path43.length - 1 >= maxDepth) return;
464
464
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
465
465
  for (const [srcId, edge] of incoming) {
466
466
  if (visited.has(srcId)) continue;
467
467
  visited.add(srcId);
468
- path42.push(srcId);
468
+ path43.push(srcId);
469
469
  edges.push(edge);
470
- step(srcId, path42, edges);
471
- path42.pop();
470
+ step(srcId, path43, edges);
471
+ path43.pop();
472
472
  edges.pop();
473
473
  visited.delete(srcId);
474
474
  }
@@ -662,26 +662,26 @@ function dominantFailingCall(graph, serviceId4, visited) {
662
662
  return best;
663
663
  }
664
664
  function followFailingCallChain(graph, originServiceId, maxDepth) {
665
- const path42 = [originServiceId];
665
+ const path43 = [originServiceId];
666
666
  const edges = [];
667
667
  const visited = /* @__PURE__ */ new Set([originServiceId]);
668
668
  let current = originServiceId;
669
669
  for (let depth = 0; depth < maxDepth; depth++) {
670
670
  const hop = dominantFailingCall(graph, current, visited);
671
671
  if (!hop) break;
672
- path42.push(hop.nextService);
672
+ path43.push(hop.nextService);
673
673
  edges.push(hop.edge);
674
674
  visited.add(hop.nextService);
675
675
  current = hop.nextService;
676
676
  }
677
677
  if (edges.length === 0) return null;
678
- return { path: path42, edges, culprit: current };
678
+ return { path: path43, edges, culprit: current };
679
679
  }
680
680
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
681
681
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
682
682
  if (!chain) return null;
683
683
  const culprit = chain.culprit;
684
- const path42 = [...chain.path];
684
+ const path43 = [...chain.path];
685
685
  const edgeProvenances = chain.edges.map((e) => e.provenance);
686
686
  const baseConfidence = confidenceFromMix(chain.edges);
687
687
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -689,14 +689,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
689
689
  if (loc) {
690
690
  let rootCauseNode = culprit;
691
691
  if (loc.fileNode) {
692
- path42.push(loc.fileNode);
692
+ path43.push(loc.fileNode);
693
693
  edgeProvenances.push(Provenance.OBSERVED);
694
694
  rootCauseNode = loc.fileNode;
695
695
  }
696
696
  return RootCauseResultSchema.parse({
697
697
  rootCauseNode,
698
698
  rootCauseReason: loc.rootCauseReason,
699
- traversalPath: path42,
699
+ traversalPath: path43,
700
700
  edgeProvenances,
701
701
  confidence,
702
702
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -708,7 +708,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
708
708
  return RootCauseResultSchema.parse({
709
709
  rootCauseNode: culprit,
710
710
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
711
- traversalPath: path42,
711
+ traversalPath: path43,
712
712
  edgeProvenances,
713
713
  confidence,
714
714
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -1879,6 +1879,19 @@ function ensureServiceNode(graph, serviceName, env) {
1879
1879
  graph.addNode(id, node);
1880
1880
  return id;
1881
1881
  }
1882
+ function ensureInfraNode(graph, kind, name, provider) {
1883
+ const id = infraId(kind, name);
1884
+ if (graph.hasNode(id)) return id;
1885
+ const node = {
1886
+ id,
1887
+ type: NodeType3.InfraNode,
1888
+ name,
1889
+ provider,
1890
+ kind
1891
+ };
1892
+ graph.addNode(id, node);
1893
+ return id;
1894
+ }
1882
1895
  function ensureDatabaseNode(graph, host, engine) {
1883
1896
  const id = databaseId(host);
1884
1897
  if (graph.hasNode(id)) return id;
@@ -4658,10 +4671,10 @@ function fastifyRouteMethods(objNode) {
4658
4671
  }
4659
4672
  return [];
4660
4673
  }
4661
- function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
4674
+ function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
4662
4675
  const tree = parseSource2(parser, source);
4663
4676
  const out = [];
4664
- const framework = hasExpress ? "express" : "fastify";
4677
+ const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
4665
4678
  walk(tree.rootNode, (node) => {
4666
4679
  if (node.type !== "call_expression") return;
4667
4680
  const fn = node.childForFieldName("function");
@@ -4811,8 +4824,9 @@ async function addRoutes(graph, services) {
4811
4824
  };
4812
4825
  const hasExpress = deps["express"] !== void 0;
4813
4826
  const hasFastify = deps["fastify"] !== void 0;
4827
+ const hasHono = deps["hono"] !== void 0;
4814
4828
  const hasNext = deps["next"] !== void 0;
4815
- if (!hasExpress && !hasFastify && !hasNext) continue;
4829
+ if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
4816
4830
  const files = await loadSourceFiles(service.dir);
4817
4831
  for (const file of files) {
4818
4832
  if (isTestPath(file.path)) continue;
@@ -4822,8 +4836,8 @@ async function addRoutes(graph, services) {
4822
4836
  try {
4823
4837
  if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
4824
4838
  routes = nextRoutesFromFile(file.content, relFile, jsParser);
4825
- } else if (hasExpress || hasFastify) {
4826
- routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
4839
+ } else if (hasExpress || hasFastify || hasHono) {
4840
+ routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
4827
4841
  } else {
4828
4842
  routes = [];
4829
4843
  }
@@ -6155,25 +6169,258 @@ async function addK8sResources(graph, scanPath) {
6155
6169
  return { nodesAdded, edgesAdded: 0 };
6156
6170
  }
6157
6171
 
6172
+ // src/extract/infra/cloudflare.ts
6173
+ import { promises as fs19 } from "fs";
6174
+ import path35 from "path";
6175
+ import { parse as parseToml2 } from "smol-toml";
6176
+ import { EdgeType as EdgeType16, Provenance as Provenance15, confidenceForExtracted as confidenceForExtracted13 } from "@neat.is/types";
6177
+ var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
6178
+ async function readWranglerConfig(dir) {
6179
+ for (const filename of WRANGLER_FILENAMES) {
6180
+ const abs = path35.join(dir, filename);
6181
+ if (!await exists(abs)) continue;
6182
+ const raw = await fs19.readFile(abs, "utf8");
6183
+ const config = filename === "wrangler.toml" ? parseToml2(raw) : JSON.parse(maskCommentsInSource(raw));
6184
+ return { config, relFile: filename, raw };
6185
+ }
6186
+ return null;
6187
+ }
6188
+ function lineContaining(raw, needle) {
6189
+ if (!needle) return void 0;
6190
+ const idx = raw.indexOf(needle);
6191
+ if (idx === -1) return void 0;
6192
+ let line = 1;
6193
+ for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
6194
+ return line;
6195
+ }
6196
+ function normalizeRoutes(config) {
6197
+ const out = [];
6198
+ const pushOne = (r) => {
6199
+ if (typeof r === "string") out.push(r);
6200
+ else if (r && typeof r === "object" && typeof r.pattern === "string") {
6201
+ out.push(r.pattern);
6202
+ }
6203
+ };
6204
+ if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
6205
+ else if (config.route) pushOne(config.route);
6206
+ return out;
6207
+ }
6208
+ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
6209
+ let nodesAdded = 0;
6210
+ let edgesAdded = 0;
6211
+ const node = makeInfraNode(kind, name, "cloudflare");
6212
+ if (!graph.hasNode(node.id)) {
6213
+ graph.addNode(node.id, node);
6214
+ nodesAdded++;
6215
+ }
6216
+ if (node.id === anchorId) return { nodesAdded, edgesAdded };
6217
+ const edgeId = extractedEdgeId2(anchorId, node.id, edgeType);
6218
+ if (!graph.hasEdge(edgeId)) {
6219
+ const edge = {
6220
+ id: edgeId,
6221
+ source: anchorId,
6222
+ target: node.id,
6223
+ type: edgeType,
6224
+ provenance: Provenance15.EXTRACTED,
6225
+ confidence: confidenceForExtracted13("structural"),
6226
+ evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
6227
+ };
6228
+ graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
6229
+ edgesAdded++;
6230
+ }
6231
+ return { nodesAdded, edgesAdded };
6232
+ }
6233
+ async function addCloudflareWorkers(graph, services, scanPath) {
6234
+ let nodesAdded = 0;
6235
+ let edgesAdded = 0;
6236
+ const discovered = [];
6237
+ const workerIndex = /* @__PURE__ */ new Map();
6238
+ for (const service of services) {
6239
+ let read;
6240
+ try {
6241
+ read = await readWranglerConfig(service.dir);
6242
+ } catch (err) {
6243
+ recordExtractionError("infra cloudflare", path35.relative(scanPath, service.dir), err);
6244
+ continue;
6245
+ }
6246
+ if (!read || !read.config.name) continue;
6247
+ const evidenceFile = toPosix2(path35.relative(scanPath, path35.join(service.dir, read.relFile)));
6248
+ discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
6249
+ }
6250
+ for (const worker of discovered) {
6251
+ const { service, config } = worker;
6252
+ const serviceNode = graph.getNodeAttributes(service.node.id);
6253
+ if (serviceNode.platform !== "cloudflare") {
6254
+ const updated = { ...serviceNode, platform: "cloudflare" };
6255
+ graph.replaceNodeAttributes(service.node.id, updated);
6256
+ }
6257
+ let anchorId = service.node.id;
6258
+ if (config.main) {
6259
+ const entryRelPath = toPosix2(path35.normalize(config.main));
6260
+ const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
6261
+ graph,
6262
+ service.pkg.name,
6263
+ service.node.id,
6264
+ entryRelPath
6265
+ );
6266
+ nodesAdded += fn;
6267
+ edgesAdded += fe;
6268
+ const fileNode = graph.getNodeAttributes(fileNodeId);
6269
+ if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
6270
+ const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
6271
+ graph.replaceNodeAttributes(fileNodeId, updated);
6272
+ }
6273
+ anchorId = fileNodeId;
6274
+ }
6275
+ workerIndex.set(config.name, { anchorId });
6276
+ }
6277
+ for (const worker of discovered) {
6278
+ const { config, evidenceFile, raw } = worker;
6279
+ const anchorId = workerIndex.get(config.name).anchorId;
6280
+ const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
6281
+ if (!graph.hasNode(runtimeNode.id)) {
6282
+ graph.addNode(runtimeNode.id, runtimeNode);
6283
+ nodesAdded++;
6284
+ }
6285
+ if (runtimeNode.id !== anchorId) {
6286
+ const runsOnId = extractedEdgeId2(anchorId, runtimeNode.id, EdgeType16.RUNS_ON);
6287
+ if (!graph.hasEdge(runsOnId)) {
6288
+ const edge = {
6289
+ id: runsOnId,
6290
+ source: anchorId,
6291
+ target: runtimeNode.id,
6292
+ type: EdgeType16.RUNS_ON,
6293
+ provenance: Provenance15.EXTRACTED,
6294
+ confidence: confidenceForExtracted13("structural"),
6295
+ evidence: {
6296
+ file: evidenceFile,
6297
+ ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
6298
+ }
6299
+ };
6300
+ graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
6301
+ edgesAdded++;
6302
+ }
6303
+ }
6304
+ for (const route of normalizeRoutes(config)) {
6305
+ const result = addResourceEdge(
6306
+ graph,
6307
+ anchorId,
6308
+ EdgeType16.CONNECTS_TO,
6309
+ "cloudflare-route",
6310
+ route,
6311
+ evidenceFile,
6312
+ lineContaining(raw, route)
6313
+ );
6314
+ nodesAdded += result.nodesAdded;
6315
+ edgesAdded += result.edgesAdded;
6316
+ }
6317
+ const bindingGroups = [
6318
+ { kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
6319
+ { kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
6320
+ { kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
6321
+ { kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
6322
+ { kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
6323
+ { kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
6324
+ ];
6325
+ for (const group of bindingGroups) {
6326
+ for (const entry of group.entries) {
6327
+ const name = group.nameOf(entry);
6328
+ if (!name) continue;
6329
+ const result = addResourceEdge(
6330
+ graph,
6331
+ anchorId,
6332
+ EdgeType16.DEPENDS_ON,
6333
+ group.kind,
6334
+ name,
6335
+ evidenceFile,
6336
+ lineContaining(raw, name)
6337
+ );
6338
+ nodesAdded += result.nodesAdded;
6339
+ edgesAdded += result.edgesAdded;
6340
+ }
6341
+ }
6342
+ for (const cron of config.triggers?.crons ?? []) {
6343
+ const result = addResourceEdge(
6344
+ graph,
6345
+ anchorId,
6346
+ EdgeType16.DEPENDS_ON,
6347
+ "cloudflare-cron",
6348
+ cron,
6349
+ evidenceFile,
6350
+ lineContaining(raw, cron)
6351
+ );
6352
+ nodesAdded += result.nodesAdded;
6353
+ edgesAdded += result.edgesAdded;
6354
+ }
6355
+ for (const varName of Object.keys(config.vars ?? {})) {
6356
+ const result = addResourceEdge(
6357
+ graph,
6358
+ anchorId,
6359
+ EdgeType16.DEPENDS_ON,
6360
+ "cloudflare-env-var",
6361
+ varName,
6362
+ evidenceFile,
6363
+ lineContaining(raw, varName)
6364
+ );
6365
+ nodesAdded += result.nodesAdded;
6366
+ edgesAdded += result.edgesAdded;
6367
+ }
6368
+ for (const svc of config.services ?? []) {
6369
+ if (!svc.service) continue;
6370
+ const target = workerIndex.get(svc.service);
6371
+ if (target && target.anchorId !== anchorId) {
6372
+ const edgeId = extractedEdgeId2(anchorId, target.anchorId, EdgeType16.CALLS);
6373
+ if (!graph.hasEdge(edgeId)) {
6374
+ const edge = {
6375
+ id: edgeId,
6376
+ source: anchorId,
6377
+ target: target.anchorId,
6378
+ type: EdgeType16.CALLS,
6379
+ provenance: Provenance15.EXTRACTED,
6380
+ confidence: confidenceForExtracted13("structural"),
6381
+ evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
6382
+ };
6383
+ graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
6384
+ edgesAdded++;
6385
+ }
6386
+ continue;
6387
+ }
6388
+ const result = addResourceEdge(
6389
+ graph,
6390
+ anchorId,
6391
+ EdgeType16.DEPENDS_ON,
6392
+ "cloudflare-service-binding",
6393
+ svc.service,
6394
+ evidenceFile,
6395
+ lineContaining(raw, svc.service)
6396
+ );
6397
+ nodesAdded += result.nodesAdded;
6398
+ edgesAdded += result.edgesAdded;
6399
+ }
6400
+ }
6401
+ return { nodesAdded, edgesAdded };
6402
+ }
6403
+
6158
6404
  // src/extract/infra/index.ts
6159
6405
  async function addInfra(graph, scanPath, services) {
6160
6406
  const compose = await addComposeInfra(graph, scanPath, services);
6161
6407
  const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
6162
6408
  const terraform = await addTerraformResources(graph, scanPath);
6163
6409
  const k8s = await addK8sResources(graph, scanPath);
6410
+ const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
6164
6411
  return {
6165
- nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
6166
- edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
6412
+ nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
6413
+ edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
6167
6414
  };
6168
6415
  }
6169
6416
 
6170
6417
  // src/extract/index.ts
6171
- import path36 from "path";
6418
+ import path37 from "path";
6172
6419
 
6173
6420
  // src/extract/retire.ts
6174
6421
  import { existsSync as existsSync2 } from "fs";
6175
- import path35 from "path";
6176
- import { NodeType as NodeType14, Provenance as Provenance15 } from "@neat.is/types";
6422
+ import path36 from "path";
6423
+ import { NodeType as NodeType14, Provenance as Provenance16 } from "@neat.is/types";
6177
6424
  function dropOrphanedFileNodes(graph) {
6178
6425
  const orphans = [];
6179
6426
  graph.forEachNode((id, attrs) => {
@@ -6190,7 +6437,7 @@ function retireEdgesByFile(graph, file) {
6190
6437
  const toDrop = [];
6191
6438
  graph.forEachEdge((id, attrs) => {
6192
6439
  const edge = attrs;
6193
- if (edge.provenance !== Provenance15.EXTRACTED) return;
6440
+ if (edge.provenance !== Provenance16.EXTRACTED) return;
6194
6441
  if (!edge.evidence?.file) return;
6195
6442
  if (edge.evidence.file === normalized) toDrop.push(id);
6196
6443
  });
@@ -6203,14 +6450,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
6203
6450
  const bases = [scanPath, ...serviceDirs];
6204
6451
  graph.forEachEdge((id, attrs) => {
6205
6452
  const edge = attrs;
6206
- if (edge.provenance !== Provenance15.EXTRACTED) return;
6453
+ if (edge.provenance !== Provenance16.EXTRACTED) return;
6207
6454
  const evidenceFile = edge.evidence?.file;
6208
6455
  if (!evidenceFile) return;
6209
- if (path35.isAbsolute(evidenceFile)) {
6456
+ if (path36.isAbsolute(evidenceFile)) {
6210
6457
  if (!existsSync2(evidenceFile)) toDrop.push(id);
6211
6458
  return;
6212
6459
  }
6213
- const found = bases.some((base) => existsSync2(path35.join(base, evidenceFile)));
6460
+ const found = bases.some((base) => existsSync2(path36.join(base, evidenceFile)));
6214
6461
  if (!found) toDrop.push(id);
6215
6462
  });
6216
6463
  for (const id of toDrop) graph.dropEdge(id);
@@ -6252,7 +6499,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
6252
6499
  }
6253
6500
  const droppedEntries = drainDroppedExtracted();
6254
6501
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
6255
- const rejectedPath = path36.join(path36.dirname(opts.errorsPath), "rejected.ndjson");
6502
+ const rejectedPath = path37.join(path37.dirname(opts.errorsPath), "rejected.ndjson");
6256
6503
  try {
6257
6504
  await writeRejectedExtracted(droppedEntries, rejectedPath);
6258
6505
  } catch (err) {
@@ -6288,10 +6535,10 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
6288
6535
  import {
6289
6536
  databaseId as databaseId3,
6290
6537
  DivergenceResultSchema,
6291
- EdgeType as EdgeType16,
6538
+ EdgeType as EdgeType17,
6292
6539
  NodeType as NodeType15,
6293
6540
  parseEdgeId,
6294
- Provenance as Provenance16
6541
+ Provenance as Provenance17
6295
6542
  } from "@neat.is/types";
6296
6543
  function bucketKey(source, target, type) {
6297
6544
  return `${type}|${source}|${target}`;
@@ -6305,17 +6552,17 @@ function bucketEdges(graph) {
6305
6552
  const key = bucketKey(e.source, e.target, e.type);
6306
6553
  const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
6307
6554
  switch (provenance) {
6308
- case Provenance16.EXTRACTED:
6555
+ case Provenance17.EXTRACTED:
6309
6556
  cur.extracted = e;
6310
6557
  break;
6311
- case Provenance16.OBSERVED:
6558
+ case Provenance17.OBSERVED:
6312
6559
  cur.observed = e;
6313
6560
  break;
6314
- case Provenance16.INFERRED:
6561
+ case Provenance17.INFERRED:
6315
6562
  cur.inferred = e;
6316
6563
  break;
6317
6564
  default:
6318
- if (e.provenance === Provenance16.STALE) cur.stale = e;
6565
+ if (e.provenance === Provenance17.STALE) cur.stale = e;
6319
6566
  }
6320
6567
  buckets.set(key, cur);
6321
6568
  });
@@ -6349,14 +6596,14 @@ function gradedConfidence(edge) {
6349
6596
  return clampConfidence(confidenceForEdge(edge));
6350
6597
  }
6351
6598
  var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
6352
- EdgeType16.CALLS,
6353
- EdgeType16.CONNECTS_TO,
6354
- EdgeType16.PUBLISHES_TO,
6355
- EdgeType16.CONSUMES_FROM
6599
+ EdgeType17.CALLS,
6600
+ EdgeType17.CONNECTS_TO,
6601
+ EdgeType17.PUBLISHES_TO,
6602
+ EdgeType17.CONSUMES_FROM
6356
6603
  ]);
6357
6604
  function detectMissingDivergences(graph, bucket) {
6358
6605
  const out = [];
6359
- if (bucket.type === EdgeType16.CONTAINS) return out;
6606
+ if (bucket.type === EdgeType17.CONTAINS) return out;
6360
6607
  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
6361
6608
  if (!nodeIsFrontier(graph, bucket.target)) {
6362
6609
  out.push({
@@ -6397,7 +6644,7 @@ function declaredHostFor(svc) {
6397
6644
  function hasExtractedConfiguredBy(graph, svcId) {
6398
6645
  for (const edgeId of graph.outboundEdges(svcId)) {
6399
6646
  const e = graph.getEdgeAttributes(edgeId);
6400
- if (e.type === EdgeType16.CONFIGURED_BY && e.provenance === Provenance16.EXTRACTED) {
6647
+ if (e.type === EdgeType17.CONFIGURED_BY && e.provenance === Provenance17.EXTRACTED) {
6401
6648
  return true;
6402
6649
  }
6403
6650
  }
@@ -6410,8 +6657,8 @@ function detectHostMismatch(graph, svcId, svc) {
6410
6657
  const out = [];
6411
6658
  for (const edgeId of graph.outboundEdges(svcId)) {
6412
6659
  const edge = graph.getEdgeAttributes(edgeId);
6413
- if (edge.type !== EdgeType16.CONNECTS_TO) continue;
6414
- if (edge.provenance !== Provenance16.OBSERVED) continue;
6660
+ if (edge.type !== EdgeType17.CONNECTS_TO) continue;
6661
+ if (edge.provenance !== Provenance17.OBSERVED) continue;
6415
6662
  const target = graph.getNodeAttributes(edge.target);
6416
6663
  if (target.type !== NodeType15.DatabaseNode) continue;
6417
6664
  const observedHost = target.host?.trim();
@@ -6435,8 +6682,8 @@ function detectCompatDivergences(graph, svcId, svc) {
6435
6682
  const deps = svc.dependencies ?? {};
6436
6683
  for (const edgeId of graph.outboundEdges(svcId)) {
6437
6684
  const edge = graph.getEdgeAttributes(edgeId);
6438
- if (edge.type !== EdgeType16.CONNECTS_TO) continue;
6439
- if (edge.provenance !== Provenance16.OBSERVED) continue;
6685
+ if (edge.type !== EdgeType17.CONNECTS_TO) continue;
6686
+ if (edge.provenance !== Provenance17.OBSERVED) continue;
6440
6687
  const target = graph.getNodeAttributes(edge.target);
6441
6688
  if (target.type !== NodeType15.DatabaseNode) continue;
6442
6689
  for (const pair of compatPairs()) {
@@ -6558,9 +6805,9 @@ function computeDivergences(graph, opts = {}) {
6558
6805
  }
6559
6806
 
6560
6807
  // src/persist.ts
6561
- import { promises as fs19 } from "fs";
6562
- import path37 from "path";
6563
- import { Provenance as Provenance17, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
6808
+ import { promises as fs20 } from "fs";
6809
+ import path38 from "path";
6810
+ import { Provenance as Provenance18, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
6564
6811
  var SCHEMA_VERSION = 4;
6565
6812
  function migrateV1ToV2(payload) {
6566
6813
  const nodes = payload.graph.nodes;
@@ -6582,7 +6829,7 @@ function migrateV2ToV3(payload) {
6582
6829
  for (const edge of edges) {
6583
6830
  const attrs = edge.attributes;
6584
6831
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
6585
- attrs.provenance = Provenance17.OBSERVED;
6832
+ attrs.provenance = Provenance18.OBSERVED;
6586
6833
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
6587
6834
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
6588
6835
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
@@ -6596,7 +6843,7 @@ function migrateV2ToV3(payload) {
6596
6843
  return { ...payload, schemaVersion: 3 };
6597
6844
  }
6598
6845
  async function ensureDir(filePath) {
6599
- await fs19.mkdir(path37.dirname(filePath), { recursive: true });
6846
+ await fs20.mkdir(path38.dirname(filePath), { recursive: true });
6600
6847
  }
6601
6848
  async function saveGraphToDisk(graph, outPath) {
6602
6849
  await ensureDir(outPath);
@@ -6606,13 +6853,13 @@ async function saveGraphToDisk(graph, outPath) {
6606
6853
  graph: graph.export()
6607
6854
  };
6608
6855
  const tmp = `${outPath}.tmp`;
6609
- await fs19.writeFile(tmp, JSON.stringify(payload), "utf8");
6610
- await fs19.rename(tmp, outPath);
6856
+ await fs20.writeFile(tmp, JSON.stringify(payload), "utf8");
6857
+ await fs20.rename(tmp, outPath);
6611
6858
  }
6612
6859
  async function loadGraphFromDisk(graph, outPath) {
6613
6860
  let raw;
6614
6861
  try {
6615
- raw = await fs19.readFile(outPath, "utf8");
6862
+ raw = await fs20.readFile(outPath, "utf8");
6616
6863
  } catch (err) {
6617
6864
  if (err.code === "ENOENT") return;
6618
6865
  throw err;
@@ -6676,7 +6923,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
6676
6923
  }
6677
6924
 
6678
6925
  // src/diff.ts
6679
- import { promises as fs20 } from "fs";
6926
+ import { promises as fs21 } from "fs";
6680
6927
  async function loadSnapshotForDiff(target) {
6681
6928
  if (/^https?:\/\//i.test(target)) {
6682
6929
  const res = await fetch(target);
@@ -6685,7 +6932,7 @@ async function loadSnapshotForDiff(target) {
6685
6932
  }
6686
6933
  return await res.json();
6687
6934
  }
6688
- const raw = await fs20.readFile(target, "utf8");
6935
+ const raw = await fs21.readFile(target, "utf8");
6689
6936
  return JSON.parse(raw);
6690
6937
  }
6691
6938
  function indexEntries(entries) {
@@ -6752,23 +6999,23 @@ function canonicalJson(value) {
6752
6999
  }
6753
7000
 
6754
7001
  // src/projects.ts
6755
- import path38 from "path";
7002
+ import path39 from "path";
6756
7003
  function pathsForProject(project, baseDir) {
6757
7004
  if (project === DEFAULT_PROJECT) {
6758
7005
  return {
6759
- snapshotPath: path38.join(baseDir, "graph.json"),
6760
- errorsPath: path38.join(baseDir, "errors.ndjson"),
6761
- staleEventsPath: path38.join(baseDir, "stale-events.ndjson"),
6762
- embeddingsCachePath: path38.join(baseDir, "embeddings.json"),
6763
- policyViolationsPath: path38.join(baseDir, "policy-violations.ndjson")
7006
+ snapshotPath: path39.join(baseDir, "graph.json"),
7007
+ errorsPath: path39.join(baseDir, "errors.ndjson"),
7008
+ staleEventsPath: path39.join(baseDir, "stale-events.ndjson"),
7009
+ embeddingsCachePath: path39.join(baseDir, "embeddings.json"),
7010
+ policyViolationsPath: path39.join(baseDir, "policy-violations.ndjson")
6764
7011
  };
6765
7012
  }
6766
7013
  return {
6767
- snapshotPath: path38.join(baseDir, `${project}.json`),
6768
- errorsPath: path38.join(baseDir, `errors.${project}.ndjson`),
6769
- staleEventsPath: path38.join(baseDir, `stale-events.${project}.ndjson`),
6770
- embeddingsCachePath: path38.join(baseDir, `embeddings.${project}.json`),
6771
- policyViolationsPath: path38.join(baseDir, `policy-violations.${project}.ndjson`)
7014
+ snapshotPath: path39.join(baseDir, `${project}.json`),
7015
+ errorsPath: path39.join(baseDir, `errors.${project}.ndjson`),
7016
+ staleEventsPath: path39.join(baseDir, `stale-events.${project}.ndjson`),
7017
+ embeddingsCachePath: path39.join(baseDir, `embeddings.${project}.json`),
7018
+ policyViolationsPath: path39.join(baseDir, `policy-violations.${project}.ndjson`)
6772
7019
  };
6773
7020
  }
6774
7021
  var Projects = class {
@@ -6807,9 +7054,9 @@ function parseExtraProjects(raw) {
6807
7054
  }
6808
7055
 
6809
7056
  // src/registry.ts
6810
- import { promises as fs21 } from "fs";
7057
+ import { promises as fs22 } from "fs";
6811
7058
  import os2 from "os";
6812
- import path39 from "path";
7059
+ import path40 from "path";
6813
7060
  import {
6814
7061
  RegistryFileSchema
6815
7062
  } from "@neat.is/types";
@@ -6817,20 +7064,20 @@ var LOCK_TIMEOUT_MS = 5e3;
6817
7064
  var LOCK_RETRY_MS = 50;
6818
7065
  function neatHome() {
6819
7066
  const override = process.env.NEAT_HOME;
6820
- if (override && override.length > 0) return path39.resolve(override);
6821
- return path39.join(os2.homedir(), ".neat");
7067
+ if (override && override.length > 0) return path40.resolve(override);
7068
+ return path40.join(os2.homedir(), ".neat");
6822
7069
  }
6823
7070
  function registryPath() {
6824
- return path39.join(neatHome(), "projects.json");
7071
+ return path40.join(neatHome(), "projects.json");
6825
7072
  }
6826
7073
  function registryLockPath() {
6827
- return path39.join(neatHome(), "projects.json.lock");
7074
+ return path40.join(neatHome(), "projects.json.lock");
6828
7075
  }
6829
7076
  function daemonPidPath() {
6830
- return path39.join(neatHome(), "neatd.pid");
7077
+ return path40.join(neatHome(), "neatd.pid");
6831
7078
  }
6832
7079
  function daemonsDir() {
6833
- return path39.join(neatHome(), "daemons");
7080
+ return path40.join(neatHome(), "daemons");
6834
7081
  }
6835
7082
  function isFiniteInt(v) {
6836
7083
  return typeof v === "number" && Number.isFinite(v);
@@ -6863,7 +7110,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
6863
7110
  const dir = daemonsDir();
6864
7111
  let names;
6865
7112
  try {
6866
- names = await fs21.readdir(dir);
7113
+ names = await fs22.readdir(dir);
6867
7114
  } catch (err) {
6868
7115
  if (err.code === "ENOENT") return [];
6869
7116
  throw err;
@@ -6871,10 +7118,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
6871
7118
  const out = [];
6872
7119
  for (const name of names) {
6873
7120
  if (!name.endsWith(".json")) continue;
6874
- const file = path39.join(dir, name);
7121
+ const file = path40.join(dir, name);
6875
7122
  let raw;
6876
7123
  try {
6877
- raw = await fs21.readFile(file, "utf8");
7124
+ raw = await fs22.readFile(file, "utf8");
6878
7125
  } catch {
6879
7126
  continue;
6880
7127
  }
@@ -6887,7 +7134,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
6887
7134
  return out;
6888
7135
  }
6889
7136
  async function removeDaemonRecord(source) {
6890
- await fs21.unlink(source).catch(() => {
7137
+ await fs22.unlink(source).catch(() => {
6891
7138
  });
6892
7139
  }
6893
7140
  async function listMachineProjects(probe = defaultDiscoveryProbe) {
@@ -6944,7 +7191,7 @@ function isPidAliveDefault(pid) {
6944
7191
  }
6945
7192
  async function readPidFile(file) {
6946
7193
  try {
6947
- const raw = await fs21.readFile(file, "utf8");
7194
+ const raw = await fs22.readFile(file, "utf8");
6948
7195
  const pid = Number.parseInt(raw.trim(), 10);
6949
7196
  return Number.isInteger(pid) && pid > 0 ? pid : void 0;
6950
7197
  } catch {
@@ -6992,32 +7239,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
6992
7239
  }
6993
7240
  }
6994
7241
  async function normalizeProjectPath(input) {
6995
- const resolved = path39.resolve(input);
7242
+ const resolved = path40.resolve(input);
6996
7243
  try {
6997
- return await fs21.realpath(resolved);
7244
+ return await fs22.realpath(resolved);
6998
7245
  } catch {
6999
7246
  return resolved;
7000
7247
  }
7001
7248
  }
7002
7249
  async function writeAtomically(target, contents) {
7003
- await fs21.mkdir(path39.dirname(target), { recursive: true });
7250
+ await fs22.mkdir(path40.dirname(target), { recursive: true });
7004
7251
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
7005
- const fd = await fs21.open(tmp, "w");
7252
+ const fd = await fs22.open(tmp, "w");
7006
7253
  try {
7007
7254
  await fd.writeFile(contents, "utf8");
7008
7255
  await fd.sync();
7009
7256
  } finally {
7010
7257
  await fd.close();
7011
7258
  }
7012
- await fs21.rename(tmp, target);
7259
+ await fs22.rename(tmp, target);
7013
7260
  }
7014
7261
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
7015
7262
  const deadline = Date.now() + timeoutMs;
7016
- await fs21.mkdir(path39.dirname(lockPath), { recursive: true });
7263
+ await fs22.mkdir(path40.dirname(lockPath), { recursive: true });
7017
7264
  let probedHolder = false;
7018
7265
  while (true) {
7019
7266
  try {
7020
- const fd = await fs21.open(lockPath, "wx");
7267
+ const fd = await fs22.open(lockPath, "wx");
7021
7268
  try {
7022
7269
  await fd.writeFile(`${process.pid}
7023
7270
  `, "utf8");
@@ -7042,7 +7289,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
7042
7289
  }
7043
7290
  }
7044
7291
  async function releaseLock(lockPath) {
7045
- await fs21.unlink(lockPath).catch(() => {
7292
+ await fs22.unlink(lockPath).catch(() => {
7046
7293
  });
7047
7294
  }
7048
7295
  async function withLock(fn) {
@@ -7058,7 +7305,7 @@ async function readRegistry() {
7058
7305
  const file = registryPath();
7059
7306
  let raw;
7060
7307
  try {
7061
- raw = await fs21.readFile(file, "utf8");
7308
+ raw = await fs22.readFile(file, "utf8");
7062
7309
  } catch (err) {
7063
7310
  if (err.code === "ENOENT") {
7064
7311
  return { version: 1, projects: [] };
@@ -7163,7 +7410,7 @@ function pruneTtlMs() {
7163
7410
  }
7164
7411
  async function statPathStatus(p) {
7165
7412
  try {
7166
- const stat = await fs21.stat(p);
7413
+ const stat = await fs22.stat(p);
7167
7414
  return stat.isDirectory() ? "present" : "unknown";
7168
7415
  } catch (err) {
7169
7416
  return err.code === "ENOENT" ? "gone" : "unknown";
@@ -7208,14 +7455,14 @@ import cors from "@fastify/cors";
7208
7455
  import { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } from "@neat.is/types";
7209
7456
 
7210
7457
  // src/extend/index.ts
7211
- import { promises as fs23 } from "fs";
7212
- import path41 from "path";
7458
+ import { promises as fs24 } from "fs";
7459
+ import path42 from "path";
7213
7460
  import os3 from "os";
7214
7461
  import { resolve as registryResolve, list as registryList } from "@neat.is/instrumentation-registry";
7215
7462
 
7216
7463
  // src/installers/package-manager.ts
7217
- import { promises as fs22 } from "fs";
7218
- import path40 from "path";
7464
+ import { promises as fs23 } from "fs";
7465
+ import path41 from "path";
7219
7466
  import { spawn } from "child_process";
7220
7467
  var LOCKFILE_PRIORITY = [
7221
7468
  { lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
@@ -7230,29 +7477,29 @@ var LOCKFILE_PRIORITY = [
7230
7477
  var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
7231
7478
  async function exists2(p) {
7232
7479
  try {
7233
- await fs22.access(p);
7480
+ await fs23.access(p);
7234
7481
  return true;
7235
7482
  } catch {
7236
7483
  return false;
7237
7484
  }
7238
7485
  }
7239
7486
  async function detectPackageManager(serviceDir) {
7240
- let dir = path40.resolve(serviceDir);
7487
+ let dir = path41.resolve(serviceDir);
7241
7488
  const stops = /* @__PURE__ */ new Set();
7242
7489
  for (let i = 0; i < 64; i++) {
7243
7490
  if (stops.has(dir)) break;
7244
7491
  stops.add(dir);
7245
7492
  for (const candidate of LOCKFILE_PRIORITY) {
7246
- const lockPath = path40.join(dir, candidate.lockfile);
7493
+ const lockPath = path41.join(dir, candidate.lockfile);
7247
7494
  if (await exists2(lockPath)) {
7248
7495
  return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
7249
7496
  }
7250
7497
  }
7251
- const parent = path40.dirname(dir);
7498
+ const parent = path41.dirname(dir);
7252
7499
  if (parent === dir) break;
7253
7500
  dir = parent;
7254
7501
  }
7255
- return { pm: "npm", cwd: path40.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
7502
+ return { pm: "npm", cwd: path41.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
7256
7503
  }
7257
7504
  async function runPackageManagerInstall(cmd) {
7258
7505
  return new Promise((resolve) => {
@@ -7294,30 +7541,30 @@ ${err.message}`
7294
7541
  // src/extend/index.ts
7295
7542
  async function fileExists2(p) {
7296
7543
  try {
7297
- await fs23.access(p);
7544
+ await fs24.access(p);
7298
7545
  return true;
7299
7546
  } catch {
7300
7547
  return false;
7301
7548
  }
7302
7549
  }
7303
7550
  async function readPackageJson(scanPath) {
7304
- const pkgPath = path41.join(scanPath, "package.json");
7305
- const raw = await fs23.readFile(pkgPath, "utf8");
7551
+ const pkgPath = path42.join(scanPath, "package.json");
7552
+ const raw = await fs24.readFile(pkgPath, "utf8");
7306
7553
  return JSON.parse(raw);
7307
7554
  }
7308
7555
  async function findHookFiles(scanPath) {
7309
- const entries = await fs23.readdir(scanPath);
7556
+ const entries = await fs24.readdir(scanPath);
7310
7557
  return entries.filter(
7311
7558
  (e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
7312
7559
  ).sort();
7313
7560
  }
7314
7561
  function extendLogPath() {
7315
- return process.env.NEAT_EXTEND_LOG ?? path41.join(os3.homedir(), ".neat", "extend-log.ndjson");
7562
+ return process.env.NEAT_EXTEND_LOG ?? path42.join(os3.homedir(), ".neat", "extend-log.ndjson");
7316
7563
  }
7317
7564
  async function appendExtendLog(entry) {
7318
7565
  const logPath = extendLogPath();
7319
- await fs23.mkdir(path41.dirname(logPath), { recursive: true });
7320
- await fs23.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
7566
+ await fs24.mkdir(path42.dirname(logPath), { recursive: true });
7567
+ await fs24.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
7321
7568
  }
7322
7569
  function splicedContent(fileContent, snippet2) {
7323
7570
  if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
@@ -7375,7 +7622,7 @@ function lookupInstrumentation(library, installedVersion) {
7375
7622
  }
7376
7623
  async function describeProjectInstrumentation(ctx) {
7377
7624
  const hookFiles = await findHookFiles(ctx.scanPath);
7378
- const envNeat = await fileExists2(path41.join(ctx.scanPath, ".env.neat"));
7625
+ const envNeat = await fileExists2(path42.join(ctx.scanPath, ".env.neat"));
7379
7626
  const registryInstrPackages = new Set(
7380
7627
  registryList().map((e) => e.instrumentation_package).filter((p) => !!p)
7381
7628
  );
@@ -7397,31 +7644,31 @@ async function applyExtension(ctx, args, options) {
7397
7644
  );
7398
7645
  }
7399
7646
  for (const file of hookFiles) {
7400
- const content = await fs23.readFile(path41.join(ctx.scanPath, file), "utf8");
7647
+ const content = await fs24.readFile(path42.join(ctx.scanPath, file), "utf8");
7401
7648
  if (content.includes(args.registration_snippet)) {
7402
7649
  return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
7403
7650
  }
7404
7651
  }
7405
7652
  const primaryFile = hookFiles[0];
7406
- const primaryPath = path41.join(ctx.scanPath, primaryFile);
7653
+ const primaryPath = path42.join(ctx.scanPath, primaryFile);
7407
7654
  const filesTouched = [];
7408
7655
  const depsAdded = [];
7409
- const pkgPath = path41.join(ctx.scanPath, "package.json");
7656
+ const pkgPath = path42.join(ctx.scanPath, "package.json");
7410
7657
  const pkg = await readPackageJson(ctx.scanPath);
7411
7658
  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
7412
7659
  pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
7413
- await fs23.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
7660
+ await fs24.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
7414
7661
  filesTouched.push("package.json");
7415
7662
  depsAdded.push(`${args.instrumentation_package}@${args.version}`);
7416
7663
  }
7417
- const hookContent = await fs23.readFile(primaryPath, "utf8");
7664
+ const hookContent = await fs24.readFile(primaryPath, "utf8");
7418
7665
  const patched = splicedContent(hookContent, args.registration_snippet);
7419
7666
  if (!patched) {
7420
7667
  throw new Error(
7421
7668
  `Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
7422
7669
  );
7423
7670
  }
7424
- await fs23.writeFile(primaryPath, patched, "utf8");
7671
+ await fs24.writeFile(primaryPath, patched, "utf8");
7425
7672
  filesTouched.push(primaryFile);
7426
7673
  const cmd = await detectPackageManager(ctx.scanPath);
7427
7674
  const installer = options?.runInstall ?? runPackageManagerInstall;
@@ -7452,7 +7699,7 @@ async function dryRunExtension(ctx, args) {
7452
7699
  };
7453
7700
  }
7454
7701
  for (const file of hookFiles) {
7455
- const content = await fs23.readFile(path41.join(ctx.scanPath, file), "utf8");
7702
+ const content = await fs24.readFile(path42.join(ctx.scanPath, file), "utf8");
7456
7703
  if (content.includes(args.registration_snippet)) {
7457
7704
  return {
7458
7705
  library: args.library,
@@ -7474,7 +7721,7 @@ async function dryRunExtension(ctx, args) {
7474
7721
  depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
7475
7722
  filesTouched.push("package.json");
7476
7723
  }
7477
- const hookContent = await fs23.readFile(path41.join(ctx.scanPath, primaryFile), "utf8");
7724
+ const hookContent = await fs24.readFile(path42.join(ctx.scanPath, primaryFile), "utf8");
7478
7725
  const patched = splicedContent(hookContent, args.registration_snippet);
7479
7726
  if (patched) {
7480
7727
  filesTouched.push(primaryFile);
@@ -7489,28 +7736,28 @@ async function rollbackExtension(ctx, args) {
7489
7736
  if (!await fileExists2(logPath)) {
7490
7737
  return { undone: false, message: "no apply found for library" };
7491
7738
  }
7492
- const raw = await fs23.readFile(logPath, "utf8");
7739
+ const raw = await fs24.readFile(logPath, "utf8");
7493
7740
  const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
7494
7741
  const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
7495
7742
  if (!match) {
7496
7743
  return { undone: false, message: "no apply found for library" };
7497
7744
  }
7498
- const pkgPath = path41.join(ctx.scanPath, "package.json");
7745
+ const pkgPath = path42.join(ctx.scanPath, "package.json");
7499
7746
  if (await fileExists2(pkgPath)) {
7500
7747
  const pkg = await readPackageJson(ctx.scanPath);
7501
7748
  if (pkg.dependencies?.[match.instrumentation_package]) {
7502
7749
  const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
7503
7750
  pkg.dependencies = rest;
7504
- await fs23.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
7751
+ await fs24.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
7505
7752
  }
7506
7753
  }
7507
7754
  const hookFiles = await findHookFiles(ctx.scanPath);
7508
7755
  for (const file of hookFiles) {
7509
- const filePath = path41.join(ctx.scanPath, file);
7510
- const content = await fs23.readFile(filePath, "utf8");
7756
+ const filePath = path42.join(ctx.scanPath, file);
7757
+ const content = await fs24.readFile(filePath, "utf8");
7511
7758
  if (content.includes(match.registration_snippet)) {
7512
7759
  const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
7513
- await fs23.writeFile(filePath, filtered, "utf8");
7760
+ await fs24.writeFile(filePath, filtered, "utf8");
7514
7761
  break;
7515
7762
  }
7516
7763
  }
@@ -8339,6 +8586,7 @@ export {
8339
8586
  reconcileObservedRelPath,
8340
8587
  ensureObservedFileNode,
8341
8588
  ensureServiceNode,
8589
+ ensureInfraNode,
8342
8590
  upsertObservedEdge,
8343
8591
  stitchTrace,
8344
8592
  makeErrorSpanWriter,
@@ -8395,4 +8643,4 @@ export {
8395
8643
  pruneRegistry,
8396
8644
  buildApi
8397
8645
  };
8398
- //# sourceMappingURL=chunk-O4MRDWD7.js.map
8646
+ //# sourceMappingURL=chunk-5T6J3WKC.js.map