@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/{chunk-VABXPLDT.js → chunk-33ZZ2ZID.js} +181 -66
- package/dist/chunk-33ZZ2ZID.js.map +1 -0
- package/dist/{chunk-ICFH326H.js → chunk-T3A2GK3X.js} +2 -2
- package/dist/cli.cjs +215 -124
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +160 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +167 -81
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +156 -70
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-VABXPLDT.js.map +0 -1
- /package/dist/{chunk-ICFH326H.js.map → chunk-T3A2GK3X.js.map} +0 -0
package/dist/neatd.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-T3A2GK3X.js";
|
|
5
5
|
import {
|
|
6
6
|
listProjects,
|
|
7
7
|
registryPath
|
|
8
|
-
} from "./chunk-
|
|
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 =
|
|
103
|
-
return
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
262
|
-
const protoRoot =
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
802
|
-
if (
|
|
803
|
-
best = { path: [...
|
|
801
|
+
function step(node, path38, edges) {
|
|
802
|
+
if (path38.length > best.path.length) {
|
|
803
|
+
best = { path: [...path38], edges: [...edges] };
|
|
804
804
|
}
|
|
805
|
-
if (
|
|
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
|
-
|
|
810
|
+
path38.push(srcId);
|
|
811
811
|
edges.push(edge);
|
|
812
|
-
step(srcId,
|
|
813
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
3569
|
-
|
|
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
|
|
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:
|
|
4282
|
-
errorsPath:
|
|
4283
|
-
staleEventsPath:
|
|
4284
|
-
embeddingsCachePath:
|
|
4285
|
-
policyViolationsPath:
|
|
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:
|
|
4290
|
-
errorsPath:
|
|
4291
|
-
staleEventsPath:
|
|
4292
|
-
embeddingsCachePath:
|
|
4293
|
-
policyViolationsPath:
|
|
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
|
|
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
|
|
4340
|
-
return
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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 ?
|
|
5261
|
-
const defaultScanPath =
|
|
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 ?
|
|
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);
|