@neat.is/core 0.5.3 → 0.5.4-dev.20260721

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  mountBearerAuth,
3
3
  readAuthEnv
4
- } from "./chunk-CFDPIMRP.js";
4
+ } from "./chunk-I4NZ7PSN.js";
5
5
 
6
6
  // src/graph.ts
7
7
  import GraphDefault from "graphology";
@@ -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, path47, edges) {
460
- if (path47.length > best.path.length) {
461
- best = { path: [...path47], edges: [...edges] };
459
+ function step(node, path48, edges) {
460
+ if (path48.length > best.path.length) {
461
+ best = { path: [...path48], edges: [...edges] };
462
462
  }
463
- if (path47.length - 1 >= maxDepth) return;
463
+ if (path48.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
- path47.push(srcId);
468
+ path48.push(srcId);
469
469
  edges.push(edge);
470
- step(srcId, path47, edges);
471
- path47.pop();
470
+ step(srcId, path48, edges);
471
+ path48.pop();
472
472
  edges.pop();
473
473
  visited.delete(srcId);
474
474
  }
@@ -662,26 +662,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
662
662
  return best;
663
663
  }
664
664
  function followFailingCallChain(graph, originServiceId, maxDepth) {
665
- const path47 = [originServiceId];
665
+ const path48 = [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
- path47.push(hop.nextService);
672
+ path48.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: path47, edges, culprit: current };
678
+ return { path: path48, 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 path47 = [...chain.path];
684
+ const path48 = [...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
- path47.push(loc.fileNode);
692
+ path48.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: path47,
699
+ traversalPath: path48,
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: path47,
711
+ traversalPath: path48,
712
712
  edgeProvenances,
713
713
  confidence,
714
714
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -2229,6 +2229,18 @@ async function handleSpan(ctx, span) {
2229
2229
  callSiteEvidence
2230
2230
  );
2231
2231
  if (result) affectedNode = targetId;
2232
+ if (span.dbSystem === "mongodb" && span.dbCollection) {
2233
+ const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
2234
+ upsertObservedEdge(
2235
+ ctx.graph,
2236
+ EdgeType3.CALLS,
2237
+ observedSource(),
2238
+ collectionId,
2239
+ ts,
2240
+ isError,
2241
+ callSiteEvidence
2242
+ );
2243
+ }
2232
2244
  }
2233
2245
  } else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
2234
2246
  const targetId = ensureMessagingDestinationNode(
@@ -5826,6 +5838,301 @@ function supabaseEndpointsFromFile(file, serviceDir) {
5826
5838
  return out;
5827
5839
  }
5828
5840
 
5841
+ // src/extract/calls/mongoose.ts
5842
+ import path31 from "path";
5843
+ import { infraId as infraId7 } from "@neat.is/types";
5844
+ var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
5845
+ var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
5846
+ var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
5847
+ var UNCOUNTABLES = /* @__PURE__ */ new Set([
5848
+ "advice",
5849
+ "energy",
5850
+ "excretion",
5851
+ "digestion",
5852
+ "cooperation",
5853
+ "health",
5854
+ "justice",
5855
+ "labour",
5856
+ "machinery",
5857
+ "equipment",
5858
+ "information",
5859
+ "pollution",
5860
+ "sewage",
5861
+ "paper",
5862
+ "money",
5863
+ "species",
5864
+ "series",
5865
+ "rain",
5866
+ "rice",
5867
+ "fish",
5868
+ "sheep",
5869
+ "moose",
5870
+ "deer",
5871
+ "news",
5872
+ "expertise",
5873
+ "status",
5874
+ "media"
5875
+ ]);
5876
+ var PLURALIZE_RULES = [
5877
+ [/human$/gi, "humans"],
5878
+ [/(m)an$/gi, "$1en"],
5879
+ [/(pe)rson$/gi, "$1ople"],
5880
+ [/(child)$/gi, "$1ren"],
5881
+ [/^(ox)$/gi, "$1en"],
5882
+ [/(ax|test)is$/gi, "$1es"],
5883
+ [/(octop|vir)us$/gi, "$1i"],
5884
+ [/(alias|status)$/gi, "$1es"],
5885
+ [/(bu)s$/gi, "$1ses"],
5886
+ [/(buffal|tomat|potat)o$/gi, "$1oes"],
5887
+ [/([ti])um$/gi, "$1a"],
5888
+ [/sis$/gi, "ses"],
5889
+ [/(?:([^f])fe|([lr])f)$/gi, "$1$2ves"],
5890
+ [/(hive)$/gi, "$1s"],
5891
+ [/([^aeiouy]|qu)y$/gi, "$1ies"],
5892
+ [/(x|ch|ss|sh)$/gi, "$1es"],
5893
+ [/(matr|vert|ind)ix|ex$/gi, "$1ices"],
5894
+ [/([m|l])ouse$/gi, "$1ice"],
5895
+ [/(kn|w|l)ife$/gi, "$1ives"],
5896
+ [/(quiz)$/gi, "$1zes"],
5897
+ [/s$/gi, "s"],
5898
+ [/([^a-z])$/, "$1"],
5899
+ [/$/gi, "s"]
5900
+ ];
5901
+ function pluralizeCollection(name) {
5902
+ const str = name.toLowerCase();
5903
+ if (UNCOUNTABLES.has(str)) return str;
5904
+ for (const [re, repl] of PLURALIZE_RULES) {
5905
+ if (str.match(re)) return str.replace(re, repl);
5906
+ }
5907
+ return str;
5908
+ }
5909
+ var MODEL_METHODS = [
5910
+ "find",
5911
+ "findOne",
5912
+ "findById",
5913
+ "findByIdAndUpdate",
5914
+ "findByIdAndDelete",
5915
+ "findOneAndUpdate",
5916
+ "findOneAndDelete",
5917
+ "findOneAndReplace",
5918
+ "countDocuments",
5919
+ "estimatedDocumentCount",
5920
+ "distinct",
5921
+ "aggregate",
5922
+ "exists",
5923
+ "where",
5924
+ "populate",
5925
+ "watch",
5926
+ "hydrate",
5927
+ "create",
5928
+ "insertMany",
5929
+ "insertOne",
5930
+ "updateOne",
5931
+ "updateMany",
5932
+ "replaceOne",
5933
+ "deleteOne",
5934
+ "deleteMany",
5935
+ "bulkWrite",
5936
+ "bulkSave",
5937
+ "save",
5938
+ // pre-v7, removed in current mongoose but present in older codebases:
5939
+ "count",
5940
+ "update",
5941
+ "remove",
5942
+ "findOneAndRemove",
5943
+ "findByIdAndRemove"
5944
+ ];
5945
+ var MODEL_METHODS_ALT = MODEL_METHODS.join("|");
5946
+ function schemaCollectionVars(content) {
5947
+ const out = /* @__PURE__ */ new Map();
5948
+ const re = /(?:const|let|var)\s+(\w+)\s*=\s*new\s+(?:mongoose\s*\.\s*)?Schema\s*\(/g;
5949
+ let m;
5950
+ while ((m = re.exec(content)) !== null) {
5951
+ const windowText = content.slice(m.index, m.index + 2e3);
5952
+ const opt = /\bcollection\s*:\s*['"`]([\w.-]+)['"`]/.exec(windowText);
5953
+ if (opt) out.set(m[1], opt[1]);
5954
+ }
5955
+ return out;
5956
+ }
5957
+ function resolveModel(modelName, rest, schemaColl, pluralizeOn) {
5958
+ const trimmed = rest.trim();
5959
+ const literalThird = /,\s*['"`]([\w.-]+)['"`]\s*$/.exec(trimmed);
5960
+ if (literalThird) return { name: literalThird[1], kind: "mongodb-collection" };
5961
+ const firstIdent = /^([A-Za-z_$][\w$]*)/.exec(trimmed)?.[1];
5962
+ if (firstIdent && schemaColl.has(firstIdent)) {
5963
+ return { name: schemaColl.get(firstIdent), kind: "mongodb-collection" };
5964
+ }
5965
+ if (/,\s*[A-Za-z_$][\w$]*\s*$/.test(trimmed)) {
5966
+ return { name: modelName, kind: "mongodb-model" };
5967
+ }
5968
+ return { name: pluralizeOn ? pluralizeCollection(modelName) : modelName, kind: "mongodb-collection" };
5969
+ }
5970
+ function collectModelDefs(content, pluralizeOn) {
5971
+ const schemaColl = schemaCollectionVars(content);
5972
+ const out = [];
5973
+ const re = /(?:(?:const|let|var)\s+(\w+)\s*=\s*)?(?:await\s+)?(?:\b\w+\s*\.\s*)?\bmodel\s*\(\s*['"`]([\w$]+)['"`]\s*(?:,\s*([\s\S]{0,300}?))?\)/g;
5974
+ let m;
5975
+ while ((m = re.exec(content)) !== null) {
5976
+ out.push({
5977
+ modelName: m[2],
5978
+ varName: m[1] ?? null,
5979
+ resolved: resolveModel(m[2], m[3] ?? "", schemaColl, pluralizeOn),
5980
+ matchText: m[0]
5981
+ });
5982
+ }
5983
+ return out;
5984
+ }
5985
+ function endpoint(r, file, serviceDir, matchText) {
5986
+ const line = lineOf(file.content, matchText);
5987
+ return {
5988
+ infraId: infraId7(r.kind, r.name),
5989
+ name: r.name,
5990
+ kind: r.kind,
5991
+ edgeType: "CALLS",
5992
+ confidenceKind: "verified-call-site",
5993
+ evidence: { file: path31.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
5994
+ };
5995
+ }
5996
+ function mongooseEndpointsFromFile(file, serviceDir) {
5997
+ const hasMongoose = MONGOOSE_IMPORT_RE.test(file.content);
5998
+ const hasMongodb = MONGODB_IMPORT_RE.test(file.content);
5999
+ if (!hasMongoose && !hasMongodb) return [];
6000
+ const content = file.content;
6001
+ const out = [];
6002
+ const seen = /* @__PURE__ */ new Set();
6003
+ const push = (r, matchText) => {
6004
+ const key = `${r.kind}/${r.name}`;
6005
+ if (seen.has(key)) return;
6006
+ seen.add(key);
6007
+ out.push(endpoint(r, file, serviceDir, matchText));
6008
+ };
6009
+ if (hasMongoose) {
6010
+ const pluralizeOn = !PLURALIZE_DISABLED_RE.test(content);
6011
+ for (const def of collectModelDefs(content, pluralizeOn)) push(def.resolved, def.matchText);
6012
+ }
6013
+ const collRe = /\.\s*collection\s*\(\s*['"`]([\w.$-]+)['"`]\s*\)/g;
6014
+ let c;
6015
+ while ((c = collRe.exec(content)) !== null) {
6016
+ push({ name: c[1], kind: "mongodb-collection" }, c[0]);
6017
+ }
6018
+ return out;
6019
+ }
6020
+ function parseDestructure(inner, specifier, out) {
6021
+ for (const raw of inner.split(",")) {
6022
+ const part = raw.trim();
6023
+ if (!part) continue;
6024
+ const asM = /^(\w+)\s+as\s+(\w+)$/.exec(part);
6025
+ const colonM = /^(\w+)\s*:\s*(\w+)$/.exec(part);
6026
+ if (asM) out.push({ local: asM[2], kind: "named", exportName: asM[1], specifier });
6027
+ else if (colonM) out.push({ local: colonM[2], kind: "named", exportName: colonM[1], specifier });
6028
+ else {
6029
+ const id = /^(\w+)$/.exec(part);
6030
+ if (id) out.push({ local: id[1], kind: "named", exportName: id[1], specifier });
6031
+ }
6032
+ }
6033
+ }
6034
+ function parseImportBindings(content) {
6035
+ const out = [];
6036
+ const esm = /import\s+([^;'"`\n]+?)\s+from\s*['"`]([^'"`]+)['"`]/g;
6037
+ let m;
6038
+ while ((m = esm.exec(content)) !== null) {
6039
+ const clause = m[1].trim();
6040
+ const spec = m[2];
6041
+ const ns = /^\*\s+as\s+(\w+)$/.exec(clause);
6042
+ if (ns) {
6043
+ out.push({ local: ns[1], kind: "namespace", specifier: spec });
6044
+ continue;
6045
+ }
6046
+ const named = /\{([^}]*)\}/.exec(clause);
6047
+ if (named) parseDestructure(named[1], spec, out);
6048
+ const def = /^(\w+)\s*(?:,|$)/.exec(clause);
6049
+ if (def && !clause.startsWith("{")) out.push({ local: def[1], kind: "default", specifier: spec });
6050
+ }
6051
+ const cjs = /(?:const|let|var)\s+(\{[^}]*\}|\w+)\s*=\s*require\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
6052
+ while ((m = cjs.exec(content)) !== null) {
6053
+ const lhs = m[1];
6054
+ const spec = m[2];
6055
+ if (lhs.startsWith("{")) parseDestructure(lhs.slice(1, -1), spec, out);
6056
+ else out.push({ local: lhs, kind: "whole", specifier: spec });
6057
+ }
6058
+ return out;
6059
+ }
6060
+ function fileExportsOf(content, pluralizeOn) {
6061
+ const defs = collectModelDefs(content, pluralizeOn).filter((d) => d.resolved.kind === "mongodb-collection");
6062
+ if (defs.length === 0) return null;
6063
+ const byVar = /* @__PURE__ */ new Map();
6064
+ for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name);
6065
+ const byName = new Map(byVar);
6066
+ let def;
6067
+ const named = /(?:module\.exports|export\s+default)\s*=\s*(\w+)\b/.exec(content);
6068
+ if (named && byVar.has(named[1])) def = byVar.get(named[1]);
6069
+ if (!def) {
6070
+ const inline = /(?:module\.exports|export\s+default)\s*=\s*(?:await\s+)?(?:\w+\s*\.\s*)?model\s*\(\s*['"`]([\w$]+)['"`]/.exec(content);
6071
+ if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]) : inline[1];
6072
+ }
6073
+ if (!def && byVar.size === 1) def = [...byVar.values()][0];
6074
+ return { byName, ...def ? { default: def } : {} };
6075
+ }
6076
+ async function mongooseCrossFileEndpoints(files, serviceDir) {
6077
+ const mongooseFiles = files.filter((f) => MONGOOSE_IMPORT_RE.test(f.content));
6078
+ if (mongooseFiles.length === 0) return [];
6079
+ const pluralizeOn = !files.some((f) => PLURALIZE_DISABLED_RE.test(f.content));
6080
+ const registry = /* @__PURE__ */ new Map();
6081
+ for (const f of mongooseFiles) {
6082
+ const fx = fileExportsOf(f.content, pluralizeOn);
6083
+ if (fx) registry.set(toPosix2(path31.relative(serviceDir, f.path)), fx);
6084
+ }
6085
+ if (registry.size === 0) return [];
6086
+ const out = [];
6087
+ const seen = /* @__PURE__ */ new Set();
6088
+ for (const f of files) {
6089
+ const bindings = parseImportBindings(f.content);
6090
+ if (bindings.length === 0) continue;
6091
+ const directColl = /* @__PURE__ */ new Map();
6092
+ const nsExports = /* @__PURE__ */ new Map();
6093
+ for (const b of bindings) {
6094
+ const resolvedRel = await resolveJsImport(b.specifier, path31.dirname(f.path), serviceDir, null);
6095
+ if (!resolvedRel) continue;
6096
+ const fx = registry.get(resolvedRel);
6097
+ if (!fx) continue;
6098
+ if (b.kind === "named" && b.exportName) {
6099
+ const coll = fx.byName.get(b.exportName);
6100
+ if (coll) directColl.set(b.local, coll);
6101
+ } else if (b.kind === "default") {
6102
+ if (fx.default) directColl.set(b.local, fx.default);
6103
+ } else {
6104
+ if (fx.default) directColl.set(b.local, fx.default);
6105
+ nsExports.set(b.local, fx);
6106
+ }
6107
+ }
6108
+ if (directColl.size === 0 && nsExports.size === 0) continue;
6109
+ const localDefs = new Set(
6110
+ collectModelDefs(f.content, pluralizeOn).map((d) => d.varName).filter((v) => v !== null)
6111
+ );
6112
+ const emit = (collection, matchText) => {
6113
+ const key = `${f.path}::${collection}`;
6114
+ if (seen.has(key)) return;
6115
+ seen.add(key);
6116
+ out.push(endpoint({ name: collection, kind: "mongodb-collection" }, f, serviceDir, matchText));
6117
+ };
6118
+ for (const [local, collection] of directColl) {
6119
+ if (localDefs.has(local)) continue;
6120
+ const qre = new RegExp(`\\b${local}\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
6121
+ let qm;
6122
+ while ((qm = qre.exec(f.content)) !== null) emit(collection, qm[0]);
6123
+ }
6124
+ for (const [local, fx] of nsExports) {
6125
+ const qre = new RegExp(`\\b${local}\\s*\\.\\s*(\\w+)\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
6126
+ let qm;
6127
+ while ((qm = qre.exec(f.content)) !== null) {
6128
+ const coll = fx.byName.get(qm[1]);
6129
+ if (coll) emit(coll, qm[0]);
6130
+ }
6131
+ }
6132
+ }
6133
+ return out;
6134
+ }
6135
+
5829
6136
  // src/extract/calls/index.ts
5830
6137
  function edgeTypeFromEndpoint(ep) {
5831
6138
  switch (ep.edgeType) {
@@ -5846,16 +6153,20 @@ async function addExternalEndpointEdges(graph, services) {
5846
6153
  for (const service of services) {
5847
6154
  const files = await loadSourceFiles(service.dir);
5848
6155
  const endpoints = [];
6156
+ const maskedFiles = [];
5849
6157
  for (const file of files) {
5850
6158
  if (isTestPath(file.path)) continue;
5851
6159
  const masked = maskCommentsInSource(file.content);
5852
6160
  const maskedFile = { path: file.path, content: masked };
6161
+ maskedFiles.push(maskedFile);
5853
6162
  endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir));
5854
6163
  endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir));
5855
6164
  endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir));
5856
6165
  endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
5857
6166
  endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
6167
+ endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
5858
6168
  }
6169
+ endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
5859
6170
  if (endpoints.length === 0) continue;
5860
6171
  const seenEdges = /* @__PURE__ */ new Set();
5861
6172
  for (const ep of endpoints) {
@@ -5926,14 +6237,14 @@ async function addCallEdges(graph, services) {
5926
6237
  }
5927
6238
 
5928
6239
  // src/extract/infra/docker-compose.ts
5929
- import path31 from "path";
6240
+ import path32 from "path";
5930
6241
  import { EdgeType as EdgeType13, Provenance as Provenance13, confidenceForExtracted as confidenceForExtracted11 } from "@neat.is/types";
5931
6242
 
5932
6243
  // src/extract/infra/shared.ts
5933
- import { NodeType as NodeType13, Provenance as Provenance12, confidenceForExtracted as confidenceForExtracted10, infraId as infraId7 } from "@neat.is/types";
6244
+ import { NodeType as NodeType13, Provenance as Provenance12, confidenceForExtracted as confidenceForExtracted10, infraId as infraId8 } from "@neat.is/types";
5934
6245
  function makeInfraNode(kind, name, provider = "self", extras) {
5935
6246
  return {
5936
- id: infraId7(kind, name),
6247
+ id: infraId8(kind, name),
5937
6248
  type: NodeType13.InfraNode,
5938
6249
  name,
5939
6250
  provider,
@@ -5996,7 +6307,7 @@ function dependsOnList(value) {
5996
6307
  }
5997
6308
  function serviceNameToServiceNode(name, services) {
5998
6309
  for (const s of services) {
5999
- if (s.node.name === name || path31.basename(s.dir) === name) return s.node.id;
6310
+ if (s.node.name === name || path32.basename(s.dir) === name) return s.node.id;
6000
6311
  }
6001
6312
  return null;
6002
6313
  }
@@ -6005,7 +6316,7 @@ async function addComposeInfra(graph, scanPath, services) {
6005
6316
  let edgesAdded = 0;
6006
6317
  let composePath = null;
6007
6318
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
6008
- const abs = path31.join(scanPath, name);
6319
+ const abs = path32.join(scanPath, name);
6009
6320
  if (await exists(abs)) {
6010
6321
  composePath = abs;
6011
6322
  break;
@@ -6018,13 +6329,13 @@ async function addComposeInfra(graph, scanPath, services) {
6018
6329
  } catch (err) {
6019
6330
  recordExtractionError(
6020
6331
  "infra docker-compose",
6021
- path31.relative(scanPath, composePath),
6332
+ path32.relative(scanPath, composePath),
6022
6333
  err
6023
6334
  );
6024
6335
  return { nodesAdded, edgesAdded };
6025
6336
  }
6026
6337
  if (!compose?.services) return { nodesAdded, edgesAdded };
6027
- const evidenceFile = path31.relative(scanPath, composePath).split(path31.sep).join("/");
6338
+ const evidenceFile = path32.relative(scanPath, composePath).split(path32.sep).join("/");
6028
6339
  const composeNameToNodeId = /* @__PURE__ */ new Map();
6029
6340
  for (const [composeName, svc] of Object.entries(compose.services)) {
6030
6341
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -6065,7 +6376,7 @@ async function addComposeInfra(graph, scanPath, services) {
6065
6376
  }
6066
6377
 
6067
6378
  // src/extract/infra/dockerfile.ts
6068
- import path32 from "path";
6379
+ import path33 from "path";
6069
6380
  import { promises as fs16 } from "fs";
6070
6381
  import { EdgeType as EdgeType14, Provenance as Provenance14, confidenceForExtracted as confidenceForExtracted12 } from "@neat.is/types";
6071
6382
  function readDockerfile(content) {
@@ -6096,7 +6407,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
6096
6407
  let nodesAdded = 0;
6097
6408
  let edgesAdded = 0;
6098
6409
  for (const service of services) {
6099
- const dockerfilePath = path32.join(service.dir, "Dockerfile");
6410
+ const dockerfilePath = path33.join(service.dir, "Dockerfile");
6100
6411
  if (!await exists(dockerfilePath)) continue;
6101
6412
  let content;
6102
6413
  try {
@@ -6104,7 +6415,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
6104
6415
  } catch (err) {
6105
6416
  recordExtractionError(
6106
6417
  "infra dockerfile",
6107
- path32.relative(scanPath, dockerfilePath),
6418
+ path33.relative(scanPath, dockerfilePath),
6108
6419
  err
6109
6420
  );
6110
6421
  continue;
@@ -6116,8 +6427,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
6116
6427
  graph.addNode(node.id, node);
6117
6428
  nodesAdded++;
6118
6429
  }
6119
- const relDockerfile = toPosix2(path32.relative(service.dir, dockerfilePath));
6120
- const evidenceFile = toPosix2(path32.relative(scanPath, dockerfilePath));
6430
+ const relDockerfile = toPosix2(path33.relative(service.dir, dockerfilePath));
6431
+ const evidenceFile = toPosix2(path33.relative(scanPath, dockerfilePath));
6121
6432
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
6122
6433
  graph,
6123
6434
  service.pkg.name,
@@ -6169,7 +6480,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
6169
6480
 
6170
6481
  // src/extract/infra/terraform.ts
6171
6482
  import { promises as fs17 } from "fs";
6172
- import path33 from "path";
6483
+ import path34 from "path";
6173
6484
  import { EdgeType as EdgeType15, Provenance as Provenance15, confidenceForExtracted as confidenceForExtracted13 } from "@neat.is/types";
6174
6485
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
6175
6486
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
@@ -6180,11 +6491,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
6180
6491
  for (const entry of entries) {
6181
6492
  if (entry.isDirectory()) {
6182
6493
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
6183
- const child = path33.join(start, entry.name);
6494
+ const child = path34.join(start, entry.name);
6184
6495
  if (await isPythonVenvDir(child)) continue;
6185
6496
  out.push(...await walkTfFiles(child, depth + 1, max));
6186
6497
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
6187
- out.push(path33.join(start, entry.name));
6498
+ out.push(path34.join(start, entry.name));
6188
6499
  }
6189
6500
  }
6190
6501
  return out;
@@ -6216,7 +6527,7 @@ async function addTerraformResources(graph, scanPath) {
6216
6527
  const files = await walkTfFiles(scanPath);
6217
6528
  for (const file of files) {
6218
6529
  const content = await fs17.readFile(file, "utf8");
6219
- const evidenceFile = toPosix2(path33.relative(scanPath, file));
6530
+ const evidenceFile = toPosix2(path34.relative(scanPath, file));
6220
6531
  const resources = [];
6221
6532
  const byKey = /* @__PURE__ */ new Map();
6222
6533
  RESOURCE_RE.lastIndex = 0;
@@ -6273,7 +6584,7 @@ async function addTerraformResources(graph, scanPath) {
6273
6584
 
6274
6585
  // src/extract/infra/k8s.ts
6275
6586
  import { promises as fs18 } from "fs";
6276
- import path34 from "path";
6587
+ import path35 from "path";
6277
6588
  import { parseAllDocuments as parseAllDocuments2 } from "yaml";
6278
6589
  var K8S_KIND_TO_INFRA_KIND = {
6279
6590
  Service: "k8s-service",
@@ -6291,11 +6602,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
6291
6602
  for (const entry of entries) {
6292
6603
  if (entry.isDirectory()) {
6293
6604
  if (IGNORED_DIRS.has(entry.name)) continue;
6294
- const child = path34.join(start, entry.name);
6605
+ const child = path35.join(start, entry.name);
6295
6606
  if (await isPythonVenvDir(child)) continue;
6296
6607
  out.push(...await walkYamlFiles2(child, depth + 1, max));
6297
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path34.extname(entry.name))) {
6298
- out.push(path34.join(start, entry.name));
6608
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path35.extname(entry.name))) {
6609
+ out.push(path35.join(start, entry.name));
6299
6610
  }
6300
6611
  }
6301
6612
  return out;
@@ -6328,13 +6639,13 @@ async function addK8sResources(graph, scanPath) {
6328
6639
 
6329
6640
  // src/extract/infra/cloudflare.ts
6330
6641
  import { promises as fs19 } from "fs";
6331
- import path35 from "path";
6642
+ import path36 from "path";
6332
6643
  import { parse as parseToml2 } from "smol-toml";
6333
6644
  import { EdgeType as EdgeType16, Provenance as Provenance16, confidenceForExtracted as confidenceForExtracted14 } from "@neat.is/types";
6334
6645
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
6335
6646
  async function readWranglerConfig(dir) {
6336
6647
  for (const filename of WRANGLER_FILENAMES) {
6337
- const abs = path35.join(dir, filename);
6648
+ const abs = path36.join(dir, filename);
6338
6649
  if (!await exists(abs)) continue;
6339
6650
  const raw = await fs19.readFile(abs, "utf8");
6340
6651
  const config = filename === "wrangler.toml" ? parseToml2(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -6397,11 +6708,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
6397
6708
  try {
6398
6709
  read = await readWranglerConfig(service.dir);
6399
6710
  } catch (err) {
6400
- recordExtractionError("infra cloudflare", path35.relative(scanPath, service.dir), err);
6711
+ recordExtractionError("infra cloudflare", path36.relative(scanPath, service.dir), err);
6401
6712
  continue;
6402
6713
  }
6403
6714
  if (!read || !read.config.name) continue;
6404
- const evidenceFile = toPosix2(path35.relative(scanPath, path35.join(service.dir, read.relFile)));
6715
+ const evidenceFile = toPosix2(path36.relative(scanPath, path36.join(service.dir, read.relFile)));
6405
6716
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
6406
6717
  }
6407
6718
  for (const worker of discovered) {
@@ -6413,7 +6724,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
6413
6724
  }
6414
6725
  let anchorId = service.node.id;
6415
6726
  if (config.main) {
6416
- const entryRelPath = toPosix2(path35.normalize(config.main));
6727
+ const entryRelPath = toPosix2(path36.normalize(config.main));
6417
6728
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
6418
6729
  graph,
6419
6730
  service.pkg.name,
@@ -6560,12 +6871,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
6560
6871
 
6561
6872
  // src/extract/infra/vercel.ts
6562
6873
  import { promises as fs20 } from "fs";
6563
- import path36 from "path";
6874
+ import path37 from "path";
6564
6875
  import { EdgeType as EdgeType17 } from "@neat.is/types";
6565
6876
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
6566
6877
  async function readVercelConfig(dir) {
6567
6878
  for (const filename of VERCEL_CONFIG_FILENAMES) {
6568
- const abs = path36.join(dir, filename);
6879
+ const abs = path37.join(dir, filename);
6569
6880
  if (!await exists(abs)) continue;
6570
6881
  const raw = await fs20.readFile(abs, "utf8");
6571
6882
  const config = JSON.parse(maskCommentsInSource(raw));
@@ -6574,7 +6885,7 @@ async function readVercelConfig(dir) {
6574
6885
  return null;
6575
6886
  }
6576
6887
  async function readLinkedProjectName(dir) {
6577
- const abs = path36.join(dir, ".vercel", "project.json");
6888
+ const abs = path37.join(dir, ".vercel", "project.json");
6578
6889
  if (!await exists(abs)) return void 0;
6579
6890
  const parsed = JSON.parse(await fs20.readFile(abs, "utf8"));
6580
6891
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
@@ -6592,7 +6903,7 @@ async function addVercelServices(graph, services, scanPath) {
6592
6903
  read = await readVercelConfig(service.dir);
6593
6904
  projectName = await readLinkedProjectName(service.dir);
6594
6905
  } catch (err) {
6595
- recordExtractionError("infra vercel", path36.relative(scanPath, service.dir), err);
6906
+ recordExtractionError("infra vercel", path37.relative(scanPath, service.dir), err);
6596
6907
  continue;
6597
6908
  }
6598
6909
  if (!read && !projectName) continue;
@@ -6608,7 +6919,7 @@ async function addVercelServices(graph, services, scanPath) {
6608
6919
  const anchorId = service.node.id;
6609
6920
  if (!read) continue;
6610
6921
  const { config, relFile, raw } = read;
6611
- const evidenceFile = toPosix2(path36.relative(scanPath, path36.join(service.dir, relFile)));
6922
+ const evidenceFile = toPosix2(path37.relative(scanPath, path37.join(service.dir, relFile)));
6612
6923
  const add = (edgeType, kind, name) => {
6613
6924
  if (!name) return;
6614
6925
  const result = emitPlatformResourceEdge(
@@ -6637,13 +6948,13 @@ async function addVercelServices(graph, services, scanPath) {
6637
6948
 
6638
6949
  // src/extract/infra/railway.ts
6639
6950
  import { promises as fs21 } from "fs";
6640
- import path37 from "path";
6951
+ import path38 from "path";
6641
6952
  import { parse as parseToml3 } from "smol-toml";
6642
6953
  import { EdgeType as EdgeType18 } from "@neat.is/types";
6643
6954
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
6644
6955
  async function readRailwayConfig(dir) {
6645
6956
  for (const filename of RAILWAY_FILENAMES) {
6646
- const abs = path37.join(dir, filename);
6957
+ const abs = path38.join(dir, filename);
6647
6958
  if (!await exists(abs)) continue;
6648
6959
  const raw = await fs21.readFile(abs, "utf8");
6649
6960
  const config = filename === "railway.toml" ? parseToml3(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -6659,7 +6970,7 @@ async function addRailwayServices(graph, services, scanPath) {
6659
6970
  try {
6660
6971
  read = await readRailwayConfig(service.dir);
6661
6972
  } catch (err) {
6662
- recordExtractionError("infra railway", path37.relative(scanPath, service.dir), err);
6973
+ recordExtractionError("infra railway", path38.relative(scanPath, service.dir), err);
6663
6974
  continue;
6664
6975
  }
6665
6976
  if (!read) continue;
@@ -6669,7 +6980,7 @@ async function addRailwayServices(graph, services, scanPath) {
6669
6980
  }
6670
6981
  const anchorId = service.node.id;
6671
6982
  const { config, relFile, raw } = read;
6672
- const evidenceFile = toPosix2(path37.relative(scanPath, path37.join(service.dir, relFile)));
6983
+ const evidenceFile = toPosix2(path38.relative(scanPath, path38.join(service.dir, relFile)));
6673
6984
  const add = (edgeType, kind, name) => {
6674
6985
  if (!name) return;
6675
6986
  const result = emitPlatformResourceEdge(
@@ -6694,12 +7005,12 @@ async function addRailwayServices(graph, services, scanPath) {
6694
7005
 
6695
7006
  // src/extract/infra/supabase.ts
6696
7007
  import { promises as fs22 } from "fs";
6697
- import path38 from "path";
7008
+ import path39 from "path";
6698
7009
  import { parse as parseToml4 } from "smol-toml";
6699
7010
  import { EdgeType as EdgeType19 } from "@neat.is/types";
6700
7011
  async function readSupabaseConfig(dir) {
6701
- const relFile = path38.join("supabase", "config.toml");
6702
- const abs = path38.join(dir, relFile);
7012
+ const relFile = path39.join("supabase", "config.toml");
7013
+ const abs = path39.join(dir, relFile);
6703
7014
  if (!await exists(abs)) return null;
6704
7015
  const raw = await fs22.readFile(abs, "utf8");
6705
7016
  const config = parseToml4(raw);
@@ -6713,7 +7024,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
6713
7024
  try {
6714
7025
  read = await readSupabaseConfig(service.dir);
6715
7026
  } catch (err) {
6716
- recordExtractionError("infra supabase", path38.relative(scanPath, service.dir), err);
7027
+ recordExtractionError("infra supabase", path39.relative(scanPath, service.dir), err);
6717
7028
  continue;
6718
7029
  }
6719
7030
  if (!read) continue;
@@ -6728,7 +7039,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
6728
7039
  });
6729
7040
  }
6730
7041
  const anchorId = service.node.id;
6731
- const evidenceFile = toPosix2(path38.relative(scanPath, path38.join(service.dir, relFile)));
7042
+ const evidenceFile = toPosix2(path39.relative(scanPath, path39.join(service.dir, relFile)));
6732
7043
  const add = (edgeType, kind, name) => {
6733
7044
  if (!name) return;
6734
7045
  const result = emitPlatformResourceEdge(
@@ -6769,11 +7080,11 @@ async function addInfra(graph, scanPath, services) {
6769
7080
  }
6770
7081
 
6771
7082
  // src/extract/index.ts
6772
- import path40 from "path";
7083
+ import path41 from "path";
6773
7084
 
6774
7085
  // src/extract/retire.ts
6775
7086
  import { existsSync as existsSync2 } from "fs";
6776
- import path39 from "path";
7087
+ import path40 from "path";
6777
7088
  import { NodeType as NodeType14, Provenance as Provenance17 } from "@neat.is/types";
6778
7089
  function dropOrphanedFileNodes(graph) {
6779
7090
  const orphans = [];
@@ -6807,11 +7118,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
6807
7118
  if (edge.provenance !== Provenance17.EXTRACTED) return;
6808
7119
  const evidenceFile = edge.evidence?.file;
6809
7120
  if (!evidenceFile) return;
6810
- if (path39.isAbsolute(evidenceFile)) {
7121
+ if (path40.isAbsolute(evidenceFile)) {
6811
7122
  if (!existsSync2(evidenceFile)) toDrop.push(id);
6812
7123
  return;
6813
7124
  }
6814
- const found = bases.some((base) => existsSync2(path39.join(base, evidenceFile)));
7125
+ const found = bases.some((base) => existsSync2(path40.join(base, evidenceFile)));
6815
7126
  if (!found) toDrop.push(id);
6816
7127
  });
6817
7128
  for (const id of toDrop) graph.dropEdge(id);
@@ -6853,7 +7164,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
6853
7164
  }
6854
7165
  const droppedEntries = drainDroppedExtracted();
6855
7166
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
6856
- const rejectedPath = path40.join(path40.dirname(opts.errorsPath), "rejected.ndjson");
7167
+ const rejectedPath = path41.join(path41.dirname(opts.errorsPath), "rejected.ndjson");
6857
7168
  try {
6858
7169
  await writeRejectedExtracted(droppedEntries, rejectedPath);
6859
7170
  } catch (err) {
@@ -7171,7 +7482,7 @@ function computeDivergences(graph, opts = {}) {
7171
7482
 
7172
7483
  // src/persist.ts
7173
7484
  import { promises as fs23 } from "fs";
7174
- import path41 from "path";
7485
+ import path42 from "path";
7175
7486
  import { Provenance as Provenance19, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
7176
7487
  var SCHEMA_VERSION = 4;
7177
7488
  function migrateV1ToV2(payload) {
@@ -7208,7 +7519,7 @@ function migrateV2ToV3(payload) {
7208
7519
  return { ...payload, schemaVersion: 3 };
7209
7520
  }
7210
7521
  async function ensureDir(filePath) {
7211
- await fs23.mkdir(path41.dirname(filePath), { recursive: true });
7522
+ await fs23.mkdir(path42.dirname(filePath), { recursive: true });
7212
7523
  }
7213
7524
  async function saveGraphToDisk(graph, outPath) {
7214
7525
  await ensureDir(outPath);
@@ -7364,23 +7675,23 @@ function canonicalJson(value) {
7364
7675
  }
7365
7676
 
7366
7677
  // src/projects.ts
7367
- import path42 from "path";
7678
+ import path43 from "path";
7368
7679
  function pathsForProject(project, baseDir) {
7369
7680
  if (project === DEFAULT_PROJECT) {
7370
7681
  return {
7371
- snapshotPath: path42.join(baseDir, "graph.json"),
7372
- errorsPath: path42.join(baseDir, "errors.ndjson"),
7373
- staleEventsPath: path42.join(baseDir, "stale-events.ndjson"),
7374
- embeddingsCachePath: path42.join(baseDir, "embeddings.json"),
7375
- policyViolationsPath: path42.join(baseDir, "policy-violations.ndjson")
7682
+ snapshotPath: path43.join(baseDir, "graph.json"),
7683
+ errorsPath: path43.join(baseDir, "errors.ndjson"),
7684
+ staleEventsPath: path43.join(baseDir, "stale-events.ndjson"),
7685
+ embeddingsCachePath: path43.join(baseDir, "embeddings.json"),
7686
+ policyViolationsPath: path43.join(baseDir, "policy-violations.ndjson")
7376
7687
  };
7377
7688
  }
7378
7689
  return {
7379
- snapshotPath: path42.join(baseDir, `${project}.json`),
7380
- errorsPath: path42.join(baseDir, `errors.${project}.ndjson`),
7381
- staleEventsPath: path42.join(baseDir, `stale-events.${project}.ndjson`),
7382
- embeddingsCachePath: path42.join(baseDir, `embeddings.${project}.json`),
7383
- policyViolationsPath: path42.join(baseDir, `policy-violations.${project}.ndjson`)
7690
+ snapshotPath: path43.join(baseDir, `${project}.json`),
7691
+ errorsPath: path43.join(baseDir, `errors.${project}.ndjson`),
7692
+ staleEventsPath: path43.join(baseDir, `stale-events.${project}.ndjson`),
7693
+ embeddingsCachePath: path43.join(baseDir, `embeddings.${project}.json`),
7694
+ policyViolationsPath: path43.join(baseDir, `policy-violations.${project}.ndjson`)
7384
7695
  };
7385
7696
  }
7386
7697
  var Projects = class {
@@ -7421,7 +7732,7 @@ function parseExtraProjects(raw) {
7421
7732
  // src/registry.ts
7422
7733
  import { promises as fs25 } from "fs";
7423
7734
  import os2 from "os";
7424
- import path43 from "path";
7735
+ import path44 from "path";
7425
7736
  import {
7426
7737
  RegistryFileSchema
7427
7738
  } from "@neat.is/types";
@@ -7429,20 +7740,20 @@ var LOCK_TIMEOUT_MS = 5e3;
7429
7740
  var LOCK_RETRY_MS = 50;
7430
7741
  function neatHome() {
7431
7742
  const override = process.env.NEAT_HOME;
7432
- if (override && override.length > 0) return path43.resolve(override);
7433
- return path43.join(os2.homedir(), ".neat");
7743
+ if (override && override.length > 0) return path44.resolve(override);
7744
+ return path44.join(os2.homedir(), ".neat");
7434
7745
  }
7435
7746
  function registryPath() {
7436
- return path43.join(neatHome(), "projects.json");
7747
+ return path44.join(neatHome(), "projects.json");
7437
7748
  }
7438
7749
  function registryLockPath() {
7439
- return path43.join(neatHome(), "projects.json.lock");
7750
+ return path44.join(neatHome(), "projects.json.lock");
7440
7751
  }
7441
7752
  function daemonPidPath() {
7442
- return path43.join(neatHome(), "neatd.pid");
7753
+ return path44.join(neatHome(), "neatd.pid");
7443
7754
  }
7444
7755
  function daemonsDir() {
7445
- return path43.join(neatHome(), "daemons");
7756
+ return path44.join(neatHome(), "daemons");
7446
7757
  }
7447
7758
  function isFiniteInt(v) {
7448
7759
  return typeof v === "number" && Number.isFinite(v);
@@ -7483,7 +7794,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
7483
7794
  const out = [];
7484
7795
  for (const name of names) {
7485
7796
  if (!name.endsWith(".json")) continue;
7486
- const file = path43.join(dir, name);
7797
+ const file = path44.join(dir, name);
7487
7798
  let raw;
7488
7799
  try {
7489
7800
  raw = await fs25.readFile(file, "utf8");
@@ -7604,7 +7915,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
7604
7915
  }
7605
7916
  }
7606
7917
  async function normalizeProjectPath(input) {
7607
- const resolved = path43.resolve(input);
7918
+ const resolved = path44.resolve(input);
7608
7919
  try {
7609
7920
  return await fs25.realpath(resolved);
7610
7921
  } catch {
@@ -7612,7 +7923,7 @@ async function normalizeProjectPath(input) {
7612
7923
  }
7613
7924
  }
7614
7925
  async function writeAtomically(target, contents) {
7615
- await fs25.mkdir(path43.dirname(target), { recursive: true });
7926
+ await fs25.mkdir(path44.dirname(target), { recursive: true });
7616
7927
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
7617
7928
  const fd = await fs25.open(tmp, "w");
7618
7929
  try {
@@ -7625,7 +7936,7 @@ async function writeAtomically(target, contents) {
7625
7936
  }
7626
7937
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
7627
7938
  const deadline = Date.now() + timeoutMs;
7628
- await fs25.mkdir(path43.dirname(lockPath), { recursive: true });
7939
+ await fs25.mkdir(path44.dirname(lockPath), { recursive: true });
7629
7940
  let probedHolder = false;
7630
7941
  while (true) {
7631
7942
  try {
@@ -7821,13 +8132,13 @@ import { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } f
7821
8132
 
7822
8133
  // src/extend/index.ts
7823
8134
  import { promises as fs27 } from "fs";
7824
- import path45 from "path";
8135
+ import path46 from "path";
7825
8136
  import os3 from "os";
7826
8137
  import { resolve as registryResolve, list as registryList } from "@neat.is/instrumentation-registry";
7827
8138
 
7828
8139
  // src/installers/package-manager.ts
7829
8140
  import { promises as fs26 } from "fs";
7830
- import path44 from "path";
8141
+ import path45 from "path";
7831
8142
  import { spawn } from "child_process";
7832
8143
  var LOCKFILE_PRIORITY = [
7833
8144
  { lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
@@ -7849,22 +8160,22 @@ async function exists2(p) {
7849
8160
  }
7850
8161
  }
7851
8162
  async function detectPackageManager(serviceDir) {
7852
- let dir = path44.resolve(serviceDir);
8163
+ let dir = path45.resolve(serviceDir);
7853
8164
  const stops = /* @__PURE__ */ new Set();
7854
8165
  for (let i = 0; i < 64; i++) {
7855
8166
  if (stops.has(dir)) break;
7856
8167
  stops.add(dir);
7857
8168
  for (const candidate of LOCKFILE_PRIORITY) {
7858
- const lockPath = path44.join(dir, candidate.lockfile);
8169
+ const lockPath = path45.join(dir, candidate.lockfile);
7859
8170
  if (await exists2(lockPath)) {
7860
8171
  return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
7861
8172
  }
7862
8173
  }
7863
- const parent = path44.dirname(dir);
8174
+ const parent = path45.dirname(dir);
7864
8175
  if (parent === dir) break;
7865
8176
  dir = parent;
7866
8177
  }
7867
- return { pm: "npm", cwd: path44.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
8178
+ return { pm: "npm", cwd: path45.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
7868
8179
  }
7869
8180
  async function runPackageManagerInstall(cmd) {
7870
8181
  return new Promise((resolve) => {
@@ -7913,7 +8224,7 @@ async function fileExists2(p) {
7913
8224
  }
7914
8225
  }
7915
8226
  async function readPackageJson(scanPath) {
7916
- const pkgPath = path45.join(scanPath, "package.json");
8227
+ const pkgPath = path46.join(scanPath, "package.json");
7917
8228
  const raw = await fs27.readFile(pkgPath, "utf8");
7918
8229
  return JSON.parse(raw);
7919
8230
  }
@@ -7932,11 +8243,11 @@ async function findHookFiles(scanPath) {
7932
8243
  for (const entry of entries) {
7933
8244
  if (entry.isDirectory()) {
7934
8245
  if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
7935
- await walk3(path45.join(dir, entry.name));
8246
+ await walk3(path46.join(dir, entry.name));
7936
8247
  } else if (entry.isFile()) {
7937
8248
  if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
7938
- const rel = path45.relative(scanPath, path45.join(dir, entry.name));
7939
- found.push(rel.split(path45.sep).join("/"));
8249
+ const rel = path46.relative(scanPath, path46.join(dir, entry.name));
8250
+ found.push(rel.split(path46.sep).join("/"));
7940
8251
  }
7941
8252
  }
7942
8253
  }
@@ -7947,7 +8258,7 @@ async function findHookFiles(scanPath) {
7947
8258
  async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
7948
8259
  let fallback = null;
7949
8260
  for (const file of hookFiles) {
7950
- const content = await fs27.readFile(path45.join(scanPath, file), "utf8");
8261
+ const content = await fs27.readFile(path46.join(scanPath, file), "utf8");
7951
8262
  const patched = splicedContent(content, snippet2);
7952
8263
  if (patched !== null) return { file, content, patched };
7953
8264
  if (fallback === null) fallback = { file, content };
@@ -7955,11 +8266,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
7955
8266
  return { file: fallback.file, content: fallback.content, patched: null };
7956
8267
  }
7957
8268
  function extendLogPath() {
7958
- return process.env.NEAT_EXTEND_LOG ?? path45.join(os3.homedir(), ".neat", "extend-log.ndjson");
8269
+ return process.env.NEAT_EXTEND_LOG ?? path46.join(os3.homedir(), ".neat", "extend-log.ndjson");
7959
8270
  }
7960
8271
  async function appendExtendLog(entry) {
7961
8272
  const logPath = extendLogPath();
7962
- await fs27.mkdir(path45.dirname(logPath), { recursive: true });
8273
+ await fs27.mkdir(path46.dirname(logPath), { recursive: true });
7963
8274
  await fs27.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
7964
8275
  }
7965
8276
  function splicedContent(fileContent, snippet2) {
@@ -8018,7 +8329,7 @@ function lookupInstrumentation(library, installedVersion) {
8018
8329
  }
8019
8330
  async function describeProjectInstrumentation(ctx) {
8020
8331
  const hookFiles = await findHookFiles(ctx.scanPath);
8021
- const envNeat = await fileExists2(path45.join(ctx.scanPath, ".env.neat"));
8332
+ const envNeat = await fileExists2(path46.join(ctx.scanPath, ".env.neat"));
8022
8333
  const registryInstrPackages = new Set(
8023
8334
  registryList().map((e) => e.instrumentation_package).filter((p) => !!p)
8024
8335
  );
@@ -8040,7 +8351,7 @@ async function applyExtension(ctx, args, options) {
8040
8351
  );
8041
8352
  }
8042
8353
  for (const file of hookFiles) {
8043
- const content = await fs27.readFile(path45.join(ctx.scanPath, file), "utf8");
8354
+ const content = await fs27.readFile(path46.join(ctx.scanPath, file), "utf8");
8044
8355
  if (content.includes(args.registration_snippet)) {
8045
8356
  return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
8046
8357
  }
@@ -8052,10 +8363,10 @@ async function applyExtension(ctx, args, options) {
8052
8363
  );
8053
8364
  }
8054
8365
  const primaryFile = primary.file;
8055
- const primaryPath = path45.join(ctx.scanPath, primaryFile);
8366
+ const primaryPath = path46.join(ctx.scanPath, primaryFile);
8056
8367
  const filesTouched = [];
8057
8368
  const depsAdded = [];
8058
- const pkgPath = path45.join(ctx.scanPath, "package.json");
8369
+ const pkgPath = path46.join(ctx.scanPath, "package.json");
8059
8370
  const pkg = await readPackageJson(ctx.scanPath);
8060
8371
  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
8061
8372
  pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
@@ -8094,7 +8405,7 @@ async function dryRunExtension(ctx, args) {
8094
8405
  };
8095
8406
  }
8096
8407
  for (const file of hookFiles) {
8097
- const content = await fs27.readFile(path45.join(ctx.scanPath, file), "utf8");
8408
+ const content = await fs27.readFile(path46.join(ctx.scanPath, file), "utf8");
8098
8409
  if (content.includes(args.registration_snippet)) {
8099
8410
  return {
8100
8411
  library: args.library,
@@ -8135,7 +8446,7 @@ async function rollbackExtension(ctx, args) {
8135
8446
  if (!match) {
8136
8447
  return { undone: false, message: "no apply found for library" };
8137
8448
  }
8138
- const pkgPath = path45.join(ctx.scanPath, "package.json");
8449
+ const pkgPath = path46.join(ctx.scanPath, "package.json");
8139
8450
  if (await fileExists2(pkgPath)) {
8140
8451
  const pkg = await readPackageJson(ctx.scanPath);
8141
8452
  if (pkg.dependencies?.[match.instrumentation_package]) {
@@ -8146,7 +8457,7 @@ async function rollbackExtension(ctx, args) {
8146
8457
  }
8147
8458
  const hookFiles = await findHookFiles(ctx.scanPath);
8148
8459
  for (const file of hookFiles) {
8149
- const filePath = path45.join(ctx.scanPath, file);
8460
+ const filePath = path46.join(ctx.scanPath, file);
8150
8461
  const content = await fs27.readFile(filePath, "utf8");
8151
8462
  if (content.includes(match.registration_snippet)) {
8152
8463
  const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
@@ -8261,7 +8572,7 @@ data: ${JSON.stringify(envelope.payload)}
8261
8572
 
8262
8573
  // src/connectors-config.ts
8263
8574
  import os4 from "os";
8264
- import path46 from "path";
8575
+ import path47 from "path";
8265
8576
  import { promises as fs28 } from "fs";
8266
8577
  var CONNECTORS_CONFIG_VERSION = 1;
8267
8578
  var EnvRefUnsetError = class extends Error {
@@ -8276,11 +8587,11 @@ var EnvRefUnsetError = class extends Error {
8276
8587
  };
8277
8588
  function neatHome2() {
8278
8589
  const override = process.env.NEAT_HOME;
8279
- if (override && override.length > 0) return path46.resolve(override);
8280
- return path46.join(os4.homedir(), ".neat");
8590
+ if (override && override.length > 0) return path47.resolve(override);
8591
+ return path47.join(os4.homedir(), ".neat");
8281
8592
  }
8282
8593
  function connectorsConfigPath(home = neatHome2()) {
8283
- return path46.join(home, "connectors.json");
8594
+ return path47.join(home, "connectors.json");
8284
8595
  }
8285
8596
  var MODE_MASK_LOOSER_THAN_0600 = 63;
8286
8597
  async function warnIfModeLooserThan0600(file) {
@@ -8411,7 +8722,7 @@ function connectorMatchesProject(entry, project) {
8411
8722
  var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
8412
8723
  var CONNECTORS_LOCK_RETRY_MS = 50;
8413
8724
  function connectorsConfigLockPath(home = neatHome2()) {
8414
- return path46.join(home, "connectors.json.lock");
8725
+ return path47.join(home, "connectors.json.lock");
8415
8726
  }
8416
8727
  function isEnvRef(value) {
8417
8728
  return value.length > 1 && value.startsWith("$");
@@ -8424,7 +8735,7 @@ function redactCredentialRef(ref) {
8424
8735
  return out;
8425
8736
  }
8426
8737
  async function writeConfigAtomically0600(file, contents) {
8427
- await fs28.mkdir(path46.dirname(file), { recursive: true });
8738
+ await fs28.mkdir(path47.dirname(file), { recursive: true });
8428
8739
  const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
8429
8740
  const fd = await fs28.open(tmp, "w", 384);
8430
8741
  try {
@@ -8438,7 +8749,7 @@ async function writeConfigAtomically0600(file, contents) {
8438
8749
  }
8439
8750
  async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
8440
8751
  const deadline = Date.now() + timeoutMs;
8441
- await fs28.mkdir(path46.dirname(lockPath), { recursive: true });
8752
+ await fs28.mkdir(path47.dirname(lockPath), { recursive: true });
8442
8753
  for (; ; ) {
8443
8754
  try {
8444
8755
  const fd = await fs28.open(lockPath, "wx");
@@ -9396,4 +9707,4 @@ export {
9396
9707
  recordConnectorPoll,
9397
9708
  buildApi
9398
9709
  };
9399
- //# sourceMappingURL=chunk-GJHEZC5K.js.map
9710
+ //# sourceMappingURL=chunk-PEFX3DBR.js.map