@neat.is/core 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
61
61
  ]);
62
62
  const publicRead = opts.publicRead === true;
63
63
  app.addHook("preHandler", (req, reply, done) => {
64
- const path71 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
65
- if (exactUnauthPaths.has(path71) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path71)) {
64
+ const path72 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
65
+ if (exactUnauthPaths.has(path72) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path72)) {
66
66
  done();
67
67
  return;
68
68
  }
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req) {
194
194
  };
195
195
  }
196
196
  function resolveProtoRoot() {
197
- const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
198
- return import_node_path39.default.resolve(here, "..", "proto");
197
+ const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
198
+ return import_node_path40.default.resolve(here, "..", "proto");
199
199
  }
200
200
  function loadTraceService() {
201
201
  const protoRoot = resolveProtoRoot();
@@ -263,13 +263,13 @@ async function startOtelGrpcReceiver(opts) {
263
263
  })
264
264
  };
265
265
  }
266
- var import_node_url2, import_node_path39, import_node_crypto2, grpc, protoLoader;
266
+ var import_node_url2, import_node_path40, import_node_crypto2, grpc, protoLoader;
267
267
  var init_otel_grpc = __esm({
268
268
  "src/otel-grpc.ts"() {
269
269
  "use strict";
270
270
  init_cjs_shims();
271
271
  import_node_url2 = require("url");
272
- import_node_path39 = __toESM(require("path"), 1);
272
+ import_node_path40 = __toESM(require("path"), 1);
273
273
  import_node_crypto2 = require("crypto");
274
274
  grpc = __toESM(require("@grpc/grpc-js"), 1);
275
275
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
415
415
  const v = attrs[key];
416
416
  if (typeof v === "string" && v.length > 0) {
417
417
  const q = v.indexOf("?");
418
- const path71 = q === -1 ? v : v.slice(0, q);
419
- if (path71.length > 0) return path71;
418
+ const path72 = q === -1 ? v : v.slice(0, q);
419
+ if (path72.length > 0) return path72;
420
420
  }
421
421
  }
422
422
  return void 0;
@@ -475,10 +475,10 @@ function parseOtlpRequest(body) {
475
475
  return out;
476
476
  }
477
477
  function loadProtoRoot() {
478
- const here = import_node_path40.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
479
- const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
478
+ const here = import_node_path41.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
479
+ const protoRoot = import_node_path41.default.resolve(here, "..", "proto");
480
480
  const root = new import_protobufjs.default.Root();
481
- root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
481
+ root.resolvePath = (_origin, target) => import_node_path41.default.resolve(protoRoot, target);
482
482
  root.loadSync(
483
483
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
484
484
  { keepCase: true }
@@ -709,12 +709,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
709
709
  }
710
710
  }
711
711
  }
712
- var import_node_path40, import_node_url3, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
712
+ var import_node_path41, import_node_url3, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
713
713
  var init_otel = __esm({
714
714
  "src/otel.ts"() {
715
715
  "use strict";
716
716
  init_cjs_shims();
717
- import_node_path40 = __toESM(require("path"), 1);
717
+ import_node_path41 = __toESM(require("path"), 1);
718
718
  import_node_url3 = require("url");
719
719
  import_fastify = __toESM(require("fastify"), 1);
720
720
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -752,7 +752,7 @@ __export(cli_exports, {
752
752
  });
753
753
  module.exports = __toCommonJS(cli_exports);
754
754
  init_cjs_shims();
755
- var import_node_path70 = __toESM(require("path"), 1);
755
+ var import_node_path71 = __toESM(require("path"), 1);
756
756
  var import_node_os6 = __toESM(require("os"), 1);
757
757
  var import_node_fs43 = require("fs");
758
758
 
@@ -1322,19 +1322,19 @@ function confidenceFromMix(edges, now = Date.now()) {
1322
1322
  function longestIncomingWalk(graph, start, maxDepth) {
1323
1323
  let best = { path: [start], edges: [] };
1324
1324
  const visited = /* @__PURE__ */ new Set([start]);
1325
- function step(node, path71, edges) {
1326
- if (path71.length > best.path.length) {
1327
- best = { path: [...path71], edges: [...edges] };
1325
+ function step(node, path72, edges) {
1326
+ if (path72.length > best.path.length) {
1327
+ best = { path: [...path72], edges: [...edges] };
1328
1328
  }
1329
- if (path71.length - 1 >= maxDepth) return;
1329
+ if (path72.length - 1 >= maxDepth) return;
1330
1330
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
1331
1331
  for (const [srcId, edge] of incoming) {
1332
1332
  if (visited.has(srcId)) continue;
1333
1333
  visited.add(srcId);
1334
- path71.push(srcId);
1334
+ path72.push(srcId);
1335
1335
  edges.push(edge);
1336
- step(srcId, path71, edges);
1337
- path71.pop();
1336
+ step(srcId, path72, edges);
1337
+ path72.pop();
1338
1338
  edges.pop();
1339
1339
  visited.delete(srcId);
1340
1340
  }
@@ -1541,26 +1541,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
1541
1541
  return best;
1542
1542
  }
1543
1543
  function followFailingCallChain(graph, originServiceId, maxDepth) {
1544
- const path71 = [originServiceId];
1544
+ const path72 = [originServiceId];
1545
1545
  const edges = [];
1546
1546
  const visited = /* @__PURE__ */ new Set([originServiceId]);
1547
1547
  let current = originServiceId;
1548
1548
  for (let depth = 0; depth < maxDepth; depth++) {
1549
1549
  const hop = dominantFailingCall(graph, current, visited);
1550
1550
  if (!hop) break;
1551
- path71.push(hop.nextService);
1551
+ path72.push(hop.nextService);
1552
1552
  edges.push(hop.edge);
1553
1553
  visited.add(hop.nextService);
1554
1554
  current = hop.nextService;
1555
1555
  }
1556
1556
  if (edges.length === 0) return null;
1557
- return { path: path71, edges, culprit: current };
1557
+ return { path: path72, edges, culprit: current };
1558
1558
  }
1559
1559
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1560
1560
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
1561
1561
  if (!chain) return null;
1562
1562
  const culprit = chain.culprit;
1563
- const path71 = [...chain.path];
1563
+ const path72 = [...chain.path];
1564
1564
  const edgeProvenances = chain.edges.map((e) => e.provenance);
1565
1565
  const baseConfidence = confidenceFromMix(chain.edges);
1566
1566
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -1568,14 +1568,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1568
1568
  if (loc) {
1569
1569
  let rootCauseNode = culprit;
1570
1570
  if (loc.fileNode) {
1571
- path71.push(loc.fileNode);
1571
+ path72.push(loc.fileNode);
1572
1572
  edgeProvenances.push(import_types.Provenance.OBSERVED);
1573
1573
  rootCauseNode = loc.fileNode;
1574
1574
  }
1575
1575
  return import_types.RootCauseResultSchema.parse({
1576
1576
  rootCauseNode,
1577
1577
  rootCauseReason: loc.rootCauseReason,
1578
- traversalPath: path71,
1578
+ traversalPath: path72,
1579
1579
  edgeProvenances,
1580
1580
  confidence,
1581
1581
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -1587,7 +1587,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1587
1587
  return import_types.RootCauseResultSchema.parse({
1588
1588
  rootCauseNode: culprit,
1589
1589
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
1590
- traversalPath: path71,
1590
+ traversalPath: path72,
1591
1591
  edgeProvenances,
1592
1592
  confidence,
1593
1593
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -6969,7 +6969,7 @@ async function addGrpcMethods(graph, services) {
6969
6969
 
6970
6970
  // src/extract/calls/index.ts
6971
6971
  init_cjs_shims();
6972
- var import_types29 = require("@neat.is/types");
6972
+ var import_types30 = require("@neat.is/types");
6973
6973
 
6974
6974
  // src/extract/calls/http.ts
6975
6975
  init_cjs_shims();
@@ -8425,12 +8425,140 @@ function drizzleEndpointsFromFile(file, serviceDir) {
8425
8425
  return out;
8426
8426
  }
8427
8427
 
8428
+ // src/extract/calls/prisma.ts
8429
+ init_cjs_shims();
8430
+ var import_node_path39 = __toESM(require("path"), 1);
8431
+ var import_types28 = require("@neat.is/types");
8432
+ var SCALAR_TYPES = /* @__PURE__ */ new Set([
8433
+ "Int",
8434
+ "String",
8435
+ "Boolean",
8436
+ "DateTime",
8437
+ "Float",
8438
+ "Decimal",
8439
+ "BigInt",
8440
+ "Bytes",
8441
+ "Json"
8442
+ ]);
8443
+ function stripLineComment(line) {
8444
+ let inStr = false;
8445
+ for (let i = 0; i < line.length; i++) {
8446
+ const ch = line[i];
8447
+ if (ch === '"' && line[i - 1] !== "\\") inStr = !inStr;
8448
+ else if (!inStr && ch === "/" && line[i + 1] === "/") return line.slice(0, i);
8449
+ }
8450
+ return line;
8451
+ }
8452
+ function netBraces(line) {
8453
+ const s = stripLineComment(line).replace(/"(\\.|[^"\\])*"/g, "");
8454
+ let n = 0;
8455
+ for (const ch of s) {
8456
+ if (ch === "{") n++;
8457
+ else if (ch === "}") n--;
8458
+ }
8459
+ return n;
8460
+ }
8461
+ function prismaColumnsFromSchema(file, serviceDir) {
8462
+ const content = file.content;
8463
+ if (!/\bmodel\s+[A-Za-z_]\w*\s*\{/.test(content)) return [];
8464
+ const lines = content.split("\n");
8465
+ const modelNames = /* @__PURE__ */ new Set();
8466
+ const enumNames = /* @__PURE__ */ new Set();
8467
+ for (const line of lines) {
8468
+ const m = line.match(/^\s*model\s+([A-Za-z_]\w*)\s*\{/);
8469
+ if (m) modelNames.add(m[1]);
8470
+ const e = line.match(/^\s*enum\s+([A-Za-z_]\w*)\s*\{/);
8471
+ if (e) enumNames.add(e[1]);
8472
+ }
8473
+ const out = [];
8474
+ const seenTable = /* @__PURE__ */ new Set();
8475
+ const finalize = (b) => {
8476
+ if (seenTable.has(b.tableName)) return;
8477
+ seenTable.add(b.tableName);
8478
+ out.push({
8479
+ infraId: (0, import_types28.infraId)("sql-table", b.tableName),
8480
+ name: b.tableName,
8481
+ kind: "sql-table",
8482
+ edgeType: "CALLS",
8483
+ confidenceKind: "structural",
8484
+ columns: b.columns,
8485
+ evidence: {
8486
+ file: import_node_path39.default.relative(serviceDir, file.path),
8487
+ line: b.startLine,
8488
+ snippet: snippet(content, b.startLine)
8489
+ }
8490
+ });
8491
+ };
8492
+ let current = null;
8493
+ let depth = 0;
8494
+ for (let i = 0; i < lines.length; i++) {
8495
+ const raw = lines[i];
8496
+ const lineNo = i + 1;
8497
+ if (current === null) {
8498
+ const header = raw.match(/^\s*(model|enum|datasource|generator|type)\s+([A-Za-z_]\w*)\b/);
8499
+ if (header && raw.includes("{")) {
8500
+ current = {
8501
+ kind: header[1],
8502
+ tableName: header[2],
8503
+ startLine: lineNo,
8504
+ columns: [],
8505
+ seenCol: /* @__PURE__ */ new Set()
8506
+ };
8507
+ depth = netBraces(raw);
8508
+ if (depth <= 0) {
8509
+ if (current.kind === "model") finalize(current);
8510
+ current = null;
8511
+ }
8512
+ }
8513
+ continue;
8514
+ }
8515
+ depth += netBraces(raw);
8516
+ if (depth <= 0) {
8517
+ if (current.kind === "model") finalize(current);
8518
+ current = null;
8519
+ continue;
8520
+ }
8521
+ if (current.kind !== "model") continue;
8522
+ const trimmed = stripLineComment(raw).trim();
8523
+ if (!trimmed) continue;
8524
+ if (trimmed.startsWith("@@")) {
8525
+ const map = trimmed.match(/@@map\(\s*"([^"]+)"\s*\)/);
8526
+ if (map) current.tableName = map[1];
8527
+ continue;
8528
+ }
8529
+ const fm = trimmed.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)/);
8530
+ if (!fm) continue;
8531
+ const fieldName = fm[1];
8532
+ const baseType = fm[2];
8533
+ if (/@relation\b/.test(trimmed) || modelNames.has(baseType)) continue;
8534
+ if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue;
8535
+ const mapM = trimmed.match(/(?<!@)@map\(\s*"([^"]+)"\s*\)/);
8536
+ const columnName = mapM ? mapM[1] : fieldName;
8537
+ if (!current.seenCol.has(columnName)) {
8538
+ current.seenCol.add(columnName);
8539
+ current.columns.push(columnName);
8540
+ }
8541
+ }
8542
+ if (current && current.kind === "model") finalize(current);
8543
+ return out;
8544
+ }
8545
+ async function prismaColumnEndpoints(serviceDir) {
8546
+ const schemaPath = await findFirst(serviceDir, [
8547
+ import_node_path39.default.join("prisma", "schema.prisma"),
8548
+ "schema.prisma"
8549
+ ]);
8550
+ if (!schemaPath) return [];
8551
+ const content = await readIfExists(schemaPath);
8552
+ if (!content) return [];
8553
+ return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir);
8554
+ }
8555
+
8428
8556
  // src/extract/calls/go.ts
8429
8557
  init_cjs_shims();
8430
- var import_node_path41 = __toESM(require("path"), 1);
8558
+ var import_node_path42 = __toESM(require("path"), 1);
8431
8559
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
8432
8560
  var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
8433
- var import_types28 = require("@neat.is/types");
8561
+ var import_types29 = require("@neat.is/types");
8434
8562
  init_otel();
8435
8563
  var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
8436
8564
  var PARSE_CHUNK8 = 16384;
@@ -8442,7 +8570,7 @@ function walk5(node, visit) {
8442
8570
  }
8443
8571
  }
8444
8572
  function goSqlEndpointsFromFile(file, serviceDir) {
8445
- if (import_node_path41.default.extname(file.path) !== ".go") return [];
8573
+ if (import_node_path42.default.extname(file.path) !== ".go") return [];
8446
8574
  const parser = new import_tree_sitter10.default();
8447
8575
  parser.setLanguage(import_tree_sitter_go3.default);
8448
8576
  const tree = parser.parse(
@@ -8462,12 +8590,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
8462
8590
  if (!table) return;
8463
8591
  const line = node.startPosition.row + 1;
8464
8592
  out.push({
8465
- infraId: (0, import_types28.infraId)("sql-table", table),
8593
+ infraId: (0, import_types29.infraId)("sql-table", table),
8466
8594
  name: table,
8467
8595
  kind: "sql-table",
8468
8596
  edgeType: "CALLS",
8469
8597
  confidenceKind: "verified-call-site",
8470
- evidence: { file: toPosix(import_node_path41.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
8598
+ evidence: { file: toPosix(import_node_path42.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
8471
8599
  });
8472
8600
  });
8473
8601
  return out;
@@ -8477,11 +8605,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
8477
8605
  function edgeTypeFromEndpoint(ep) {
8478
8606
  switch (ep.edgeType) {
8479
8607
  case "PUBLISHES_TO":
8480
- return import_types29.EdgeType.PUBLISHES_TO;
8608
+ return import_types30.EdgeType.PUBLISHES_TO;
8481
8609
  case "CONSUMES_FROM":
8482
- return import_types29.EdgeType.CONSUMES_FROM;
8610
+ return import_types30.EdgeType.CONSUMES_FROM;
8483
8611
  default:
8484
- return import_types29.EdgeType.CALLS;
8612
+ return import_types30.EdgeType.CALLS;
8485
8613
  }
8486
8614
  }
8487
8615
  function isAwsKind(kind) {
@@ -8516,13 +8644,14 @@ async function addExternalEndpointEdges(graph, services) {
8516
8644
  }
8517
8645
  endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
8518
8646
  endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
8647
+ endpoints.push(...await prismaColumnEndpoints(service.dir));
8519
8648
  if (endpoints.length === 0) continue;
8520
8649
  const seenEdges = /* @__PURE__ */ new Set();
8521
8650
  for (const ep of endpoints) {
8522
8651
  if (!graph.hasNode(ep.infraId)) {
8523
8652
  const node = {
8524
8653
  id: ep.infraId,
8525
- type: import_types29.NodeType.InfraNode,
8654
+ type: import_types30.NodeType.InfraNode,
8526
8655
  name: ep.name,
8527
8656
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
8528
8657
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -8535,20 +8664,20 @@ async function addExternalEndpointEdges(graph, services) {
8535
8664
  }
8536
8665
  if (ep.columns && ep.columns.length > 0) {
8537
8666
  const node = graph.getNodeAttributes(ep.infraId);
8538
- if (node.type === import_types29.NodeType.InfraNode) {
8667
+ if (node.type === import_types30.NodeType.InfraNode) {
8539
8668
  graph.replaceNodeAttributes(ep.infraId, {
8540
8669
  ...node,
8541
8670
  columns: foldColumns(
8542
8671
  node.columns,
8543
8672
  ep.columns,
8544
- import_types29.Provenance.EXTRACTED,
8545
- (0, import_types29.confidenceForExtracted)(ep.confidenceKind)
8673
+ import_types30.Provenance.EXTRACTED,
8674
+ (0, import_types30.confidenceForExtracted)(ep.confidenceKind)
8546
8675
  )
8547
8676
  });
8548
8677
  }
8549
8678
  }
8550
8679
  const edgeType = edgeTypeFromEndpoint(ep);
8551
- const confidence = (0, import_types29.confidenceForExtracted)(ep.confidenceKind);
8680
+ const confidence = (0, import_types30.confidenceForExtracted)(ep.confidenceKind);
8552
8681
  const relFile = toPosix(ep.evidence.file);
8553
8682
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
8554
8683
  graph,
@@ -8558,7 +8687,7 @@ async function addExternalEndpointEdges(graph, services) {
8558
8687
  );
8559
8688
  nodesAdded += n;
8560
8689
  edgesAdded += e;
8561
- if (!(0, import_types29.passesExtractedFloor)(confidence)) {
8690
+ if (!(0, import_types30.passesExtractedFloor)(confidence)) {
8562
8691
  noteExtractedDropped({
8563
8692
  source: fileNodeId,
8564
8693
  target: ep.infraId,
@@ -8578,7 +8707,7 @@ async function addExternalEndpointEdges(graph, services) {
8578
8707
  source: fileNodeId,
8579
8708
  target: ep.infraId,
8580
8709
  type: edgeType,
8581
- provenance: import_types29.Provenance.EXTRACTED,
8710
+ provenance: import_types30.Provenance.EXTRACTED,
8582
8711
  confidence,
8583
8712
  evidence: ep.evidence
8584
8713
  };
@@ -8604,16 +8733,16 @@ init_cjs_shims();
8604
8733
 
8605
8734
  // src/extract/infra/docker-compose.ts
8606
8735
  init_cjs_shims();
8607
- var import_node_path42 = __toESM(require("path"), 1);
8608
- var import_types31 = require("@neat.is/types");
8736
+ var import_node_path43 = __toESM(require("path"), 1);
8737
+ var import_types32 = require("@neat.is/types");
8609
8738
 
8610
8739
  // src/extract/infra/shared.ts
8611
8740
  init_cjs_shims();
8612
- var import_types30 = require("@neat.is/types");
8741
+ var import_types31 = require("@neat.is/types");
8613
8742
  function makeInfraNode(kind, name, provider = "self", extras) {
8614
8743
  return {
8615
- id: (0, import_types30.infraId)(kind, name),
8616
- type: import_types30.NodeType.InfraNode,
8744
+ id: (0, import_types31.infraId)(kind, name),
8745
+ type: import_types31.NodeType.InfraNode,
8617
8746
  name,
8618
8747
  provider,
8619
8748
  kind,
@@ -8657,8 +8786,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
8657
8786
  source: anchorId,
8658
8787
  target: node.id,
8659
8788
  type: edgeType,
8660
- provenance: import_types30.Provenance.EXTRACTED,
8661
- confidence: (0, import_types30.confidenceForExtracted)("structural"),
8789
+ provenance: import_types31.Provenance.EXTRACTED,
8790
+ confidence: (0, import_types31.confidenceForExtracted)("structural"),
8662
8791
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
8663
8792
  };
8664
8793
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8675,7 +8804,7 @@ function dependsOnList(value) {
8675
8804
  }
8676
8805
  function serviceNameToServiceNode(name, services) {
8677
8806
  for (const s of services) {
8678
- if (s.node.name === name || import_node_path42.default.basename(s.dir) === name) return s.node.id;
8807
+ if (s.node.name === name || import_node_path43.default.basename(s.dir) === name) return s.node.id;
8679
8808
  }
8680
8809
  return null;
8681
8810
  }
@@ -8684,7 +8813,7 @@ async function addComposeInfra(graph, scanPath, services) {
8684
8813
  let edgesAdded = 0;
8685
8814
  let composePath = null;
8686
8815
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
8687
- const abs = import_node_path42.default.join(scanPath, name);
8816
+ const abs = import_node_path43.default.join(scanPath, name);
8688
8817
  if (await exists(abs)) {
8689
8818
  composePath = abs;
8690
8819
  break;
@@ -8697,13 +8826,13 @@ async function addComposeInfra(graph, scanPath, services) {
8697
8826
  } catch (err) {
8698
8827
  recordExtractionError(
8699
8828
  "infra docker-compose",
8700
- import_node_path42.default.relative(scanPath, composePath),
8829
+ import_node_path43.default.relative(scanPath, composePath),
8701
8830
  err
8702
8831
  );
8703
8832
  return { nodesAdded, edgesAdded };
8704
8833
  }
8705
8834
  if (!compose?.services) return { nodesAdded, edgesAdded };
8706
- const evidenceFile = import_node_path42.default.relative(scanPath, composePath).split(import_node_path42.default.sep).join("/");
8835
+ const evidenceFile = import_node_path43.default.relative(scanPath, composePath).split(import_node_path43.default.sep).join("/");
8707
8836
  const composeNameToNodeId = /* @__PURE__ */ new Map();
8708
8837
  for (const [composeName, svc] of Object.entries(compose.services)) {
8709
8838
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -8725,15 +8854,15 @@ async function addComposeInfra(graph, scanPath, services) {
8725
8854
  for (const dep of dependsOnList(svc.depends_on)) {
8726
8855
  const targetId = composeNameToNodeId.get(dep);
8727
8856
  if (!targetId) continue;
8728
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types31.EdgeType.DEPENDS_ON);
8857
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types32.EdgeType.DEPENDS_ON);
8729
8858
  if (graph.hasEdge(edgeId)) continue;
8730
8859
  const edge = {
8731
8860
  id: edgeId,
8732
8861
  source: sourceId,
8733
8862
  target: targetId,
8734
- type: import_types31.EdgeType.DEPENDS_ON,
8735
- provenance: import_types31.Provenance.EXTRACTED,
8736
- confidence: (0, import_types31.confidenceForExtracted)("structural"),
8863
+ type: import_types32.EdgeType.DEPENDS_ON,
8864
+ provenance: import_types32.Provenance.EXTRACTED,
8865
+ confidence: (0, import_types32.confidenceForExtracted)("structural"),
8737
8866
  evidence: { file: evidenceFile }
8738
8867
  };
8739
8868
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8745,9 +8874,9 @@ async function addComposeInfra(graph, scanPath, services) {
8745
8874
 
8746
8875
  // src/extract/infra/dockerfile.ts
8747
8876
  init_cjs_shims();
8748
- var import_node_path43 = __toESM(require("path"), 1);
8877
+ var import_node_path44 = __toESM(require("path"), 1);
8749
8878
  var import_node_fs18 = require("fs");
8750
- var import_types32 = require("@neat.is/types");
8879
+ var import_types33 = require("@neat.is/types");
8751
8880
  function readDockerfile(content) {
8752
8881
  let image = null;
8753
8882
  const ports = [];
@@ -8776,7 +8905,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8776
8905
  let nodesAdded = 0;
8777
8906
  let edgesAdded = 0;
8778
8907
  for (const service of services) {
8779
- const dockerfilePath = import_node_path43.default.join(service.dir, "Dockerfile");
8908
+ const dockerfilePath = import_node_path44.default.join(service.dir, "Dockerfile");
8780
8909
  if (!await exists(dockerfilePath)) continue;
8781
8910
  let content;
8782
8911
  try {
@@ -8784,7 +8913,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8784
8913
  } catch (err) {
8785
8914
  recordExtractionError(
8786
8915
  "infra dockerfile",
8787
- import_node_path43.default.relative(scanPath, dockerfilePath),
8916
+ import_node_path44.default.relative(scanPath, dockerfilePath),
8788
8917
  err
8789
8918
  );
8790
8919
  continue;
@@ -8796,8 +8925,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8796
8925
  graph.addNode(node.id, node);
8797
8926
  nodesAdded++;
8798
8927
  }
8799
- const relDockerfile = toPosix(import_node_path43.default.relative(service.dir, dockerfilePath));
8800
- const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, dockerfilePath));
8928
+ const relDockerfile = toPosix(import_node_path44.default.relative(service.dir, dockerfilePath));
8929
+ const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, dockerfilePath));
8801
8930
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
8802
8931
  graph,
8803
8932
  service.pkg.name,
@@ -8806,15 +8935,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8806
8935
  );
8807
8936
  nodesAdded += fn;
8808
8937
  edgesAdded += fe;
8809
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types32.EdgeType.RUNS_ON);
8938
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types33.EdgeType.RUNS_ON);
8810
8939
  if (!graph.hasEdge(edgeId)) {
8811
8940
  const edge = {
8812
8941
  id: edgeId,
8813
8942
  source: fileNodeId,
8814
8943
  target: node.id,
8815
- type: import_types32.EdgeType.RUNS_ON,
8816
- provenance: import_types32.Provenance.EXTRACTED,
8817
- confidence: (0, import_types32.confidenceForExtracted)("structural"),
8944
+ type: import_types33.EdgeType.RUNS_ON,
8945
+ provenance: import_types33.Provenance.EXTRACTED,
8946
+ confidence: (0, import_types33.confidenceForExtracted)("structural"),
8818
8947
  evidence: {
8819
8948
  file: evidenceFile,
8820
8949
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -8829,15 +8958,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8829
8958
  graph.addNode(portNode.id, portNode);
8830
8959
  nodesAdded++;
8831
8960
  }
8832
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types32.EdgeType.CONNECTS_TO);
8961
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types33.EdgeType.CONNECTS_TO);
8833
8962
  if (graph.hasEdge(portEdgeId)) continue;
8834
8963
  const portEdge = {
8835
8964
  id: portEdgeId,
8836
8965
  source: fileNodeId,
8837
8966
  target: portNode.id,
8838
- type: import_types32.EdgeType.CONNECTS_TO,
8839
- provenance: import_types32.Provenance.EXTRACTED,
8840
- confidence: (0, import_types32.confidenceForExtracted)("structural"),
8967
+ type: import_types33.EdgeType.CONNECTS_TO,
8968
+ provenance: import_types33.Provenance.EXTRACTED,
8969
+ confidence: (0, import_types33.confidenceForExtracted)("structural"),
8841
8970
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
8842
8971
  };
8843
8972
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -8850,8 +8979,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8850
8979
  // src/extract/infra/terraform.ts
8851
8980
  init_cjs_shims();
8852
8981
  var import_node_fs19 = require("fs");
8853
- var import_node_path44 = __toESM(require("path"), 1);
8854
- var import_types33 = require("@neat.is/types");
8982
+ var import_node_path45 = __toESM(require("path"), 1);
8983
+ var import_types34 = require("@neat.is/types");
8855
8984
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
8856
8985
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
8857
8986
  async function walkTfFiles(start, depth = 0, max = 5) {
@@ -8861,11 +8990,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
8861
8990
  for (const entry2 of entries) {
8862
8991
  if (entry2.isDirectory()) {
8863
8992
  if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
8864
- const child = import_node_path44.default.join(start, entry2.name);
8993
+ const child = import_node_path45.default.join(start, entry2.name);
8865
8994
  if (await isPythonVenvDir(child)) continue;
8866
8995
  out.push(...await walkTfFiles(child, depth + 1, max));
8867
8996
  } else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
8868
- out.push(import_node_path44.default.join(start, entry2.name));
8997
+ out.push(import_node_path45.default.join(start, entry2.name));
8869
8998
  }
8870
8999
  }
8871
9000
  return out;
@@ -8897,7 +9026,7 @@ async function addTerraformResources(graph, scanPath) {
8897
9026
  const files = await walkTfFiles(scanPath);
8898
9027
  for (const file of files) {
8899
9028
  const content = await import_node_fs19.promises.readFile(file, "utf8");
8900
- const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, file));
9029
+ const evidenceFile = toPosix(import_node_path45.default.relative(scanPath, file));
8901
9030
  const resources = [];
8902
9031
  const byKey = /* @__PURE__ */ new Map();
8903
9032
  RESOURCE_RE.lastIndex = 0;
@@ -8932,16 +9061,16 @@ async function addTerraformResources(graph, scanPath) {
8932
9061
  if (!target) continue;
8933
9062
  if (seen.has(target.nodeId)) continue;
8934
9063
  seen.add(target.nodeId);
8935
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types33.EdgeType.DEPENDS_ON);
9064
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types34.EdgeType.DEPENDS_ON);
8936
9065
  if (graph.hasEdge(edgeId)) continue;
8937
9066
  const line = lineAt2(content, resource.bodyOffset + ref.index);
8938
9067
  const edge = {
8939
9068
  id: edgeId,
8940
9069
  source: resource.nodeId,
8941
9070
  target: target.nodeId,
8942
- type: import_types33.EdgeType.DEPENDS_ON,
8943
- provenance: import_types33.Provenance.EXTRACTED,
8944
- confidence: (0, import_types33.confidenceForExtracted)("structural"),
9071
+ type: import_types34.EdgeType.DEPENDS_ON,
9072
+ provenance: import_types34.Provenance.EXTRACTED,
9073
+ confidence: (0, import_types34.confidenceForExtracted)("structural"),
8945
9074
  evidence: { file: evidenceFile, line, snippet: key }
8946
9075
  };
8947
9076
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8955,7 +9084,7 @@ async function addTerraformResources(graph, scanPath) {
8955
9084
  // src/extract/infra/k8s.ts
8956
9085
  init_cjs_shims();
8957
9086
  var import_node_fs20 = require("fs");
8958
- var import_node_path45 = __toESM(require("path"), 1);
9087
+ var import_node_path46 = __toESM(require("path"), 1);
8959
9088
  var import_yaml3 = require("yaml");
8960
9089
  var K8S_KIND_TO_INFRA_KIND = {
8961
9090
  Service: "k8s-service",
@@ -8973,11 +9102,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
8973
9102
  for (const entry2 of entries) {
8974
9103
  if (entry2.isDirectory()) {
8975
9104
  if (IGNORED_DIRS.has(entry2.name)) continue;
8976
- const child = import_node_path45.default.join(start, entry2.name);
9105
+ const child = import_node_path46.default.join(start, entry2.name);
8977
9106
  if (await isPythonVenvDir(child)) continue;
8978
9107
  out.push(...await walkYamlFiles2(child, depth + 1, max));
8979
- } else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path45.default.extname(entry2.name))) {
8980
- out.push(import_node_path45.default.join(start, entry2.name));
9108
+ } else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path46.default.extname(entry2.name))) {
9109
+ out.push(import_node_path46.default.join(start, entry2.name));
8981
9110
  }
8982
9111
  }
8983
9112
  return out;
@@ -9011,13 +9140,13 @@ async function addK8sResources(graph, scanPath) {
9011
9140
  // src/extract/infra/cloudflare.ts
9012
9141
  init_cjs_shims();
9013
9142
  var import_node_fs21 = require("fs");
9014
- var import_node_path46 = __toESM(require("path"), 1);
9143
+ var import_node_path47 = __toESM(require("path"), 1);
9015
9144
  var import_smol_toml2 = require("smol-toml");
9016
- var import_types34 = require("@neat.is/types");
9145
+ var import_types35 = require("@neat.is/types");
9017
9146
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
9018
9147
  async function readWranglerConfig(dir) {
9019
9148
  for (const filename of WRANGLER_FILENAMES) {
9020
- const abs = import_node_path46.default.join(dir, filename);
9149
+ const abs = import_node_path47.default.join(dir, filename);
9021
9150
  if (!await exists(abs)) continue;
9022
9151
  const raw = await import_node_fs21.promises.readFile(abs, "utf8");
9023
9152
  const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9061,8 +9190,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
9061
9190
  source: anchorId,
9062
9191
  target: node.id,
9063
9192
  type: edgeType,
9064
- provenance: import_types34.Provenance.EXTRACTED,
9065
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9193
+ provenance: import_types35.Provenance.EXTRACTED,
9194
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9066
9195
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
9067
9196
  };
9068
9197
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9080,11 +9209,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9080
9209
  try {
9081
9210
  read = await readWranglerConfig(service.dir);
9082
9211
  } catch (err) {
9083
- recordExtractionError("infra cloudflare", import_node_path46.default.relative(scanPath, service.dir), err);
9212
+ recordExtractionError("infra cloudflare", import_node_path47.default.relative(scanPath, service.dir), err);
9084
9213
  continue;
9085
9214
  }
9086
9215
  if (!read || !read.config.name) continue;
9087
- const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, read.relFile)));
9216
+ const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, read.relFile)));
9088
9217
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
9089
9218
  }
9090
9219
  for (const worker of discovered) {
@@ -9096,7 +9225,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9096
9225
  }
9097
9226
  let anchorId = service.node.id;
9098
9227
  if (config.main) {
9099
- const entryRelPath = toPosix(import_node_path46.default.normalize(config.main));
9228
+ const entryRelPath = toPosix(import_node_path47.default.normalize(config.main));
9100
9229
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9101
9230
  graph,
9102
9231
  service.pkg.name,
@@ -9123,15 +9252,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9123
9252
  nodesAdded++;
9124
9253
  }
9125
9254
  if (runtimeNode.id !== anchorId) {
9126
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types34.EdgeType.RUNS_ON);
9255
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types35.EdgeType.RUNS_ON);
9127
9256
  if (!graph.hasEdge(runsOnId)) {
9128
9257
  const edge = {
9129
9258
  id: runsOnId,
9130
9259
  source: anchorId,
9131
9260
  target: runtimeNode.id,
9132
- type: import_types34.EdgeType.RUNS_ON,
9133
- provenance: import_types34.Provenance.EXTRACTED,
9134
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9261
+ type: import_types35.EdgeType.RUNS_ON,
9262
+ provenance: import_types35.Provenance.EXTRACTED,
9263
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9135
9264
  evidence: {
9136
9265
  file: evidenceFile,
9137
9266
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -9145,7 +9274,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9145
9274
  const result = addResourceEdge(
9146
9275
  graph,
9147
9276
  anchorId,
9148
- import_types34.EdgeType.CONNECTS_TO,
9277
+ import_types35.EdgeType.CONNECTS_TO,
9149
9278
  "cloudflare-route",
9150
9279
  route,
9151
9280
  evidenceFile,
@@ -9169,7 +9298,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9169
9298
  const result = addResourceEdge(
9170
9299
  graph,
9171
9300
  anchorId,
9172
- import_types34.EdgeType.DEPENDS_ON,
9301
+ import_types35.EdgeType.DEPENDS_ON,
9173
9302
  group.kind,
9174
9303
  name,
9175
9304
  evidenceFile,
@@ -9183,7 +9312,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9183
9312
  const result = addResourceEdge(
9184
9313
  graph,
9185
9314
  anchorId,
9186
- import_types34.EdgeType.DEPENDS_ON,
9315
+ import_types35.EdgeType.DEPENDS_ON,
9187
9316
  "cloudflare-cron",
9188
9317
  cron,
9189
9318
  evidenceFile,
@@ -9196,7 +9325,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9196
9325
  const result = addResourceEdge(
9197
9326
  graph,
9198
9327
  anchorId,
9199
- import_types34.EdgeType.DEPENDS_ON,
9328
+ import_types35.EdgeType.DEPENDS_ON,
9200
9329
  "cloudflare-env-var",
9201
9330
  varName,
9202
9331
  evidenceFile,
@@ -9209,15 +9338,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9209
9338
  if (!svc.service) continue;
9210
9339
  const target = workerIndex.get(svc.service);
9211
9340
  if (target && target.anchorId !== anchorId) {
9212
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types34.EdgeType.CALLS);
9341
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types35.EdgeType.CALLS);
9213
9342
  if (!graph.hasEdge(edgeId)) {
9214
9343
  const edge = {
9215
9344
  id: edgeId,
9216
9345
  source: anchorId,
9217
9346
  target: target.anchorId,
9218
- type: import_types34.EdgeType.CALLS,
9219
- provenance: import_types34.Provenance.EXTRACTED,
9220
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9347
+ type: import_types35.EdgeType.CALLS,
9348
+ provenance: import_types35.Provenance.EXTRACTED,
9349
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9221
9350
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
9222
9351
  };
9223
9352
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9228,7 +9357,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9228
9357
  const result = addResourceEdge(
9229
9358
  graph,
9230
9359
  anchorId,
9231
- import_types34.EdgeType.DEPENDS_ON,
9360
+ import_types35.EdgeType.DEPENDS_ON,
9232
9361
  "cloudflare-service-binding",
9233
9362
  svc.service,
9234
9363
  evidenceFile,
@@ -9244,12 +9373,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9244
9373
  // src/extract/infra/vercel.ts
9245
9374
  init_cjs_shims();
9246
9375
  var import_node_fs22 = require("fs");
9247
- var import_node_path47 = __toESM(require("path"), 1);
9248
- var import_types35 = require("@neat.is/types");
9376
+ var import_node_path48 = __toESM(require("path"), 1);
9377
+ var import_types36 = require("@neat.is/types");
9249
9378
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
9250
9379
  async function readVercelConfig(dir) {
9251
9380
  for (const filename of VERCEL_CONFIG_FILENAMES) {
9252
- const abs = import_node_path47.default.join(dir, filename);
9381
+ const abs = import_node_path48.default.join(dir, filename);
9253
9382
  if (!await exists(abs)) continue;
9254
9383
  const raw = await import_node_fs22.promises.readFile(abs, "utf8");
9255
9384
  const config = JSON.parse(maskCommentsInSource(raw));
@@ -9258,7 +9387,7 @@ async function readVercelConfig(dir) {
9258
9387
  return null;
9259
9388
  }
9260
9389
  async function readLinkedProjectName(dir) {
9261
- const abs = import_node_path47.default.join(dir, ".vercel", "project.json");
9390
+ const abs = import_node_path48.default.join(dir, ".vercel", "project.json");
9262
9391
  if (!await exists(abs)) return void 0;
9263
9392
  const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
9264
9393
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
@@ -9276,7 +9405,7 @@ async function addVercelServices(graph, services, scanPath) {
9276
9405
  read = await readVercelConfig(service.dir);
9277
9406
  projectName = await readLinkedProjectName(service.dir);
9278
9407
  } catch (err) {
9279
- recordExtractionError("infra vercel", import_node_path47.default.relative(scanPath, service.dir), err);
9408
+ recordExtractionError("infra vercel", import_node_path48.default.relative(scanPath, service.dir), err);
9280
9409
  continue;
9281
9410
  }
9282
9411
  if (!read && !projectName) continue;
@@ -9292,7 +9421,7 @@ async function addVercelServices(graph, services, scanPath) {
9292
9421
  const anchorId = service.node.id;
9293
9422
  if (!read) continue;
9294
9423
  const { config, relFile, raw } = read;
9295
- const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
9424
+ const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
9296
9425
  const add = (edgeType, kind, name) => {
9297
9426
  if (!name) return;
9298
9427
  const result = emitPlatformResourceEdge(
@@ -9308,12 +9437,12 @@ async function addVercelServices(graph, services, scanPath) {
9308
9437
  nodesAdded += result.nodesAdded;
9309
9438
  edgesAdded += result.edgesAdded;
9310
9439
  };
9311
- add(import_types35.EdgeType.RUNS_ON, "vercel", "vercel");
9312
- for (const cron of config.crons ?? []) add(import_types35.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9313
- for (const varName of Object.keys(config.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9314
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9440
+ add(import_types36.EdgeType.RUNS_ON, "vercel", "vercel");
9441
+ for (const cron of config.crons ?? []) add(import_types36.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9442
+ for (const varName of Object.keys(config.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9443
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9315
9444
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
9316
- add(import_types35.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9445
+ add(import_types36.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9317
9446
  }
9318
9447
  }
9319
9448
  return { nodesAdded, edgesAdded };
@@ -9322,13 +9451,13 @@ async function addVercelServices(graph, services, scanPath) {
9322
9451
  // src/extract/infra/railway.ts
9323
9452
  init_cjs_shims();
9324
9453
  var import_node_fs23 = require("fs");
9325
- var import_node_path48 = __toESM(require("path"), 1);
9454
+ var import_node_path49 = __toESM(require("path"), 1);
9326
9455
  var import_smol_toml3 = require("smol-toml");
9327
- var import_types36 = require("@neat.is/types");
9456
+ var import_types37 = require("@neat.is/types");
9328
9457
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
9329
9458
  async function readRailwayConfig(dir) {
9330
9459
  for (const filename of RAILWAY_FILENAMES) {
9331
- const abs = import_node_path48.default.join(dir, filename);
9460
+ const abs = import_node_path49.default.join(dir, filename);
9332
9461
  if (!await exists(abs)) continue;
9333
9462
  const raw = await import_node_fs23.promises.readFile(abs, "utf8");
9334
9463
  const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9344,7 +9473,7 @@ async function addRailwayServices(graph, services, scanPath) {
9344
9473
  try {
9345
9474
  read = await readRailwayConfig(service.dir);
9346
9475
  } catch (err) {
9347
- recordExtractionError("infra railway", import_node_path48.default.relative(scanPath, service.dir), err);
9476
+ recordExtractionError("infra railway", import_node_path49.default.relative(scanPath, service.dir), err);
9348
9477
  continue;
9349
9478
  }
9350
9479
  if (!read) continue;
@@ -9354,7 +9483,7 @@ async function addRailwayServices(graph, services, scanPath) {
9354
9483
  }
9355
9484
  const anchorId = service.node.id;
9356
9485
  const { config, relFile, raw } = read;
9357
- const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
9486
+ const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
9358
9487
  const add = (edgeType, kind, name) => {
9359
9488
  if (!name) return;
9360
9489
  const result = emitPlatformResourceEdge(
@@ -9370,9 +9499,9 @@ async function addRailwayServices(graph, services, scanPath) {
9370
9499
  nodesAdded += result.nodesAdded;
9371
9500
  edgesAdded += result.edgesAdded;
9372
9501
  };
9373
- add(import_types36.EdgeType.RUNS_ON, "railway", "railway");
9374
- add(import_types36.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
9375
- add(import_types36.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
9502
+ add(import_types37.EdgeType.RUNS_ON, "railway", "railway");
9503
+ add(import_types37.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
9504
+ add(import_types37.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
9376
9505
  }
9377
9506
  return { nodesAdded, edgesAdded };
9378
9507
  }
@@ -9380,12 +9509,12 @@ async function addRailwayServices(graph, services, scanPath) {
9380
9509
  // src/extract/infra/supabase.ts
9381
9510
  init_cjs_shims();
9382
9511
  var import_node_fs24 = require("fs");
9383
- var import_node_path49 = __toESM(require("path"), 1);
9512
+ var import_node_path50 = __toESM(require("path"), 1);
9384
9513
  var import_smol_toml4 = require("smol-toml");
9385
- var import_types37 = require("@neat.is/types");
9514
+ var import_types38 = require("@neat.is/types");
9386
9515
  async function readSupabaseConfig(dir) {
9387
- const relFile = import_node_path49.default.join("supabase", "config.toml");
9388
- const abs = import_node_path49.default.join(dir, relFile);
9516
+ const relFile = import_node_path50.default.join("supabase", "config.toml");
9517
+ const abs = import_node_path50.default.join(dir, relFile);
9389
9518
  if (!await exists(abs)) return null;
9390
9519
  const raw = await import_node_fs24.promises.readFile(abs, "utf8");
9391
9520
  const config = (0, import_smol_toml4.parse)(raw);
@@ -9399,7 +9528,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9399
9528
  try {
9400
9529
  read = await readSupabaseConfig(service.dir);
9401
9530
  } catch (err) {
9402
- recordExtractionError("infra supabase", import_node_path49.default.relative(scanPath, service.dir), err);
9531
+ recordExtractionError("infra supabase", import_node_path50.default.relative(scanPath, service.dir), err);
9403
9532
  continue;
9404
9533
  }
9405
9534
  if (!read) continue;
@@ -9414,7 +9543,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9414
9543
  });
9415
9544
  }
9416
9545
  const anchorId = service.node.id;
9417
- const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
9546
+ const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, import_node_path50.default.join(service.dir, relFile)));
9418
9547
  const add = (edgeType, kind, name) => {
9419
9548
  if (!name) return;
9420
9549
  const result = emitPlatformResourceEdge(
@@ -9430,10 +9559,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
9430
9559
  nodesAdded += result.nodesAdded;
9431
9560
  edgesAdded += result.edgesAdded;
9432
9561
  };
9433
- add(import_types37.EdgeType.RUNS_ON, "supabase", "supabase");
9434
- for (const fn of Object.keys(config.functions ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "supabase-function", fn);
9435
- if (config.storage) add(import_types37.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
9436
- if (config.auth) add(import_types37.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
9562
+ add(import_types38.EdgeType.RUNS_ON, "supabase", "supabase");
9563
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types38.EdgeType.DEPENDS_ON, "supabase-function", fn);
9564
+ if (config.storage) add(import_types38.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
9565
+ if (config.auth) add(import_types38.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
9437
9566
  }
9438
9567
  return { nodesAdded, edgesAdded };
9439
9568
  }
@@ -9455,17 +9584,17 @@ async function addInfra(graph, scanPath, services) {
9455
9584
  }
9456
9585
 
9457
9586
  // src/extract/index.ts
9458
- var import_node_path51 = __toESM(require("path"), 1);
9587
+ var import_node_path52 = __toESM(require("path"), 1);
9459
9588
 
9460
9589
  // src/extract/retire.ts
9461
9590
  init_cjs_shims();
9462
9591
  var import_node_fs25 = require("fs");
9463
- var import_node_path50 = __toESM(require("path"), 1);
9464
- var import_types38 = require("@neat.is/types");
9592
+ var import_node_path51 = __toESM(require("path"), 1);
9593
+ var import_types39 = require("@neat.is/types");
9465
9594
  function dropOrphanedFileNodes(graph) {
9466
9595
  const orphans = [];
9467
9596
  graph.forEachNode((id, attrs) => {
9468
- if (attrs.type !== import_types38.NodeType.FileNode) return;
9597
+ if (attrs.type !== import_types39.NodeType.FileNode) return;
9469
9598
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
9470
9599
  orphans.push(id);
9471
9600
  }
@@ -9478,7 +9607,7 @@ function retireEdgesByFile(graph, file) {
9478
9607
  const toDrop = [];
9479
9608
  graph.forEachEdge((id, attrs) => {
9480
9609
  const edge = attrs;
9481
- if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
9610
+ if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
9482
9611
  if (!edge.evidence?.file) return;
9483
9612
  if (edge.evidence.file === normalized) toDrop.push(id);
9484
9613
  });
@@ -9491,14 +9620,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
9491
9620
  const bases = [scanPath, ...serviceDirs];
9492
9621
  graph.forEachEdge((id, attrs) => {
9493
9622
  const edge = attrs;
9494
- if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
9623
+ if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
9495
9624
  const evidenceFile = edge.evidence?.file;
9496
9625
  if (!evidenceFile) return;
9497
- if (import_node_path50.default.isAbsolute(evidenceFile)) {
9626
+ if (import_node_path51.default.isAbsolute(evidenceFile)) {
9498
9627
  if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
9499
9628
  return;
9500
9629
  }
9501
- const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path50.default.join(base, evidenceFile)));
9630
+ const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path51.default.join(base, evidenceFile)));
9502
9631
  if (!found) toDrop.push(id);
9503
9632
  });
9504
9633
  for (const id of toDrop) graph.dropEdge(id);
@@ -9551,7 +9680,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
9551
9680
  }
9552
9681
  const droppedEntries = drainDroppedExtracted();
9553
9682
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
9554
- const rejectedPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.errorsPath), "rejected.ndjson");
9683
+ const rejectedPath = import_node_path52.default.join(import_node_path52.default.dirname(opts.errorsPath), "rejected.ndjson");
9555
9684
  try {
9556
9685
  await writeRejectedExtracted(droppedEntries, rejectedPath);
9557
9686
  } catch (err) {
@@ -9585,39 +9714,39 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
9585
9714
 
9586
9715
  // src/divergences.ts
9587
9716
  init_cjs_shims();
9588
- var import_types39 = require("@neat.is/types");
9717
+ var import_types40 = require("@neat.is/types");
9589
9718
  function bucketKey(source, target, type) {
9590
9719
  return `${type}|${source}|${target}`;
9591
9720
  }
9592
9721
  function bucketSourceFor(graph, edge) {
9593
- if (edge.type !== import_types39.EdgeType.CONNECTS_TO) return edge.source;
9594
- const parsed = (0, import_types39.parseFileId)(edge.source);
9722
+ if (edge.type !== import_types40.EdgeType.CONNECTS_TO) return edge.source;
9723
+ const parsed = (0, import_types40.parseFileId)(edge.source);
9595
9724
  if (!parsed || !graph.hasNode(edge.target)) return edge.source;
9596
9725
  const target = graph.getNodeAttributes(edge.target);
9597
- if (target.type !== import_types39.NodeType.DatabaseNode) return edge.source;
9598
- return (0, import_types39.serviceId)(parsed.service);
9726
+ if (target.type !== import_types40.NodeType.DatabaseNode) return edge.source;
9727
+ return (0, import_types40.serviceId)(parsed.service);
9599
9728
  }
9600
9729
  function bucketEdges(graph) {
9601
9730
  const buckets2 = /* @__PURE__ */ new Map();
9602
9731
  graph.forEachEdge((id, attrs) => {
9603
9732
  const e = attrs;
9604
- const parsed = (0, import_types39.parseEdgeId)(id);
9733
+ const parsed = (0, import_types40.parseEdgeId)(id);
9605
9734
  const provenance = parsed?.provenance ?? e.provenance;
9606
9735
  const source = bucketSourceFor(graph, e);
9607
9736
  const key = bucketKey(source, e.target, e.type);
9608
9737
  const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
9609
9738
  switch (provenance) {
9610
- case import_types39.Provenance.EXTRACTED:
9739
+ case import_types40.Provenance.EXTRACTED:
9611
9740
  cur.extracted = e;
9612
9741
  break;
9613
- case import_types39.Provenance.OBSERVED:
9742
+ case import_types40.Provenance.OBSERVED:
9614
9743
  cur.observed = e;
9615
9744
  break;
9616
- case import_types39.Provenance.INFERRED:
9745
+ case import_types40.Provenance.INFERRED:
9617
9746
  cur.inferred = e;
9618
9747
  break;
9619
9748
  default:
9620
- if (e.provenance === import_types39.Provenance.STALE) cur.stale = e;
9749
+ if (e.provenance === import_types40.Provenance.STALE) cur.stale = e;
9621
9750
  }
9622
9751
  buckets2.set(key, cur);
9623
9752
  });
@@ -9626,17 +9755,17 @@ function bucketEdges(graph) {
9626
9755
  function nodeIsFrontier(graph, nodeId) {
9627
9756
  if (!graph.hasNode(nodeId)) return false;
9628
9757
  const attrs = graph.getNodeAttributes(nodeId);
9629
- return attrs.type === import_types39.NodeType.FrontierNode;
9758
+ return attrs.type === import_types40.NodeType.FrontierNode;
9630
9759
  }
9631
9760
  function nodeIsWebsocketChannel(graph, nodeId) {
9632
9761
  if (!graph.hasNode(nodeId)) return false;
9633
9762
  const attrs = graph.getNodeAttributes(nodeId);
9634
- return attrs.type === import_types39.NodeType.WebSocketChannelNode;
9763
+ return attrs.type === import_types40.NodeType.WebSocketChannelNode;
9635
9764
  }
9636
9765
  function nodeIsSymbol(graph, nodeId) {
9637
9766
  if (!graph.hasNode(nodeId)) return false;
9638
9767
  const attrs = graph.getNodeAttributes(nodeId);
9639
- return attrs.type === import_types39.NodeType.SymbolNode;
9768
+ return attrs.type === import_types40.NodeType.SymbolNode;
9640
9769
  }
9641
9770
  function clampConfidence(n) {
9642
9771
  if (!Number.isFinite(n)) return 0;
@@ -9656,14 +9785,14 @@ function gradedConfidence(edge) {
9656
9785
  return clampConfidence(confidenceForEdge(edge));
9657
9786
  }
9658
9787
  var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
9659
- import_types39.EdgeType.CALLS,
9660
- import_types39.EdgeType.CONNECTS_TO,
9661
- import_types39.EdgeType.PUBLISHES_TO,
9662
- import_types39.EdgeType.CONSUMES_FROM
9788
+ import_types40.EdgeType.CALLS,
9789
+ import_types40.EdgeType.CONNECTS_TO,
9790
+ import_types40.EdgeType.PUBLISHES_TO,
9791
+ import_types40.EdgeType.CONSUMES_FROM
9663
9792
  ]);
9664
9793
  function detectMissingDivergences(graph, bucket) {
9665
9794
  const out = [];
9666
- if (bucket.type === import_types39.EdgeType.CONTAINS) return out;
9795
+ if (bucket.type === import_types40.EdgeType.CONTAINS) return out;
9667
9796
  if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
9668
9797
  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
9669
9798
  if (!nodeIsFrontier(graph, bucket.target)) {
@@ -9705,7 +9834,7 @@ function declaredHostFor(svc) {
9705
9834
  function hasExtractedConfiguredBy(graph, svcId) {
9706
9835
  for (const edgeId of graph.outboundEdges(svcId)) {
9707
9836
  const e = graph.getEdgeAttributes(edgeId);
9708
- if (e.type === import_types39.EdgeType.CONFIGURED_BY && e.provenance === import_types39.Provenance.EXTRACTED) {
9837
+ if (e.type === import_types40.EdgeType.CONFIGURED_BY && e.provenance === import_types40.Provenance.EXTRACTED) {
9709
9838
  return true;
9710
9839
  }
9711
9840
  }
@@ -9718,10 +9847,10 @@ function detectHostMismatch(graph, svcId, svc) {
9718
9847
  const out = [];
9719
9848
  for (const edgeId of graph.outboundEdges(svcId)) {
9720
9849
  const edge = graph.getEdgeAttributes(edgeId);
9721
- if (edge.type !== import_types39.EdgeType.CONNECTS_TO) continue;
9722
- if (edge.provenance !== import_types39.Provenance.OBSERVED) continue;
9850
+ if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
9851
+ if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
9723
9852
  const target = graph.getNodeAttributes(edge.target);
9724
- if (target.type !== import_types39.NodeType.DatabaseNode) continue;
9853
+ if (target.type !== import_types40.NodeType.DatabaseNode) continue;
9725
9854
  const observedHost = target.host?.trim();
9726
9855
  if (!observedHost) continue;
9727
9856
  if (observedHost === declaredHost) continue;
@@ -9743,10 +9872,10 @@ function detectCompatDivergences(graph, svcId, svc) {
9743
9872
  const deps = svc.dependencies ?? {};
9744
9873
  for (const edgeId of graph.outboundEdges(svcId)) {
9745
9874
  const edge = graph.getEdgeAttributes(edgeId);
9746
- if (edge.type !== import_types39.EdgeType.CONNECTS_TO) continue;
9747
- if (edge.provenance !== import_types39.Provenance.OBSERVED) continue;
9875
+ if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
9876
+ if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
9748
9877
  const target = graph.getNodeAttributes(edge.target);
9749
- if (target.type !== import_types39.NodeType.DatabaseNode) continue;
9878
+ if (target.type !== import_types40.NodeType.DatabaseNode) continue;
9750
9879
  for (const pair of compatPairs()) {
9751
9880
  if (pair.engine !== target.engine) continue;
9752
9881
  const declared = deps[pair.driver];
@@ -9843,7 +9972,7 @@ function suppressHostMismatchHalves(all) {
9843
9972
  for (const d of all) {
9844
9973
  if (d.type !== "host-mismatch") continue;
9845
9974
  observedHalf.add(`${d.source}->${d.target}`);
9846
- declaredHalf.add((0, import_types39.databaseId)(d.extractedHost));
9975
+ declaredHalf.add((0, import_types40.databaseId)(d.extractedHost));
9847
9976
  }
9848
9977
  if (observedHalf.size === 0) return all;
9849
9978
  return all.filter((d) => {
@@ -9862,13 +9991,13 @@ function computeDivergences(graph, opts = {}) {
9862
9991
  }
9863
9992
  graph.forEachNode((nodeId, attrs) => {
9864
9993
  const n = attrs;
9865
- if (n.type === import_types39.NodeType.ServiceNode) {
9994
+ if (n.type === import_types40.NodeType.ServiceNode) {
9866
9995
  const svc = n;
9867
9996
  for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
9868
9997
  for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
9869
9998
  return;
9870
9999
  }
9871
- if (n.type === import_types39.NodeType.InfraNode && n.kind === "sql-table") {
10000
+ if (n.type === import_types40.NodeType.InfraNode && n.kind === "sql-table") {
9872
10001
  for (const d of detectColumnDrift(n)) all.push(d);
9873
10002
  }
9874
10003
  });
@@ -9904,7 +10033,7 @@ function computeDivergences(graph, opts = {}) {
9904
10033
  const bc = "column" in b && b.column ? b.column : "";
9905
10034
  return ac.localeCompare(bc);
9906
10035
  });
9907
- return import_types39.DivergenceResultSchema.parse({
10036
+ return import_types40.DivergenceResultSchema.parse({
9908
10037
  divergences: filtered,
9909
10038
  totalAffected: filtered.length,
9910
10039
  computedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -9914,8 +10043,8 @@ function computeDivergences(graph, opts = {}) {
9914
10043
  // src/persist.ts
9915
10044
  init_cjs_shims();
9916
10045
  var import_node_fs26 = require("fs");
9917
- var import_node_path52 = __toESM(require("path"), 1);
9918
- var import_types40 = require("@neat.is/types");
10046
+ var import_node_path53 = __toESM(require("path"), 1);
10047
+ var import_types41 = require("@neat.is/types");
9919
10048
  var SCHEMA_VERSION = 6;
9920
10049
  function migrateV1ToV2(payload) {
9921
10050
  const nodes = payload.graph.nodes;
@@ -9939,7 +10068,7 @@ function migrateV5ToV6(payload) {
9939
10068
  if (Array.isArray(nodes)) {
9940
10069
  for (const node of nodes) {
9941
10070
  const attrs = node.attributes;
9942
- if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
10071
+ if (!attrs || attrs.type !== import_types41.NodeType.InfraNode) continue;
9943
10072
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
9944
10073
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
9945
10074
  }
@@ -9952,12 +10081,12 @@ function migrateV2ToV3(payload) {
9952
10081
  for (const edge of edges) {
9953
10082
  const attrs = edge.attributes;
9954
10083
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
9955
- attrs.provenance = import_types40.Provenance.OBSERVED;
10084
+ attrs.provenance = import_types41.Provenance.OBSERVED;
9956
10085
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
9957
10086
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
9958
10087
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
9959
10088
  if (type && source && target) {
9960
- const newId = (0, import_types40.observedEdgeId)(source, target, type);
10089
+ const newId = (0, import_types41.observedEdgeId)(source, target, type);
9961
10090
  attrs.id = newId;
9962
10091
  if (edge.key) edge.key = newId;
9963
10092
  }
@@ -9966,7 +10095,7 @@ function migrateV2ToV3(payload) {
9966
10095
  return { ...payload, schemaVersion: 3 };
9967
10096
  }
9968
10097
  async function ensureDir(filePath) {
9969
- await import_node_fs26.promises.mkdir(import_node_path52.default.dirname(filePath), { recursive: true });
10098
+ await import_node_fs26.promises.mkdir(import_node_path53.default.dirname(filePath), { recursive: true });
9970
10099
  }
9971
10100
  async function saveGraphToDisk(graph, outPath) {
9972
10101
  await ensureDir(outPath);
@@ -10054,7 +10183,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
10054
10183
  // src/gitignore.ts
10055
10184
  init_cjs_shims();
10056
10185
  var import_node_fs27 = require("fs");
10057
- var import_node_path53 = __toESM(require("path"), 1);
10186
+ var import_node_path54 = __toESM(require("path"), 1);
10058
10187
  var NEAT_OUT_LINE = "neat-out/";
10059
10188
  var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
10060
10189
  function isNeatOutLine(line) {
@@ -10062,7 +10191,7 @@ function isNeatOutLine(line) {
10062
10191
  return trimmed === "neat-out/" || trimmed === "neat-out";
10063
10192
  }
10064
10193
  async function ensureNeatOutIgnored(projectDir) {
10065
- const file = import_node_path53.default.join(projectDir, ".gitignore");
10194
+ const file = import_node_path54.default.join(projectDir, ".gitignore");
10066
10195
  let existing = null;
10067
10196
  try {
10068
10197
  existing = await import_node_fs27.promises.readFile(file, "utf8");
@@ -10089,7 +10218,7 @@ ${NEAT_OUT_LINE}
10089
10218
 
10090
10219
  // src/summary.ts
10091
10220
  init_cjs_shims();
10092
- var import_types41 = require("@neat.is/types");
10221
+ var import_types42 = require("@neat.is/types");
10093
10222
  function renderOtelEnvBlock() {
10094
10223
  return [
10095
10224
  "for prod OTel routing, set these in your deploy platform's env:",
@@ -10099,19 +10228,19 @@ function renderOtelEnvBlock() {
10099
10228
  }
10100
10229
  function findIncompatServices(nodes) {
10101
10230
  return nodes.filter(
10102
- (n) => n.type === import_types41.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
10231
+ (n) => n.type === import_types42.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
10103
10232
  );
10104
10233
  }
10105
10234
  function servicesWithoutObserved(nodes, edges) {
10106
10235
  const seen = /* @__PURE__ */ new Set();
10107
10236
  for (const e of edges) {
10108
- if (e.provenance === import_types41.Provenance.OBSERVED) {
10237
+ if (e.provenance === import_types42.Provenance.OBSERVED) {
10109
10238
  seen.add(e.source);
10110
10239
  seen.add(e.target);
10111
10240
  }
10112
10241
  }
10113
10242
  return nodes.filter(
10114
- (n) => n.type === import_types41.NodeType.ServiceNode && !seen.has(n.id)
10243
+ (n) => n.type === import_types42.NodeType.ServiceNode && !seen.has(n.id)
10115
10244
  );
10116
10245
  }
10117
10246
  function formatDivergence(d) {
@@ -10186,26 +10315,26 @@ function formatIncompat(inc) {
10186
10315
  // src/watch.ts
10187
10316
  init_cjs_shims();
10188
10317
  var import_node_fs36 = __toESM(require("fs"), 1);
10189
- var import_node_path62 = __toESM(require("path"), 1);
10318
+ var import_node_path63 = __toESM(require("path"), 1);
10190
10319
  var import_chokidar = __toESM(require("chokidar"), 1);
10191
10320
 
10192
10321
  // src/api.ts
10193
10322
  init_cjs_shims();
10194
10323
  var import_fastify2 = __toESM(require("fastify"), 1);
10195
10324
  var import_cors = __toESM(require("@fastify/cors"), 1);
10196
- var import_types59 = require("@neat.is/types");
10325
+ var import_types60 = require("@neat.is/types");
10197
10326
 
10198
10327
  // src/extend/index.ts
10199
10328
  init_cjs_shims();
10200
10329
  var import_node_fs29 = require("fs");
10201
- var import_node_path55 = __toESM(require("path"), 1);
10330
+ var import_node_path56 = __toESM(require("path"), 1);
10202
10331
  var import_node_os2 = __toESM(require("os"), 1);
10203
10332
  var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
10204
10333
 
10205
10334
  // src/installers/package-manager.ts
10206
10335
  init_cjs_shims();
10207
10336
  var import_node_fs28 = require("fs");
10208
- var import_node_path54 = __toESM(require("path"), 1);
10337
+ var import_node_path55 = __toESM(require("path"), 1);
10209
10338
  var import_node_child_process = require("child_process");
10210
10339
  var LOCKFILE_PRIORITY = [
10211
10340
  { lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
@@ -10227,22 +10356,22 @@ async function exists2(p) {
10227
10356
  }
10228
10357
  }
10229
10358
  async function detectPackageManager(serviceDir) {
10230
- let dir = import_node_path54.default.resolve(serviceDir);
10359
+ let dir = import_node_path55.default.resolve(serviceDir);
10231
10360
  const stops = /* @__PURE__ */ new Set();
10232
10361
  for (let i = 0; i < 64; i++) {
10233
10362
  if (stops.has(dir)) break;
10234
10363
  stops.add(dir);
10235
10364
  for (const candidate of LOCKFILE_PRIORITY) {
10236
- const lockPath = import_node_path54.default.join(dir, candidate.lockfile);
10365
+ const lockPath = import_node_path55.default.join(dir, candidate.lockfile);
10237
10366
  if (await exists2(lockPath)) {
10238
10367
  return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
10239
10368
  }
10240
10369
  }
10241
- const parent = import_node_path54.default.dirname(dir);
10370
+ const parent = import_node_path55.default.dirname(dir);
10242
10371
  if (parent === dir) break;
10243
10372
  dir = parent;
10244
10373
  }
10245
- return { pm: "npm", cwd: import_node_path54.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
10374
+ return { pm: "npm", cwd: import_node_path55.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
10246
10375
  }
10247
10376
  async function runPackageManagerInstall(cmd) {
10248
10377
  return new Promise((resolve) => {
@@ -10291,7 +10420,7 @@ async function fileExists2(p) {
10291
10420
  }
10292
10421
  }
10293
10422
  async function readPackageJson(scanPath) {
10294
- const pkgPath = import_node_path55.default.join(scanPath, "package.json");
10423
+ const pkgPath = import_node_path56.default.join(scanPath, "package.json");
10295
10424
  const raw = await import_node_fs29.promises.readFile(pkgPath, "utf8");
10296
10425
  return JSON.parse(raw);
10297
10426
  }
@@ -10310,11 +10439,11 @@ async function findHookFiles(scanPath) {
10310
10439
  for (const entry2 of entries) {
10311
10440
  if (entry2.isDirectory()) {
10312
10441
  if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
10313
- await walk6(import_node_path55.default.join(dir, entry2.name));
10442
+ await walk6(import_node_path56.default.join(dir, entry2.name));
10314
10443
  } else if (entry2.isFile()) {
10315
10444
  if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
10316
- const rel = import_node_path55.default.relative(scanPath, import_node_path55.default.join(dir, entry2.name));
10317
- found.push(rel.split(import_node_path55.default.sep).join("/"));
10445
+ const rel = import_node_path56.default.relative(scanPath, import_node_path56.default.join(dir, entry2.name));
10446
+ found.push(rel.split(import_node_path56.default.sep).join("/"));
10318
10447
  }
10319
10448
  }
10320
10449
  }
@@ -10325,7 +10454,7 @@ async function findHookFiles(scanPath) {
10325
10454
  async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
10326
10455
  let fallback = null;
10327
10456
  for (const file of hookFiles) {
10328
- const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(scanPath, file), "utf8");
10457
+ const content = await import_node_fs29.promises.readFile(import_node_path56.default.join(scanPath, file), "utf8");
10329
10458
  const patched = splicedContent(content, snippet2);
10330
10459
  if (patched !== null) return { file, content, patched };
10331
10460
  if (fallback === null) fallback = { file, content };
@@ -10333,11 +10462,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
10333
10462
  return { file: fallback.file, content: fallback.content, patched: null };
10334
10463
  }
10335
10464
  function extendLogPath() {
10336
- return process.env.NEAT_EXTEND_LOG ?? import_node_path55.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
10465
+ return process.env.NEAT_EXTEND_LOG ?? import_node_path56.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
10337
10466
  }
10338
10467
  async function appendExtendLog(entry2) {
10339
10468
  const logPath = extendLogPath();
10340
- await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(logPath), { recursive: true });
10469
+ await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(logPath), { recursive: true });
10341
10470
  await import_node_fs29.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
10342
10471
  }
10343
10472
  function splicedContent(fileContent, snippet2) {
@@ -10396,7 +10525,7 @@ function lookupInstrumentation(library, installedVersion) {
10396
10525
  }
10397
10526
  async function describeProjectInstrumentation(ctx) {
10398
10527
  const hookFiles = await findHookFiles(ctx.scanPath);
10399
- const envNeat = await fileExists2(import_node_path55.default.join(ctx.scanPath, ".env.neat"));
10528
+ const envNeat = await fileExists2(import_node_path56.default.join(ctx.scanPath, ".env.neat"));
10400
10529
  const registryInstrPackages = new Set(
10401
10530
  (0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
10402
10531
  );
@@ -10418,7 +10547,7 @@ async function applyExtension(ctx, args, options) {
10418
10547
  );
10419
10548
  }
10420
10549
  for (const file of hookFiles) {
10421
- const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
10550
+ const content = await import_node_fs29.promises.readFile(import_node_path56.default.join(ctx.scanPath, file), "utf8");
10422
10551
  if (content.includes(args.registration_snippet)) {
10423
10552
  return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
10424
10553
  }
@@ -10430,10 +10559,10 @@ async function applyExtension(ctx, args, options) {
10430
10559
  );
10431
10560
  }
10432
10561
  const primaryFile = primary.file;
10433
- const primaryPath = import_node_path55.default.join(ctx.scanPath, primaryFile);
10562
+ const primaryPath = import_node_path56.default.join(ctx.scanPath, primaryFile);
10434
10563
  const filesTouched = [];
10435
10564
  const depsAdded = [];
10436
- const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
10565
+ const pkgPath = import_node_path56.default.join(ctx.scanPath, "package.json");
10437
10566
  const pkg = await readPackageJson(ctx.scanPath);
10438
10567
  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
10439
10568
  pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
@@ -10472,7 +10601,7 @@ async function dryRunExtension(ctx, args) {
10472
10601
  };
10473
10602
  }
10474
10603
  for (const file of hookFiles) {
10475
- const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
10604
+ const content = await import_node_fs29.promises.readFile(import_node_path56.default.join(ctx.scanPath, file), "utf8");
10476
10605
  if (content.includes(args.registration_snippet)) {
10477
10606
  return {
10478
10607
  library: args.library,
@@ -10513,7 +10642,7 @@ async function rollbackExtension(ctx, args) {
10513
10642
  if (!match) {
10514
10643
  return { undone: false, message: "no apply found for library" };
10515
10644
  }
10516
- const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
10645
+ const pkgPath = import_node_path56.default.join(ctx.scanPath, "package.json");
10517
10646
  if (await fileExists2(pkgPath)) {
10518
10647
  const pkg = await readPackageJson(ctx.scanPath);
10519
10648
  if (pkg.dependencies?.[match.instrumentation_package]) {
@@ -10524,7 +10653,7 @@ async function rollbackExtension(ctx, args) {
10524
10653
  }
10525
10654
  const hookFiles = await findHookFiles(ctx.scanPath);
10526
10655
  for (const file of hookFiles) {
10527
- const filePath = import_node_path55.default.join(ctx.scanPath, file);
10656
+ const filePath = import_node_path56.default.join(ctx.scanPath, file);
10528
10657
  const content = await import_node_fs29.promises.readFile(filePath, "utf8");
10529
10658
  if (content.includes(match.registration_snippet)) {
10530
10659
  const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
@@ -10662,23 +10791,23 @@ function canonicalJson(value) {
10662
10791
 
10663
10792
  // src/projects.ts
10664
10793
  init_cjs_shims();
10665
- var import_node_path56 = __toESM(require("path"), 1);
10794
+ var import_node_path57 = __toESM(require("path"), 1);
10666
10795
  function pathsForProject(project, baseDir) {
10667
10796
  if (project === DEFAULT_PROJECT) {
10668
10797
  return {
10669
- snapshotPath: import_node_path56.default.join(baseDir, "graph.json"),
10670
- errorsPath: import_node_path56.default.join(baseDir, "errors.ndjson"),
10671
- staleEventsPath: import_node_path56.default.join(baseDir, "stale-events.ndjson"),
10672
- embeddingsCachePath: import_node_path56.default.join(baseDir, "embeddings.json"),
10673
- policyViolationsPath: import_node_path56.default.join(baseDir, "policy-violations.ndjson")
10798
+ snapshotPath: import_node_path57.default.join(baseDir, "graph.json"),
10799
+ errorsPath: import_node_path57.default.join(baseDir, "errors.ndjson"),
10800
+ staleEventsPath: import_node_path57.default.join(baseDir, "stale-events.ndjson"),
10801
+ embeddingsCachePath: import_node_path57.default.join(baseDir, "embeddings.json"),
10802
+ policyViolationsPath: import_node_path57.default.join(baseDir, "policy-violations.ndjson")
10674
10803
  };
10675
10804
  }
10676
10805
  return {
10677
- snapshotPath: import_node_path56.default.join(baseDir, `${project}.json`),
10678
- errorsPath: import_node_path56.default.join(baseDir, `errors.${project}.ndjson`),
10679
- staleEventsPath: import_node_path56.default.join(baseDir, `stale-events.${project}.ndjson`),
10680
- embeddingsCachePath: import_node_path56.default.join(baseDir, `embeddings.${project}.json`),
10681
- policyViolationsPath: import_node_path56.default.join(baseDir, `policy-violations.${project}.ndjson`)
10806
+ snapshotPath: import_node_path57.default.join(baseDir, `${project}.json`),
10807
+ errorsPath: import_node_path57.default.join(baseDir, `errors.${project}.ndjson`),
10808
+ staleEventsPath: import_node_path57.default.join(baseDir, `stale-events.${project}.ndjson`),
10809
+ embeddingsCachePath: import_node_path57.default.join(baseDir, `embeddings.${project}.json`),
10810
+ policyViolationsPath: import_node_path57.default.join(baseDir, `policy-violations.${project}.ndjson`)
10682
10811
  };
10683
10812
  }
10684
10813
  var Projects = class {
@@ -10716,26 +10845,26 @@ var Projects = class {
10716
10845
  init_cjs_shims();
10717
10846
  var import_node_fs31 = require("fs");
10718
10847
  var import_node_os3 = __toESM(require("os"), 1);
10719
- var import_node_path57 = __toESM(require("path"), 1);
10720
- var import_types42 = require("@neat.is/types");
10848
+ var import_node_path58 = __toESM(require("path"), 1);
10849
+ var import_types43 = require("@neat.is/types");
10721
10850
  var LOCK_TIMEOUT_MS = 5e3;
10722
10851
  var LOCK_RETRY_MS = 50;
10723
10852
  function neatHome() {
10724
10853
  const override = process.env.NEAT_HOME;
10725
- if (override && override.length > 0) return import_node_path57.default.resolve(override);
10726
- return import_node_path57.default.join(import_node_os3.default.homedir(), ".neat");
10854
+ if (override && override.length > 0) return import_node_path58.default.resolve(override);
10855
+ return import_node_path58.default.join(import_node_os3.default.homedir(), ".neat");
10727
10856
  }
10728
10857
  function registryPath() {
10729
- return import_node_path57.default.join(neatHome(), "projects.json");
10858
+ return import_node_path58.default.join(neatHome(), "projects.json");
10730
10859
  }
10731
10860
  function registryLockPath() {
10732
- return import_node_path57.default.join(neatHome(), "projects.json.lock");
10861
+ return import_node_path58.default.join(neatHome(), "projects.json.lock");
10733
10862
  }
10734
10863
  function daemonPidPath() {
10735
- return import_node_path57.default.join(neatHome(), "neatd.pid");
10864
+ return import_node_path58.default.join(neatHome(), "neatd.pid");
10736
10865
  }
10737
10866
  function daemonsDir() {
10738
- return import_node_path57.default.join(neatHome(), "daemons");
10867
+ return import_node_path58.default.join(neatHome(), "daemons");
10739
10868
  }
10740
10869
  function isFiniteInt(v) {
10741
10870
  return typeof v === "number" && Number.isFinite(v);
@@ -10776,7 +10905,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
10776
10905
  const out = [];
10777
10906
  for (const name of names) {
10778
10907
  if (!name.endsWith(".json")) continue;
10779
- const file = import_node_path57.default.join(dir, name);
10908
+ const file = import_node_path58.default.join(dir, name);
10780
10909
  let raw;
10781
10910
  try {
10782
10911
  raw = await import_node_fs31.promises.readFile(file, "utf8");
@@ -10897,7 +11026,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
10897
11026
  }
10898
11027
  }
10899
11028
  async function normalizeProjectPath(input) {
10900
- const resolved = import_node_path57.default.resolve(input);
11029
+ const resolved = import_node_path58.default.resolve(input);
10901
11030
  try {
10902
11031
  return await import_node_fs31.promises.realpath(resolved);
10903
11032
  } catch {
@@ -10905,7 +11034,7 @@ async function normalizeProjectPath(input) {
10905
11034
  }
10906
11035
  }
10907
11036
  async function writeAtomically(target, contents) {
10908
- await import_node_fs31.promises.mkdir(import_node_path57.default.dirname(target), { recursive: true });
11037
+ await import_node_fs31.promises.mkdir(import_node_path58.default.dirname(target), { recursive: true });
10909
11038
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
10910
11039
  const fd = await import_node_fs31.promises.open(tmp, "w");
10911
11040
  try {
@@ -10918,7 +11047,7 @@ async function writeAtomically(target, contents) {
10918
11047
  }
10919
11048
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
10920
11049
  const deadline = Date.now() + timeoutMs;
10921
- await import_node_fs31.promises.mkdir(import_node_path57.default.dirname(lockPath), { recursive: true });
11050
+ await import_node_fs31.promises.mkdir(import_node_path58.default.dirname(lockPath), { recursive: true });
10922
11051
  let probedHolder = false;
10923
11052
  while (true) {
10924
11053
  try {
@@ -10971,10 +11100,10 @@ async function readRegistry() {
10971
11100
  throw err;
10972
11101
  }
10973
11102
  const parsed = JSON.parse(raw);
10974
- return import_types42.RegistryFileSchema.parse(parsed);
11103
+ return import_types43.RegistryFileSchema.parse(parsed);
10975
11104
  }
10976
11105
  async function writeRegistry(reg) {
10977
- const validated = import_types42.RegistryFileSchema.parse(reg);
11106
+ const validated = import_types43.RegistryFileSchema.parse(reg);
10978
11107
  await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
10979
11108
  }
10980
11109
  var ProjectNameCollisionError = class extends Error {
@@ -11160,7 +11289,7 @@ init_auth();
11160
11289
  // src/connectors-config.ts
11161
11290
  init_cjs_shims();
11162
11291
  var import_node_os4 = __toESM(require("os"), 1);
11163
- var import_node_path58 = __toESM(require("path"), 1);
11292
+ var import_node_path59 = __toESM(require("path"), 1);
11164
11293
  var import_node_fs32 = require("fs");
11165
11294
  var CONNECTORS_CONFIG_VERSION = 1;
11166
11295
  var EnvRefUnsetError = class extends Error {
@@ -11175,11 +11304,11 @@ var EnvRefUnsetError = class extends Error {
11175
11304
  };
11176
11305
  function neatHome2() {
11177
11306
  const override = process.env.NEAT_HOME;
11178
- if (override && override.length > 0) return import_node_path58.default.resolve(override);
11179
- return import_node_path58.default.join(import_node_os4.default.homedir(), ".neat");
11307
+ if (override && override.length > 0) return import_node_path59.default.resolve(override);
11308
+ return import_node_path59.default.join(import_node_os4.default.homedir(), ".neat");
11180
11309
  }
11181
11310
  function connectorsConfigPath(home = neatHome2()) {
11182
- return import_node_path58.default.join(home, "connectors.json");
11311
+ return import_node_path59.default.join(home, "connectors.json");
11183
11312
  }
11184
11313
  var MODE_MASK_LOOSER_THAN_0600 = 63;
11185
11314
  async function warnIfModeLooserThan0600(file) {
@@ -11310,7 +11439,7 @@ function connectorMatchesProject(entry2, project) {
11310
11439
  var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
11311
11440
  var CONNECTORS_LOCK_RETRY_MS = 50;
11312
11441
  function connectorsConfigLockPath(home = neatHome2()) {
11313
- return import_node_path58.default.join(home, "connectors.json.lock");
11442
+ return import_node_path59.default.join(home, "connectors.json.lock");
11314
11443
  }
11315
11444
  function isEnvRef(value) {
11316
11445
  return value.length > 1 && value.startsWith("$");
@@ -11323,7 +11452,7 @@ function redactCredentialRef(ref) {
11323
11452
  return out;
11324
11453
  }
11325
11454
  async function writeConfigAtomically0600(file, contents) {
11326
- await import_node_fs32.promises.mkdir(import_node_path58.default.dirname(file), { recursive: true });
11455
+ await import_node_fs32.promises.mkdir(import_node_path59.default.dirname(file), { recursive: true });
11327
11456
  const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
11328
11457
  const fd = await import_node_fs32.promises.open(tmp, "w", 384);
11329
11458
  try {
@@ -11337,7 +11466,7 @@ async function writeConfigAtomically0600(file, contents) {
11337
11466
  }
11338
11467
  async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
11339
11468
  const deadline = Date.now() + timeoutMs;
11340
- await import_node_fs32.promises.mkdir(import_node_path58.default.dirname(lockPath), { recursive: true });
11469
+ await import_node_fs32.promises.mkdir(import_node_path59.default.dirname(lockPath), { recursive: true });
11341
11470
  for (; ; ) {
11342
11471
  try {
11343
11472
  const fd = await import_node_fs32.promises.open(lockPath, "wx");
@@ -11487,15 +11616,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
11487
11616
 
11488
11617
  // src/connectors/index.ts
11489
11618
  init_cjs_shims();
11490
- var import_types43 = require("@neat.is/types");
11619
+ var import_types44 = require("@neat.is/types");
11491
11620
  var NO_ENV = "unknown";
11492
11621
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
11493
11622
  if (!graph.hasNode(targetNodeId)) return void 0;
11494
11623
  const sites = [];
11495
11624
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
11496
11625
  const edge = graph.getEdgeAttributes(edgeId);
11497
- if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
11498
- const parsed = (0, import_types43.parseFileId)(edge.source);
11626
+ if (edge.provenance !== import_types44.Provenance.EXTRACTED) continue;
11627
+ const parsed = (0, import_types44.parseFileId)(edge.source);
11499
11628
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
11500
11629
  const site = { relPath: edge.evidence.file };
11501
11630
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -11506,7 +11635,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
11506
11635
  function routeCallSiteFor(graph, targetNodeId) {
11507
11636
  if (!graph.hasNode(targetNodeId)) return void 0;
11508
11637
  const attrs = graph.getNodeAttributes(targetNodeId);
11509
- if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
11638
+ if (attrs.type !== import_types44.NodeType.RouteNode || !attrs.path) return void 0;
11510
11639
  const site = { relPath: attrs.path };
11511
11640
  if (attrs.line !== void 0) site.line = attrs.line;
11512
11641
  return site;
@@ -11983,10 +12112,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
11983
12112
  // src/connectors/supabase/map.ts
11984
12113
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
11985
12114
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
11986
- function targetFromRestPath(path71) {
11987
- const rpcMatch = REST_RPC_PATH_RE.exec(path71);
12115
+ function targetFromRestPath(path72) {
12116
+ const rpcMatch = REST_RPC_PATH_RE.exec(path72);
11988
12117
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
11989
- const tableMatch = REST_TABLE_PATH_RE.exec(path71);
12118
+ const tableMatch = REST_TABLE_PATH_RE.exec(path72);
11990
12119
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
11991
12120
  return null;
11992
12121
  }
@@ -12097,23 +12226,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
12097
12226
 
12098
12227
  // src/connectors/supabase/resolve.ts
12099
12228
  init_cjs_shims();
12100
- var import_types45 = require("@neat.is/types");
12229
+ var import_types46 = require("@neat.is/types");
12101
12230
  function createSupabaseResolveTarget(graph, config) {
12102
12231
  return (signal, _ctx) => {
12103
12232
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
12104
12233
  return null;
12105
12234
  }
12106
- const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
12235
+ const subResourceId = (0, import_types46.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
12107
12236
  if (graph.hasNode(subResourceId)) {
12108
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
12237
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types46.EdgeType.CALLS };
12109
12238
  }
12110
- const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
12239
+ const bareResourceId = (0, import_types46.infraId)(signal.targetKind, signal.targetName);
12111
12240
  if (graph.hasNode(bareResourceId)) {
12112
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
12241
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types46.EdgeType.CALLS };
12113
12242
  }
12114
- const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
12243
+ const projectLevelId = (0, import_types46.infraId)("supabase", config.nodeRef);
12115
12244
  if (graph.hasNode(projectLevelId)) {
12116
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
12245
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types46.EdgeType.CALLS };
12117
12246
  }
12118
12247
  return null;
12119
12248
  };
@@ -12206,7 +12335,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
12206
12335
 
12207
12336
  // src/connectors/railway/index.ts
12208
12337
  init_cjs_shims();
12209
- var import_types49 = require("@neat.is/types");
12338
+ var import_types50 = require("@neat.is/types");
12210
12339
 
12211
12340
  // src/connectors/railway/client.ts
12212
12341
  init_cjs_shims();
@@ -12357,7 +12486,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
12357
12486
  const out = [];
12358
12487
  graph.forEachNode((_id, attrs) => {
12359
12488
  const node = attrs;
12360
- if (node.type !== import_types49.NodeType.RouteNode) return;
12489
+ if (node.type !== import_types50.NodeType.RouteNode) return;
12361
12490
  const route = attrs;
12362
12491
  if (route.service !== serviceName) return;
12363
12492
  out.push({
@@ -12461,12 +12590,12 @@ function createRailwayResolveTarget(config) {
12461
12590
  const serviceName = config.serviceNameById[config.serviceId];
12462
12591
  if (!serviceName) return null;
12463
12592
  if (signal.targetKind === ROUTE_TARGET_KIND) {
12464
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
12593
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types50.EdgeType.CALLS };
12465
12594
  }
12466
12595
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
12467
12596
  const peerName = config.serviceNameById[signal.targetName];
12468
12597
  if (!peerName) return null;
12469
- return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
12598
+ return { targetNodeId: (0, import_types50.serviceId)(peerName), serviceName, edgeType: import_types50.EdgeType.CONNECTS_TO };
12470
12599
  }
12471
12600
  return null;
12472
12601
  };
@@ -12590,9 +12719,9 @@ function parseFirebaseTargetName(targetName) {
12590
12719
  const secondSep = rest.indexOf(FIELD_SEP);
12591
12720
  if (secondSep === -1) return null;
12592
12721
  const method = rest.slice(0, secondSep);
12593
- const path71 = rest.slice(secondSep + 1);
12594
- if (!resourceName || !method || !path71) return null;
12595
- return { resourceName, method, path: path71 };
12722
+ const path72 = rest.slice(secondSep + 1);
12723
+ if (!resourceName || !method || !path72) return null;
12724
+ return { resourceName, method, path: path72 };
12596
12725
  }
12597
12726
  function resourceNameFor(type, labels) {
12598
12727
  if (!labels) return null;
@@ -12630,14 +12759,14 @@ function mapLogEntryToSignal(entry2) {
12630
12759
  if (!req) return null;
12631
12760
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
12632
12761
  const method = req.requestMethod.toUpperCase();
12633
- const path71 = pathFromRequestUrl(req.requestUrl);
12634
- if (path71 === null) return null;
12762
+ const path72 = pathFromRequestUrl(req.requestUrl);
12763
+ if (path72 === null) return null;
12635
12764
  const timestamp = entry2.timestamp;
12636
12765
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
12637
12766
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
12638
12767
  return {
12639
12768
  targetKind: resourceType,
12640
- targetName: packFirebaseTargetName({ resourceName, method, path: path71 }),
12769
+ targetName: packFirebaseTargetName({ resourceName, method, path: path72 }),
12641
12770
  callCount: 1,
12642
12771
  errorCount: isError ? 1 : 0,
12643
12772
  lastObservedIso: timestamp
@@ -12654,7 +12783,7 @@ function mapLogEntriesToSignals(entries) {
12654
12783
 
12655
12784
  // src/connectors/firebase/resolve.ts
12656
12785
  init_cjs_shims();
12657
- var import_types50 = require("@neat.is/types");
12786
+ var import_types51 = require("@neat.is/types");
12658
12787
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
12659
12788
  switch (resourceType) {
12660
12789
  case "cloud_function":
@@ -12669,7 +12798,7 @@ function routeEntriesFor(graph, serviceName) {
12669
12798
  const entries = [];
12670
12799
  graph.forEachNode((_id, attrs) => {
12671
12800
  const node = attrs;
12672
- if (node.type !== import_types50.NodeType.RouteNode) return;
12801
+ if (node.type !== import_types51.NodeType.RouteNode) return;
12673
12802
  const route = attrs;
12674
12803
  if (route.service !== serviceName) return;
12675
12804
  entries.push({
@@ -12701,7 +12830,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
12701
12830
  return {
12702
12831
  targetNodeId: match.routeNodeId,
12703
12832
  serviceName,
12704
- edgeType: import_types50.EdgeType.CALLS
12833
+ edgeType: import_types51.EdgeType.CALLS
12705
12834
  };
12706
12835
  };
12707
12836
  }
@@ -12728,7 +12857,7 @@ init_cjs_shims();
12728
12857
 
12729
12858
  // src/connectors/cloudflare/connector.ts
12730
12859
  init_cjs_shims();
12731
- var import_types52 = require("@neat.is/types");
12860
+ var import_types53 = require("@neat.is/types");
12732
12861
 
12733
12862
  // src/connectors/cloudflare/client.ts
12734
12863
  init_cjs_shims();
@@ -12844,7 +12973,7 @@ function mapEventToSignal(event) {
12844
12973
  if (Number.isNaN(observedAt.getTime())) return null;
12845
12974
  const statusCode = metadata?.statusCode;
12846
12975
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
12847
- const path71 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12976
+ const path72 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12848
12977
  return {
12849
12978
  targetKind: CLOUDFLARE_TARGET_KIND,
12850
12979
  targetName: scriptName,
@@ -12852,7 +12981,7 @@ function mapEventToSignal(event) {
12852
12981
  errorCount: isError ? 1 : 0,
12853
12982
  lastObservedIso: observedAt.toISOString(),
12854
12983
  method,
12855
- ...path71 ? { path: path71 } : {},
12984
+ ...path72 ? { path: path72 } : {},
12856
12985
  ...typeof statusCode === "number" ? { statusCode } : {},
12857
12986
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
12858
12987
  };
@@ -12892,19 +13021,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
12892
13021
  graph.forEachNode((id, attrs) => {
12893
13022
  if (found) return;
12894
13023
  const a = attrs;
12895
- if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
13024
+ if (a.type === import_types53.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
12896
13025
  found = id;
12897
13026
  }
12898
13027
  });
12899
13028
  return found;
12900
13029
  }
12901
- function findMatchingRouteNode(graph, serviceName, method, path71) {
12902
- const normalizedPath = normalizePathTemplate(path71);
13030
+ function findMatchingRouteNode(graph, serviceName, method, path72) {
13031
+ const normalizedPath = normalizePathTemplate(path72);
12903
13032
  let found = null;
12904
13033
  graph.forEachNode((id, attrs) => {
12905
13034
  if (found) return;
12906
13035
  const a = attrs;
12907
- if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
13036
+ if (a.type !== import_types53.NodeType.RouteNode || a.service !== serviceName) return;
12908
13037
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
12909
13038
  const routeMethod = (a.method ?? "").toUpperCase();
12910
13039
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -12916,18 +13045,18 @@ function createCloudflareResolveTarget(config, graph) {
12916
13045
  return (signal) => {
12917
13046
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
12918
13047
  const scriptName = signal.targetName;
12919
- const { method, path: path71 } = signal;
13048
+ const { method, path: path72 } = signal;
12920
13049
  const resolveRouteGrain = (serviceName, wholeFileId) => {
12921
- if (!method || !path71) return wholeFileId;
12922
- return findMatchingRouteNode(graph, serviceName, method, path71) ?? wholeFileId;
13050
+ if (!method || !path72) return wholeFileId;
13051
+ return findMatchingRouteNode(graph, serviceName, method, path72) ?? wholeFileId;
12923
13052
  };
12924
13053
  const mapping = config.workers?.[scriptName];
12925
13054
  if (mapping) {
12926
- const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
13055
+ const wholeFileId = (0, import_types53.fileId)(mapping.service, mapping.entryFile);
12927
13056
  return {
12928
13057
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
12929
13058
  serviceName: mapping.service,
12930
- edgeType: import_types52.EdgeType.CALLS
13059
+ edgeType: import_types53.EdgeType.CALLS
12931
13060
  };
12932
13061
  }
12933
13062
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -12936,13 +13065,13 @@ function createCloudflareResolveTarget(config, graph) {
12936
13065
  return {
12937
13066
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
12938
13067
  serviceName: fileNode.service,
12939
- edgeType: import_types52.EdgeType.CALLS
13068
+ edgeType: import_types53.EdgeType.CALLS
12940
13069
  };
12941
13070
  }
12942
13071
  return {
12943
- targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
13072
+ targetNodeId: (0, import_types53.infraId)("cloudflare-worker", scriptName),
12944
13073
  serviceName: scriptName,
12945
- edgeType: import_types52.EdgeType.CALLS,
13074
+ edgeType: import_types53.EdgeType.CALLS,
12946
13075
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
12947
13076
  };
12948
13077
  };
@@ -13138,14 +13267,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
13138
13267
 
13139
13268
  // src/connectors/neon/resolve.ts
13140
13269
  init_cjs_shims();
13141
- var import_types56 = require("@neat.is/types");
13270
+ var import_types57 = require("@neat.is/types");
13142
13271
  function createNeonResolveTarget(config) {
13143
13272
  return (signal) => {
13144
13273
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
13145
13274
  return {
13146
- targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
13275
+ targetNodeId: (0, import_types57.infraId)("sql-table", signal.targetName),
13147
13276
  serviceName: config.serviceName,
13148
- edgeType: import_types56.EdgeType.CALLS,
13277
+ edgeType: import_types57.EdgeType.CALLS,
13149
13278
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
13150
13279
  };
13151
13280
  };
@@ -13788,11 +13917,11 @@ function registerRoutes(scope, ctx) {
13788
13917
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
13789
13918
  const parsed = [];
13790
13919
  for (const c of candidates) {
13791
- const r = import_types59.DivergenceTypeSchema.safeParse(c);
13920
+ const r = import_types60.DivergenceTypeSchema.safeParse(c);
13792
13921
  if (!r.success) {
13793
13922
  return reply.code(400).send({
13794
13923
  error: `unknown divergence type "${c}"`,
13795
- allowed: import_types59.DivergenceTypeSchema.options
13924
+ allowed: import_types60.DivergenceTypeSchema.options
13796
13925
  });
13797
13926
  }
13798
13927
  parsed.push(r.data);
@@ -14101,7 +14230,7 @@ function registerRoutes(scope, ctx) {
14101
14230
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
14102
14231
  let violations = await log.readAll();
14103
14232
  if (req.query.severity) {
14104
- const sev = import_types59.PolicySeveritySchema.safeParse(req.query.severity);
14233
+ const sev = import_types60.PolicySeveritySchema.safeParse(req.query.severity);
14105
14234
  if (!sev.success) {
14106
14235
  return reply.code(400).send({
14107
14236
  error: "invalid severity",
@@ -14140,7 +14269,7 @@ function registerRoutes(scope, ctx) {
14140
14269
  scope.post("/policies/check", async (req, reply) => {
14141
14270
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
14142
14271
  if (!proj) return;
14143
- const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req.body ?? {});
14272
+ const parsed = import_types60.PoliciesCheckBodySchema.safeParse(req.body ?? {});
14144
14273
  if (!parsed.success) {
14145
14274
  return reply.code(400).send({
14146
14275
  error: "invalid /policies/check body",
@@ -14462,7 +14591,7 @@ init_otel();
14462
14591
  // src/daemon.ts
14463
14592
  init_cjs_shims();
14464
14593
  var import_node_fs34 = require("fs");
14465
- var import_node_path60 = __toESM(require("path"), 1);
14594
+ var import_node_path61 = __toESM(require("path"), 1);
14466
14595
  var import_node_module = require("module");
14467
14596
  init_otel();
14468
14597
  init_auth();
@@ -14470,28 +14599,28 @@ init_auth();
14470
14599
  // src/unrouted.ts
14471
14600
  init_cjs_shims();
14472
14601
  var import_node_fs33 = require("fs");
14473
- var import_node_path59 = __toESM(require("path"), 1);
14602
+ var import_node_path60 = __toESM(require("path"), 1);
14474
14603
 
14475
14604
  // src/daemon.ts
14476
- var import_types60 = require("@neat.is/types");
14605
+ var import_types61 = require("@neat.is/types");
14477
14606
  function daemonJsonPath(scanPath) {
14478
- return import_node_path60.default.join(scanPath, "neat-out", "daemon.json");
14607
+ return import_node_path61.default.join(scanPath, "neat-out", "daemon.json");
14479
14608
  }
14480
14609
  function daemonsDiscoveryDir(home) {
14481
14610
  const base = home && home.length > 0 ? home : neatHomeFromEnv();
14482
- return import_node_path60.default.join(base, "daemons");
14611
+ return import_node_path61.default.join(base, "daemons");
14483
14612
  }
14484
14613
  function daemonDiscoveryPath(project, home) {
14485
- return import_node_path60.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
14614
+ return import_node_path61.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
14486
14615
  }
14487
14616
  function sanitizeDiscoveryName(project) {
14488
14617
  return project.replace(/[^A-Za-z0-9._-]/g, "_");
14489
14618
  }
14490
14619
  function neatHomeFromEnv() {
14491
14620
  const env = process.env.NEAT_HOME;
14492
- if (env && env.length > 0) return import_node_path60.default.resolve(env);
14621
+ if (env && env.length > 0) return import_node_path61.default.resolve(env);
14493
14622
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
14494
- return import_node_path60.default.join(home, ".neat");
14623
+ return import_node_path61.default.join(home, ".neat");
14495
14624
  }
14496
14625
  async function readDaemonRecord(scanPath) {
14497
14626
  try {
@@ -14562,7 +14691,7 @@ init_otel_grpc();
14562
14691
  // src/search.ts
14563
14692
  init_cjs_shims();
14564
14693
  var import_node_fs35 = require("fs");
14565
- var import_node_path61 = __toESM(require("path"), 1);
14694
+ var import_node_path62 = __toESM(require("path"), 1);
14566
14695
  var import_node_crypto4 = require("crypto");
14567
14696
  var DEFAULT_LIMIT = 10;
14568
14697
  var NOMIC_DIM = 768;
@@ -14725,7 +14854,7 @@ async function readCache(cachePath) {
14725
14854
  }
14726
14855
  }
14727
14856
  async function writeCache(cachePath, cache) {
14728
- await import_node_fs35.promises.mkdir(import_node_path61.default.dirname(cachePath), { recursive: true });
14857
+ await import_node_fs35.promises.mkdir(import_node_path62.default.dirname(cachePath), { recursive: true });
14729
14858
  await import_node_fs35.promises.writeFile(cachePath, JSON.stringify(cache));
14730
14859
  }
14731
14860
  var VectorIndex = class {
@@ -14883,8 +15012,8 @@ var ALL_PHASES = [
14883
15012
  ];
14884
15013
  function classifyChange(relPath) {
14885
15014
  const phases = /* @__PURE__ */ new Set();
14886
- const base = import_node_path62.default.basename(relPath).toLowerCase();
14887
- const segments = relPath.split(import_node_path62.default.sep).map((s) => s.toLowerCase());
15015
+ const base = import_node_path63.default.basename(relPath).toLowerCase();
15016
+ const segments = relPath.split(import_node_path63.default.sep).map((s) => s.toLowerCase());
14888
15017
  if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
14889
15018
  phases.add("services");
14890
15019
  phases.add("aliases");
@@ -15012,9 +15141,9 @@ function countWatchableDirs(scanPath, limit) {
15012
15141
  for (const e of entries) {
15013
15142
  if (count >= limit) return;
15014
15143
  if (!e.isDirectory()) continue;
15015
- if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path62.default.join(dir, e.name) + import_node_path62.default.sep))) continue;
15144
+ if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path63.default.join(dir, e.name) + import_node_path63.default.sep))) continue;
15016
15145
  count++;
15017
- if (depth < 2) visit(import_node_path62.default.join(dir, e.name), depth + 1);
15146
+ if (depth < 2) visit(import_node_path63.default.join(dir, e.name), depth + 1);
15018
15147
  }
15019
15148
  };
15020
15149
  visit(scanPath, 0);
@@ -15032,8 +15161,8 @@ async function startWatch(graph, opts) {
15032
15161
  const projectName = opts.project ?? DEFAULT_PROJECT;
15033
15162
  await loadGraphFromDisk(graph, opts.outPath);
15034
15163
  const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
15035
- const policyFilePath = import_node_path62.default.join(opts.scanPath, "policy.json");
15036
- const policyViolationsPath = import_node_path62.default.join(import_node_path62.default.dirname(opts.outPath), "policy-violations.ndjson");
15164
+ const policyFilePath = import_node_path63.default.join(opts.scanPath, "policy.json");
15165
+ const policyViolationsPath = import_node_path63.default.join(import_node_path63.default.dirname(opts.outPath), "policy-violations.ndjson");
15037
15166
  let policies = [];
15038
15167
  try {
15039
15168
  policies = await loadPolicyFile(policyFilePath);
@@ -15093,7 +15222,7 @@ async function startWatch(graph, opts) {
15093
15222
  assertBindAuthority(host, auth.authToken);
15094
15223
  const port = opts.port ?? 8080;
15095
15224
  const otelPort = opts.otelPort ?? 4318;
15096
- const cachePath = opts.embeddingsCachePath ?? import_node_path62.default.join(import_node_path62.default.dirname(opts.outPath), "embeddings.json");
15225
+ const cachePath = opts.embeddingsCachePath ?? import_node_path63.default.join(import_node_path63.default.dirname(opts.outPath), "embeddings.json");
15097
15226
  let searchIndex;
15098
15227
  try {
15099
15228
  searchIndex = await buildSearchIndex(graph, { cachePath });
@@ -15111,7 +15240,7 @@ async function startWatch(graph, opts) {
15111
15240
  // Paths are derived from the explicit options the watch caller passes
15112
15241
  // — pathsForProject is only used to fill in the embeddings/snapshot
15113
15242
  // fields so the registry shape is complete.
15114
- ...pathsForProject(projectName, import_node_path62.default.dirname(opts.outPath)),
15243
+ ...pathsForProject(projectName, import_node_path63.default.dirname(opts.outPath)),
15115
15244
  snapshotPath: opts.outPath,
15116
15245
  errorsPath: opts.errorsPath,
15117
15246
  staleEventsPath: opts.staleEventsPath
@@ -15229,9 +15358,9 @@ async function startWatch(graph, opts) {
15229
15358
  };
15230
15359
  const onPath = (absPath) => {
15231
15360
  if (shouldIgnore(absPath)) return;
15232
- const rel = import_node_path62.default.relative(opts.scanPath, absPath);
15361
+ const rel = import_node_path63.default.relative(opts.scanPath, absPath);
15233
15362
  if (!rel || rel.startsWith("..")) return;
15234
- pendingPaths.add(rel.split(import_node_path62.default.sep).join("/"));
15363
+ pendingPaths.add(rel.split(import_node_path63.default.sep).join("/"));
15235
15364
  const phases = classifyChange(rel);
15236
15365
  if (phases.size === 0) {
15237
15366
  for (const p of ALL_PHASES) pending.add(p);
@@ -15289,7 +15418,7 @@ async function startWatch(graph, opts) {
15289
15418
  // src/deploy/detect.ts
15290
15419
  init_cjs_shims();
15291
15420
  var import_node_fs37 = require("fs");
15292
- var import_node_path63 = __toESM(require("path"), 1);
15421
+ var import_node_path64 = __toESM(require("path"), 1);
15293
15422
  var import_node_child_process2 = require("child_process");
15294
15423
  var import_node_crypto5 = require("crypto");
15295
15424
  function generateToken() {
@@ -15389,7 +15518,7 @@ async function runDeploy(opts = {}) {
15389
15518
  const token = generateToken();
15390
15519
  switch (substrate) {
15391
15520
  case "docker-compose": {
15392
- const artifactPath = import_node_path63.default.join(cwd, "docker-compose.neat.yml");
15521
+ const artifactPath = import_node_path64.default.join(cwd, "docker-compose.neat.yml");
15393
15522
  const contents = emitDockerCompose(cwd);
15394
15523
  await import_node_fs37.promises.writeFile(artifactPath, contents, "utf8");
15395
15524
  return {
@@ -15397,11 +15526,11 @@ async function runDeploy(opts = {}) {
15397
15526
  artifactPath,
15398
15527
  token,
15399
15528
  contents,
15400
- startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path63.default.basename(artifactPath)} up -d`
15529
+ startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path64.default.basename(artifactPath)} up -d`
15401
15530
  };
15402
15531
  }
15403
15532
  case "systemd": {
15404
- const artifactPath = import_node_path63.default.join(cwd, "neat.service");
15533
+ const artifactPath = import_node_path64.default.join(cwd, "neat.service");
15405
15534
  const contents = emitSystemdUnit(cwd);
15406
15535
  await import_node_fs37.promises.writeFile(artifactPath, contents, "utf8");
15407
15536
  return {
@@ -15437,7 +15566,7 @@ init_cjs_shims();
15437
15566
  // src/installers/javascript.ts
15438
15567
  init_cjs_shims();
15439
15568
  var import_node_fs38 = require("fs");
15440
- var import_node_path64 = __toESM(require("path"), 1);
15569
+ var import_node_path65 = __toESM(require("path"), 1);
15441
15570
  var import_semver2 = __toESM(require("semver"), 1);
15442
15571
 
15443
15572
  // src/installers/templates.ts
@@ -16104,11 +16233,11 @@ var OTEL_ENV = {
16104
16233
  value: "http://localhost:4318/projects/<project>/v1/traces"
16105
16234
  };
16106
16235
  function serviceNodeName(pkg, serviceDir) {
16107
- return pkg.name ?? import_node_path64.default.basename(serviceDir);
16236
+ return pkg.name ?? import_node_path65.default.basename(serviceDir);
16108
16237
  }
16109
16238
  function projectToken(pkg, serviceDir, project) {
16110
16239
  if (project && project.length > 0) return project;
16111
- return pkg.name ?? import_node_path64.default.basename(serviceDir);
16240
+ return pkg.name ?? import_node_path65.default.basename(serviceDir);
16112
16241
  }
16113
16242
  async function readJsonFile(p) {
16114
16243
  try {
@@ -16121,16 +16250,16 @@ async function readJsonFile(p) {
16121
16250
  async function detectRuntimeKind(pkgRoot, pkg) {
16122
16251
  const deps = allDeps(pkg);
16123
16252
  if ("react-native" in deps || "expo" in deps) return "react-native";
16124
- const appJson = await readJsonFile(import_node_path64.default.join(pkgRoot, "app.json"));
16253
+ const appJson = await readJsonFile(import_node_path65.default.join(pkgRoot, "app.json"));
16125
16254
  if (appJson && typeof appJson === "object" && "expo" in appJson) {
16126
16255
  return "react-native";
16127
16256
  }
16128
- if (await exists3(import_node_path64.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path64.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path64.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
16257
+ if (await exists3(import_node_path65.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path65.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path65.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
16129
16258
  return "browser-bundle";
16130
16259
  }
16131
- if (await exists3(import_node_path64.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
16132
- if (await exists3(import_node_path64.default.join(pkgRoot, "bun.lockb"))) return "bun";
16133
- if (await exists3(import_node_path64.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path64.default.join(pkgRoot, "deno.lock"))) {
16260
+ if (await exists3(import_node_path65.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
16261
+ if (await exists3(import_node_path65.default.join(pkgRoot, "bun.lockb"))) return "bun";
16262
+ if (await exists3(import_node_path65.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path65.default.join(pkgRoot, "deno.lock"))) {
16134
16263
  return "deno";
16135
16264
  }
16136
16265
  const engines = pkg.engines ?? {};
@@ -16139,7 +16268,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
16139
16268
  }
16140
16269
  async function readPackageJson2(serviceDir) {
16141
16270
  try {
16142
- const raw = await import_node_fs38.promises.readFile(import_node_path64.default.join(serviceDir, "package.json"), "utf8");
16271
+ const raw = await import_node_fs38.promises.readFile(import_node_path65.default.join(serviceDir, "package.json"), "utf8");
16143
16272
  return JSON.parse(raw);
16144
16273
  } catch {
16145
16274
  return null;
@@ -16183,7 +16312,7 @@ function needsVersionUpgrade(installed, expected) {
16183
16312
  var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
16184
16313
  async function findNextConfig(serviceDir) {
16185
16314
  for (const name of NEXT_CONFIG_CANDIDATES) {
16186
- const candidate = import_node_path64.default.join(serviceDir, name);
16315
+ const candidate = import_node_path65.default.join(serviceDir, name);
16187
16316
  if (await exists3(candidate)) return candidate;
16188
16317
  }
16189
16318
  return null;
@@ -16252,7 +16381,7 @@ function hasRemixDependency(pkg) {
16252
16381
  }
16253
16382
  async function findRemixEntry(serviceDir) {
16254
16383
  for (const rel of REMIX_ENTRY_CANDIDATES) {
16255
- const candidate = import_node_path64.default.join(serviceDir, rel);
16384
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16256
16385
  if (await exists3(candidate)) return candidate;
16257
16386
  }
16258
16387
  return null;
@@ -16264,14 +16393,14 @@ function hasSvelteKitDependency(pkg) {
16264
16393
  }
16265
16394
  async function findSvelteKitHooks(serviceDir) {
16266
16395
  for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
16267
- const candidate = import_node_path64.default.join(serviceDir, rel);
16396
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16268
16397
  if (await exists3(candidate)) return candidate;
16269
16398
  }
16270
16399
  return null;
16271
16400
  }
16272
16401
  async function findSvelteKitConfig(serviceDir) {
16273
16402
  for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
16274
- const candidate = import_node_path64.default.join(serviceDir, rel);
16403
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16275
16404
  if (await exists3(candidate)) return candidate;
16276
16405
  }
16277
16406
  return null;
@@ -16282,7 +16411,7 @@ function hasNuxtDependency(pkg) {
16282
16411
  }
16283
16412
  async function findNuxtConfig(serviceDir) {
16284
16413
  for (const name of NUXT_CONFIG_CANDIDATES) {
16285
- const candidate = import_node_path64.default.join(serviceDir, name);
16414
+ const candidate = import_node_path65.default.join(serviceDir, name);
16286
16415
  if (await exists3(candidate)) return candidate;
16287
16416
  }
16288
16417
  return null;
@@ -16293,7 +16422,7 @@ function hasAstroDependency(pkg) {
16293
16422
  }
16294
16423
  async function findAstroConfig(serviceDir) {
16295
16424
  for (const name of ASTRO_CONFIG_CANDIDATES) {
16296
- const candidate = import_node_path64.default.join(serviceDir, name);
16425
+ const candidate = import_node_path65.default.join(serviceDir, name);
16297
16426
  if (await exists3(candidate)) return candidate;
16298
16427
  }
16299
16428
  return null;
@@ -16307,7 +16436,7 @@ function parseNextMajor(range) {
16307
16436
  return Number.isFinite(n) ? n : null;
16308
16437
  }
16309
16438
  async function isTypeScriptProject(serviceDir) {
16310
- return exists3(import_node_path64.default.join(serviceDir, "tsconfig.json"));
16439
+ return exists3(import_node_path65.default.join(serviceDir, "tsconfig.json"));
16311
16440
  }
16312
16441
  var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
16313
16442
  var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
@@ -16356,7 +16485,7 @@ function entryFromScript(script) {
16356
16485
  }
16357
16486
  async function resolveEntry(serviceDir, pkg) {
16358
16487
  if (typeof pkg.main === "string" && pkg.main.length > 0) {
16359
- const candidate = import_node_path64.default.resolve(serviceDir, pkg.main);
16488
+ const candidate = import_node_path65.default.resolve(serviceDir, pkg.main);
16360
16489
  if (await exists3(candidate)) return candidate;
16361
16490
  }
16362
16491
  if (pkg.bin) {
@@ -16370,40 +16499,40 @@ async function resolveEntry(serviceDir, pkg) {
16370
16499
  if (typeof first === "string") binEntry = first;
16371
16500
  }
16372
16501
  if (binEntry) {
16373
- const candidate = import_node_path64.default.resolve(serviceDir, binEntry);
16502
+ const candidate = import_node_path65.default.resolve(serviceDir, binEntry);
16374
16503
  if (await exists3(candidate)) return candidate;
16375
16504
  }
16376
16505
  }
16377
16506
  const startEntry = entryFromScript(pkg.scripts?.start);
16378
16507
  if (startEntry) {
16379
- const candidate = import_node_path64.default.resolve(serviceDir, startEntry);
16508
+ const candidate = import_node_path65.default.resolve(serviceDir, startEntry);
16380
16509
  if (await exists3(candidate)) return candidate;
16381
16510
  }
16382
16511
  const devEntry = entryFromScript(pkg.scripts?.dev);
16383
16512
  if (devEntry) {
16384
- const candidate = import_node_path64.default.resolve(serviceDir, devEntry);
16513
+ const candidate = import_node_path65.default.resolve(serviceDir, devEntry);
16385
16514
  if (await exists3(candidate)) return candidate;
16386
16515
  }
16387
16516
  for (const rel of SRC_INDEX_CANDIDATES) {
16388
- const candidate = import_node_path64.default.join(serviceDir, rel);
16517
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16389
16518
  if (await exists3(candidate)) return candidate;
16390
16519
  }
16391
16520
  for (const rel of SRC_NAMED_CANDIDATES) {
16392
- const candidate = import_node_path64.default.join(serviceDir, rel);
16521
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16393
16522
  if (await exists3(candidate)) return candidate;
16394
16523
  }
16395
16524
  for (const rel of ROOT_NAMED_CANDIDATES) {
16396
- const candidate = import_node_path64.default.join(serviceDir, rel);
16525
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16397
16526
  if (await exists3(candidate)) return candidate;
16398
16527
  }
16399
16528
  for (const name of INDEX_CANDIDATES) {
16400
- const candidate = import_node_path64.default.join(serviceDir, name);
16529
+ const candidate = import_node_path65.default.join(serviceDir, name);
16401
16530
  if (await exists3(candidate)) return candidate;
16402
16531
  }
16403
16532
  return null;
16404
16533
  }
16405
16534
  function dispatchEntry(entryFile, pkg) {
16406
- const ext = import_node_path64.default.extname(entryFile).toLowerCase();
16535
+ const ext = import_node_path65.default.extname(entryFile).toLowerCase();
16407
16536
  if (ext === ".ts" || ext === ".tsx") return pkg.type === "module" ? "ts" : "ts-cjs";
16408
16537
  if (ext === ".mjs") return "esm";
16409
16538
  if (ext === ".cjs") return "cjs";
@@ -16421,9 +16550,9 @@ function otelInitContents(flavor) {
16421
16550
  return OTEL_INIT_CJS;
16422
16551
  }
16423
16552
  function injectionLine(flavor, entryFile, otelInitFile) {
16424
- let rel = import_node_path64.default.relative(import_node_path64.default.dirname(entryFile), otelInitFile);
16553
+ let rel = import_node_path65.default.relative(import_node_path65.default.dirname(entryFile), otelInitFile);
16425
16554
  if (!rel.startsWith(".")) rel = `./${rel}`;
16426
- rel = rel.split(import_node_path64.default.sep).join("/");
16555
+ rel = rel.split(import_node_path65.default.sep).join("/");
16427
16556
  if (flavor === "cjs") return `require('${rel}')`;
16428
16557
  if (flavor === "esm") return `import '${rel}'`;
16429
16558
  const tsRel = rel.replace(/\.ts$/, "");
@@ -16436,27 +16565,27 @@ function lineIsOtelInjection(line) {
16436
16565
  }
16437
16566
  async function detectsSrcLayout(serviceDir) {
16438
16567
  const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
16439
- exists3(import_node_path64.default.join(serviceDir, "src", "app")),
16440
- exists3(import_node_path64.default.join(serviceDir, "src", "pages")),
16441
- exists3(import_node_path64.default.join(serviceDir, "app")),
16442
- exists3(import_node_path64.default.join(serviceDir, "pages"))
16568
+ exists3(import_node_path65.default.join(serviceDir, "src", "app")),
16569
+ exists3(import_node_path65.default.join(serviceDir, "src", "pages")),
16570
+ exists3(import_node_path65.default.join(serviceDir, "app")),
16571
+ exists3(import_node_path65.default.join(serviceDir, "pages"))
16443
16572
  ]);
16444
16573
  return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
16445
16574
  }
16446
16575
  async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
16447
16576
  const useTs = await isTypeScriptProject(serviceDir);
16448
16577
  const srcLayout = await detectsSrcLayout(serviceDir);
16449
- const baseDir = srcLayout ? import_node_path64.default.join(serviceDir, "src") : serviceDir;
16450
- const instrumentationFile = import_node_path64.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
16451
- const instrumentationNodeFile = import_node_path64.default.join(
16578
+ const baseDir = srcLayout ? import_node_path65.default.join(serviceDir, "src") : serviceDir;
16579
+ const instrumentationFile = import_node_path65.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
16580
+ const instrumentationNodeFile = import_node_path65.default.join(
16452
16581
  baseDir,
16453
16582
  useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
16454
16583
  );
16455
- const instrumentationEdgeFile = import_node_path64.default.join(
16584
+ const instrumentationEdgeFile = import_node_path65.default.join(
16456
16585
  baseDir,
16457
16586
  useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
16458
16587
  );
16459
- const envNeatFile = import_node_path64.default.join(baseDir, ".env.neat");
16588
+ const envNeatFile = import_node_path65.default.join(baseDir, ".env.neat");
16460
16589
  const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
16461
16590
  const dependencyEdits = [];
16462
16591
  for (const sdk of SDK_PACKAGES) {
@@ -16581,7 +16710,7 @@ function buildDependencyEdits(pkg, manifestPath) {
16581
16710
  return edits;
16582
16711
  }
16583
16712
  async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
16584
- const envNeatFile = import_node_path64.default.join(serviceDir, ".env.neat");
16713
+ const envNeatFile = import_node_path65.default.join(serviceDir, ".env.neat");
16585
16714
  if (!await exists3(envNeatFile)) {
16586
16715
  generatedFiles.push({
16587
16716
  file: envNeatFile,
@@ -16616,7 +16745,7 @@ function fileImportsOtelHook(raw, specifiers) {
16616
16745
  }
16617
16746
  async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
16618
16747
  const useTs = await isTypeScriptProject(serviceDir);
16619
- const otelServerFile = import_node_path64.default.join(
16748
+ const otelServerFile = import_node_path65.default.join(
16620
16749
  serviceDir,
16621
16750
  useTs ? "app/otel.server.ts" : "app/otel.server.js"
16622
16751
  );
@@ -16673,11 +16802,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
16673
16802
  }
16674
16803
  async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
16675
16804
  const useTs = await isTypeScriptProject(serviceDir);
16676
- const otelInitFile = import_node_path64.default.join(
16805
+ const otelInitFile = import_node_path65.default.join(
16677
16806
  serviceDir,
16678
16807
  useTs ? "src/otel-init.ts" : "src/otel-init.js"
16679
16808
  );
16680
- const resolvedHooksFile = hooksFile ?? import_node_path64.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
16809
+ const resolvedHooksFile = hooksFile ?? import_node_path65.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
16681
16810
  const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
16682
16811
  const generatedFiles = [];
16683
16812
  const entrypointEdits = [];
@@ -16739,11 +16868,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
16739
16868
  }
16740
16869
  async function planNuxt(serviceDir, pkg, manifestPath, project) {
16741
16870
  const useTs = await isTypeScriptProject(serviceDir);
16742
- const otelPluginFile = import_node_path64.default.join(
16871
+ const otelPluginFile = import_node_path65.default.join(
16743
16872
  serviceDir,
16744
16873
  useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
16745
16874
  );
16746
- const otelInitFile = import_node_path64.default.join(
16875
+ const otelInitFile = import_node_path65.default.join(
16747
16876
  serviceDir,
16748
16877
  useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
16749
16878
  );
@@ -16794,19 +16923,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
16794
16923
  var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
16795
16924
  async function findAstroMiddleware(serviceDir) {
16796
16925
  for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
16797
- const candidate = import_node_path64.default.join(serviceDir, rel);
16926
+ const candidate = import_node_path65.default.join(serviceDir, rel);
16798
16927
  if (await exists3(candidate)) return candidate;
16799
16928
  }
16800
16929
  return null;
16801
16930
  }
16802
16931
  async function planAstro(serviceDir, pkg, manifestPath, project) {
16803
16932
  const useTs = await isTypeScriptProject(serviceDir);
16804
- const otelInitFile = import_node_path64.default.join(
16933
+ const otelInitFile = import_node_path65.default.join(
16805
16934
  serviceDir,
16806
16935
  useTs ? "src/otel-init.ts" : "src/otel-init.js"
16807
16936
  );
16808
16937
  const existingMiddleware = await findAstroMiddleware(serviceDir);
16809
- const middlewareFile = existingMiddleware ?? import_node_path64.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
16938
+ const middlewareFile = existingMiddleware ?? import_node_path65.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
16810
16939
  const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
16811
16940
  const generatedFiles = [];
16812
16941
  const entrypointEdits = [];
@@ -16902,7 +17031,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
16902
17031
  }
16903
17032
  async function plan(serviceDir, opts) {
16904
17033
  const pkg = await readPackageJson2(serviceDir);
16905
- const manifestPath = import_node_path64.default.join(serviceDir, "package.json");
17034
+ const manifestPath = import_node_path65.default.join(serviceDir, "package.json");
16906
17035
  const project = opts?.project;
16907
17036
  const empty = {
16908
17037
  language: "javascript",
@@ -16937,8 +17066,8 @@ async function plan(serviceDir, opts) {
16937
17066
  return { ...empty, libOnly: true };
16938
17067
  }
16939
17068
  const flavor = dispatchEntry(entryFile, pkg);
16940
- const otelInitFile = import_node_path64.default.join(import_node_path64.default.dirname(entryFile), otelInitFilename(flavor));
16941
- const envNeatFile = import_node_path64.default.join(serviceDir, ".env.neat");
17069
+ const otelInitFile = import_node_path65.default.join(import_node_path65.default.dirname(entryFile), otelInitFilename(flavor));
17070
+ const envNeatFile = import_node_path65.default.join(serviceDir, ".env.neat");
16942
17071
  const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
16943
17072
  const dependencyEdits = [];
16944
17073
  for (const sdk of SDK_PACKAGES) {
@@ -17007,13 +17136,13 @@ async function plan(serviceDir, opts) {
17007
17136
  };
17008
17137
  }
17009
17138
  function isAllowedWritePath(serviceDir, target) {
17010
- const rel = import_node_path64.default.relative(serviceDir, target);
17139
+ const rel = import_node_path65.default.relative(serviceDir, target);
17011
17140
  if (rel.startsWith("..")) return false;
17012
- const base = import_node_path64.default.basename(target);
17141
+ const base = import_node_path65.default.basename(target);
17013
17142
  if (base === "package.json") return true;
17014
17143
  if (base === ".env.neat") return true;
17015
17144
  if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
17016
- const relPosix = rel.split(import_node_path64.default.sep).join("/");
17145
+ const relPosix = rel.split(import_node_path65.default.sep).join("/");
17017
17146
  if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
17018
17147
  if (relPosix === base) return true;
17019
17148
  if (relPosix === `src/${base}`) return true;
@@ -17030,7 +17159,7 @@ function isAllowedWritePath(serviceDir, target) {
17030
17159
  return false;
17031
17160
  }
17032
17161
  async function writeAtomic(file, contents) {
17033
- await import_node_fs38.promises.mkdir(import_node_path64.default.dirname(file), { recursive: true });
17162
+ await import_node_fs38.promises.mkdir(import_node_path65.default.dirname(file), { recursive: true });
17034
17163
  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
17035
17164
  await import_node_fs38.promises.writeFile(tmp, contents, "utf8");
17036
17165
  await import_node_fs38.promises.rename(tmp, file);
@@ -17214,7 +17343,7 @@ async function rollback(installPlan, originals, createdFiles) {
17214
17343
  ...removed.map((f) => `removed: ${f}`),
17215
17344
  ""
17216
17345
  ];
17217
- const rollbackPath = import_node_path64.default.join(installPlan.serviceDir, "neat-rollback.patch");
17346
+ const rollbackPath = import_node_path65.default.join(installPlan.serviceDir, "neat-rollback.patch");
17218
17347
  await import_node_fs38.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
17219
17348
  }
17220
17349
  function injectInstrumentationHook(raw) {
@@ -17245,7 +17374,7 @@ var javascriptInstaller = {
17245
17374
  // src/installers/python.ts
17246
17375
  init_cjs_shims();
17247
17376
  var import_node_fs39 = require("fs");
17248
- var import_node_path65 = __toESM(require("path"), 1);
17377
+ var import_node_path66 = __toESM(require("path"), 1);
17249
17378
  var SDK_PACKAGES2 = [
17250
17379
  { name: "opentelemetry-distro", version: ">=0.49b0" },
17251
17380
  { name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
@@ -17343,7 +17472,7 @@ async function writeFileAtomic(file, contents) {
17343
17472
  await import_node_fs39.promises.rename(tmp, file);
17344
17473
  }
17345
17474
  async function resolvePyEntrypoint(serviceDir) {
17346
- const procfile = import_node_path65.default.join(serviceDir, "Procfile");
17475
+ const procfile = import_node_path66.default.join(serviceDir, "Procfile");
17347
17476
  if (await exists4(procfile)) {
17348
17477
  const raw = await import_node_fs39.promises.readFile(procfile, "utf8");
17349
17478
  for (const line of raw.split(/\r?\n/)) {
@@ -17353,20 +17482,20 @@ async function resolvePyEntrypoint(serviceDir) {
17353
17482
  const asgi = cmd.match(/\b(?:uvicorn|gunicorn|hypercorn|daphne)\s+([\w.]+):/);
17354
17483
  if (asgi) {
17355
17484
  const modPath = asgi[1].replace(/\./g, "/");
17356
- const asFile = import_node_path65.default.join(serviceDir, `${modPath}.py`);
17485
+ const asFile = import_node_path66.default.join(serviceDir, `${modPath}.py`);
17357
17486
  if (await exists4(asFile)) return asFile;
17358
- const asPkg = import_node_path65.default.join(serviceDir, modPath, "__init__.py");
17487
+ const asPkg = import_node_path66.default.join(serviceDir, modPath, "__init__.py");
17359
17488
  if (await exists4(asPkg)) return asPkg;
17360
17489
  }
17361
17490
  const runFile = cmd.match(/\b(?:python3?|fastapi\s+(?:run|dev))\s+([\w./-]+\.py)\b/);
17362
17491
  if (runFile) {
17363
- const p = import_node_path65.default.join(serviceDir, runFile[1]);
17492
+ const p = import_node_path66.default.join(serviceDir, runFile[1]);
17364
17493
  if (await exists4(p)) return p;
17365
17494
  }
17366
17495
  }
17367
17496
  }
17368
17497
  for (const name of ["main.py", "app.py", "asgi.py", "wsgi.py", "manage.py", "server.py"]) {
17369
- const p = import_node_path65.default.join(serviceDir, name);
17498
+ const p = import_node_path66.default.join(serviceDir, name);
17370
17499
  if (await exists4(p)) return p;
17371
17500
  }
17372
17501
  return null;
@@ -17392,7 +17521,7 @@ async function exists4(p) {
17392
17521
  async function detect2(serviceDir) {
17393
17522
  const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
17394
17523
  for (const m of markers) {
17395
- if (await exists4(import_node_path65.default.join(serviceDir, m))) return true;
17524
+ if (await exists4(import_node_path66.default.join(serviceDir, m))) return true;
17396
17525
  }
17397
17526
  return false;
17398
17527
  }
@@ -17402,7 +17531,7 @@ function reqPackageName(line) {
17402
17531
  return head.replace(/[<>=!~].*$/, "").toLowerCase();
17403
17532
  }
17404
17533
  async function planRequirementsTxtEdits(serviceDir) {
17405
- const file = import_node_path65.default.join(serviceDir, "requirements.txt");
17534
+ const file = import_node_path66.default.join(serviceDir, "requirements.txt");
17406
17535
  if (!await exists4(file)) return null;
17407
17536
  const raw = await import_node_fs39.promises.readFile(file, "utf8");
17408
17537
  const presentNames = new Set(
@@ -17412,7 +17541,7 @@ async function planRequirementsTxtEdits(serviceDir) {
17412
17541
  return { manifest: file, missing: [...missing] };
17413
17542
  }
17414
17543
  async function planProcfileEdits(serviceDir) {
17415
- const procfile = import_node_path65.default.join(serviceDir, "Procfile");
17544
+ const procfile = import_node_path66.default.join(serviceDir, "Procfile");
17416
17545
  if (!await exists4(procfile)) return [];
17417
17546
  const raw = await import_node_fs39.promises.readFile(procfile, "utf8");
17418
17547
  const edits = [];
@@ -17450,7 +17579,7 @@ async function plan2(serviceDir) {
17450
17579
  }
17451
17580
  const entrypointEdits = await planProcfileEdits(serviceDir);
17452
17581
  const entryFile = await resolvePyEntrypoint(serviceDir);
17453
- const generatedFiles = entryFile ? [{ file: import_node_path65.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
17582
+ const generatedFiles = entryFile ? [{ file: import_node_path66.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
17454
17583
  if (dependencyEdits.length === 0 && entrypointEdits.length === 0 && !entryFile) {
17455
17584
  return empty;
17456
17585
  }
@@ -17518,7 +17647,7 @@ async function apply2(installPlan) {
17518
17647
  if (raw === void 0) {
17519
17648
  throw new Error(`python installer: cannot read ${file} during apply`);
17520
17649
  }
17521
- const base = import_node_path65.default.basename(file);
17650
+ const base = import_node_path66.default.basename(file);
17522
17651
  if (base === "requirements.txt") {
17523
17652
  const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
17524
17653
  if (edits.length > 0) {
@@ -17573,7 +17702,7 @@ async function rollback2(installPlan, originals, createdFiles = []) {
17573
17702
  ...removed.map((f) => `removed: ${f}`),
17574
17703
  ""
17575
17704
  ];
17576
- const rollbackPath = import_node_path65.default.join(installPlan.serviceDir, "neat-rollback.patch");
17705
+ const rollbackPath = import_node_path66.default.join(installPlan.serviceDir, "neat-rollback.patch");
17577
17706
  await import_node_fs39.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
17578
17707
  }
17579
17708
  var pythonInstaller = {
@@ -17586,7 +17715,7 @@ var pythonInstaller = {
17586
17715
  // src/installers/go.ts
17587
17716
  init_cjs_shims();
17588
17717
  var import_node_fs40 = require("fs");
17589
- var import_node_path66 = __toESM(require("path"), 1);
17718
+ var import_node_path67 = __toESM(require("path"), 1);
17590
17719
  var GO_DEPS = [
17591
17720
  { name: "go.opentelemetry.io/otel", version: "v1.38.0" },
17592
17721
  { name: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp", version: "v1.38.0" },
@@ -17596,13 +17725,13 @@ async function exists5(file) {
17596
17725
  return import_node_fs40.promises.stat(file).then(() => true, () => false);
17597
17726
  }
17598
17727
  async function findMain(serviceDir) {
17599
- const root = import_node_path66.default.join(serviceDir, "main.go");
17728
+ const root = import_node_path67.default.join(serviceDir, "main.go");
17600
17729
  if (await exists5(root)) return root;
17601
- const cmd = import_node_path66.default.join(serviceDir, "cmd");
17730
+ const cmd = import_node_path67.default.join(serviceDir, "cmd");
17602
17731
  const entries = await import_node_fs40.promises.readdir(cmd, { withFileTypes: true }).catch(() => []);
17603
17732
  for (const entry2 of entries.sort((a, b) => a.name.localeCompare(b.name))) {
17604
17733
  if (!entry2.isDirectory()) continue;
17605
- const candidate = import_node_path66.default.join(cmd, entry2.name, "main.go");
17734
+ const candidate = import_node_path67.default.join(cmd, entry2.name, "main.go");
17606
17735
  if (await exists5(candidate)) return candidate;
17607
17736
  }
17608
17737
  return null;
@@ -17677,17 +17806,17 @@ func init() {
17677
17806
  `;
17678
17807
  }
17679
17808
  async function detect3(serviceDir) {
17680
- return exists5(import_node_path66.default.join(serviceDir, "go.mod"));
17809
+ return exists5(import_node_path67.default.join(serviceDir, "go.mod"));
17681
17810
  }
17682
17811
  async function plan3(serviceDir) {
17683
- const manifest = import_node_path66.default.join(serviceDir, "go.mod");
17812
+ const manifest = import_node_path67.default.join(serviceDir, "go.mod");
17684
17813
  const raw = await import_node_fs40.promises.readFile(manifest, "utf8");
17685
17814
  const main2 = await findMain(serviceDir);
17686
17815
  const dependencyEdits = GO_DEPS.filter((dep) => !raw.includes(dep.name)).map((dep) => ({ file: manifest, kind: "add", ...dep }));
17687
17816
  if (!main2) return { language: "go", serviceDir, dependencyEdits: [], entrypointEdits: [], envEdits: [], libOnly: true };
17688
17817
  const source = await import_node_fs40.promises.readFile(main2, "utf8");
17689
17818
  const packageName = source.match(/^\s*package\s+(\w+)\s*$/m)?.[1] ?? "main";
17690
- const generated = import_node_path66.default.join(import_node_path66.default.dirname(main2), "neat_otel.go");
17819
+ const generated = import_node_path67.default.join(import_node_path67.default.dirname(main2), "neat_otel.go");
17691
17820
  const generatedFiles = await exists5(generated) ? [] : [{ file: generated, contents: neatOtelGo(packageName) }];
17692
17821
  return { language: "go", serviceDir, dependencyEdits, entrypointEdits: [], envEdits: [], generatedFiles, entryFile: main2 };
17693
17822
  }
@@ -17829,7 +17958,7 @@ init_cjs_shims();
17829
17958
  var import_node_fs41 = require("fs");
17830
17959
  var import_node_http = __toESM(require("http"), 1);
17831
17960
  var import_node_net = __toESM(require("net"), 1);
17832
- var import_node_path67 = __toESM(require("path"), 1);
17961
+ var import_node_path68 = __toESM(require("path"), 1);
17833
17962
  var import_node_url4 = require("url");
17834
17963
  var import_node_child_process3 = require("child_process");
17835
17964
  var import_node_readline = __toESM(require("readline"), 1);
@@ -17839,7 +17968,7 @@ async function extractAndPersist(opts) {
17839
17968
  const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
17840
17969
  resetGraph(graphKey);
17841
17970
  const graph = getGraph(graphKey);
17842
- const projectPaths = pathsForProject(graphKey, import_node_path67.default.join(opts.scanPath, "neat-out"));
17971
+ const projectPaths = pathsForProject(graphKey, import_node_path68.default.join(opts.scanPath, "neat-out"));
17843
17972
  const extraction = await extractFromDirectory(graph, opts.scanPath, {
17844
17973
  errorsPath: projectPaths.errorsPath
17845
17974
  });
@@ -17891,7 +18020,7 @@ async function applyInstallersOver(services, project, options = {}) {
17891
18020
  libOnly++;
17892
18021
  const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
17893
18022
  if (appDeps.length > 0) {
17894
- const svcName = import_node_path67.default.basename(svc.dir);
18023
+ const svcName = import_node_path68.default.basename(svc.dir);
17895
18024
  const list = appDeps.join(", ");
17896
18025
  console.warn(
17897
18026
  `neat: runtime layer won't engage for ${svcName}: no entry point found.
@@ -17904,7 +18033,7 @@ async function applyInstallersOver(services, project, options = {}) {
17904
18033
  console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
17905
18034
  } else if (outcome.outcome === "react-native") {
17906
18035
  reactNative++;
17907
- const svcName = import_node_path67.default.basename(svc.dir);
18036
+ const svcName = import_node_path68.default.basename(svc.dir);
17908
18037
  console.log(
17909
18038
  `neat: ${svc.dir} detected as React Native / Expo
17910
18039
  The installer doesn't cover this runtime deterministically.
@@ -17915,7 +18044,7 @@ async function applyInstallersOver(services, project, options = {}) {
17915
18044
  );
17916
18045
  } else if (outcome.outcome === "bun") {
17917
18046
  bun++;
17918
- const svcName = import_node_path67.default.basename(svc.dir);
18047
+ const svcName = import_node_path68.default.basename(svc.dir);
17919
18048
  console.log(
17920
18049
  `neat: ${svc.dir} detected as Bun
17921
18050
  The installer doesn't cover this runtime deterministically.
@@ -17926,7 +18055,7 @@ async function applyInstallersOver(services, project, options = {}) {
17926
18055
  );
17927
18056
  } else if (outcome.outcome === "deno") {
17928
18057
  deno++;
17929
- const svcName = import_node_path67.default.basename(svc.dir);
18058
+ const svcName = import_node_path68.default.basename(svc.dir);
17930
18059
  console.log(
17931
18060
  `neat: ${svc.dir} detected as Deno
17932
18061
  The installer doesn't cover this runtime deterministically.
@@ -17937,7 +18066,7 @@ async function applyInstallersOver(services, project, options = {}) {
17937
18066
  );
17938
18067
  } else if (outcome.outcome === "cloudflare-workers") {
17939
18068
  cloudflareWorkers++;
17940
- const svcName = import_node_path67.default.basename(svc.dir);
18069
+ const svcName = import_node_path68.default.basename(svc.dir);
17941
18070
  console.log(
17942
18071
  `neat: ${svc.dir} detected as Cloudflare Workers
17943
18072
  The installer doesn't cover this runtime deterministically.
@@ -17948,7 +18077,7 @@ async function applyInstallersOver(services, project, options = {}) {
17948
18077
  );
17949
18078
  } else if (outcome.outcome === "electron") {
17950
18079
  electron++;
17951
- const svcName = import_node_path67.default.basename(svc.dir);
18080
+ const svcName = import_node_path68.default.basename(svc.dir);
17952
18081
  console.log(
17953
18082
  `neat: ${svc.dir} detected as Electron
17954
18083
  The installer doesn't cover this runtime deterministically.
@@ -17961,7 +18090,7 @@ async function applyInstallersOver(services, project, options = {}) {
17961
18090
  if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
17962
18091
  const gaps = uninstrumentedLibraries(svc.pkg);
17963
18092
  if (gaps.length > 0) {
17964
- const svcName = import_node_path67.default.basename(svc.dir);
18093
+ const svcName = import_node_path68.default.basename(svc.dir);
17965
18094
  const list = gaps.join(", ");
17966
18095
  const subject = gaps.length === 1 ? "this library" : "these libraries";
17967
18096
  const aux = gaps.length === 1 ? "isn't" : "aren't";
@@ -18167,8 +18296,8 @@ async function persistedPortsFor(scanPath) {
18167
18296
  return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
18168
18297
  }
18169
18298
  async function acquireSpawnLock(scanPath) {
18170
- const lockPath = import_node_path67.default.join(scanPath, "neat-out", "daemon.spawn.lock");
18171
- await import_node_fs41.promises.mkdir(import_node_path67.default.dirname(lockPath), { recursive: true });
18299
+ const lockPath = import_node_path68.default.join(scanPath, "neat-out", "daemon.spawn.lock");
18300
+ await import_node_fs41.promises.mkdir(import_node_path68.default.dirname(lockPath), { recursive: true });
18172
18301
  const STALE_LOCK_MS = 6e4;
18173
18302
  try {
18174
18303
  const fd = await import_node_fs41.promises.open(lockPath, "wx");
@@ -18213,13 +18342,13 @@ async function healthIsForProject(restPort, project) {
18213
18342
  return false;
18214
18343
  }
18215
18344
  function daemonLogPath(projectPath3) {
18216
- return import_node_path67.default.join(projectPath3, "neat-out", "daemon.log");
18345
+ return import_node_path68.default.join(projectPath3, "neat-out", "daemon.log");
18217
18346
  }
18218
18347
  function spawnDaemonDetached(spec) {
18219
- const here = import_node_path67.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
18348
+ const here = import_node_path68.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
18220
18349
  const candidates = [
18221
- import_node_path67.default.join(here, "neatd.cjs"),
18222
- import_node_path67.default.join(here, "neatd.js")
18350
+ import_node_path68.default.join(here, "neatd.cjs"),
18351
+ import_node_path68.default.join(here, "neatd.js")
18223
18352
  ];
18224
18353
  let entry2 = null;
18225
18354
  const fsSync = require("fs");
@@ -18249,7 +18378,7 @@ function spawnDaemonDetached(spec) {
18249
18378
  let logFd = null;
18250
18379
  if (spec) {
18251
18380
  const logPath = daemonLogPath(spec.projectPath);
18252
- fsSync.mkdirSync(import_node_path67.default.dirname(logPath), { recursive: true });
18381
+ fsSync.mkdirSync(import_node_path68.default.dirname(logPath), { recursive: true });
18253
18382
  logFd = fsSync.openSync(logPath, "a");
18254
18383
  }
18255
18384
  const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
@@ -18448,7 +18577,7 @@ async function runOrchestrator(opts) {
18448
18577
  result.steps.browser = openBrowser(dashboardUrl);
18449
18578
  }
18450
18579
  const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
18451
- const daemonLog = daemonRunning ? import_node_path67.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
18580
+ const daemonLog = daemonRunning ? import_node_path68.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
18452
18581
  printSummary(result, graph, dashboardUrl, daemonLog);
18453
18582
  return result;
18454
18583
  }
@@ -18907,7 +19036,7 @@ async function runConnectorCommand(rawArgs, deps = {}) {
18907
19036
 
18908
19037
  // src/hooks-cli.ts
18909
19038
  init_cjs_shims();
18910
- var import_node_path68 = __toESM(require("path"), 1);
19039
+ var import_node_path69 = __toESM(require("path"), 1);
18911
19040
  var import_node_os5 = __toESM(require("os"), 1);
18912
19041
  var import_node_fs42 = require("fs");
18913
19042
  var import_node_url5 = require("url");
@@ -18916,14 +19045,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
18916
19045
  var GUIDE_INSTALL_NAME = "neat-graph-first.md";
18917
19046
  var HOOK_MATCHER = "Grep|Glob|Bash";
18918
19047
  function moduleDir() {
18919
- return typeof __dirname !== "undefined" ? __dirname : import_node_path68.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
19048
+ return typeof __dirname !== "undefined" ? __dirname : import_node_path69.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
18920
19049
  }
18921
19050
  async function readSkillAsset(rel) {
18922
19051
  const here = moduleDir();
18923
19052
  const candidates = [
18924
- import_node_path68.default.resolve(here, "../../claude-skill", rel),
18925
- import_node_path68.default.resolve(here, "../../../claude-skill", rel),
18926
- import_node_path68.default.resolve(here, "../claude-skill", rel)
19053
+ import_node_path69.default.resolve(here, "../../claude-skill", rel),
19054
+ import_node_path69.default.resolve(here, "../../../claude-skill", rel),
19055
+ import_node_path69.default.resolve(here, "../claude-skill", rel)
18927
19056
  ];
18928
19057
  for (const candidate of candidates) {
18929
19058
  try {
@@ -18937,17 +19066,17 @@ async function readSkillAsset(rel) {
18937
19066
  }
18938
19067
  function neatHome3() {
18939
19068
  const override = process.env.NEAT_HOME;
18940
- if (override && override.length > 0) return import_node_path68.default.resolve(override);
18941
- return import_node_path68.default.join(import_node_os5.default.homedir(), ".neat");
19069
+ if (override && override.length > 0) return import_node_path69.default.resolve(override);
19070
+ return import_node_path69.default.join(import_node_os5.default.homedir(), ".neat");
18942
19071
  }
18943
19072
  function claudeSettingsPath() {
18944
19073
  const override = process.env.NEAT_CLAUDE_SETTINGS;
18945
- if (override && override.length > 0) return import_node_path68.default.resolve(override);
19074
+ if (override && override.length > 0) return import_node_path69.default.resolve(override);
18946
19075
  const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os5.default.homedir();
18947
- return import_node_path68.default.join(home, ".claude", "settings.json");
19076
+ return import_node_path69.default.join(home, ".claude", "settings.json");
18948
19077
  }
18949
19078
  function installedHookPath() {
18950
- return import_node_path68.default.join(neatHome3(), "hooks", HOOK_FILENAME);
19079
+ return import_node_path69.default.join(neatHome3(), "hooks", HOOK_FILENAME);
18951
19080
  }
18952
19081
  function isNeatSearchEntry(entry2) {
18953
19082
  return (entry2.hooks ?? []).some(
@@ -18980,9 +19109,9 @@ async function runHooks(opts) {
18980
19109
  const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
18981
19110
  const guide = await readSkillAsset(GUIDE_FILENAME);
18982
19111
  const scriptPath = installedHookPath();
18983
- await import_node_fs42.promises.mkdir(import_node_path68.default.dirname(scriptPath), { recursive: true });
19112
+ await import_node_fs42.promises.mkdir(import_node_path69.default.dirname(scriptPath), { recursive: true });
18984
19113
  await import_node_fs42.promises.writeFile(scriptPath, hookScript, { mode: 493 });
18985
- const guidePath = import_node_path68.default.join(neatHome3(), GUIDE_INSTALL_NAME);
19114
+ const guidePath = import_node_path69.default.join(neatHome3(), GUIDE_INSTALL_NAME);
18986
19115
  await import_node_fs42.promises.writeFile(guidePath, guide, "utf8");
18987
19116
  const settingsFile = claudeSettingsPath();
18988
19117
  let settings = {};
@@ -19009,7 +19138,7 @@ async function runHooks(opts) {
19009
19138
  ...settings,
19010
19139
  hooks: { ...hooks, PreToolUse: preToolUse }
19011
19140
  };
19012
- await import_node_fs42.promises.mkdir(import_node_path68.default.dirname(settingsFile), { recursive: true });
19141
+ await import_node_fs42.promises.mkdir(import_node_path69.default.dirname(settingsFile), { recursive: true });
19013
19142
  await import_node_fs42.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
19014
19143
  console.log(`neat hooks: installed the search-nudge hook`);
19015
19144
  console.log(` script: ${scriptPath}`);
@@ -19081,11 +19210,11 @@ async function runHooksCommand(args) {
19081
19210
 
19082
19211
  // src/monitor.ts
19083
19212
  init_cjs_shims();
19084
- var import_types62 = require("@neat.is/types");
19213
+ var import_types63 = require("@neat.is/types");
19085
19214
 
19086
19215
  // src/cli-client.ts
19087
19216
  init_cjs_shims();
19088
- var import_types61 = require("@neat.is/types");
19217
+ var import_types62 = require("@neat.is/types");
19089
19218
  var HttpError = class extends Error {
19090
19219
  constructor(status2, message, responseBody = "") {
19091
19220
  super(message);
@@ -19110,10 +19239,10 @@ function createHttpClient(baseUrl, bearerToken) {
19110
19239
  const root = baseUrl.replace(/\/$/, "");
19111
19240
  const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
19112
19241
  return {
19113
- async get(path71) {
19242
+ async get(path72) {
19114
19243
  let res;
19115
19244
  try {
19116
- res = await fetch(`${root}${path71}`, {
19245
+ res = await fetch(`${root}${path72}`, {
19117
19246
  headers: { ...authHeader }
19118
19247
  });
19119
19248
  } catch (err) {
@@ -19125,16 +19254,16 @@ function createHttpClient(baseUrl, bearerToken) {
19125
19254
  const body = await res.text().catch(() => "");
19126
19255
  throw new HttpError(
19127
19256
  res.status,
19128
- `${res.status} ${res.statusText} on GET ${path71}: ${body}`,
19257
+ `${res.status} ${res.statusText} on GET ${path72}: ${body}`,
19129
19258
  body
19130
19259
  );
19131
19260
  }
19132
19261
  return await res.json();
19133
19262
  },
19134
- async post(path71, body) {
19263
+ async post(path72, body) {
19135
19264
  let res;
19136
19265
  try {
19137
- res = await fetch(`${root}${path71}`, {
19266
+ res = await fetch(`${root}${path72}`, {
19138
19267
  method: "POST",
19139
19268
  headers: { "content-type": "application/json", ...authHeader },
19140
19269
  body: JSON.stringify(body)
@@ -19148,7 +19277,7 @@ function createHttpClient(baseUrl, bearerToken) {
19148
19277
  const text = await res.text().catch(() => "");
19149
19278
  throw new HttpError(
19150
19279
  res.status,
19151
- `${res.status} ${res.statusText} on POST ${path71}: ${text}`,
19280
+ `${res.status} ${res.statusText} on POST ${path72}: ${text}`,
19152
19281
  text
19153
19282
  );
19154
19283
  }
@@ -19162,12 +19291,12 @@ function projectPath(project, suffix) {
19162
19291
  }
19163
19292
  async function runRootCause(client, input) {
19164
19293
  const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
19165
- const path71 = projectPath(
19294
+ const path72 = projectPath(
19166
19295
  input.project,
19167
19296
  `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
19168
19297
  );
19169
19298
  try {
19170
- const result = await client.get(path71);
19299
+ const result = await client.get(path72);
19171
19300
  const arrowPath = result.traversalPath.join(" \u2190 ");
19172
19301
  const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
19173
19302
  const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
@@ -19193,12 +19322,12 @@ async function runRootCause(client, input) {
19193
19322
  }
19194
19323
  async function runBlastRadius(client, input) {
19195
19324
  const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
19196
- const path71 = projectPath(
19325
+ const path72 = projectPath(
19197
19326
  input.project,
19198
19327
  `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
19199
19328
  );
19200
19329
  try {
19201
- const result = await client.get(path71);
19330
+ const result = await client.get(path72);
19202
19331
  if (result.totalAffected === 0) {
19203
19332
  return {
19204
19333
  summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
@@ -19227,17 +19356,17 @@ async function runBlastRadius(client, input) {
19227
19356
  }
19228
19357
  }
19229
19358
  function formatBlastEntry(n) {
19230
- const tag = n.edgeProvenance === import_types61.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
19359
+ const tag = n.edgeProvenance === import_types62.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
19231
19360
  return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
19232
19361
  }
19233
19362
  async function runDependencies(client, input) {
19234
19363
  const depth = input.depth ?? 3;
19235
- const path71 = projectPath(
19364
+ const path72 = projectPath(
19236
19365
  input.project,
19237
19366
  `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
19238
19367
  );
19239
19368
  try {
19240
- const result = await client.get(path71);
19369
+ const result = await client.get(path72);
19241
19370
  if (result.total === 0) {
19242
19371
  return {
19243
19372
  summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
@@ -19284,7 +19413,7 @@ async function runObservedDependencies(client, input) {
19284
19413
  if (result.observed) {
19285
19414
  return {
19286
19415
  summary: `${input.nodeId} makes no outbound runtime calls, but OTel has observed it receiving traffic on ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 it's a pure receiver.`,
19287
- provenance: import_types61.Provenance.OBSERVED
19416
+ provenance: import_types62.Provenance.OBSERVED
19288
19417
  };
19289
19418
  }
19290
19419
  const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
@@ -19294,7 +19423,7 @@ async function runObservedDependencies(client, input) {
19294
19423
  return {
19295
19424
  summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
19296
19425
  block: blockLines.join("\n"),
19297
- provenance: import_types61.Provenance.OBSERVED
19426
+ provenance: import_types62.Provenance.OBSERVED
19298
19427
  };
19299
19428
  } catch (err) {
19300
19429
  if (err instanceof HttpError && err.status === 404) {
@@ -19329,9 +19458,9 @@ function formatDuration(ms) {
19329
19458
  return `${Math.round(h / 24)}d`;
19330
19459
  }
19331
19460
  async function runIncidents(client, input) {
19332
- const path71 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
19461
+ const path72 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
19333
19462
  try {
19334
- const body = await client.get(path71);
19463
+ const body = await client.get(path72);
19335
19464
  const events = body.events;
19336
19465
  if (events.length === 0) {
19337
19466
  return {
@@ -19348,7 +19477,7 @@ async function runIncidents(client, input) {
19348
19477
  return {
19349
19478
  summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
19350
19479
  block: blockLines.join("\n"),
19351
- provenance: import_types61.Provenance.OBSERVED
19480
+ provenance: import_types62.Provenance.OBSERVED
19352
19481
  };
19353
19482
  } catch (err) {
19354
19483
  if (err instanceof HttpError && err.status === 404) {
@@ -19457,7 +19586,7 @@ async function runStaleEdges(client, input) {
19457
19586
  return {
19458
19587
  summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
19459
19588
  block: blockLines.join("\n"),
19460
- provenance: import_types61.Provenance.STALE
19589
+ provenance: import_types62.Provenance.STALE
19461
19590
  };
19462
19591
  }
19463
19592
  async function runPolicies(client, input) {
@@ -19616,10 +19745,10 @@ async function pushSnapshotToRemote(input) {
19616
19745
 
19617
19746
  // src/monitor.ts
19618
19747
  var OBSERVED_DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
19619
- import_types62.EdgeType.CALLS,
19620
- import_types62.EdgeType.CONNECTS_TO,
19621
- import_types62.EdgeType.PUBLISHES_TO,
19622
- import_types62.EdgeType.CONSUMES_FROM
19748
+ import_types63.EdgeType.CALLS,
19749
+ import_types63.EdgeType.CONNECTS_TO,
19750
+ import_types63.EdgeType.PUBLISHES_TO,
19751
+ import_types63.EdgeType.CONSUMES_FROM
19623
19752
  ]);
19624
19753
  function divergenceKey(d) {
19625
19754
  const column = "column" in d && d.column ? d.column : "";
@@ -19664,7 +19793,7 @@ function formatDivergenceLine2(d) {
19664
19793
  }
19665
19794
  }
19666
19795
  function formatStaleLine(edgeId) {
19667
- const parsed = (0, import_types62.parseEdgeId)(edgeId);
19796
+ const parsed = (0, import_types63.parseEdgeId)(edgeId);
19668
19797
  if (parsed) {
19669
19798
  return `\u22EF stale ${parsed.source} \u2192 ${parsed.target} (observed edge went quiet)`;
19670
19799
  }
@@ -19677,7 +19806,7 @@ function divergenceJson(d) {
19677
19806
  return JSON.stringify({ kind: "divergence", ...d });
19678
19807
  }
19679
19808
  function staleJson(edgeId) {
19680
- const parsed = (0, import_types62.parseEdgeId)(edgeId);
19809
+ const parsed = (0, import_types63.parseEdgeId)(edgeId);
19681
19810
  return JSON.stringify({
19682
19811
  kind: "stale",
19683
19812
  edgeId,
@@ -19729,7 +19858,7 @@ var MonitorEmitter = class {
19729
19858
  // ignores non-OBSERVED edges and non-dependency edge types (structural
19730
19859
  // ownership), so only real runtime dependencies reach stdout.
19731
19860
  emitObservedEdge(edge) {
19732
- if (edge.provenance !== import_types62.Provenance.OBSERVED) return false;
19861
+ if (edge.provenance !== import_types63.Provenance.OBSERVED) return false;
19733
19862
  if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false;
19734
19863
  const key = `edge|${edge.id}`;
19735
19864
  if (this.seen.has(key)) return false;
@@ -19844,7 +19973,7 @@ async function runMonitor(opts) {
19844
19973
  case "edge-added": {
19845
19974
  const payload = safeParse(frame.data);
19846
19975
  const edge = payload?.edge;
19847
- if (edge && edge.provenance === import_types62.Provenance.OBSERVED) {
19976
+ if (edge && edge.provenance === import_types63.Provenance.OBSERVED) {
19848
19977
  emitter.emitObservedEdge(edge);
19849
19978
  scheduleRead();
19850
19979
  }
@@ -19918,7 +20047,7 @@ function sleep(ms, signal) {
19918
20047
 
19919
20048
  // src/cli-verbs.ts
19920
20049
  init_cjs_shims();
19921
- var import_node_path69 = __toESM(require("path"), 1);
20050
+ var import_node_path70 = __toESM(require("path"), 1);
19922
20051
  async function resolveProjectEntry(opts) {
19923
20052
  const entries = await listProjects();
19924
20053
  if (opts.project) {
@@ -19928,7 +20057,7 @@ async function resolveProjectEntry(opts) {
19928
20057
  const cwd = opts.cwd ?? process.cwd();
19929
20058
  const resolvedCwd = await normalizeProjectPath(cwd);
19930
20059
  for (const entry2 of entries) {
19931
- if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path69.default.sep}`)) {
20060
+ if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path70.default.sep}`)) {
19932
20061
  return entry2;
19933
20062
  }
19934
20063
  }
@@ -20081,7 +20210,7 @@ async function runSync(opts) {
20081
20210
  }
20082
20211
 
20083
20212
  // src/cli.ts
20084
- var import_types63 = require("@neat.is/types");
20213
+ var import_types64 = require("@neat.is/types");
20085
20214
  function isNpxInvocation() {
20086
20215
  if (process.env.npm_command === "exec") return true;
20087
20216
  const execpath = process.env.npm_execpath ?? "";
@@ -20400,12 +20529,12 @@ async function runInit(opts) {
20400
20529
  printDiscoveryReport(opts, services);
20401
20530
  const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
20402
20531
  const patch = renderPatch(sections);
20403
- const patchPath = import_node_path70.default.join(opts.scanPath, "neat.patch");
20532
+ const patchPath = import_node_path71.default.join(opts.scanPath, "neat.patch");
20404
20533
  if (opts.dryRun) {
20405
20534
  await import_node_fs43.promises.writeFile(patchPath, patch, "utf8");
20406
20535
  written.push(patchPath);
20407
20536
  console.log(`dry-run: patch written to ${patchPath}`);
20408
- const gitignorePath = import_node_path70.default.join(opts.scanPath, ".gitignore");
20537
+ const gitignorePath = import_node_path71.default.join(opts.scanPath, ".gitignore");
20409
20538
  const gitignoreExists = await import_node_fs43.promises.stat(gitignorePath).then(() => true).catch(() => false);
20410
20539
  const verb = gitignoreExists ? "append" : "create";
20411
20540
  console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
@@ -20417,9 +20546,9 @@ async function runInit(opts) {
20417
20546
  const graph = getGraph(graphKey);
20418
20547
  const projectPaths = pathsForProject(
20419
20548
  graphKey,
20420
- import_node_path70.default.join(opts.scanPath, "neat-out")
20549
+ import_node_path71.default.join(opts.scanPath, "neat-out")
20421
20550
  );
20422
- const errorsPath = import_node_path70.default.join(import_node_path70.default.dirname(opts.outPath), import_node_path70.default.basename(projectPaths.errorsPath));
20551
+ const errorsPath = import_node_path71.default.join(import_node_path71.default.dirname(opts.outPath), import_node_path71.default.basename(projectPaths.errorsPath));
20423
20552
  const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
20424
20553
  await saveGraphToDisk(graph, opts.outPath);
20425
20554
  written.push(opts.outPath);
@@ -20538,9 +20667,9 @@ var CLAUDE_SKILL_CONFIG = {
20538
20667
  };
20539
20668
  function claudeConfigPath() {
20540
20669
  const override = process.env.NEAT_CLAUDE_CONFIG;
20541
- if (override && override.length > 0) return import_node_path70.default.resolve(override);
20670
+ if (override && override.length > 0) return import_node_path71.default.resolve(override);
20542
20671
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
20543
- return import_node_path70.default.join(home, ".claude.json");
20672
+ return import_node_path71.default.join(home, ".claude.json");
20544
20673
  }
20545
20674
  async function runSkill(opts) {
20546
20675
  const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
@@ -20564,7 +20693,7 @@ async function runSkill(opts) {
20564
20693
  ...existing,
20565
20694
  mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
20566
20695
  };
20567
- await import_node_fs43.promises.mkdir(import_node_path70.default.dirname(target), { recursive: true });
20696
+ await import_node_fs43.promises.mkdir(import_node_path71.default.dirname(target), { recursive: true });
20568
20697
  await import_node_fs43.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
20569
20698
  console.log(`neat skill: wrote mcpServers.neat to ${target}`);
20570
20699
  console.log("restart Claude Code to pick up the new MCP server.");
@@ -20630,12 +20759,12 @@ async function main() {
20630
20759
  console.error("neat init: --apply and --dry-run are mutually exclusive");
20631
20760
  process.exit(2);
20632
20761
  }
20633
- const scanPath = import_node_path70.default.resolve(target);
20762
+ const scanPath = import_node_path71.default.resolve(target);
20634
20763
  const projectExplicit = parsed.project !== null;
20635
- const projectName = projectExplicit ? project : import_node_path70.default.basename(scanPath);
20764
+ const projectName = projectExplicit ? project : import_node_path71.default.basename(scanPath);
20636
20765
  const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
20637
- const fallback = pathsForProject(projectKey, import_node_path70.default.join(scanPath, "neat-out")).snapshotPath;
20638
- const outPath = import_node_path70.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
20766
+ const fallback = pathsForProject(projectKey, import_node_path71.default.join(scanPath, "neat-out")).snapshotPath;
20767
+ const outPath = import_node_path71.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
20639
20768
  const result = await runInit({
20640
20769
  scanPath,
20641
20770
  outPath,
@@ -20656,21 +20785,21 @@ async function main() {
20656
20785
  usage2();
20657
20786
  process.exit(2);
20658
20787
  }
20659
- const scanPath = import_node_path70.default.resolve(target);
20788
+ const scanPath = import_node_path71.default.resolve(target);
20660
20789
  const stat = await import_node_fs43.promises.stat(scanPath).catch(() => null);
20661
20790
  if (!stat || !stat.isDirectory()) {
20662
20791
  console.error(`neat watch: ${scanPath} is not a directory`);
20663
20792
  process.exit(2);
20664
20793
  }
20665
- const projectPaths = pathsForProject(project, import_node_path70.default.join(scanPath, "neat-out"));
20666
- const outPath = import_node_path70.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
20667
- const errorsPath = import_node_path70.default.resolve(
20668
- process.env.NEAT_ERRORS_PATH ?? import_node_path70.default.join(import_node_path70.default.dirname(outPath), import_node_path70.default.basename(projectPaths.errorsPath))
20794
+ const projectPaths = pathsForProject(project, import_node_path71.default.join(scanPath, "neat-out"));
20795
+ const outPath = import_node_path71.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
20796
+ const errorsPath = import_node_path71.default.resolve(
20797
+ process.env.NEAT_ERRORS_PATH ?? import_node_path71.default.join(import_node_path71.default.dirname(outPath), import_node_path71.default.basename(projectPaths.errorsPath))
20669
20798
  );
20670
- const staleEventsPath = import_node_path70.default.resolve(
20671
- process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path70.default.join(import_node_path70.default.dirname(outPath), import_node_path70.default.basename(projectPaths.staleEventsPath))
20799
+ const staleEventsPath = import_node_path71.default.resolve(
20800
+ process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path71.default.join(import_node_path71.default.dirname(outPath), import_node_path71.default.basename(projectPaths.staleEventsPath))
20672
20801
  );
20673
- const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path70.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
20802
+ const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path71.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
20674
20803
  const handle = await startWatch(getGraph(project), {
20675
20804
  scanPath,
20676
20805
  outPath,
@@ -20679,7 +20808,7 @@ async function main() {
20679
20808
  project,
20680
20809
  // Resolve NEAT_HOME so a `neat watch` picks up connectors added to
20681
20810
  // ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
20682
- neatHome: process.env.NEAT_HOME ? import_node_path70.default.resolve(process.env.NEAT_HOME) : import_node_path70.default.join(import_node_os6.default.homedir(), ".neat"),
20811
+ neatHome: process.env.NEAT_HOME ? import_node_path71.default.resolve(process.env.NEAT_HOME) : import_node_path71.default.join(import_node_os6.default.homedir(), ".neat"),
20683
20812
  ...embeddingsCachePath ? { embeddingsCachePath } : {},
20684
20813
  host: process.env.HOST ?? "0.0.0.0",
20685
20814
  port: Number(process.env.PORT ?? 8080),
@@ -20861,11 +20990,11 @@ async function main() {
20861
20990
  process.exit(1);
20862
20991
  }
20863
20992
  async function tryOrchestrator(cmd, parsed) {
20864
- const scanPath = import_node_path70.default.resolve(cmd);
20993
+ const scanPath = import_node_path71.default.resolve(cmd);
20865
20994
  const stat = await import_node_fs43.promises.stat(scanPath).catch(() => null);
20866
20995
  if (!stat || !stat.isDirectory()) return null;
20867
20996
  const projectExplicit = parsed.project !== null;
20868
- const projectName = projectExplicit ? parsed.project : import_node_path70.default.basename(scanPath);
20997
+ const projectName = projectExplicit ? parsed.project : import_node_path71.default.basename(scanPath);
20869
20998
  const result = await runOrchestrator({
20870
20999
  scanPath,
20871
21000
  project: projectName,
@@ -21054,10 +21183,10 @@ async function runQueryVerb(cmd, parsed) {
21054
21183
  const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
21055
21184
  const out = [];
21056
21185
  for (const p of parts) {
21057
- const r = import_types63.DivergenceTypeSchema.safeParse(p);
21186
+ const r = import_types64.DivergenceTypeSchema.safeParse(p);
21058
21187
  if (!r.success) {
21059
21188
  console.error(
21060
- `neat divergences: unknown --type "${p}". allowed: ${import_types63.DivergenceTypeSchema.options.join(", ")}`
21189
+ `neat divergences: unknown --type "${p}". allowed: ${import_types64.DivergenceTypeSchema.options.join(", ")}`
21061
21190
  );
21062
21191
  return 2;
21063
21192
  }