@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/index.cjs CHANGED
@@ -100,8 +100,8 @@ function reshapeGrpcRequest(req) {
100
100
  };
101
101
  }
102
102
  function resolveProtoRoot() {
103
- const here = import_node_path33.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
104
- return import_node_path33.default.resolve(here, "..", "proto");
103
+ const here = import_node_path34.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
104
+ return import_node_path34.default.resolve(here, "..", "proto");
105
105
  }
106
106
  function loadTraceService() {
107
107
  const protoRoot = resolveProtoRoot();
@@ -156,13 +156,13 @@ async function startOtelGrpcReceiver(opts) {
156
156
  })
157
157
  };
158
158
  }
159
- var import_node_url, import_node_path33, grpc, protoLoader;
159
+ var import_node_url, import_node_path34, grpc, protoLoader;
160
160
  var init_otel_grpc = __esm({
161
161
  "src/otel-grpc.ts"() {
162
162
  "use strict";
163
163
  init_cjs_shims();
164
164
  import_node_url = require("url");
165
- import_node_path33 = __toESM(require("path"), 1);
165
+ import_node_path34 = __toESM(require("path"), 1);
166
166
  grpc = __toESM(require("@grpc/grpc-js"), 1);
167
167
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
168
168
  init_otel();
@@ -259,10 +259,10 @@ function parseOtlpRequest(body) {
259
259
  }
260
260
  function loadProtobufDecoder() {
261
261
  if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
262
- const here = import_node_path34.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
263
- const protoRoot = import_node_path34.default.resolve(here, "..", "proto");
262
+ const here = import_node_path35.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
263
+ const protoRoot = import_node_path35.default.resolve(here, "..", "proto");
264
264
  const root = new import_protobufjs.default.Root();
265
- root.resolvePath = (_origin, target) => import_node_path34.default.resolve(protoRoot, target);
265
+ root.resolvePath = (_origin, target) => import_node_path35.default.resolve(protoRoot, target);
266
266
  root.loadSync(
267
267
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
268
268
  { keepCase: true }
@@ -362,12 +362,12 @@ function logSpanHandler(span) {
362
362
  `otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
363
363
  );
364
364
  }
365
- var import_node_path34, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
365
+ var import_node_path35, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
366
366
  var init_otel = __esm({
367
367
  "src/otel.ts"() {
368
368
  "use strict";
369
369
  init_cjs_shims();
370
- import_node_path34 = __toESM(require("path"), 1);
370
+ import_node_path35 = __toESM(require("path"), 1);
371
371
  import_node_url2 = require("url");
372
372
  import_fastify2 = __toESM(require("fastify"), 1);
373
373
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -876,19 +876,19 @@ function confidenceFromMix(edges, now = Date.now()) {
876
876
  function longestIncomingWalk(graph, start, maxDepth) {
877
877
  let best = { path: [start], edges: [] };
878
878
  const visited = /* @__PURE__ */ new Set([start]);
879
- function step(node, path36, edges) {
880
- if (path36.length > best.path.length) {
881
- best = { path: [...path36], edges: [...edges] };
879
+ function step(node, path37, edges) {
880
+ if (path37.length > best.path.length) {
881
+ best = { path: [...path37], edges: [...edges] };
882
882
  }
883
- if (path36.length - 1 >= maxDepth) return;
883
+ if (path37.length - 1 >= maxDepth) return;
884
884
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
885
885
  for (const [srcId, edge] of incoming) {
886
886
  if (visited.has(srcId)) continue;
887
887
  visited.add(srcId);
888
- path36.push(srcId);
888
+ path37.push(srcId);
889
889
  edges.push(edge);
890
- step(srcId, path36, edges);
891
- path36.pop();
890
+ step(srcId, path37, edges);
891
+ path37.pop();
892
892
  edges.pop();
893
893
  visited.delete(srcId);
894
894
  }
@@ -1577,35 +1577,37 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
1577
1577
  const existing = graph.getEdgeAttributes(id);
1578
1578
  const newSpanCount = (existing.signal?.spanCount ?? existing.callCount ?? 0) + 1;
1579
1579
  const newErrorCount = (existing.signal?.errorCount ?? 0) + (isError ? 1 : 0);
1580
+ const newSignal = {
1581
+ spanCount: newSpanCount,
1582
+ errorCount: newErrorCount,
1583
+ lastObservedAgeMs: 0
1584
+ };
1580
1585
  const updated = {
1581
1586
  ...existing,
1582
1587
  provenance: import_types3.Provenance.OBSERVED,
1583
1588
  lastObserved: ts,
1584
1589
  callCount: newSpanCount,
1585
- signal: {
1586
- spanCount: newSpanCount,
1587
- errorCount: newErrorCount,
1588
- lastObservedAgeMs: 0
1589
- },
1590
- confidence: 1
1590
+ signal: newSignal,
1591
+ confidence: (0, import_types3.confidenceForObservedSignal)(newSignal)
1591
1592
  };
1592
1593
  graph.replaceEdgeAttributes(id, updated);
1593
1594
  return { edge: updated, created: false };
1594
1595
  }
1596
+ const signal = {
1597
+ spanCount: 1,
1598
+ errorCount: isError ? 1 : 0,
1599
+ lastObservedAgeMs: 0
1600
+ };
1595
1601
  const edge = {
1596
1602
  id,
1597
1603
  source,
1598
1604
  target,
1599
1605
  type,
1600
1606
  provenance: import_types3.Provenance.OBSERVED,
1601
- confidence: 1,
1607
+ confidence: (0, import_types3.confidenceForObservedSignal)(signal),
1602
1608
  lastObserved: ts,
1603
1609
  callCount: 1,
1604
- signal: {
1605
- spanCount: 1,
1606
- errorCount: isError ? 1 : 0,
1607
- lastObservedAgeMs: 0
1608
- }
1610
+ signal
1609
1611
  };
1610
1612
  graph.addEdgeWithKey(id, source, target, edge);
1611
1613
  return { edge, created: true };
@@ -2232,6 +2234,23 @@ async function writeExtractionErrors(errors, errorsPath) {
2232
2234
  const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
2233
2235
  await import_node_fs7.promises.appendFile(errorsPath, lines, "utf8");
2234
2236
  }
2237
+ var droppedSink = [];
2238
+ function noteExtractedDropped(edge) {
2239
+ droppedSink.push(edge);
2240
+ }
2241
+ function drainDroppedExtracted() {
2242
+ return droppedSink.splice(0, droppedSink.length);
2243
+ }
2244
+ function isRejectedLogEnabled() {
2245
+ const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG;
2246
+ return raw === "1" || raw === "true";
2247
+ }
2248
+ async function writeRejectedExtracted(drops, rejectedPath) {
2249
+ if (drops.length === 0) return;
2250
+ await import_node_fs7.promises.mkdir(import_node_path7.default.dirname(rejectedPath), { recursive: true });
2251
+ const lines = drops.map((d) => JSON.stringify({ ...d, ts: (/* @__PURE__ */ new Date()).toISOString() })).join("\n") + "\n";
2252
+ await import_node_fs7.promises.appendFile(rejectedPath, lines, "utf8");
2253
+ }
2235
2254
 
2236
2255
  // src/extract/services.ts
2237
2256
  var DEFAULT_SCAN_DEPTH = 5;
@@ -3170,6 +3189,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
3170
3189
  target: dbNode.id,
3171
3190
  type: import_types7.EdgeType.CONNECTS_TO,
3172
3191
  provenance: import_types7.Provenance.EXTRACTED,
3192
+ confidence: (0, import_types7.confidenceForExtracted)("structural"),
3173
3193
  // ADR-032 / #140 — every EXTRACTED edge carries evidence.file.
3174
3194
  // Ghost-edge cleanup keys retirement on this; the conditional
3175
3195
  // sourceFile spread that used to live here was a v0.1.x leftover.
@@ -3244,6 +3264,7 @@ async function addConfigNodes(graph, services, scanPath) {
3244
3264
  target: node.id,
3245
3265
  type: import_types8.EdgeType.CONFIGURED_BY,
3246
3266
  provenance: import_types8.Provenance.EXTRACTED,
3267
+ confidence: (0, import_types8.confidenceForExtracted)("structural"),
3247
3268
  evidence: { file: relPath.split(import_node_path18.default.sep).join("/") }
3248
3269
  };
3249
3270
  if (!graph.hasEdge(edge.id)) {
@@ -3398,17 +3419,32 @@ async function addHttpCallEdges(graph, services) {
3398
3419
  for (const [targetId, evidenceFile] of seenTargets) {
3399
3420
  const fileContent = files.find((f) => f.path === evidenceFile.file)?.content ?? "";
3400
3421
  const line = lineOf(fileContent, `//${evidenceFile.host}`);
3422
+ const confidence = (0, import_types9.confidenceForExtracted)("hostname-shape-match");
3423
+ const ev = {
3424
+ file: import_node_path20.default.relative(service.dir, evidenceFile.file),
3425
+ line,
3426
+ snippet: snippet(fileContent, line)
3427
+ };
3428
+ const edgeId = (0, import_types4.extractedEdgeId)(service.node.id, targetId, import_types9.EdgeType.CALLS);
3429
+ if (!(0, import_types9.passesExtractedFloor)(confidence)) {
3430
+ noteExtractedDropped({
3431
+ source: service.node.id,
3432
+ target: targetId,
3433
+ type: import_types9.EdgeType.CALLS,
3434
+ confidence,
3435
+ confidenceKind: "hostname-shape-match",
3436
+ evidence: ev
3437
+ });
3438
+ continue;
3439
+ }
3401
3440
  const edge = {
3402
- id: (0, import_types4.extractedEdgeId)(service.node.id, targetId, import_types9.EdgeType.CALLS),
3441
+ id: edgeId,
3403
3442
  source: service.node.id,
3404
3443
  target: targetId,
3405
3444
  type: import_types9.EdgeType.CALLS,
3406
3445
  provenance: import_types9.Provenance.EXTRACTED,
3407
- evidence: {
3408
- file: import_node_path20.default.relative(service.dir, evidenceFile.file),
3409
- line,
3410
- snippet: snippet(fileContent, line)
3411
- }
3446
+ confidence,
3447
+ evidence: ev
3412
3448
  };
3413
3449
  if (!graph.hasEdge(edge.id)) {
3414
3450
  graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
@@ -3447,6 +3483,10 @@ function kafkaEndpointsFromFile(file, serviceDir) {
3447
3483
  name: topic,
3448
3484
  kind: "kafka-topic",
3449
3485
  edgeType,
3486
+ // `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})` —
3487
+ // framework-aware (kafkajs / node-rdkafka shape). Verified-call-site
3488
+ // tier (ADR-066).
3489
+ confidenceKind: "verified-call-site",
3450
3490
  evidence: {
3451
3491
  file: import_node_path21.default.relative(serviceDir, file.path),
3452
3492
  line,
@@ -3479,6 +3519,10 @@ function redisEndpointsFromFile(file, serviceDir) {
3479
3519
  name: host,
3480
3520
  kind: "redis",
3481
3521
  edgeType: "CALLS",
3522
+ // `redis://host` URL literal — the scheme is structural support, but no
3523
+ // call expression is verified to wire it through. URL-with-structural-
3524
+ // support tier (ADR-066).
3525
+ confidenceKind: "url-with-structural-support",
3482
3526
  evidence: {
3483
3527
  file: import_node_path22.default.relative(serviceDir, file.path),
3484
3528
  line,
@@ -3520,6 +3564,10 @@ function awsEndpointsFromFile(file, serviceDir) {
3520
3564
  name,
3521
3565
  kind,
3522
3566
  edgeType: "CALLS",
3567
+ // SDK marker (S3Client, GetCommand, etc.) plus a Bucket/TableName
3568
+ // literal — framework-aware recognizer, verified-call-site tier
3569
+ // (ADR-066).
3570
+ confidenceKind: "verified-call-site",
3523
3571
  evidence: {
3524
3572
  file: import_node_path23.default.relative(serviceDir, file.path),
3525
3573
  line,
@@ -3599,6 +3647,10 @@ function grpcEndpointsFromFile(file, serviceDir) {
3599
3647
  name,
3600
3648
  kind,
3601
3649
  edgeType: "CALLS",
3650
+ // `new <Name>Client(...)` with @aws-sdk/* or @grpc/grpc-js import
3651
+ // context — import-aware classification per #238. Verified-call-site
3652
+ // tier (ADR-066).
3653
+ confidenceKind: "verified-call-site",
3602
3654
  evidence: {
3603
3655
  file: import_node_path24.default.relative(serviceDir, file.path),
3604
3656
  line,
@@ -3659,6 +3711,18 @@ async function addExternalEndpointEdges(graph, services) {
3659
3711
  const edgeId = (0, import_types4.extractedEdgeId)(service.node.id, ep.infraId, edgeType);
3660
3712
  if (seenEdges.has(edgeId)) continue;
3661
3713
  seenEdges.add(edgeId);
3714
+ const confidence = (0, import_types14.confidenceForExtracted)(ep.confidenceKind);
3715
+ if (!(0, import_types14.passesExtractedFloor)(confidence)) {
3716
+ noteExtractedDropped({
3717
+ source: service.node.id,
3718
+ target: ep.infraId,
3719
+ type: edgeType,
3720
+ confidence,
3721
+ confidenceKind: ep.confidenceKind,
3722
+ evidence: ep.evidence
3723
+ });
3724
+ continue;
3725
+ }
3662
3726
  if (!graph.hasEdge(edgeId)) {
3663
3727
  const edge = {
3664
3728
  id: edgeId,
@@ -3666,6 +3730,7 @@ async function addExternalEndpointEdges(graph, services) {
3666
3730
  target: ep.infraId,
3667
3731
  type: edgeType,
3668
3732
  provenance: import_types14.Provenance.EXTRACTED,
3733
+ confidence,
3669
3734
  evidence: ep.evidence
3670
3735
  };
3671
3736
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -3785,6 +3850,7 @@ async function addComposeInfra(graph, scanPath, services) {
3785
3850
  target: targetId,
3786
3851
  type: import_types16.EdgeType.DEPENDS_ON,
3787
3852
  provenance: import_types16.Provenance.EXTRACTED,
3853
+ confidence: (0, import_types16.confidenceForExtracted)("structural"),
3788
3854
  evidence: { file: evidenceFile }
3789
3855
  };
3790
3856
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -3845,6 +3911,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
3845
3911
  target: node.id,
3846
3912
  type: import_types17.EdgeType.RUNS_ON,
3847
3913
  provenance: import_types17.Provenance.EXTRACTED,
3914
+ confidence: (0, import_types17.confidenceForExtracted)("structural"),
3848
3915
  evidence: {
3849
3916
  file: import_node_path26.default.relative(scanPath, dockerfilePath).split(import_node_path26.default.sep).join("/")
3850
3917
  }
@@ -3961,6 +4028,9 @@ async function addInfra(graph, scanPath, services) {
3961
4028
  };
3962
4029
  }
3963
4030
 
4031
+ // src/extract/index.ts
4032
+ var import_node_path30 = __toESM(require("path"), 1);
4033
+
3964
4034
  // src/extract/retire.ts
3965
4035
  init_cjs_shims();
3966
4036
  var import_node_fs17 = require("fs");
@@ -4013,13 +4083,26 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
4013
4083
  );
4014
4084
  }
4015
4085
  }
4086
+ const droppedEntries = drainDroppedExtracted();
4087
+ if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
4088
+ const rejectedPath = import_node_path30.default.join(import_node_path30.default.dirname(opts.errorsPath), "rejected.ndjson");
4089
+ try {
4090
+ await writeRejectedExtracted(droppedEntries, rejectedPath);
4091
+ } catch (err) {
4092
+ console.warn(
4093
+ `[neat] failed to write rejected extracted edges to ${rejectedPath}: ${err.message}`
4094
+ );
4095
+ }
4096
+ }
4016
4097
  const result = {
4017
4098
  nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
4018
4099
  edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
4019
4100
  frontiersPromoted,
4020
4101
  extractionErrors: errorEntries.length,
4021
4102
  errorEntries,
4022
- ghostsRetired
4103
+ ghostsRetired,
4104
+ extractedDropped: droppedEntries.length,
4105
+ droppedEntries
4023
4106
  };
4024
4107
  emitNeatEvent({
4025
4108
  type: "extraction-complete",
@@ -4037,7 +4120,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
4037
4120
  // src/persist.ts
4038
4121
  init_cjs_shims();
4039
4122
  var import_node_fs18 = require("fs");
4040
- var import_node_path30 = __toESM(require("path"), 1);
4123
+ var import_node_path31 = __toESM(require("path"), 1);
4041
4124
  var SCHEMA_VERSION = 2;
4042
4125
  function migrateV1ToV2(payload) {
4043
4126
  const nodes = payload.graph.nodes;
@@ -4051,7 +4134,7 @@ function migrateV1ToV2(payload) {
4051
4134
  return { ...payload, schemaVersion: 2 };
4052
4135
  }
4053
4136
  async function ensureDir(filePath) {
4054
- await import_node_fs18.promises.mkdir(import_node_path30.default.dirname(filePath), { recursive: true });
4137
+ await import_node_fs18.promises.mkdir(import_node_path31.default.dirname(filePath), { recursive: true });
4055
4138
  }
4056
4139
  async function saveGraphToDisk(graph, outPath) {
4057
4140
  await ensureDir(outPath);
@@ -4163,14 +4246,6 @@ function nodeIsFrontier(graph, nodeId) {
4163
4246
  const attrs = graph.getNodeAttributes(nodeId);
4164
4247
  return attrs.type === import_types19.NodeType.FrontierNode;
4165
4248
  }
4166
- function hasAnyObservedFromSource(graph, sourceId) {
4167
- if (!graph.hasNode(sourceId)) return false;
4168
- for (const edgeId of graph.outboundEdges(sourceId)) {
4169
- const e = graph.getEdgeAttributes(edgeId);
4170
- if (e.provenance === import_types19.Provenance.OBSERVED) return true;
4171
- }
4172
- return false;
4173
- }
4174
4249
  function clampConfidence(n) {
4175
4250
  if (!Number.isFinite(n)) return 0;
4176
4251
  return Math.max(0, Math.min(1, n));
@@ -4184,32 +4259,34 @@ function reasonForMissingExtracted(source, target, type) {
4184
4259
  var RECOMMENDATION_MISSING_OBSERVED = "Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.";
4185
4260
  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.";
4186
4261
  var RECOMMENDATION_HOST_MISMATCH = "Check environment-specific config overrides \u2014 the runtime host differs from what static configuration declares.";
4262
+ function gradedConfidence(edge) {
4263
+ if (typeof edge.confidence === "number") return clampConfidence(edge.confidence);
4264
+ return clampConfidence(confidenceForEdge(edge));
4265
+ }
4187
4266
  function detectMissingDivergences(graph, bucket) {
4188
4267
  const out = [];
4189
4268
  if (bucket.extracted && !bucket.observed) {
4190
4269
  if (!nodeIsFrontier(graph, bucket.target)) {
4191
- const sourceHasTraffic = hasAnyObservedFromSource(graph, bucket.source);
4192
4270
  out.push({
4193
4271
  type: "missing-observed",
4194
4272
  source: bucket.source,
4195
4273
  target: bucket.target,
4196
4274
  edgeType: bucket.type,
4197
4275
  extracted: bucket.extracted,
4198
- confidence: sourceHasTraffic ? 1 : 0.5,
4276
+ confidence: gradedConfidence(bucket.extracted),
4199
4277
  reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),
4200
4278
  recommendation: RECOMMENDATION_MISSING_OBSERVED
4201
4279
  });
4202
4280
  }
4203
4281
  }
4204
4282
  if (bucket.observed && !bucket.extracted) {
4205
- const cascaded = clampConfidence(confidenceForEdge(bucket.observed));
4206
4283
  out.push({
4207
4284
  type: "missing-extracted",
4208
4285
  source: bucket.source,
4209
4286
  target: bucket.target,
4210
4287
  edgeType: bucket.type,
4211
4288
  observed: bucket.observed,
4212
- confidence: cascaded,
4289
+ confidence: gradedConfidence(bucket.observed),
4213
4290
  reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),
4214
4291
  recommendation: RECOMMENDATION_MISSING_EXTRACTED
4215
4292
  });
@@ -4348,8 +4425,17 @@ function computeDivergences(graph, opts = {}) {
4348
4425
  const target = opts.node;
4349
4426
  filtered = filtered.filter((d) => involvesNode(d, target));
4350
4427
  }
4428
+ const TYPE_LEADERSHIP = {
4429
+ "missing-extracted": 0,
4430
+ "missing-observed": 1,
4431
+ "version-mismatch": 2,
4432
+ "host-mismatch": 3,
4433
+ "compat-violation": 4
4434
+ };
4351
4435
  filtered.sort((a, b) => {
4352
4436
  if (b.confidence !== a.confidence) return b.confidence - a.confidence;
4437
+ const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type];
4438
+ if (lead !== 0) return lead;
4353
4439
  if (a.type !== b.type) return a.type.localeCompare(b.type);
4354
4440
  if (a.source !== b.source) return a.source.localeCompare(b.source);
4355
4441
  return a.target.localeCompare(b.target);
@@ -4440,23 +4526,23 @@ function canonicalJson(value) {
4440
4526
 
4441
4527
  // src/projects.ts
4442
4528
  init_cjs_shims();
4443
- var import_node_path31 = __toESM(require("path"), 1);
4529
+ var import_node_path32 = __toESM(require("path"), 1);
4444
4530
  function pathsForProject(project, baseDir) {
4445
4531
  if (project === DEFAULT_PROJECT) {
4446
4532
  return {
4447
- snapshotPath: import_node_path31.default.join(baseDir, "graph.json"),
4448
- errorsPath: import_node_path31.default.join(baseDir, "errors.ndjson"),
4449
- staleEventsPath: import_node_path31.default.join(baseDir, "stale-events.ndjson"),
4450
- embeddingsCachePath: import_node_path31.default.join(baseDir, "embeddings.json"),
4451
- policyViolationsPath: import_node_path31.default.join(baseDir, "policy-violations.ndjson")
4533
+ snapshotPath: import_node_path32.default.join(baseDir, "graph.json"),
4534
+ errorsPath: import_node_path32.default.join(baseDir, "errors.ndjson"),
4535
+ staleEventsPath: import_node_path32.default.join(baseDir, "stale-events.ndjson"),
4536
+ embeddingsCachePath: import_node_path32.default.join(baseDir, "embeddings.json"),
4537
+ policyViolationsPath: import_node_path32.default.join(baseDir, "policy-violations.ndjson")
4452
4538
  };
4453
4539
  }
4454
4540
  return {
4455
- snapshotPath: import_node_path31.default.join(baseDir, `${project}.json`),
4456
- errorsPath: import_node_path31.default.join(baseDir, `errors.${project}.ndjson`),
4457
- staleEventsPath: import_node_path31.default.join(baseDir, `stale-events.${project}.ndjson`),
4458
- embeddingsCachePath: import_node_path31.default.join(baseDir, `embeddings.${project}.json`),
4459
- policyViolationsPath: import_node_path31.default.join(baseDir, `policy-violations.${project}.ndjson`)
4541
+ snapshotPath: import_node_path32.default.join(baseDir, `${project}.json`),
4542
+ errorsPath: import_node_path32.default.join(baseDir, `errors.${project}.ndjson`),
4543
+ staleEventsPath: import_node_path32.default.join(baseDir, `stale-events.${project}.ndjson`),
4544
+ embeddingsCachePath: import_node_path32.default.join(baseDir, `embeddings.${project}.json`),
4545
+ policyViolationsPath: import_node_path32.default.join(baseDir, `policy-violations.${project}.ndjson`)
4460
4546
  };
4461
4547
  }
4462
4548
  var Projects = class {
@@ -4494,23 +4580,23 @@ var Projects = class {
4494
4580
  init_cjs_shims();
4495
4581
  var import_node_fs20 = require("fs");
4496
4582
  var import_node_os2 = __toESM(require("os"), 1);
4497
- var import_node_path32 = __toESM(require("path"), 1);
4583
+ var import_node_path33 = __toESM(require("path"), 1);
4498
4584
  var import_types20 = require("@neat.is/types");
4499
4585
  var LOCK_TIMEOUT_MS = 5e3;
4500
4586
  var LOCK_RETRY_MS = 50;
4501
4587
  function neatHome() {
4502
4588
  const override = process.env.NEAT_HOME;
4503
- if (override && override.length > 0) return import_node_path32.default.resolve(override);
4504
- return import_node_path32.default.join(import_node_os2.default.homedir(), ".neat");
4589
+ if (override && override.length > 0) return import_node_path33.default.resolve(override);
4590
+ return import_node_path33.default.join(import_node_os2.default.homedir(), ".neat");
4505
4591
  }
4506
4592
  function registryPath() {
4507
- return import_node_path32.default.join(neatHome(), "projects.json");
4593
+ return import_node_path33.default.join(neatHome(), "projects.json");
4508
4594
  }
4509
4595
  function registryLockPath() {
4510
- return import_node_path32.default.join(neatHome(), "projects.json.lock");
4596
+ return import_node_path33.default.join(neatHome(), "projects.json.lock");
4511
4597
  }
4512
4598
  async function normalizeProjectPath(input) {
4513
- const resolved = import_node_path32.default.resolve(input);
4599
+ const resolved = import_node_path33.default.resolve(input);
4514
4600
  try {
4515
4601
  return await import_node_fs20.promises.realpath(resolved);
4516
4602
  } catch {
@@ -4518,7 +4604,7 @@ async function normalizeProjectPath(input) {
4518
4604
  }
4519
4605
  }
4520
4606
  async function writeAtomically(target, contents) {
4521
- await import_node_fs20.promises.mkdir(import_node_path32.default.dirname(target), { recursive: true });
4607
+ await import_node_fs20.promises.mkdir(import_node_path33.default.dirname(target), { recursive: true });
4522
4608
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
4523
4609
  const fd = await import_node_fs20.promises.open(tmp, "w");
4524
4610
  try {
@@ -4531,7 +4617,7 @@ async function writeAtomically(target, contents) {
4531
4617
  }
4532
4618
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS) {
4533
4619
  const deadline = Date.now() + timeoutMs;
4534
- await import_node_fs20.promises.mkdir(import_node_path32.default.dirname(lockPath), { recursive: true });
4620
+ await import_node_fs20.promises.mkdir(import_node_path33.default.dirname(lockPath), { recursive: true });
4535
4621
  while (true) {
4536
4622
  try {
4537
4623
  const fd = await import_node_fs20.promises.open(lockPath, "wx");
@@ -5147,14 +5233,14 @@ init_otel_grpc();
5147
5233
  // src/daemon.ts
5148
5234
  init_cjs_shims();
5149
5235
  var import_node_fs21 = require("fs");
5150
- var import_node_path35 = __toESM(require("path"), 1);
5236
+ var import_node_path36 = __toESM(require("path"), 1);
5151
5237
  init_otel();
5152
5238
  function neatHomeFor(opts) {
5153
- if (opts.neatHome && opts.neatHome.length > 0) return import_node_path35.default.resolve(opts.neatHome);
5239
+ if (opts.neatHome && opts.neatHome.length > 0) return import_node_path36.default.resolve(opts.neatHome);
5154
5240
  const env = process.env.NEAT_HOME;
5155
- if (env && env.length > 0) return import_node_path35.default.resolve(env);
5241
+ if (env && env.length > 0) return import_node_path36.default.resolve(env);
5156
5242
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
5157
- return import_node_path35.default.join(home, ".neat");
5243
+ return import_node_path36.default.join(home, ".neat");
5158
5244
  }
5159
5245
  function routeSpanToProject(serviceName, projects) {
5160
5246
  if (!serviceName) return DEFAULT_PROJECT;
@@ -5167,7 +5253,7 @@ function routeSpanToProject(serviceName, projects) {
5167
5253
  return DEFAULT_PROJECT;
5168
5254
  }
5169
5255
  async function bootstrapProject(entry) {
5170
- const paths = pathsForProject(entry.name, import_node_path35.default.join(entry.path, "neat-out"));
5256
+ const paths = pathsForProject(entry.name, import_node_path36.default.join(entry.path, "neat-out"));
5171
5257
  try {
5172
5258
  const stat = await import_node_fs21.promises.stat(entry.path);
5173
5259
  if (!stat.isDirectory()) {
@@ -5240,7 +5326,7 @@ async function startDaemon(opts = {}) {
5240
5326
  `neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
5241
5327
  );
5242
5328
  }
5243
- const pidPath = import_node_path35.default.join(home, "neatd.pid");
5329
+ const pidPath = import_node_path36.default.join(home, "neatd.pid");
5244
5330
  await writeAtomically(pidPath, `${process.pid}
5245
5331
  `);
5246
5332
  const slots = /* @__PURE__ */ new Map();