@neat.is/core 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/neatd.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startDaemon
4
- } from "./chunk-ICFH326H.js";
4
+ } from "./chunk-T3A2GK3X.js";
5
5
  import {
6
6
  listProjects,
7
7
  registryPath
8
- } from "./chunk-VABXPLDT.js";
8
+ } from "./chunk-33ZZ2ZID.js";
9
9
  import {
10
10
  __require
11
11
  } from "./chunk-4ASCXBZF.js";
package/dist/server.cjs CHANGED
@@ -99,8 +99,8 @@ function reshapeGrpcRequest(req) {
99
99
  };
100
100
  }
101
101
  function resolveProtoRoot() {
102
- const here = import_node_path33.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
103
- return import_node_path33.default.resolve(here, "..", "proto");
102
+ const here = import_node_path34.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
103
+ return import_node_path34.default.resolve(here, "..", "proto");
104
104
  }
105
105
  function loadTraceService() {
106
106
  const protoRoot = resolveProtoRoot();
@@ -155,13 +155,13 @@ async function startOtelGrpcReceiver(opts) {
155
155
  })
156
156
  };
157
157
  }
158
- var import_node_url, import_node_path33, grpc, protoLoader;
158
+ var import_node_url, import_node_path34, grpc, protoLoader;
159
159
  var init_otel_grpc = __esm({
160
160
  "src/otel-grpc.ts"() {
161
161
  "use strict";
162
162
  init_cjs_shims();
163
163
  import_node_url = require("url");
164
- import_node_path33 = __toESM(require("path"), 1);
164
+ import_node_path34 = __toESM(require("path"), 1);
165
165
  grpc = __toESM(require("@grpc/grpc-js"), 1);
166
166
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
167
167
  init_otel();
@@ -258,10 +258,10 @@ function parseOtlpRequest(body) {
258
258
  }
259
259
  function loadProtobufDecoder() {
260
260
  if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
261
- const here = import_node_path34.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
262
- const protoRoot = import_node_path34.default.resolve(here, "..", "proto");
261
+ const here = import_node_path35.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
262
+ const protoRoot = import_node_path35.default.resolve(here, "..", "proto");
263
263
  const root = new import_protobufjs.default.Root();
264
- root.resolvePath = (_origin, target) => import_node_path34.default.resolve(protoRoot, target);
264
+ root.resolvePath = (_origin, target) => import_node_path35.default.resolve(protoRoot, target);
265
265
  root.loadSync(
266
266
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
267
267
  { keepCase: true }
@@ -353,12 +353,12 @@ async function buildOtelReceiver(opts) {
353
353
  };
354
354
  return decorated;
355
355
  }
356
- var import_node_path34, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
356
+ var import_node_path35, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
357
357
  var init_otel = __esm({
358
358
  "src/otel.ts"() {
359
359
  "use strict";
360
360
  init_cjs_shims();
361
- import_node_path34 = __toESM(require("path"), 1);
361
+ import_node_path35 = __toESM(require("path"), 1);
362
362
  import_node_url2 = require("url");
363
363
  import_fastify2 = __toESM(require("fastify"), 1);
364
364
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -368,7 +368,7 @@ var init_otel = __esm({
368
368
 
369
369
  // src/server.ts
370
370
  init_cjs_shims();
371
- var import_node_path36 = __toESM(require("path"), 1);
371
+ var import_node_path37 = __toESM(require("path"), 1);
372
372
 
373
373
  // src/graph.ts
374
374
  init_cjs_shims();
@@ -798,19 +798,19 @@ function confidenceFromMix(edges, now = Date.now()) {
798
798
  function longestIncomingWalk(graph, start, maxDepth) {
799
799
  let best = { path: [start], edges: [] };
800
800
  const visited = /* @__PURE__ */ new Set([start]);
801
- function step(node, path37, edges) {
802
- if (path37.length > best.path.length) {
803
- best = { path: [...path37], edges: [...edges] };
801
+ function step(node, path38, edges) {
802
+ if (path38.length > best.path.length) {
803
+ best = { path: [...path38], edges: [...edges] };
804
804
  }
805
- if (path37.length - 1 >= maxDepth) return;
805
+ if (path38.length - 1 >= maxDepth) return;
806
806
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
807
807
  for (const [srcId, edge] of incoming) {
808
808
  if (visited.has(srcId)) continue;
809
809
  visited.add(srcId);
810
- path37.push(srcId);
810
+ path38.push(srcId);
811
811
  edges.push(edge);
812
- step(srcId, path37, edges);
813
- path37.pop();
812
+ step(srcId, path38, edges);
813
+ path38.pop();
814
814
  edges.pop();
815
815
  visited.delete(srcId);
816
816
  }
@@ -1029,14 +1029,6 @@ function nodeIsFrontier(graph, nodeId) {
1029
1029
  const attrs = graph.getNodeAttributes(nodeId);
1030
1030
  return attrs.type === import_types2.NodeType.FrontierNode;
1031
1031
  }
1032
- function hasAnyObservedFromSource(graph, sourceId) {
1033
- if (!graph.hasNode(sourceId)) return false;
1034
- for (const edgeId of graph.outboundEdges(sourceId)) {
1035
- const e = graph.getEdgeAttributes(edgeId);
1036
- if (e.provenance === import_types2.Provenance.OBSERVED) return true;
1037
- }
1038
- return false;
1039
- }
1040
1032
  function clampConfidence(n) {
1041
1033
  if (!Number.isFinite(n)) return 0;
1042
1034
  return Math.max(0, Math.min(1, n));
@@ -1050,32 +1042,34 @@ function reasonForMissingExtracted(source, target, type) {
1050
1042
  var RECOMMENDATION_MISSING_OBSERVED = "Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.";
1051
1043
  var RECOMMENDATION_MISSING_EXTRACTED = "Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.";
1052
1044
  var RECOMMENDATION_HOST_MISMATCH = "Check environment-specific config overrides \u2014 the runtime host differs from what static configuration declares.";
1045
+ function gradedConfidence(edge) {
1046
+ if (typeof edge.confidence === "number") return clampConfidence(edge.confidence);
1047
+ return clampConfidence(confidenceForEdge(edge));
1048
+ }
1053
1049
  function detectMissingDivergences(graph, bucket) {
1054
1050
  const out = [];
1055
1051
  if (bucket.extracted && !bucket.observed) {
1056
1052
  if (!nodeIsFrontier(graph, bucket.target)) {
1057
- const sourceHasTraffic = hasAnyObservedFromSource(graph, bucket.source);
1058
1053
  out.push({
1059
1054
  type: "missing-observed",
1060
1055
  source: bucket.source,
1061
1056
  target: bucket.target,
1062
1057
  edgeType: bucket.type,
1063
1058
  extracted: bucket.extracted,
1064
- confidence: sourceHasTraffic ? 1 : 0.5,
1059
+ confidence: gradedConfidence(bucket.extracted),
1065
1060
  reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),
1066
1061
  recommendation: RECOMMENDATION_MISSING_OBSERVED
1067
1062
  });
1068
1063
  }
1069
1064
  }
1070
1065
  if (bucket.observed && !bucket.extracted) {
1071
- const cascaded = clampConfidence(confidenceForEdge(bucket.observed));
1072
1066
  out.push({
1073
1067
  type: "missing-extracted",
1074
1068
  source: bucket.source,
1075
1069
  target: bucket.target,
1076
1070
  edgeType: bucket.type,
1077
1071
  observed: bucket.observed,
1078
- confidence: cascaded,
1072
+ confidence: gradedConfidence(bucket.observed),
1079
1073
  reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),
1080
1074
  recommendation: RECOMMENDATION_MISSING_EXTRACTED
1081
1075
  });
@@ -1214,8 +1208,17 @@ function computeDivergences(graph, opts = {}) {
1214
1208
  const target = opts.node;
1215
1209
  filtered = filtered.filter((d) => involvesNode(d, target));
1216
1210
  }
1211
+ const TYPE_LEADERSHIP = {
1212
+ "missing-extracted": 0,
1213
+ "missing-observed": 1,
1214
+ "version-mismatch": 2,
1215
+ "host-mismatch": 3,
1216
+ "compat-violation": 4
1217
+ };
1217
1218
  filtered.sort((a, b) => {
1218
1219
  if (b.confidence !== a.confidence) return b.confidence - a.confidence;
1220
+ const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type];
1221
+ if (lead !== 0) return lead;
1219
1222
  if (a.type !== b.type) return a.type.localeCompare(b.type);
1220
1223
  if (a.source !== b.source) return a.source.localeCompare(b.source);
1221
1224
  return a.target.localeCompare(b.target);
@@ -1761,35 +1764,37 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
1761
1764
  const existing = graph.getEdgeAttributes(id);
1762
1765
  const newSpanCount = (existing.signal?.spanCount ?? existing.callCount ?? 0) + 1;
1763
1766
  const newErrorCount = (existing.signal?.errorCount ?? 0) + (isError ? 1 : 0);
1767
+ const newSignal = {
1768
+ spanCount: newSpanCount,
1769
+ errorCount: newErrorCount,
1770
+ lastObservedAgeMs: 0
1771
+ };
1764
1772
  const updated = {
1765
1773
  ...existing,
1766
1774
  provenance: import_types4.Provenance.OBSERVED,
1767
1775
  lastObserved: ts,
1768
1776
  callCount: newSpanCount,
1769
- signal: {
1770
- spanCount: newSpanCount,
1771
- errorCount: newErrorCount,
1772
- lastObservedAgeMs: 0
1773
- },
1774
- confidence: 1
1777
+ signal: newSignal,
1778
+ confidence: (0, import_types4.confidenceForObservedSignal)(newSignal)
1775
1779
  };
1776
1780
  graph.replaceEdgeAttributes(id, updated);
1777
1781
  return { edge: updated, created: false };
1778
1782
  }
1783
+ const signal = {
1784
+ spanCount: 1,
1785
+ errorCount: isError ? 1 : 0,
1786
+ lastObservedAgeMs: 0
1787
+ };
1779
1788
  const edge = {
1780
1789
  id,
1781
1790
  source,
1782
1791
  target,
1783
1792
  type,
1784
1793
  provenance: import_types4.Provenance.OBSERVED,
1785
- confidence: 1,
1794
+ confidence: (0, import_types4.confidenceForObservedSignal)(signal),
1786
1795
  lastObserved: ts,
1787
1796
  callCount: 1,
1788
- signal: {
1789
- spanCount: 1,
1790
- errorCount: isError ? 1 : 0,
1791
- lastObservedAgeMs: 0
1792
- }
1797
+ signal
1793
1798
  };
1794
1799
  graph.addEdgeWithKey(id, source, target, edge);
1795
1800
  return { edge, created: true };
@@ -2393,6 +2398,23 @@ async function writeExtractionErrors(errors, errorsPath) {
2393
2398
  const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
2394
2399
  await import_node_fs7.promises.appendFile(errorsPath, lines, "utf8");
2395
2400
  }
2401
+ var droppedSink = [];
2402
+ function noteExtractedDropped(edge) {
2403
+ droppedSink.push(edge);
2404
+ }
2405
+ function drainDroppedExtracted() {
2406
+ return droppedSink.splice(0, droppedSink.length);
2407
+ }
2408
+ function isRejectedLogEnabled() {
2409
+ const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG;
2410
+ return raw === "1" || raw === "true";
2411
+ }
2412
+ async function writeRejectedExtracted(drops, rejectedPath) {
2413
+ if (drops.length === 0) return;
2414
+ await import_node_fs7.promises.mkdir(import_node_path7.default.dirname(rejectedPath), { recursive: true });
2415
+ const lines = drops.map((d) => JSON.stringify({ ...d, ts: (/* @__PURE__ */ new Date()).toISOString() })).join("\n") + "\n";
2416
+ await import_node_fs7.promises.appendFile(rejectedPath, lines, "utf8");
2417
+ }
2396
2418
 
2397
2419
  // src/extract/services.ts
2398
2420
  var DEFAULT_SCAN_DEPTH = 5;
@@ -3331,6 +3353,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
3331
3353
  target: dbNode.id,
3332
3354
  type: import_types8.EdgeType.CONNECTS_TO,
3333
3355
  provenance: import_types8.Provenance.EXTRACTED,
3356
+ confidence: (0, import_types8.confidenceForExtracted)("structural"),
3334
3357
  // ADR-032 / #140 — every EXTRACTED edge carries evidence.file.
3335
3358
  // Ghost-edge cleanup keys retirement on this; the conditional
3336
3359
  // sourceFile spread that used to live here was a v0.1.x leftover.
@@ -3405,6 +3428,7 @@ async function addConfigNodes(graph, services, scanPath) {
3405
3428
  target: node.id,
3406
3429
  type: import_types9.EdgeType.CONFIGURED_BY,
3407
3430
  provenance: import_types9.Provenance.EXTRACTED,
3431
+ confidence: (0, import_types9.confidenceForExtracted)("structural"),
3408
3432
  evidence: { file: relPath.split(import_node_path18.default.sep).join("/") }
3409
3433
  };
3410
3434
  if (!graph.hasEdge(edge.id)) {
@@ -3559,17 +3583,32 @@ async function addHttpCallEdges(graph, services) {
3559
3583
  for (const [targetId, evidenceFile] of seenTargets) {
3560
3584
  const fileContent = files.find((f) => f.path === evidenceFile.file)?.content ?? "";
3561
3585
  const line = lineOf(fileContent, `//${evidenceFile.host}`);
3586
+ const confidence = (0, import_types10.confidenceForExtracted)("hostname-shape-match");
3587
+ const ev = {
3588
+ file: import_node_path20.default.relative(service.dir, evidenceFile.file),
3589
+ line,
3590
+ snippet: snippet(fileContent, line)
3591
+ };
3592
+ const edgeId = (0, import_types5.extractedEdgeId)(service.node.id, targetId, import_types10.EdgeType.CALLS);
3593
+ if (!(0, import_types10.passesExtractedFloor)(confidence)) {
3594
+ noteExtractedDropped({
3595
+ source: service.node.id,
3596
+ target: targetId,
3597
+ type: import_types10.EdgeType.CALLS,
3598
+ confidence,
3599
+ confidenceKind: "hostname-shape-match",
3600
+ evidence: ev
3601
+ });
3602
+ continue;
3603
+ }
3562
3604
  const edge = {
3563
- id: (0, import_types5.extractedEdgeId)(service.node.id, targetId, import_types10.EdgeType.CALLS),
3605
+ id: edgeId,
3564
3606
  source: service.node.id,
3565
3607
  target: targetId,
3566
3608
  type: import_types10.EdgeType.CALLS,
3567
3609
  provenance: import_types10.Provenance.EXTRACTED,
3568
- evidence: {
3569
- file: import_node_path20.default.relative(service.dir, evidenceFile.file),
3570
- line,
3571
- snippet: snippet(fileContent, line)
3572
- }
3610
+ confidence,
3611
+ evidence: ev
3573
3612
  };
3574
3613
  if (!graph.hasEdge(edge.id)) {
3575
3614
  graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
@@ -3608,6 +3647,10 @@ function kafkaEndpointsFromFile(file, serviceDir) {
3608
3647
  name: topic,
3609
3648
  kind: "kafka-topic",
3610
3649
  edgeType,
3650
+ // `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})` —
3651
+ // framework-aware (kafkajs / node-rdkafka shape). Verified-call-site
3652
+ // tier (ADR-066).
3653
+ confidenceKind: "verified-call-site",
3611
3654
  evidence: {
3612
3655
  file: import_node_path21.default.relative(serviceDir, file.path),
3613
3656
  line,
@@ -3640,6 +3683,10 @@ function redisEndpointsFromFile(file, serviceDir) {
3640
3683
  name: host,
3641
3684
  kind: "redis",
3642
3685
  edgeType: "CALLS",
3686
+ // `redis://host` URL literal — the scheme is structural support, but no
3687
+ // call expression is verified to wire it through. URL-with-structural-
3688
+ // support tier (ADR-066).
3689
+ confidenceKind: "url-with-structural-support",
3643
3690
  evidence: {
3644
3691
  file: import_node_path22.default.relative(serviceDir, file.path),
3645
3692
  line,
@@ -3681,6 +3728,10 @@ function awsEndpointsFromFile(file, serviceDir) {
3681
3728
  name,
3682
3729
  kind,
3683
3730
  edgeType: "CALLS",
3731
+ // SDK marker (S3Client, GetCommand, etc.) plus a Bucket/TableName
3732
+ // literal — framework-aware recognizer, verified-call-site tier
3733
+ // (ADR-066).
3734
+ confidenceKind: "verified-call-site",
3684
3735
  evidence: {
3685
3736
  file: import_node_path23.default.relative(serviceDir, file.path),
3686
3737
  line,
@@ -3760,6 +3811,10 @@ function grpcEndpointsFromFile(file, serviceDir) {
3760
3811
  name,
3761
3812
  kind,
3762
3813
  edgeType: "CALLS",
3814
+ // `new <Name>Client(...)` with @aws-sdk/* or @grpc/grpc-js import
3815
+ // context — import-aware classification per #238. Verified-call-site
3816
+ // tier (ADR-066).
3817
+ confidenceKind: "verified-call-site",
3763
3818
  evidence: {
3764
3819
  file: import_node_path24.default.relative(serviceDir, file.path),
3765
3820
  line,
@@ -3820,6 +3875,18 @@ async function addExternalEndpointEdges(graph, services) {
3820
3875
  const edgeId = (0, import_types5.extractedEdgeId)(service.node.id, ep.infraId, edgeType);
3821
3876
  if (seenEdges.has(edgeId)) continue;
3822
3877
  seenEdges.add(edgeId);
3878
+ const confidence = (0, import_types15.confidenceForExtracted)(ep.confidenceKind);
3879
+ if (!(0, import_types15.passesExtractedFloor)(confidence)) {
3880
+ noteExtractedDropped({
3881
+ source: service.node.id,
3882
+ target: ep.infraId,
3883
+ type: edgeType,
3884
+ confidence,
3885
+ confidenceKind: ep.confidenceKind,
3886
+ evidence: ep.evidence
3887
+ });
3888
+ continue;
3889
+ }
3823
3890
  if (!graph.hasEdge(edgeId)) {
3824
3891
  const edge = {
3825
3892
  id: edgeId,
@@ -3827,6 +3894,7 @@ async function addExternalEndpointEdges(graph, services) {
3827
3894
  target: ep.infraId,
3828
3895
  type: edgeType,
3829
3896
  provenance: import_types15.Provenance.EXTRACTED,
3897
+ confidence,
3830
3898
  evidence: ep.evidence
3831
3899
  };
3832
3900
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -3946,6 +4014,7 @@ async function addComposeInfra(graph, scanPath, services) {
3946
4014
  target: targetId,
3947
4015
  type: import_types17.EdgeType.DEPENDS_ON,
3948
4016
  provenance: import_types17.Provenance.EXTRACTED,
4017
+ confidence: (0, import_types17.confidenceForExtracted)("structural"),
3949
4018
  evidence: { file: evidenceFile }
3950
4019
  };
3951
4020
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -4006,6 +4075,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
4006
4075
  target: node.id,
4007
4076
  type: import_types18.EdgeType.RUNS_ON,
4008
4077
  provenance: import_types18.Provenance.EXTRACTED,
4078
+ confidence: (0, import_types18.confidenceForExtracted)("structural"),
4009
4079
  evidence: {
4010
4080
  file: import_node_path26.default.relative(scanPath, dockerfilePath).split(import_node_path26.default.sep).join("/")
4011
4081
  }
@@ -4122,6 +4192,9 @@ async function addInfra(graph, scanPath, services) {
4122
4192
  };
4123
4193
  }
4124
4194
 
4195
+ // src/extract/index.ts
4196
+ var import_node_path30 = __toESM(require("path"), 1);
4197
+
4125
4198
  // src/extract/retire.ts
4126
4199
  init_cjs_shims();
4127
4200
  var import_node_fs17 = require("fs");
@@ -4174,13 +4247,26 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
4174
4247
  );
4175
4248
  }
4176
4249
  }
4250
+ const droppedEntries = drainDroppedExtracted();
4251
+ if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
4252
+ const rejectedPath = import_node_path30.default.join(import_node_path30.default.dirname(opts.errorsPath), "rejected.ndjson");
4253
+ try {
4254
+ await writeRejectedExtracted(droppedEntries, rejectedPath);
4255
+ } catch (err) {
4256
+ console.warn(
4257
+ `[neat] failed to write rejected extracted edges to ${rejectedPath}: ${err.message}`
4258
+ );
4259
+ }
4260
+ }
4177
4261
  const result = {
4178
4262
  nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
4179
4263
  edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
4180
4264
  frontiersPromoted,
4181
4265
  extractionErrors: errorEntries.length,
4182
4266
  errorEntries,
4183
- ghostsRetired
4267
+ ghostsRetired,
4268
+ extractedDropped: droppedEntries.length,
4269
+ droppedEntries
4184
4270
  };
4185
4271
  emitNeatEvent({
4186
4272
  type: "extraction-complete",
@@ -4274,23 +4360,23 @@ function canonicalJson(value) {
4274
4360
 
4275
4361
  // src/projects.ts
4276
4362
  init_cjs_shims();
4277
- var import_node_path30 = __toESM(require("path"), 1);
4363
+ var import_node_path31 = __toESM(require("path"), 1);
4278
4364
  function pathsForProject(project, baseDir) {
4279
4365
  if (project === DEFAULT_PROJECT) {
4280
4366
  return {
4281
- snapshotPath: import_node_path30.default.join(baseDir, "graph.json"),
4282
- errorsPath: import_node_path30.default.join(baseDir, "errors.ndjson"),
4283
- staleEventsPath: import_node_path30.default.join(baseDir, "stale-events.ndjson"),
4284
- embeddingsCachePath: import_node_path30.default.join(baseDir, "embeddings.json"),
4285
- policyViolationsPath: import_node_path30.default.join(baseDir, "policy-violations.ndjson")
4367
+ snapshotPath: import_node_path31.default.join(baseDir, "graph.json"),
4368
+ errorsPath: import_node_path31.default.join(baseDir, "errors.ndjson"),
4369
+ staleEventsPath: import_node_path31.default.join(baseDir, "stale-events.ndjson"),
4370
+ embeddingsCachePath: import_node_path31.default.join(baseDir, "embeddings.json"),
4371
+ policyViolationsPath: import_node_path31.default.join(baseDir, "policy-violations.ndjson")
4286
4372
  };
4287
4373
  }
4288
4374
  return {
4289
- snapshotPath: import_node_path30.default.join(baseDir, `${project}.json`),
4290
- errorsPath: import_node_path30.default.join(baseDir, `errors.${project}.ndjson`),
4291
- staleEventsPath: import_node_path30.default.join(baseDir, `stale-events.${project}.ndjson`),
4292
- embeddingsCachePath: import_node_path30.default.join(baseDir, `embeddings.${project}.json`),
4293
- policyViolationsPath: import_node_path30.default.join(baseDir, `policy-violations.${project}.ndjson`)
4375
+ snapshotPath: import_node_path31.default.join(baseDir, `${project}.json`),
4376
+ errorsPath: import_node_path31.default.join(baseDir, `errors.${project}.ndjson`),
4377
+ staleEventsPath: import_node_path31.default.join(baseDir, `stale-events.${project}.ndjson`),
4378
+ embeddingsCachePath: import_node_path31.default.join(baseDir, `embeddings.${project}.json`),
4379
+ policyViolationsPath: import_node_path31.default.join(baseDir, `policy-violations.${project}.ndjson`)
4294
4380
  };
4295
4381
  }
4296
4382
  var Projects = class {
@@ -4332,15 +4418,15 @@ function parseExtraProjects(raw) {
4332
4418
  init_cjs_shims();
4333
4419
  var import_node_fs19 = require("fs");
4334
4420
  var import_node_os2 = __toESM(require("os"), 1);
4335
- var import_node_path31 = __toESM(require("path"), 1);
4421
+ var import_node_path32 = __toESM(require("path"), 1);
4336
4422
  var import_types20 = require("@neat.is/types");
4337
4423
  function neatHome() {
4338
4424
  const override = process.env.NEAT_HOME;
4339
- if (override && override.length > 0) return import_node_path31.default.resolve(override);
4340
- return import_node_path31.default.join(import_node_os2.default.homedir(), ".neat");
4425
+ if (override && override.length > 0) return import_node_path32.default.resolve(override);
4426
+ return import_node_path32.default.join(import_node_os2.default.homedir(), ".neat");
4341
4427
  }
4342
4428
  function registryPath() {
4343
- return import_node_path31.default.join(neatHome(), "projects.json");
4429
+ return import_node_path32.default.join(neatHome(), "projects.json");
4344
4430
  }
4345
4431
  async function readRegistry() {
4346
4432
  const file = registryPath();
@@ -4850,7 +4936,7 @@ async function buildApi(opts) {
4850
4936
  // src/persist.ts
4851
4937
  init_cjs_shims();
4852
4938
  var import_node_fs20 = require("fs");
4853
- var import_node_path32 = __toESM(require("path"), 1);
4939
+ var import_node_path33 = __toESM(require("path"), 1);
4854
4940
  var SCHEMA_VERSION = 2;
4855
4941
  function migrateV1ToV2(payload) {
4856
4942
  const nodes = payload.graph.nodes;
@@ -4864,7 +4950,7 @@ function migrateV1ToV2(payload) {
4864
4950
  return { ...payload, schemaVersion: 2 };
4865
4951
  }
4866
4952
  async function ensureDir(filePath) {
4867
- await import_node_fs20.promises.mkdir(import_node_path32.default.dirname(filePath), { recursive: true });
4953
+ await import_node_fs20.promises.mkdir(import_node_path33.default.dirname(filePath), { recursive: true });
4868
4954
  }
4869
4955
  async function saveGraphToDisk(graph, outPath) {
4870
4956
  await ensureDir(outPath);
@@ -4938,7 +5024,7 @@ init_otel_grpc();
4938
5024
  // src/search.ts
4939
5025
  init_cjs_shims();
4940
5026
  var import_node_fs21 = require("fs");
4941
- var import_node_path35 = __toESM(require("path"), 1);
5027
+ var import_node_path36 = __toESM(require("path"), 1);
4942
5028
  var import_node_crypto = require("crypto");
4943
5029
  var DEFAULT_LIMIT = 10;
4944
5030
  var NOMIC_DIM = 768;
@@ -5077,7 +5163,7 @@ async function readCache(cachePath) {
5077
5163
  }
5078
5164
  }
5079
5165
  async function writeCache(cachePath, cache) {
5080
- await import_node_fs21.promises.mkdir(import_node_path35.default.dirname(cachePath), { recursive: true });
5166
+ await import_node_fs21.promises.mkdir(import_node_path36.default.dirname(cachePath), { recursive: true });
5081
5167
  await import_node_fs21.promises.writeFile(cachePath, JSON.stringify(cache));
5082
5168
  }
5083
5169
  var VectorIndex = class {
@@ -5257,14 +5343,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
5257
5343
  async function main() {
5258
5344
  const baseDirEnv = process.env.NEAT_OUT_DIR;
5259
5345
  const legacyOutPath = process.env.NEAT_OUT_PATH;
5260
- const baseDir = baseDirEnv ? import_node_path36.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path36.default.resolve(import_node_path36.default.dirname(legacyOutPath)) : import_node_path36.default.resolve("./neat-out");
5261
- const defaultScanPath = import_node_path36.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
5346
+ const baseDir = baseDirEnv ? import_node_path37.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path37.default.resolve(import_node_path37.default.dirname(legacyOutPath)) : import_node_path37.default.resolve("./neat-out");
5347
+ const defaultScanPath = import_node_path37.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
5262
5348
  const registry = new Projects();
5263
5349
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
5264
5350
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
5265
5351
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
5266
5352
  const projectScan = process.env[envKey];
5267
- await bootProject(registry, name, projectScan ? import_node_path36.default.resolve(projectScan) : void 0, baseDir);
5353
+ await bootProject(registry, name, projectScan ? import_node_path37.default.resolve(projectScan) : void 0, baseDir);
5268
5354
  }
5269
5355
  const host = process.env.HOST ?? "0.0.0.0";
5270
5356
  const port = Number(process.env.PORT ?? 8080);