@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/{chunk-MDBE23Y3.js → chunk-3SBEY67S.js} +2 -2
- package/dist/{chunk-RR4LWQQB.js → chunk-BY6ZP5WA.js} +267 -139
- package/dist/chunk-BY6ZP5WA.js.map +1 -0
- package/dist/cli.cjs +600 -471
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +425 -296
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +434 -305
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +357 -228
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-RR4LWQQB.js.map +0 -1
- /package/dist/{chunk-MDBE23Y3.js.map → chunk-3SBEY67S.js.map} +0 -0
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
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
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 =
|
|
198
|
-
return
|
|
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,
|
|
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
|
-
|
|
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
|
|
419
|
-
if (
|
|
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 =
|
|
479
|
-
const protoRoot =
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
1326
|
-
if (
|
|
1327
|
-
best = { path: [...
|
|
1325
|
+
function step(node, path72, edges) {
|
|
1326
|
+
if (path72.length > best.path.length) {
|
|
1327
|
+
best = { path: [...path72], edges: [...edges] };
|
|
1328
1328
|
}
|
|
1329
|
-
if (
|
|
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
|
-
|
|
1334
|
+
path72.push(srcId);
|
|
1335
1335
|
edges.push(edge);
|
|
1336
|
-
step(srcId,
|
|
1337
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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,
|
|
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(
|
|
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
|
|
8608
|
+
return import_types30.EdgeType.PUBLISHES_TO;
|
|
8481
8609
|
case "CONSUMES_FROM":
|
|
8482
|
-
return
|
|
8610
|
+
return import_types30.EdgeType.CONSUMES_FROM;
|
|
8483
8611
|
default:
|
|
8484
|
-
return
|
|
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:
|
|
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 ===
|
|
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
|
-
|
|
8545
|
-
(0,
|
|
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,
|
|
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,
|
|
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:
|
|
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
|
|
8608
|
-
var
|
|
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
|
|
8741
|
+
var import_types31 = require("@neat.is/types");
|
|
8613
8742
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
8614
8743
|
return {
|
|
8615
|
-
id: (0,
|
|
8616
|
-
type:
|
|
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:
|
|
8661
|
-
confidence: (0,
|
|
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 ||
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
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:
|
|
8735
|
-
provenance:
|
|
8736
|
-
confidence: (0,
|
|
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
|
|
8877
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8749
8878
|
var import_node_fs18 = require("fs");
|
|
8750
|
-
var
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
8800
|
-
const evidenceFile = toPosix(
|
|
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,
|
|
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:
|
|
8816
|
-
provenance:
|
|
8817
|
-
confidence: (0,
|
|
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,
|
|
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:
|
|
8839
|
-
provenance:
|
|
8840
|
-
confidence: (0,
|
|
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
|
|
8854
|
-
var
|
|
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 =
|
|
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(
|
|
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(
|
|
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,
|
|
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:
|
|
8943
|
-
provenance:
|
|
8944
|
-
confidence: (0,
|
|
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
|
|
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 =
|
|
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(
|
|
8980
|
-
out.push(
|
|
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
|
|
9143
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9015
9144
|
var import_smol_toml2 = require("smol-toml");
|
|
9016
|
-
var
|
|
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 =
|
|
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:
|
|
9065
|
-
confidence: (0,
|
|
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",
|
|
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(
|
|
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(
|
|
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,
|
|
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:
|
|
9133
|
-
provenance:
|
|
9134
|
-
confidence: (0,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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:
|
|
9219
|
-
provenance:
|
|
9220
|
-
confidence: (0,
|
|
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
|
-
|
|
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
|
|
9248
|
-
var
|
|
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 =
|
|
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 =
|
|
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",
|
|
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(
|
|
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(
|
|
9312
|
-
for (const cron of config.crons ?? []) add(
|
|
9313
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
9314
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
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(
|
|
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
|
|
9454
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9326
9455
|
var import_smol_toml3 = require("smol-toml");
|
|
9327
|
-
var
|
|
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 =
|
|
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",
|
|
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(
|
|
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(
|
|
9374
|
-
add(
|
|
9375
|
-
add(
|
|
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
|
|
9512
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9384
9513
|
var import_smol_toml4 = require("smol-toml");
|
|
9385
|
-
var
|
|
9514
|
+
var import_types38 = require("@neat.is/types");
|
|
9386
9515
|
async function readSupabaseConfig(dir) {
|
|
9387
|
-
const relFile =
|
|
9388
|
-
const abs =
|
|
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",
|
|
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(
|
|
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(
|
|
9434
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
9435
|
-
if (config.storage) add(
|
|
9436
|
-
if (config.auth) add(
|
|
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
|
|
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
|
|
9464
|
-
var
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
9623
|
+
if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
|
|
9495
9624
|
const evidenceFile = edge.evidence?.file;
|
|
9496
9625
|
if (!evidenceFile) return;
|
|
9497
|
-
if (
|
|
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)(
|
|
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 =
|
|
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
|
|
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 !==
|
|
9594
|
-
const parsed = (0,
|
|
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 !==
|
|
9598
|
-
return (0,
|
|
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,
|
|
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
|
|
9739
|
+
case import_types40.Provenance.EXTRACTED:
|
|
9611
9740
|
cur.extracted = e;
|
|
9612
9741
|
break;
|
|
9613
|
-
case
|
|
9742
|
+
case import_types40.Provenance.OBSERVED:
|
|
9614
9743
|
cur.observed = e;
|
|
9615
9744
|
break;
|
|
9616
|
-
case
|
|
9745
|
+
case import_types40.Provenance.INFERRED:
|
|
9617
9746
|
cur.inferred = e;
|
|
9618
9747
|
break;
|
|
9619
9748
|
default:
|
|
9620
|
-
if (e.provenance ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
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 ===
|
|
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 ===
|
|
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 !==
|
|
9722
|
-
if (edge.provenance !==
|
|
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 !==
|
|
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 !==
|
|
9747
|
-
if (edge.provenance !==
|
|
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 !==
|
|
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,
|
|
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 ===
|
|
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 ===
|
|
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
|
|
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
|
|
9918
|
-
var
|
|
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 !==
|
|
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 =
|
|
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,
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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(
|
|
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 =
|
|
10317
|
-
found.push(rel.split(
|
|
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(
|
|
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 ??
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
10562
|
+
const primaryPath = import_node_path56.default.join(ctx.scanPath, primaryFile);
|
|
10434
10563
|
const filesTouched = [];
|
|
10435
10564
|
const depsAdded = [];
|
|
10436
|
-
const pkgPath =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
10670
|
-
errorsPath:
|
|
10671
|
-
staleEventsPath:
|
|
10672
|
-
embeddingsCachePath:
|
|
10673
|
-
policyViolationsPath:
|
|
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:
|
|
10678
|
-
errorsPath:
|
|
10679
|
-
staleEventsPath:
|
|
10680
|
-
embeddingsCachePath:
|
|
10681
|
-
policyViolationsPath:
|
|
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
|
|
10720
|
-
var
|
|
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
|
|
10726
|
-
return
|
|
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
|
|
10858
|
+
return import_node_path58.default.join(neatHome(), "projects.json");
|
|
10730
10859
|
}
|
|
10731
10860
|
function registryLockPath() {
|
|
10732
|
-
return
|
|
10861
|
+
return import_node_path58.default.join(neatHome(), "projects.json.lock");
|
|
10733
10862
|
}
|
|
10734
10863
|
function daemonPidPath() {
|
|
10735
|
-
return
|
|
10864
|
+
return import_node_path58.default.join(neatHome(), "neatd.pid");
|
|
10736
10865
|
}
|
|
10737
10866
|
function daemonsDir() {
|
|
10738
|
-
return
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
11103
|
+
return import_types43.RegistryFileSchema.parse(parsed);
|
|
10975
11104
|
}
|
|
10976
11105
|
async function writeRegistry(reg) {
|
|
10977
|
-
const validated =
|
|
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
|
|
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
|
|
11179
|
-
return
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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 !==
|
|
11498
|
-
const parsed = (0,
|
|
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 !==
|
|
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(
|
|
11987
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
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(
|
|
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
|
|
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,
|
|
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:
|
|
12237
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types46.EdgeType.CALLS };
|
|
12109
12238
|
}
|
|
12110
|
-
const bareResourceId = (0,
|
|
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:
|
|
12241
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types46.EdgeType.CALLS };
|
|
12113
12242
|
}
|
|
12114
|
-
const projectLevelId = (0,
|
|
12243
|
+
const projectLevelId = (0, import_types46.infraId)("supabase", config.nodeRef);
|
|
12115
12244
|
if (graph.hasNode(projectLevelId)) {
|
|
12116
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
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
|
|
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 !==
|
|
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:
|
|
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,
|
|
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
|
|
12594
|
-
if (!resourceName || !method || !
|
|
12595
|
-
return { resourceName, method, path:
|
|
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
|
|
12634
|
-
if (
|
|
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:
|
|
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
|
|
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 !==
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
...
|
|
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 ===
|
|
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,
|
|
12902
|
-
const normalizedPath = normalizePathTemplate(
|
|
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 !==
|
|
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:
|
|
13048
|
+
const { method, path: path72 } = signal;
|
|
12920
13049
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
12921
|
-
if (!method || !
|
|
12922
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
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,
|
|
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:
|
|
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:
|
|
13068
|
+
edgeType: import_types53.EdgeType.CALLS
|
|
12940
13069
|
};
|
|
12941
13070
|
}
|
|
12942
13071
|
return {
|
|
12943
|
-
targetNodeId: (0,
|
|
13072
|
+
targetNodeId: (0, import_types53.infraId)("cloudflare-worker", scriptName),
|
|
12944
13073
|
serviceName: scriptName,
|
|
12945
|
-
edgeType:
|
|
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
|
|
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,
|
|
13275
|
+
targetNodeId: (0, import_types57.infraId)("sql-table", signal.targetName),
|
|
13147
13276
|
serviceName: config.serviceName,
|
|
13148
|
-
edgeType:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
14602
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
14474
14603
|
|
|
14475
14604
|
// src/daemon.ts
|
|
14476
|
-
var
|
|
14605
|
+
var import_types61 = require("@neat.is/types");
|
|
14477
14606
|
function daemonJsonPath(scanPath) {
|
|
14478
|
-
return
|
|
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
|
|
14611
|
+
return import_node_path61.default.join(base, "daemons");
|
|
14483
14612
|
}
|
|
14484
14613
|
function daemonDiscoveryPath(project, home) {
|
|
14485
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
14887
|
-
const segments = relPath.split(
|
|
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(
|
|
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(
|
|
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 =
|
|
15036
|
-
const policyViolationsPath =
|
|
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 ??
|
|
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,
|
|
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 =
|
|
15361
|
+
const rel = import_node_path63.default.relative(opts.scanPath, absPath);
|
|
15233
15362
|
if (!rel || rel.startsWith("..")) return;
|
|
15234
|
-
pendingPaths.add(rel.split(
|
|
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
|
|
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 =
|
|
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 ${
|
|
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 =
|
|
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
|
|
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 ??
|
|
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 ??
|
|
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(
|
|
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(
|
|
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(
|
|
16132
|
-
if (await exists3(
|
|
16133
|
-
if (await exists3(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
16440
|
-
exists3(
|
|
16441
|
-
exists3(
|
|
16442
|
-
exists3(
|
|
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 ?
|
|
16450
|
-
const instrumentationFile =
|
|
16451
|
-
const instrumentationNodeFile =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 =
|
|
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 =
|
|
16941
|
-
const envNeatFile =
|
|
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 =
|
|
17139
|
+
const rel = import_node_path65.default.relative(serviceDir, target);
|
|
17011
17140
|
if (rel.startsWith("..")) return false;
|
|
17012
|
-
const base =
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
17485
|
+
const asFile = import_node_path66.default.join(serviceDir, `${modPath}.py`);
|
|
17357
17486
|
if (await exists4(asFile)) return asFile;
|
|
17358
|
-
const asPkg =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
17728
|
+
const root = import_node_path67.default.join(serviceDir, "main.go");
|
|
17600
17729
|
if (await exists5(root)) return root;
|
|
17601
|
-
const 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 =
|
|
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(
|
|
17809
|
+
return exists5(import_node_path67.default.join(serviceDir, "go.mod"));
|
|
17681
17810
|
}
|
|
17682
17811
|
async function plan3(serviceDir) {
|
|
17683
|
-
const manifest =
|
|
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 =
|
|
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
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
18171
|
-
await import_node_fs41.promises.mkdir(
|
|
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
|
|
18345
|
+
return import_node_path68.default.join(projectPath3, "neat-out", "daemon.log");
|
|
18217
18346
|
}
|
|
18218
18347
|
function spawnDaemonDetached(spec) {
|
|
18219
|
-
const here =
|
|
18348
|
+
const here = import_node_path68.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
|
|
18220
18349
|
const candidates = [
|
|
18221
|
-
|
|
18222
|
-
|
|
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(
|
|
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 ?
|
|
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
|
|
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 :
|
|
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
|
-
|
|
18925
|
-
|
|
18926
|
-
|
|
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
|
|
18941
|
-
return
|
|
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
|
|
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
|
|
19076
|
+
return import_node_path69.default.join(home, ".claude", "settings.json");
|
|
18948
19077
|
}
|
|
18949
19078
|
function installedHookPath() {
|
|
18950
|
-
return
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
19213
|
+
var import_types63 = require("@neat.is/types");
|
|
19085
19214
|
|
|
19086
19215
|
// src/cli-client.ts
|
|
19087
19216
|
init_cjs_shims();
|
|
19088
|
-
var
|
|
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(
|
|
19242
|
+
async get(path72) {
|
|
19114
19243
|
let res;
|
|
19115
19244
|
try {
|
|
19116
|
-
res = await fetch(`${root}${
|
|
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 ${
|
|
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(
|
|
19263
|
+
async post(path72, body) {
|
|
19135
19264
|
let res;
|
|
19136
19265
|
try {
|
|
19137
|
-
res = await fetch(`${root}${
|
|
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 ${
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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 ===
|
|
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
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
-
|
|
19620
|
-
|
|
19621
|
-
|
|
19622
|
-
|
|
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,
|
|
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,
|
|
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 !==
|
|
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 ===
|
|
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
|
|
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}${
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
20549
|
+
import_node_path71.default.join(opts.scanPath, "neat-out")
|
|
20421
20550
|
);
|
|
20422
|
-
const 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
|
|
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
|
|
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(
|
|
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 =
|
|
20762
|
+
const scanPath = import_node_path71.default.resolve(target);
|
|
20634
20763
|
const projectExplicit = parsed.project !== null;
|
|
20635
|
-
const projectName = projectExplicit ? project :
|
|
20764
|
+
const projectName = projectExplicit ? project : import_node_path71.default.basename(scanPath);
|
|
20636
20765
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
20637
|
-
const fallback = pathsForProject(projectKey,
|
|
20638
|
-
const outPath =
|
|
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 =
|
|
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,
|
|
20666
|
-
const outPath =
|
|
20667
|
-
const errorsPath =
|
|
20668
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
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 =
|
|
20671
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
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 ?
|
|
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 ?
|
|
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 =
|
|
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 :
|
|
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 =
|
|
21186
|
+
const r = import_types64.DivergenceTypeSchema.safeParse(p);
|
|
21058
21187
|
if (!r.success) {
|
|
21059
21188
|
console.error(
|
|
21060
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
21189
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types64.DivergenceTypeSchema.options.join(", ")}`
|
|
21061
21190
|
);
|
|
21062
21191
|
return 2;
|
|
21063
21192
|
}
|