@neat.is/core 0.6.0 → 0.6.2-dev.20260722
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-BZ3AJVAC.js → chunk-2MAGU6RB.js} +11 -2
- package/dist/chunk-2MAGU6RB.js.map +1 -0
- package/dist/{chunk-5PVQJLPR.js → chunk-64JJOXES.js} +3 -3
- package/dist/{chunk-MVINCLQM.js → chunk-OY7FGJAX.js} +2 -2
- package/dist/{chunk-CS4GHQO3.js → chunk-ZZ3VUCWL.js} +1581 -1329
- package/dist/chunk-ZZ3VUCWL.js.map +1 -0
- package/dist/cli.cjs +730 -468
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +579 -317
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +588 -326
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-XS45HBET.js → otel-grpc-AHNPM5LX.js} +3 -3
- package/dist/server.cjs +2683 -2417
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-BZ3AJVAC.js.map +0 -1
- package/dist/chunk-CS4GHQO3.js.map +0 -1
- /package/dist/{chunk-5PVQJLPR.js.map → chunk-64JJOXES.js.map} +0 -0
- /package/dist/{chunk-MVINCLQM.js.map → chunk-OY7FGJAX.js.map} +0 -0
- /package/dist/{otel-grpc-XS45HBET.js.map → otel-grpc-AHNPM5LX.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 path64 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path64) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path64)) {
|
|
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_path51.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path51.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_path51, 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_path51 = __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);
|
|
@@ -347,6 +347,14 @@ function normalizeDbSystem(attrs) {
|
|
|
347
347
|
if (typeof raw !== "string") return void 0;
|
|
348
348
|
return raw === "mongoose" ? "mongodb" : raw;
|
|
349
349
|
}
|
|
350
|
+
function tableFromSqlStatement(sql) {
|
|
351
|
+
if (typeof sql !== "string" || sql.length === 0) return null;
|
|
352
|
+
if (/\bjoin\b/i.test(sql)) return null;
|
|
353
|
+
const froms = sql.match(/\bfrom\b/gi);
|
|
354
|
+
if (froms && froms.length > 1) return null;
|
|
355
|
+
const m = /\b(?:from|into|update)\s+(?:"?[\w$]+"?\s*\.\s*)?"?([a-zA-Z_][\w$]*)"?/i.exec(sql);
|
|
356
|
+
return m ? m[1] : null;
|
|
357
|
+
}
|
|
350
358
|
function messagingDestinationOf(attrs) {
|
|
351
359
|
for (const key of ["messaging.destination.name", "messaging.destination"]) {
|
|
352
360
|
const v = attrs[key];
|
|
@@ -367,8 +375,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
367
375
|
const v = attrs[key];
|
|
368
376
|
if (typeof v === "string" && v.length > 0) {
|
|
369
377
|
const q = v.indexOf("?");
|
|
370
|
-
const
|
|
371
|
-
if (
|
|
378
|
+
const path64 = q === -1 ? v : v.slice(0, q);
|
|
379
|
+
if (path64.length > 0) return path64;
|
|
372
380
|
}
|
|
373
381
|
}
|
|
374
382
|
return void 0;
|
|
@@ -404,6 +412,7 @@ function parseOtlpRequest(body) {
|
|
|
404
412
|
dbSystem: normalizeDbSystem(attrs),
|
|
405
413
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
406
414
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
415
|
+
dbTable: typeof attrs["db.statement"] === "string" ? tableFromSqlStatement(attrs["db.statement"]) ?? void 0 : void 0,
|
|
407
416
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
408
417
|
messagingDestination: messagingDestinationOf(attrs),
|
|
409
418
|
graphqlOperationName: typeof attrs["graphql.operation.name"] === "string" && attrs["graphql.operation.name"].length > 0 ? attrs["graphql.operation.name"] : void 0,
|
|
@@ -423,10 +432,10 @@ function parseOtlpRequest(body) {
|
|
|
423
432
|
return out;
|
|
424
433
|
}
|
|
425
434
|
function loadProtoRoot() {
|
|
426
|
-
const here =
|
|
427
|
-
const protoRoot =
|
|
435
|
+
const here = import_node_path52.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
436
|
+
const protoRoot = import_node_path52.default.resolve(here, "..", "proto");
|
|
428
437
|
const root = new import_protobufjs.default.Root();
|
|
429
|
-
root.resolvePath = (_origin, target) =>
|
|
438
|
+
root.resolvePath = (_origin, target) => import_node_path52.default.resolve(protoRoot, target);
|
|
430
439
|
root.loadSync(
|
|
431
440
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
432
441
|
{ keepCase: true }
|
|
@@ -654,12 +663,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
654
663
|
}
|
|
655
664
|
}
|
|
656
665
|
}
|
|
657
|
-
var
|
|
666
|
+
var import_node_path52, import_node_url3, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
658
667
|
var init_otel = __esm({
|
|
659
668
|
"src/otel.ts"() {
|
|
660
669
|
"use strict";
|
|
661
670
|
init_cjs_shims();
|
|
662
|
-
|
|
671
|
+
import_node_path52 = __toESM(require("path"), 1);
|
|
663
672
|
import_node_url3 = require("url");
|
|
664
673
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
665
674
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -696,7 +705,7 @@ __export(cli_exports, {
|
|
|
696
705
|
});
|
|
697
706
|
module.exports = __toCommonJS(cli_exports);
|
|
698
707
|
init_cjs_shims();
|
|
699
|
-
var
|
|
708
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
700
709
|
var import_node_fs41 = require("fs");
|
|
701
710
|
|
|
702
711
|
// src/banner.ts
|
|
@@ -1262,19 +1271,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1262
1271
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1263
1272
|
let best = { path: [start], edges: [] };
|
|
1264
1273
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1265
|
-
function step(node,
|
|
1266
|
-
if (
|
|
1267
|
-
best = { path: [...
|
|
1274
|
+
function step(node, path64, edges) {
|
|
1275
|
+
if (path64.length > best.path.length) {
|
|
1276
|
+
best = { path: [...path64], edges: [...edges] };
|
|
1268
1277
|
}
|
|
1269
|
-
if (
|
|
1278
|
+
if (path64.length - 1 >= maxDepth) return;
|
|
1270
1279
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1271
1280
|
for (const [srcId, edge] of incoming) {
|
|
1272
1281
|
if (visited.has(srcId)) continue;
|
|
1273
1282
|
visited.add(srcId);
|
|
1274
|
-
|
|
1283
|
+
path64.push(srcId);
|
|
1275
1284
|
edges.push(edge);
|
|
1276
|
-
step(srcId,
|
|
1277
|
-
|
|
1285
|
+
step(srcId, path64, edges);
|
|
1286
|
+
path64.pop();
|
|
1278
1287
|
edges.pop();
|
|
1279
1288
|
visited.delete(srcId);
|
|
1280
1289
|
}
|
|
@@ -1282,11 +1291,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1282
1291
|
step(start, [start], []);
|
|
1283
1292
|
return best;
|
|
1284
1293
|
}
|
|
1285
|
-
function databaseRootCauseShape(graph, origin,
|
|
1294
|
+
function databaseRootCauseShape(graph, origin, walk4) {
|
|
1286
1295
|
const targetDb = origin;
|
|
1287
1296
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1288
1297
|
if (candidatePairs.length === 0) return null;
|
|
1289
|
-
for (const id of
|
|
1298
|
+
for (const id of walk4.path) {
|
|
1290
1299
|
const owner = resolveOwningService(graph, id);
|
|
1291
1300
|
if (!owner) continue;
|
|
1292
1301
|
const { id: serviceId6, svc } = owner;
|
|
@@ -1313,8 +1322,8 @@ function databaseRootCauseShape(graph, origin, walk3) {
|
|
|
1313
1322
|
}
|
|
1314
1323
|
return null;
|
|
1315
1324
|
}
|
|
1316
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1317
|
-
for (const id of
|
|
1325
|
+
function serviceRootCauseShape(graph, _origin, walk4) {
|
|
1326
|
+
for (const id of walk4.path) {
|
|
1318
1327
|
const owner = resolveOwningService(graph, id);
|
|
1319
1328
|
if (!owner) continue;
|
|
1320
1329
|
const { id: serviceId6, svc } = owner;
|
|
@@ -1350,10 +1359,10 @@ function serviceRootCauseShape(graph, _origin, walk3) {
|
|
|
1350
1359
|
}
|
|
1351
1360
|
return null;
|
|
1352
1361
|
}
|
|
1353
|
-
function fileRootCauseShape(graph, origin,
|
|
1362
|
+
function fileRootCauseShape(graph, origin, walk4) {
|
|
1354
1363
|
const owner = resolveOwningService(graph, origin.id);
|
|
1355
1364
|
if (!owner) return null;
|
|
1356
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1365
|
+
return serviceRootCauseShape(graph, owner.svc, walk4);
|
|
1357
1366
|
}
|
|
1358
1367
|
var rootCauseShapes = {
|
|
1359
1368
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1365,16 +1374,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1365
1374
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1366
1375
|
const shape = rootCauseShapes[origin.type];
|
|
1367
1376
|
if (shape) {
|
|
1368
|
-
const
|
|
1369
|
-
const match = shape(graph, origin,
|
|
1377
|
+
const walk4 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1378
|
+
const match = shape(graph, origin, walk4);
|
|
1370
1379
|
if (match) {
|
|
1371
1380
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1372
1381
|
return import_types.RootCauseResultSchema.parse({
|
|
1373
1382
|
rootCauseNode: match.rootCauseNode,
|
|
1374
1383
|
rootCauseReason: reason,
|
|
1375
|
-
traversalPath:
|
|
1376
|
-
edgeProvenances:
|
|
1377
|
-
confidence: confidenceFromMix(
|
|
1384
|
+
traversalPath: walk4.path,
|
|
1385
|
+
edgeProvenances: walk4.edges.map((e) => e.provenance),
|
|
1386
|
+
confidence: confidenceFromMix(walk4.edges),
|
|
1378
1387
|
fixRecommendation: match.fixRecommendation
|
|
1379
1388
|
});
|
|
1380
1389
|
}
|
|
@@ -1395,8 +1404,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1395
1404
|
if (relevant.length === 0) return null;
|
|
1396
1405
|
const latest = [...relevant].sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
1397
1406
|
const attrs = latest.attributes ?? {};
|
|
1398
|
-
const filepath =
|
|
1399
|
-
const lineno =
|
|
1407
|
+
const filepath = codeFilepathOf(attrs);
|
|
1408
|
+
const lineno = codeLinenoOf(attrs);
|
|
1400
1409
|
const route = typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0;
|
|
1401
1410
|
const location = filepath ? `${filepath}${lineno !== void 0 ? `:${lineno}` : ""}` : void 0;
|
|
1402
1411
|
const sameMode = relevant.filter((ev) => ev.errorMessage === latest.errorMessage);
|
|
@@ -1468,26 +1477,26 @@ function dominantFailingCall(graph, serviceId6, visited) {
|
|
|
1468
1477
|
return best;
|
|
1469
1478
|
}
|
|
1470
1479
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1471
|
-
const
|
|
1480
|
+
const path64 = [originServiceId];
|
|
1472
1481
|
const edges = [];
|
|
1473
1482
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1474
1483
|
let current = originServiceId;
|
|
1475
1484
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1476
1485
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1477
1486
|
if (!hop) break;
|
|
1478
|
-
|
|
1487
|
+
path64.push(hop.nextService);
|
|
1479
1488
|
edges.push(hop.edge);
|
|
1480
1489
|
visited.add(hop.nextService);
|
|
1481
1490
|
current = hop.nextService;
|
|
1482
1491
|
}
|
|
1483
1492
|
if (edges.length === 0) return null;
|
|
1484
|
-
return { path:
|
|
1493
|
+
return { path: path64, edges, culprit: current };
|
|
1485
1494
|
}
|
|
1486
1495
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1487
1496
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1488
1497
|
if (!chain) return null;
|
|
1489
1498
|
const culprit = chain.culprit;
|
|
1490
|
-
const
|
|
1499
|
+
const path64 = [...chain.path];
|
|
1491
1500
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1492
1501
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1493
1502
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1495,14 +1504,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1495
1504
|
if (loc) {
|
|
1496
1505
|
let rootCauseNode = culprit;
|
|
1497
1506
|
if (loc.fileNode) {
|
|
1498
|
-
|
|
1507
|
+
path64.push(loc.fileNode);
|
|
1499
1508
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1500
1509
|
rootCauseNode = loc.fileNode;
|
|
1501
1510
|
}
|
|
1502
1511
|
return import_types.RootCauseResultSchema.parse({
|
|
1503
1512
|
rootCauseNode,
|
|
1504
1513
|
rootCauseReason: loc.rootCauseReason,
|
|
1505
|
-
traversalPath:
|
|
1514
|
+
traversalPath: path64,
|
|
1506
1515
|
edgeProvenances,
|
|
1507
1516
|
confidence,
|
|
1508
1517
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1514,7 +1523,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1514
1523
|
return import_types.RootCauseResultSchema.parse({
|
|
1515
1524
|
rootCauseNode: culprit,
|
|
1516
1525
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1517
|
-
traversalPath:
|
|
1526
|
+
traversalPath: path64,
|
|
1518
1527
|
edgeProvenances,
|
|
1519
1528
|
confidence,
|
|
1520
1529
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2272,9 +2281,30 @@ function isLoopbackHost(host) {
|
|
|
2272
2281
|
const h = host.toLowerCase();
|
|
2273
2282
|
return h === "localhost" || h === "ip6-localhost" || h === "::1" || h === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(h);
|
|
2274
2283
|
}
|
|
2284
|
+
var CODE_FILE_PATH_ATTR = "code.file.path";
|
|
2275
2285
|
var CODE_FILEPATH_ATTR = "code.filepath";
|
|
2286
|
+
var CODE_LINE_NUMBER_ATTR = "code.line.number";
|
|
2276
2287
|
var CODE_LINENO_ATTR = "code.lineno";
|
|
2288
|
+
var CODE_FUNCTION_NAME_ATTR = "code.function.name";
|
|
2277
2289
|
var CODE_FUNCTION_ATTR = "code.function";
|
|
2290
|
+
function codeFilepathOf(attrs) {
|
|
2291
|
+
const stable = attrs[CODE_FILE_PATH_ATTR];
|
|
2292
|
+
if (typeof stable === "string" && stable.length > 0) return stable;
|
|
2293
|
+
const prior = attrs[CODE_FILEPATH_ATTR];
|
|
2294
|
+
return typeof prior === "string" && prior.length > 0 ? prior : void 0;
|
|
2295
|
+
}
|
|
2296
|
+
function codeLinenoOf(attrs) {
|
|
2297
|
+
const stable = attrs[CODE_LINE_NUMBER_ATTR];
|
|
2298
|
+
if (typeof stable === "number" && Number.isFinite(stable)) return stable;
|
|
2299
|
+
const prior = attrs[CODE_LINENO_ATTR];
|
|
2300
|
+
return typeof prior === "number" && Number.isFinite(prior) ? prior : void 0;
|
|
2301
|
+
}
|
|
2302
|
+
function codeFunctionOf(attrs) {
|
|
2303
|
+
const stable = attrs[CODE_FUNCTION_NAME_ATTR];
|
|
2304
|
+
if (typeof stable === "string" && stable.length > 0) return stable;
|
|
2305
|
+
const prior = attrs[CODE_FUNCTION_ATTR];
|
|
2306
|
+
return typeof prior === "string" && prior.length > 0 ? prior : void 0;
|
|
2307
|
+
}
|
|
2278
2308
|
function toPosix(p) {
|
|
2279
2309
|
return p.split("\\").join("/");
|
|
2280
2310
|
}
|
|
@@ -2352,10 +2382,9 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
2352
2382
|
}
|
|
2353
2383
|
}
|
|
2354
2384
|
function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
2355
|
-
const filepath = span.attributes
|
|
2356
|
-
if (
|
|
2357
|
-
|
|
2358
|
-
let line = typeof linenoRaw === "number" && Number.isFinite(linenoRaw) ? linenoRaw : void 0;
|
|
2385
|
+
const filepath = codeFilepathOf(span.attributes);
|
|
2386
|
+
if (filepath === void 0) return null;
|
|
2387
|
+
let line = codeLinenoOf(span.attributes);
|
|
2359
2388
|
const abs = toPosix(filepath).replace(/^file:\/\//, "");
|
|
2360
2389
|
const resolved = resolveDistToSrc(abs, line);
|
|
2361
2390
|
let effectivePath = filepath;
|
|
@@ -2370,8 +2399,7 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
|
2370
2399
|
if (!resolved && abs.endsWith(".js") && relPath.startsWith("dist/") && serviceNode?.name) {
|
|
2371
2400
|
warnNoSourceMaps(serviceNode.name);
|
|
2372
2401
|
}
|
|
2373
|
-
const
|
|
2374
|
-
const fn = typeof fnRaw === "string" && fnRaw.length > 0 ? fnRaw : void 0;
|
|
2402
|
+
const fn = codeFunctionOf(span.attributes);
|
|
2375
2403
|
return {
|
|
2376
2404
|
relPath,
|
|
2377
2405
|
...line !== void 0 ? { line } : {},
|
|
@@ -2953,6 +2981,18 @@ async function handleSpan(ctx, span) {
|
|
|
2953
2981
|
callSiteEvidence
|
|
2954
2982
|
);
|
|
2955
2983
|
}
|
|
2984
|
+
if (span.dbTable) {
|
|
2985
|
+
const tableId = ensureInfraNode(ctx.graph, "sql-table", span.dbTable, "self");
|
|
2986
|
+
upsertObservedEdge(
|
|
2987
|
+
ctx.graph,
|
|
2988
|
+
import_types3.EdgeType.CALLS,
|
|
2989
|
+
observedSource(),
|
|
2990
|
+
tableId,
|
|
2991
|
+
ts,
|
|
2992
|
+
isError,
|
|
2993
|
+
callSiteEvidence
|
|
2994
|
+
);
|
|
2995
|
+
}
|
|
2956
2996
|
}
|
|
2957
2997
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
2958
2998
|
const targetId = ensureMessagingDestinationNode(
|
|
@@ -4132,14 +4172,14 @@ function buildServiceHostIndex(services) {
|
|
|
4132
4172
|
}
|
|
4133
4173
|
async function walkSourceFiles(dir) {
|
|
4134
4174
|
const out = [];
|
|
4135
|
-
async function
|
|
4175
|
+
async function walk4(current) {
|
|
4136
4176
|
const entries = await import_node_fs11.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
4137
4177
|
for (const entry2 of entries) {
|
|
4138
4178
|
const full = import_node_path11.default.join(current, entry2.name);
|
|
4139
4179
|
if (entry2.isDirectory()) {
|
|
4140
4180
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
4141
4181
|
if (await isPythonVenvDir(full)) continue;
|
|
4142
|
-
await
|
|
4182
|
+
await walk4(full);
|
|
4143
4183
|
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path11.default.extname(entry2.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
4144
4184
|
// would attribute our instrumentation imports to the user's service.
|
|
4145
4185
|
!isNeatAuthoredSourceFile(entry2.name)) {
|
|
@@ -4147,7 +4187,7 @@ async function walkSourceFiles(dir) {
|
|
|
4147
4187
|
}
|
|
4148
4188
|
}
|
|
4149
4189
|
}
|
|
4150
|
-
await
|
|
4190
|
+
await walk4(dir);
|
|
4151
4191
|
return out;
|
|
4152
4192
|
}
|
|
4153
4193
|
async function loadSourceFiles(dir) {
|
|
@@ -5297,20 +5337,20 @@ var import_node_path22 = __toESM(require("path"), 1);
|
|
|
5297
5337
|
var import_types10 = require("@neat.is/types");
|
|
5298
5338
|
async function walkConfigFiles(dir) {
|
|
5299
5339
|
const out = [];
|
|
5300
|
-
async function
|
|
5340
|
+
async function walk4(current) {
|
|
5301
5341
|
const entries = await import_node_fs15.promises.readdir(current, { withFileTypes: true });
|
|
5302
5342
|
for (const entry2 of entries) {
|
|
5303
5343
|
const full = import_node_path22.default.join(current, entry2.name);
|
|
5304
5344
|
if (entry2.isDirectory()) {
|
|
5305
5345
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
5306
5346
|
if (await isPythonVenvDir(full)) continue;
|
|
5307
|
-
await
|
|
5347
|
+
await walk4(full);
|
|
5308
5348
|
} else if (entry2.isFile() && isConfigFile(entry2.name).match) {
|
|
5309
5349
|
out.push(full);
|
|
5310
5350
|
}
|
|
5311
5351
|
}
|
|
5312
5352
|
}
|
|
5313
|
-
await
|
|
5353
|
+
await walk4(dir);
|
|
5314
5354
|
return out;
|
|
5315
5355
|
}
|
|
5316
5356
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -5363,6 +5403,7 @@ init_cjs_shims();
|
|
|
5363
5403
|
var import_node_path23 = __toESM(require("path"), 1);
|
|
5364
5404
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
5365
5405
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5406
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
5366
5407
|
var import_types11 = require("@neat.is/types");
|
|
5367
5408
|
var PARSE_CHUNK2 = 16384;
|
|
5368
5409
|
function parseSource2(parser, source) {
|
|
@@ -5375,6 +5416,11 @@ function makeJsParser2() {
|
|
|
5375
5416
|
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
5376
5417
|
return p;
|
|
5377
5418
|
}
|
|
5419
|
+
function makePyParser2() {
|
|
5420
|
+
const p = new import_tree_sitter2.default();
|
|
5421
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
5422
|
+
return p;
|
|
5423
|
+
}
|
|
5378
5424
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
5379
5425
|
"get",
|
|
5380
5426
|
"post",
|
|
@@ -5387,6 +5433,7 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
5387
5433
|
]);
|
|
5388
5434
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
5389
5435
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
5436
|
+
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
5390
5437
|
function canonicalizeTemplate(raw) {
|
|
5391
5438
|
let p = raw.split("?")[0].split("#")[0];
|
|
5392
5439
|
if (!p.startsWith("/")) p = "/" + p;
|
|
@@ -5614,8 +5661,102 @@ function nextRoutesFromFile(source, relFile, parser) {
|
|
|
5614
5661
|
}
|
|
5615
5662
|
return [];
|
|
5616
5663
|
}
|
|
5664
|
+
function pyStaticStringText(node) {
|
|
5665
|
+
if (node.type !== "string") return null;
|
|
5666
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
5667
|
+
const child = node.namedChild(i);
|
|
5668
|
+
if (child?.type === "interpolation") return null;
|
|
5669
|
+
if (child?.type === "string_content") return child.text;
|
|
5670
|
+
}
|
|
5671
|
+
return "";
|
|
5672
|
+
}
|
|
5673
|
+
function keywordArrayStrings(argsNode, key) {
|
|
5674
|
+
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
5675
|
+
const arg = argsNode.namedChild(i);
|
|
5676
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5677
|
+
if (arg.childForFieldName("name")?.text !== key) continue;
|
|
5678
|
+
const val = arg.childForFieldName("value");
|
|
5679
|
+
if (!val || val.type !== "list") return [];
|
|
5680
|
+
const out = [];
|
|
5681
|
+
for (let j = 0; j < val.namedChildCount; j++) {
|
|
5682
|
+
const el = val.namedChild(j);
|
|
5683
|
+
if (el?.type === "string") {
|
|
5684
|
+
const s = pyStaticStringText(el);
|
|
5685
|
+
if (s) out.push(s);
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
return out;
|
|
5689
|
+
}
|
|
5690
|
+
return [];
|
|
5691
|
+
}
|
|
5692
|
+
function collectApiRouterPrefixes(root) {
|
|
5693
|
+
const prefixes = /* @__PURE__ */ new Map();
|
|
5694
|
+
walk(root, (node) => {
|
|
5695
|
+
if (node.type !== "assignment") return;
|
|
5696
|
+
const right = node.childForFieldName("right");
|
|
5697
|
+
if (!right || right.type !== "call") return;
|
|
5698
|
+
const fn = right.childForFieldName("function");
|
|
5699
|
+
if (!fn) return;
|
|
5700
|
+
const ctor = fn.type === "attribute" ? fn.childForFieldName("attribute")?.text : fn.text;
|
|
5701
|
+
if (ctor !== "APIRouter") return;
|
|
5702
|
+
const left = node.childForFieldName("left");
|
|
5703
|
+
if (!left || left.type !== "identifier") return;
|
|
5704
|
+
const args = right.childForFieldName("arguments");
|
|
5705
|
+
if (!args) return;
|
|
5706
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
5707
|
+
const arg = args.namedChild(i);
|
|
5708
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5709
|
+
if (arg.childForFieldName("name")?.text !== "prefix") continue;
|
|
5710
|
+
const val = arg.childForFieldName("value");
|
|
5711
|
+
const p = val ? pyStaticStringText(val) : null;
|
|
5712
|
+
if (p !== null) prefixes.set(left.text, p);
|
|
5713
|
+
}
|
|
5714
|
+
});
|
|
5715
|
+
return prefixes;
|
|
5716
|
+
}
|
|
5717
|
+
function fastapiRoutesFromSource(source, parser) {
|
|
5718
|
+
const tree = parseSource2(parser, source);
|
|
5719
|
+
const prefixes = collectApiRouterPrefixes(tree.rootNode);
|
|
5720
|
+
const out = [];
|
|
5721
|
+
walk(tree.rootNode, (node) => {
|
|
5722
|
+
if (node.type !== "decorator") return;
|
|
5723
|
+
const call = node.namedChild(0);
|
|
5724
|
+
if (!call || call.type !== "call") return;
|
|
5725
|
+
const fn = call.childForFieldName("function");
|
|
5726
|
+
if (!fn || fn.type !== "attribute") return;
|
|
5727
|
+
const method = fn.childForFieldName("attribute")?.text?.toLowerCase();
|
|
5728
|
+
if (!method) return;
|
|
5729
|
+
const isVerb = FASTAPI_METHODS.has(method);
|
|
5730
|
+
if (!isVerb && method !== "api_route") return;
|
|
5731
|
+
const args = call.childForFieldName("arguments");
|
|
5732
|
+
const first = args?.namedChild(0);
|
|
5733
|
+
if (!first || first.type !== "string") return;
|
|
5734
|
+
const rawPath = pyStaticStringText(first);
|
|
5735
|
+
if (rawPath === null || !rawPath.startsWith("/")) return;
|
|
5736
|
+
const obj = fn.childForFieldName("object")?.text;
|
|
5737
|
+
const prefix = obj ? prefixes.get(obj) ?? "" : "";
|
|
5738
|
+
const pathTemplate = canonicalizeTemplate(prefix + rawPath);
|
|
5739
|
+
const line = node.startPosition.row + 1;
|
|
5740
|
+
if (isVerb) {
|
|
5741
|
+
out.push({ method: method.toUpperCase(), pathTemplate, line, framework: "fastapi" });
|
|
5742
|
+
return;
|
|
5743
|
+
}
|
|
5744
|
+
const methods = keywordArrayStrings(args, "methods");
|
|
5745
|
+
const list = methods.length > 0 ? methods : ["ALL"];
|
|
5746
|
+
for (const m of list) {
|
|
5747
|
+
out.push({
|
|
5748
|
+
method: m === "ALL" ? "ALL" : m.toUpperCase(),
|
|
5749
|
+
pathTemplate,
|
|
5750
|
+
line,
|
|
5751
|
+
framework: "fastapi"
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
});
|
|
5755
|
+
return out;
|
|
5756
|
+
}
|
|
5617
5757
|
async function addRoutes(graph, services) {
|
|
5618
5758
|
const jsParser = makeJsParser2();
|
|
5759
|
+
const pyParser = makePyParser2();
|
|
5619
5760
|
let nodesAdded = 0;
|
|
5620
5761
|
let edgesAdded = 0;
|
|
5621
5762
|
for (const service of services) {
|
|
@@ -5627,15 +5768,20 @@ async function addRoutes(graph, services) {
|
|
|
5627
5768
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5628
5769
|
const hasHono = deps["hono"] !== void 0;
|
|
5629
5770
|
const hasNext = deps["next"] !== void 0;
|
|
5630
|
-
|
|
5771
|
+
const hasFastapi = deps["fastapi"] !== void 0;
|
|
5772
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasFastapi) continue;
|
|
5631
5773
|
const files = await loadSourceFiles(service.dir);
|
|
5632
5774
|
for (const file of files) {
|
|
5633
5775
|
if (isTestPath(file.path)) continue;
|
|
5634
|
-
|
|
5776
|
+
const ext = import_node_path23.default.extname(file.path);
|
|
5777
|
+
const isPy = ext === ".py";
|
|
5778
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy) continue;
|
|
5635
5779
|
const relFile = toPosix2(import_node_path23.default.relative(service.dir, file.path));
|
|
5636
5780
|
let routes;
|
|
5637
5781
|
try {
|
|
5638
|
-
if (
|
|
5782
|
+
if (isPy) {
|
|
5783
|
+
routes = hasFastapi ? fastapiRoutesFromSource(file.content, pyParser) : [];
|
|
5784
|
+
} else if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5639
5785
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5640
5786
|
} else if (hasExpress || hasFastify || hasHono) {
|
|
5641
5787
|
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
@@ -5731,20 +5877,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
5731
5877
|
}
|
|
5732
5878
|
async function walkProtoFiles(dir) {
|
|
5733
5879
|
const out = [];
|
|
5734
|
-
async function
|
|
5880
|
+
async function walk4(current) {
|
|
5735
5881
|
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
5736
5882
|
for (const entry2 of entries) {
|
|
5737
5883
|
const full = import_node_path24.default.join(current, entry2.name);
|
|
5738
5884
|
if (entry2.isDirectory()) {
|
|
5739
5885
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
5740
5886
|
if (await isPythonVenvDir(full)) continue;
|
|
5741
|
-
await
|
|
5887
|
+
await walk4(full);
|
|
5742
5888
|
} else if (entry2.isFile() && import_node_path24.default.extname(entry2.name) === PROTO_EXTENSION) {
|
|
5743
5889
|
out.push(full);
|
|
5744
5890
|
}
|
|
5745
5891
|
}
|
|
5746
5892
|
}
|
|
5747
|
-
await
|
|
5893
|
+
await walk4(dir);
|
|
5748
5894
|
return out;
|
|
5749
5895
|
}
|
|
5750
5896
|
async function addGrpcMethods(graph, services) {
|
|
@@ -5812,14 +5958,14 @@ async function addGrpcMethods(graph, services) {
|
|
|
5812
5958
|
|
|
5813
5959
|
// src/extract/calls/index.ts
|
|
5814
5960
|
init_cjs_shims();
|
|
5815
|
-
var
|
|
5961
|
+
var import_types22 = require("@neat.is/types");
|
|
5816
5962
|
|
|
5817
5963
|
// src/extract/calls/http.ts
|
|
5818
5964
|
init_cjs_shims();
|
|
5819
5965
|
var import_node_path25 = __toESM(require("path"), 1);
|
|
5820
5966
|
var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
|
|
5821
5967
|
var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5822
|
-
var
|
|
5968
|
+
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
5823
5969
|
var import_types13 = require("@neat.is/types");
|
|
5824
5970
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
5825
5971
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
@@ -5874,14 +6020,14 @@ function makeJsParser3() {
|
|
|
5874
6020
|
p.setLanguage(import_tree_sitter_javascript3.default);
|
|
5875
6021
|
return p;
|
|
5876
6022
|
}
|
|
5877
|
-
function
|
|
6023
|
+
function makePyParser3() {
|
|
5878
6024
|
const p = new import_tree_sitter3.default();
|
|
5879
|
-
p.setLanguage(
|
|
6025
|
+
p.setLanguage(import_tree_sitter_python3.default);
|
|
5880
6026
|
return p;
|
|
5881
6027
|
}
|
|
5882
6028
|
async function addHttpCallEdges(graph, services) {
|
|
5883
6029
|
const jsParser = makeJsParser3();
|
|
5884
|
-
const pyParser =
|
|
6030
|
+
const pyParser = makePyParser3();
|
|
5885
6031
|
const { knownHosts, hostToNodeId } = buildServiceHostIndex(services);
|
|
5886
6032
|
let nodesAdded = 0;
|
|
5887
6033
|
let edgesAdded = 0;
|
|
@@ -6821,15 +6967,130 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
6821
6967
|
return out;
|
|
6822
6968
|
}
|
|
6823
6969
|
|
|
6970
|
+
// src/extract/calls/sqlalchemy.ts
|
|
6971
|
+
init_cjs_shims();
|
|
6972
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
6973
|
+
var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
|
|
6974
|
+
var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
|
|
6975
|
+
var import_types21 = require("@neat.is/types");
|
|
6976
|
+
var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
|
|
6977
|
+
var PARSE_CHUNK5 = 16384;
|
|
6978
|
+
function makePyParser4() {
|
|
6979
|
+
const p = new import_tree_sitter5.default();
|
|
6980
|
+
p.setLanguage(import_tree_sitter_python4.default);
|
|
6981
|
+
return p;
|
|
6982
|
+
}
|
|
6983
|
+
function parseSource5(parser, source) {
|
|
6984
|
+
return parser.parse(
|
|
6985
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK5)
|
|
6986
|
+
);
|
|
6987
|
+
}
|
|
6988
|
+
function flaskSqlalchemyTableName(className) {
|
|
6989
|
+
return className.replace(/((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))/g, "_$1").toLowerCase().replace(/^_+/, "");
|
|
6990
|
+
}
|
|
6991
|
+
function namedChildren(node) {
|
|
6992
|
+
const out = [];
|
|
6993
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6994
|
+
const c = node.namedChild(i);
|
|
6995
|
+
if (c) out.push(c);
|
|
6996
|
+
}
|
|
6997
|
+
return out;
|
|
6998
|
+
}
|
|
6999
|
+
function pyStaticStringText2(node) {
|
|
7000
|
+
if (node.type !== "string") return null;
|
|
7001
|
+
for (const child of namedChildren(node)) {
|
|
7002
|
+
if (child.type === "interpolation") return null;
|
|
7003
|
+
if (child.type === "string_content") return child.text;
|
|
7004
|
+
}
|
|
7005
|
+
return "";
|
|
7006
|
+
}
|
|
7007
|
+
function explicitTablename(body) {
|
|
7008
|
+
for (const stmt of namedChildren(body)) {
|
|
7009
|
+
if (stmt.type !== "expression_statement") continue;
|
|
7010
|
+
const assign = stmt.namedChild(0);
|
|
7011
|
+
if (assign?.type !== "assignment") continue;
|
|
7012
|
+
if (assign.childForFieldName("left")?.text !== "__tablename__") continue;
|
|
7013
|
+
const right = assign.childForFieldName("right");
|
|
7014
|
+
if (right?.type === "string") {
|
|
7015
|
+
const s = pyStaticStringText2(right);
|
|
7016
|
+
return s ? { name: s } : "computed";
|
|
7017
|
+
}
|
|
7018
|
+
return "computed";
|
|
7019
|
+
}
|
|
7020
|
+
return null;
|
|
7021
|
+
}
|
|
7022
|
+
function extendsFlaskModel(cls) {
|
|
7023
|
+
const supers = cls.childForFieldName("superclasses");
|
|
7024
|
+
if (!supers) return false;
|
|
7025
|
+
for (const a of namedChildren(supers)) {
|
|
7026
|
+
const t = a.text;
|
|
7027
|
+
if (t === "db.Model" || t === "Model" || t.endsWith(".Model")) return true;
|
|
7028
|
+
}
|
|
7029
|
+
return false;
|
|
7030
|
+
}
|
|
7031
|
+
function walk3(node, visit) {
|
|
7032
|
+
visit(node);
|
|
7033
|
+
for (const c of namedChildren(node)) walk3(c, visit);
|
|
7034
|
+
}
|
|
7035
|
+
function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
7036
|
+
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
7037
|
+
const tree = parseSource5(makePyParser4(), file.content);
|
|
7038
|
+
const out = [];
|
|
7039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7040
|
+
const push = (name, line) => {
|
|
7041
|
+
if (seen.has(name)) return;
|
|
7042
|
+
seen.add(name);
|
|
7043
|
+
out.push({
|
|
7044
|
+
infraId: (0, import_types21.infraId)("sql-table", name),
|
|
7045
|
+
name,
|
|
7046
|
+
kind: "sql-table",
|
|
7047
|
+
edgeType: "CALLS",
|
|
7048
|
+
confidenceKind: "verified-call-site",
|
|
7049
|
+
evidence: {
|
|
7050
|
+
file: import_node_path33.default.relative(serviceDir, file.path),
|
|
7051
|
+
line,
|
|
7052
|
+
snippet: snippet(file.content, line)
|
|
7053
|
+
}
|
|
7054
|
+
});
|
|
7055
|
+
};
|
|
7056
|
+
walk3(tree.rootNode, (node) => {
|
|
7057
|
+
if (node.type === "class_definition") {
|
|
7058
|
+
const body = node.childForFieldName("body");
|
|
7059
|
+
const nameNode = node.childForFieldName("name");
|
|
7060
|
+
if (!body || !nameNode) return;
|
|
7061
|
+
const line = node.startPosition.row + 1;
|
|
7062
|
+
const explicit = explicitTablename(body);
|
|
7063
|
+
if (explicit === "computed") return;
|
|
7064
|
+
if (explicit) {
|
|
7065
|
+
push(explicit.name, line);
|
|
7066
|
+
return;
|
|
7067
|
+
}
|
|
7068
|
+
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line);
|
|
7069
|
+
return;
|
|
7070
|
+
}
|
|
7071
|
+
if (node.type === "call") {
|
|
7072
|
+
const fn = node.childForFieldName("function");
|
|
7073
|
+
const fnText = fn?.text;
|
|
7074
|
+
if (fnText !== "Table" && fnText !== "sa.Table" && fnText !== "sqlalchemy.Table") return;
|
|
7075
|
+
const first = node.childForFieldName("arguments")?.namedChild(0);
|
|
7076
|
+
if (first?.type === "string") {
|
|
7077
|
+
const s = pyStaticStringText2(first);
|
|
7078
|
+
if (s) push(s, node.startPosition.row + 1);
|
|
7079
|
+
}
|
|
7080
|
+
}
|
|
7081
|
+
});
|
|
7082
|
+
return out;
|
|
7083
|
+
}
|
|
7084
|
+
|
|
6824
7085
|
// src/extract/calls/index.ts
|
|
6825
7086
|
function edgeTypeFromEndpoint(ep) {
|
|
6826
7087
|
switch (ep.edgeType) {
|
|
6827
7088
|
case "PUBLISHES_TO":
|
|
6828
|
-
return
|
|
7089
|
+
return import_types22.EdgeType.PUBLISHES_TO;
|
|
6829
7090
|
case "CONSUMES_FROM":
|
|
6830
|
-
return
|
|
7091
|
+
return import_types22.EdgeType.CONSUMES_FROM;
|
|
6831
7092
|
default:
|
|
6832
|
-
return
|
|
7093
|
+
return import_types22.EdgeType.CALLS;
|
|
6833
7094
|
}
|
|
6834
7095
|
}
|
|
6835
7096
|
function isAwsKind(kind) {
|
|
@@ -6853,6 +7114,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6853
7114
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
6854
7115
|
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
6855
7116
|
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
7117
|
+
endpoints.push(...sqlalchemyEndpointsFromFile(maskedFile, service.dir));
|
|
6856
7118
|
}
|
|
6857
7119
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
6858
7120
|
if (endpoints.length === 0) continue;
|
|
@@ -6861,7 +7123,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6861
7123
|
if (!graph.hasNode(ep.infraId)) {
|
|
6862
7124
|
const node = {
|
|
6863
7125
|
id: ep.infraId,
|
|
6864
|
-
type:
|
|
7126
|
+
type: import_types22.NodeType.InfraNode,
|
|
6865
7127
|
name: ep.name,
|
|
6866
7128
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
6867
7129
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -6873,7 +7135,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6873
7135
|
nodesAdded++;
|
|
6874
7136
|
}
|
|
6875
7137
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
6876
|
-
const confidence = (0,
|
|
7138
|
+
const confidence = (0, import_types22.confidenceForExtracted)(ep.confidenceKind);
|
|
6877
7139
|
const relFile = toPosix2(ep.evidence.file);
|
|
6878
7140
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
6879
7141
|
graph,
|
|
@@ -6883,7 +7145,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6883
7145
|
);
|
|
6884
7146
|
nodesAdded += n;
|
|
6885
7147
|
edgesAdded += e;
|
|
6886
|
-
if (!(0,
|
|
7148
|
+
if (!(0, import_types22.passesExtractedFloor)(confidence)) {
|
|
6887
7149
|
noteExtractedDropped({
|
|
6888
7150
|
source: fileNodeId,
|
|
6889
7151
|
target: ep.infraId,
|
|
@@ -6903,7 +7165,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6903
7165
|
source: fileNodeId,
|
|
6904
7166
|
target: ep.infraId,
|
|
6905
7167
|
type: edgeType,
|
|
6906
|
-
provenance:
|
|
7168
|
+
provenance: import_types22.Provenance.EXTRACTED,
|
|
6907
7169
|
confidence,
|
|
6908
7170
|
evidence: ep.evidence
|
|
6909
7171
|
};
|
|
@@ -6929,16 +7191,16 @@ init_cjs_shims();
|
|
|
6929
7191
|
|
|
6930
7192
|
// src/extract/infra/docker-compose.ts
|
|
6931
7193
|
init_cjs_shims();
|
|
6932
|
-
var
|
|
6933
|
-
var
|
|
7194
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
7195
|
+
var import_types24 = require("@neat.is/types");
|
|
6934
7196
|
|
|
6935
7197
|
// src/extract/infra/shared.ts
|
|
6936
7198
|
init_cjs_shims();
|
|
6937
|
-
var
|
|
7199
|
+
var import_types23 = require("@neat.is/types");
|
|
6938
7200
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
6939
7201
|
return {
|
|
6940
|
-
id: (0,
|
|
6941
|
-
type:
|
|
7202
|
+
id: (0, import_types23.infraId)(kind, name),
|
|
7203
|
+
type: import_types23.NodeType.InfraNode,
|
|
6942
7204
|
name,
|
|
6943
7205
|
provider,
|
|
6944
7206
|
kind,
|
|
@@ -6982,8 +7244,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
6982
7244
|
source: anchorId,
|
|
6983
7245
|
target: node.id,
|
|
6984
7246
|
type: edgeType,
|
|
6985
|
-
provenance:
|
|
6986
|
-
confidence: (0,
|
|
7247
|
+
provenance: import_types23.Provenance.EXTRACTED,
|
|
7248
|
+
confidence: (0, import_types23.confidenceForExtracted)("structural"),
|
|
6987
7249
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6988
7250
|
};
|
|
6989
7251
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7000,7 +7262,7 @@ function dependsOnList(value) {
|
|
|
7000
7262
|
}
|
|
7001
7263
|
function serviceNameToServiceNode(name, services) {
|
|
7002
7264
|
for (const s of services) {
|
|
7003
|
-
if (s.node.name === name ||
|
|
7265
|
+
if (s.node.name === name || import_node_path34.default.basename(s.dir) === name) return s.node.id;
|
|
7004
7266
|
}
|
|
7005
7267
|
return null;
|
|
7006
7268
|
}
|
|
@@ -7009,7 +7271,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7009
7271
|
let edgesAdded = 0;
|
|
7010
7272
|
let composePath = null;
|
|
7011
7273
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
7012
|
-
const abs =
|
|
7274
|
+
const abs = import_node_path34.default.join(scanPath, name);
|
|
7013
7275
|
if (await exists(abs)) {
|
|
7014
7276
|
composePath = abs;
|
|
7015
7277
|
break;
|
|
@@ -7022,13 +7284,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7022
7284
|
} catch (err) {
|
|
7023
7285
|
recordExtractionError(
|
|
7024
7286
|
"infra docker-compose",
|
|
7025
|
-
|
|
7287
|
+
import_node_path34.default.relative(scanPath, composePath),
|
|
7026
7288
|
err
|
|
7027
7289
|
);
|
|
7028
7290
|
return { nodesAdded, edgesAdded };
|
|
7029
7291
|
}
|
|
7030
7292
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
7031
|
-
const evidenceFile =
|
|
7293
|
+
const evidenceFile = import_node_path34.default.relative(scanPath, composePath).split(import_node_path34.default.sep).join("/");
|
|
7032
7294
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
7033
7295
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
7034
7296
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -7050,15 +7312,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7050
7312
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
7051
7313
|
const targetId = composeNameToNodeId.get(dep);
|
|
7052
7314
|
if (!targetId) continue;
|
|
7053
|
-
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId,
|
|
7315
|
+
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId, import_types24.EdgeType.DEPENDS_ON);
|
|
7054
7316
|
if (graph.hasEdge(edgeId)) continue;
|
|
7055
7317
|
const edge = {
|
|
7056
7318
|
id: edgeId,
|
|
7057
7319
|
source: sourceId,
|
|
7058
7320
|
target: targetId,
|
|
7059
|
-
type:
|
|
7060
|
-
provenance:
|
|
7061
|
-
confidence: (0,
|
|
7321
|
+
type: import_types24.EdgeType.DEPENDS_ON,
|
|
7322
|
+
provenance: import_types24.Provenance.EXTRACTED,
|
|
7323
|
+
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
7062
7324
|
evidence: { file: evidenceFile }
|
|
7063
7325
|
};
|
|
7064
7326
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7070,9 +7332,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7070
7332
|
|
|
7071
7333
|
// src/extract/infra/dockerfile.ts
|
|
7072
7334
|
init_cjs_shims();
|
|
7073
|
-
var
|
|
7335
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
7074
7336
|
var import_node_fs17 = require("fs");
|
|
7075
|
-
var
|
|
7337
|
+
var import_types25 = require("@neat.is/types");
|
|
7076
7338
|
function readDockerfile(content) {
|
|
7077
7339
|
let image = null;
|
|
7078
7340
|
const ports = [];
|
|
@@ -7101,7 +7363,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7101
7363
|
let nodesAdded = 0;
|
|
7102
7364
|
let edgesAdded = 0;
|
|
7103
7365
|
for (const service of services) {
|
|
7104
|
-
const dockerfilePath =
|
|
7366
|
+
const dockerfilePath = import_node_path35.default.join(service.dir, "Dockerfile");
|
|
7105
7367
|
if (!await exists(dockerfilePath)) continue;
|
|
7106
7368
|
let content;
|
|
7107
7369
|
try {
|
|
@@ -7109,7 +7371,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7109
7371
|
} catch (err) {
|
|
7110
7372
|
recordExtractionError(
|
|
7111
7373
|
"infra dockerfile",
|
|
7112
|
-
|
|
7374
|
+
import_node_path35.default.relative(scanPath, dockerfilePath),
|
|
7113
7375
|
err
|
|
7114
7376
|
);
|
|
7115
7377
|
continue;
|
|
@@ -7121,8 +7383,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7121
7383
|
graph.addNode(node.id, node);
|
|
7122
7384
|
nodesAdded++;
|
|
7123
7385
|
}
|
|
7124
|
-
const relDockerfile = toPosix2(
|
|
7125
|
-
const evidenceFile = toPosix2(
|
|
7386
|
+
const relDockerfile = toPosix2(import_node_path35.default.relative(service.dir, dockerfilePath));
|
|
7387
|
+
const evidenceFile = toPosix2(import_node_path35.default.relative(scanPath, dockerfilePath));
|
|
7126
7388
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7127
7389
|
graph,
|
|
7128
7390
|
service.pkg.name,
|
|
@@ -7131,15 +7393,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7131
7393
|
);
|
|
7132
7394
|
nodesAdded += fn;
|
|
7133
7395
|
edgesAdded += fe;
|
|
7134
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
7396
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types25.EdgeType.RUNS_ON);
|
|
7135
7397
|
if (!graph.hasEdge(edgeId)) {
|
|
7136
7398
|
const edge = {
|
|
7137
7399
|
id: edgeId,
|
|
7138
7400
|
source: fileNodeId,
|
|
7139
7401
|
target: node.id,
|
|
7140
|
-
type:
|
|
7141
|
-
provenance:
|
|
7142
|
-
confidence: (0,
|
|
7402
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
7403
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7404
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7143
7405
|
evidence: {
|
|
7144
7406
|
file: evidenceFile,
|
|
7145
7407
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -7154,15 +7416,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7154
7416
|
graph.addNode(portNode.id, portNode);
|
|
7155
7417
|
nodesAdded++;
|
|
7156
7418
|
}
|
|
7157
|
-
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id,
|
|
7419
|
+
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id, import_types25.EdgeType.CONNECTS_TO);
|
|
7158
7420
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
7159
7421
|
const portEdge = {
|
|
7160
7422
|
id: portEdgeId,
|
|
7161
7423
|
source: fileNodeId,
|
|
7162
7424
|
target: portNode.id,
|
|
7163
|
-
type:
|
|
7164
|
-
provenance:
|
|
7165
|
-
confidence: (0,
|
|
7425
|
+
type: import_types25.EdgeType.CONNECTS_TO,
|
|
7426
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7427
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7166
7428
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
7167
7429
|
};
|
|
7168
7430
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -7175,8 +7437,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7175
7437
|
// src/extract/infra/terraform.ts
|
|
7176
7438
|
init_cjs_shims();
|
|
7177
7439
|
var import_node_fs18 = require("fs");
|
|
7178
|
-
var
|
|
7179
|
-
var
|
|
7440
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
7441
|
+
var import_types26 = require("@neat.is/types");
|
|
7180
7442
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
7181
7443
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
7182
7444
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -7186,11 +7448,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
7186
7448
|
for (const entry2 of entries) {
|
|
7187
7449
|
if (entry2.isDirectory()) {
|
|
7188
7450
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
7189
|
-
const child =
|
|
7451
|
+
const child = import_node_path36.default.join(start, entry2.name);
|
|
7190
7452
|
if (await isPythonVenvDir(child)) continue;
|
|
7191
7453
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
7192
7454
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
7193
|
-
out.push(
|
|
7455
|
+
out.push(import_node_path36.default.join(start, entry2.name));
|
|
7194
7456
|
}
|
|
7195
7457
|
}
|
|
7196
7458
|
return out;
|
|
@@ -7222,7 +7484,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7222
7484
|
const files = await walkTfFiles(scanPath);
|
|
7223
7485
|
for (const file of files) {
|
|
7224
7486
|
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
7225
|
-
const evidenceFile = toPosix2(
|
|
7487
|
+
const evidenceFile = toPosix2(import_node_path36.default.relative(scanPath, file));
|
|
7226
7488
|
const resources = [];
|
|
7227
7489
|
const byKey = /* @__PURE__ */ new Map();
|
|
7228
7490
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -7257,16 +7519,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7257
7519
|
if (!target) continue;
|
|
7258
7520
|
if (seen.has(target.nodeId)) continue;
|
|
7259
7521
|
seen.add(target.nodeId);
|
|
7260
|
-
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
7522
|
+
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId, import_types26.EdgeType.DEPENDS_ON);
|
|
7261
7523
|
if (graph.hasEdge(edgeId)) continue;
|
|
7262
7524
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
7263
7525
|
const edge = {
|
|
7264
7526
|
id: edgeId,
|
|
7265
7527
|
source: resource.nodeId,
|
|
7266
7528
|
target: target.nodeId,
|
|
7267
|
-
type:
|
|
7268
|
-
provenance:
|
|
7269
|
-
confidence: (0,
|
|
7529
|
+
type: import_types26.EdgeType.DEPENDS_ON,
|
|
7530
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7531
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7270
7532
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
7271
7533
|
};
|
|
7272
7534
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7280,7 +7542,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7280
7542
|
// src/extract/infra/k8s.ts
|
|
7281
7543
|
init_cjs_shims();
|
|
7282
7544
|
var import_node_fs19 = require("fs");
|
|
7283
|
-
var
|
|
7545
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7284
7546
|
var import_yaml3 = require("yaml");
|
|
7285
7547
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
7286
7548
|
Service: "k8s-service",
|
|
@@ -7298,11 +7560,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
7298
7560
|
for (const entry2 of entries) {
|
|
7299
7561
|
if (entry2.isDirectory()) {
|
|
7300
7562
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
7301
|
-
const child =
|
|
7563
|
+
const child = import_node_path37.default.join(start, entry2.name);
|
|
7302
7564
|
if (await isPythonVenvDir(child)) continue;
|
|
7303
7565
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
7304
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
7305
|
-
out.push(
|
|
7566
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path37.default.extname(entry2.name))) {
|
|
7567
|
+
out.push(import_node_path37.default.join(start, entry2.name));
|
|
7306
7568
|
}
|
|
7307
7569
|
}
|
|
7308
7570
|
return out;
|
|
@@ -7336,13 +7598,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
7336
7598
|
// src/extract/infra/cloudflare.ts
|
|
7337
7599
|
init_cjs_shims();
|
|
7338
7600
|
var import_node_fs20 = require("fs");
|
|
7339
|
-
var
|
|
7601
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7340
7602
|
var import_smol_toml2 = require("smol-toml");
|
|
7341
|
-
var
|
|
7603
|
+
var import_types27 = require("@neat.is/types");
|
|
7342
7604
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
7343
7605
|
async function readWranglerConfig(dir) {
|
|
7344
7606
|
for (const filename of WRANGLER_FILENAMES) {
|
|
7345
|
-
const abs =
|
|
7607
|
+
const abs = import_node_path38.default.join(dir, filename);
|
|
7346
7608
|
if (!await exists(abs)) continue;
|
|
7347
7609
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
7348
7610
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7386,8 +7648,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
7386
7648
|
source: anchorId,
|
|
7387
7649
|
target: node.id,
|
|
7388
7650
|
type: edgeType,
|
|
7389
|
-
provenance:
|
|
7390
|
-
confidence: (0,
|
|
7651
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7652
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7391
7653
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7392
7654
|
};
|
|
7393
7655
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7405,11 +7667,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7405
7667
|
try {
|
|
7406
7668
|
read = await readWranglerConfig(service.dir);
|
|
7407
7669
|
} catch (err) {
|
|
7408
|
-
recordExtractionError("infra cloudflare",
|
|
7670
|
+
recordExtractionError("infra cloudflare", import_node_path38.default.relative(scanPath, service.dir), err);
|
|
7409
7671
|
continue;
|
|
7410
7672
|
}
|
|
7411
7673
|
if (!read || !read.config.name) continue;
|
|
7412
|
-
const evidenceFile = toPosix2(
|
|
7674
|
+
const evidenceFile = toPosix2(import_node_path38.default.relative(scanPath, import_node_path38.default.join(service.dir, read.relFile)));
|
|
7413
7675
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
7414
7676
|
}
|
|
7415
7677
|
for (const worker of discovered) {
|
|
@@ -7421,7 +7683,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7421
7683
|
}
|
|
7422
7684
|
let anchorId = service.node.id;
|
|
7423
7685
|
if (config.main) {
|
|
7424
|
-
const entryRelPath = toPosix2(
|
|
7686
|
+
const entryRelPath = toPosix2(import_node_path38.default.normalize(config.main));
|
|
7425
7687
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7426
7688
|
graph,
|
|
7427
7689
|
service.pkg.name,
|
|
@@ -7448,15 +7710,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7448
7710
|
nodesAdded++;
|
|
7449
7711
|
}
|
|
7450
7712
|
if (runtimeNode.id !== anchorId) {
|
|
7451
|
-
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
7713
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types27.EdgeType.RUNS_ON);
|
|
7452
7714
|
if (!graph.hasEdge(runsOnId)) {
|
|
7453
7715
|
const edge = {
|
|
7454
7716
|
id: runsOnId,
|
|
7455
7717
|
source: anchorId,
|
|
7456
7718
|
target: runtimeNode.id,
|
|
7457
|
-
type:
|
|
7458
|
-
provenance:
|
|
7459
|
-
confidence: (0,
|
|
7719
|
+
type: import_types27.EdgeType.RUNS_ON,
|
|
7720
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7721
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7460
7722
|
evidence: {
|
|
7461
7723
|
file: evidenceFile,
|
|
7462
7724
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -7470,7 +7732,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7470
7732
|
const result = addResourceEdge(
|
|
7471
7733
|
graph,
|
|
7472
7734
|
anchorId,
|
|
7473
|
-
|
|
7735
|
+
import_types27.EdgeType.CONNECTS_TO,
|
|
7474
7736
|
"cloudflare-route",
|
|
7475
7737
|
route,
|
|
7476
7738
|
evidenceFile,
|
|
@@ -7494,7 +7756,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7494
7756
|
const result = addResourceEdge(
|
|
7495
7757
|
graph,
|
|
7496
7758
|
anchorId,
|
|
7497
|
-
|
|
7759
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7498
7760
|
group.kind,
|
|
7499
7761
|
name,
|
|
7500
7762
|
evidenceFile,
|
|
@@ -7508,7 +7770,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7508
7770
|
const result = addResourceEdge(
|
|
7509
7771
|
graph,
|
|
7510
7772
|
anchorId,
|
|
7511
|
-
|
|
7773
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7512
7774
|
"cloudflare-cron",
|
|
7513
7775
|
cron,
|
|
7514
7776
|
evidenceFile,
|
|
@@ -7521,7 +7783,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7521
7783
|
const result = addResourceEdge(
|
|
7522
7784
|
graph,
|
|
7523
7785
|
anchorId,
|
|
7524
|
-
|
|
7786
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7525
7787
|
"cloudflare-env-var",
|
|
7526
7788
|
varName,
|
|
7527
7789
|
evidenceFile,
|
|
@@ -7534,15 +7796,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7534
7796
|
if (!svc.service) continue;
|
|
7535
7797
|
const target = workerIndex.get(svc.service);
|
|
7536
7798
|
if (target && target.anchorId !== anchorId) {
|
|
7537
|
-
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId,
|
|
7799
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types27.EdgeType.CALLS);
|
|
7538
7800
|
if (!graph.hasEdge(edgeId)) {
|
|
7539
7801
|
const edge = {
|
|
7540
7802
|
id: edgeId,
|
|
7541
7803
|
source: anchorId,
|
|
7542
7804
|
target: target.anchorId,
|
|
7543
|
-
type:
|
|
7544
|
-
provenance:
|
|
7545
|
-
confidence: (0,
|
|
7805
|
+
type: import_types27.EdgeType.CALLS,
|
|
7806
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7807
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7546
7808
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
7547
7809
|
};
|
|
7548
7810
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7553,7 +7815,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7553
7815
|
const result = addResourceEdge(
|
|
7554
7816
|
graph,
|
|
7555
7817
|
anchorId,
|
|
7556
|
-
|
|
7818
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7557
7819
|
"cloudflare-service-binding",
|
|
7558
7820
|
svc.service,
|
|
7559
7821
|
evidenceFile,
|
|
@@ -7569,12 +7831,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7569
7831
|
// src/extract/infra/vercel.ts
|
|
7570
7832
|
init_cjs_shims();
|
|
7571
7833
|
var import_node_fs21 = require("fs");
|
|
7572
|
-
var
|
|
7573
|
-
var
|
|
7834
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7835
|
+
var import_types28 = require("@neat.is/types");
|
|
7574
7836
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
7575
7837
|
async function readVercelConfig(dir) {
|
|
7576
7838
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
7577
|
-
const abs =
|
|
7839
|
+
const abs = import_node_path39.default.join(dir, filename);
|
|
7578
7840
|
if (!await exists(abs)) continue;
|
|
7579
7841
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
7580
7842
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7583,7 +7845,7 @@ async function readVercelConfig(dir) {
|
|
|
7583
7845
|
return null;
|
|
7584
7846
|
}
|
|
7585
7847
|
async function readLinkedProjectName(dir) {
|
|
7586
|
-
const abs =
|
|
7848
|
+
const abs = import_node_path39.default.join(dir, ".vercel", "project.json");
|
|
7587
7849
|
if (!await exists(abs)) return void 0;
|
|
7588
7850
|
const parsed = JSON.parse(await import_node_fs21.promises.readFile(abs, "utf8"));
|
|
7589
7851
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -7601,7 +7863,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7601
7863
|
read = await readVercelConfig(service.dir);
|
|
7602
7864
|
projectName = await readLinkedProjectName(service.dir);
|
|
7603
7865
|
} catch (err) {
|
|
7604
|
-
recordExtractionError("infra vercel",
|
|
7866
|
+
recordExtractionError("infra vercel", import_node_path39.default.relative(scanPath, service.dir), err);
|
|
7605
7867
|
continue;
|
|
7606
7868
|
}
|
|
7607
7869
|
if (!read && !projectName) continue;
|
|
@@ -7617,7 +7879,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7617
7879
|
const anchorId = service.node.id;
|
|
7618
7880
|
if (!read) continue;
|
|
7619
7881
|
const { config, relFile, raw } = read;
|
|
7620
|
-
const evidenceFile = toPosix2(
|
|
7882
|
+
const evidenceFile = toPosix2(import_node_path39.default.relative(scanPath, import_node_path39.default.join(service.dir, relFile)));
|
|
7621
7883
|
const add = (edgeType, kind, name) => {
|
|
7622
7884
|
if (!name) return;
|
|
7623
7885
|
const result = emitPlatformResourceEdge(
|
|
@@ -7633,12 +7895,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7633
7895
|
nodesAdded += result.nodesAdded;
|
|
7634
7896
|
edgesAdded += result.edgesAdded;
|
|
7635
7897
|
};
|
|
7636
|
-
add(
|
|
7637
|
-
for (const cron of config.crons ?? []) add(
|
|
7638
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
7639
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
7898
|
+
add(import_types28.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
7899
|
+
for (const cron of config.crons ?? []) add(import_types28.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
7900
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7901
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7640
7902
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
7641
|
-
add(
|
|
7903
|
+
add(import_types28.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
7642
7904
|
}
|
|
7643
7905
|
}
|
|
7644
7906
|
return { nodesAdded, edgesAdded };
|
|
@@ -7647,13 +7909,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7647
7909
|
// src/extract/infra/railway.ts
|
|
7648
7910
|
init_cjs_shims();
|
|
7649
7911
|
var import_node_fs22 = require("fs");
|
|
7650
|
-
var
|
|
7912
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7651
7913
|
var import_smol_toml3 = require("smol-toml");
|
|
7652
|
-
var
|
|
7914
|
+
var import_types29 = require("@neat.is/types");
|
|
7653
7915
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
7654
7916
|
async function readRailwayConfig(dir) {
|
|
7655
7917
|
for (const filename of RAILWAY_FILENAMES) {
|
|
7656
|
-
const abs =
|
|
7918
|
+
const abs = import_node_path40.default.join(dir, filename);
|
|
7657
7919
|
if (!await exists(abs)) continue;
|
|
7658
7920
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
7659
7921
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7669,7 +7931,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7669
7931
|
try {
|
|
7670
7932
|
read = await readRailwayConfig(service.dir);
|
|
7671
7933
|
} catch (err) {
|
|
7672
|
-
recordExtractionError("infra railway",
|
|
7934
|
+
recordExtractionError("infra railway", import_node_path40.default.relative(scanPath, service.dir), err);
|
|
7673
7935
|
continue;
|
|
7674
7936
|
}
|
|
7675
7937
|
if (!read) continue;
|
|
@@ -7679,7 +7941,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7679
7941
|
}
|
|
7680
7942
|
const anchorId = service.node.id;
|
|
7681
7943
|
const { config, relFile, raw } = read;
|
|
7682
|
-
const evidenceFile = toPosix2(
|
|
7944
|
+
const evidenceFile = toPosix2(import_node_path40.default.relative(scanPath, import_node_path40.default.join(service.dir, relFile)));
|
|
7683
7945
|
const add = (edgeType, kind, name) => {
|
|
7684
7946
|
if (!name) return;
|
|
7685
7947
|
const result = emitPlatformResourceEdge(
|
|
@@ -7695,9 +7957,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7695
7957
|
nodesAdded += result.nodesAdded;
|
|
7696
7958
|
edgesAdded += result.edgesAdded;
|
|
7697
7959
|
};
|
|
7698
|
-
add(
|
|
7699
|
-
add(
|
|
7700
|
-
add(
|
|
7960
|
+
add(import_types29.EdgeType.RUNS_ON, "railway", "railway");
|
|
7961
|
+
add(import_types29.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
7962
|
+
add(import_types29.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
7701
7963
|
}
|
|
7702
7964
|
return { nodesAdded, edgesAdded };
|
|
7703
7965
|
}
|
|
@@ -7705,12 +7967,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7705
7967
|
// src/extract/infra/supabase.ts
|
|
7706
7968
|
init_cjs_shims();
|
|
7707
7969
|
var import_node_fs23 = require("fs");
|
|
7708
|
-
var
|
|
7970
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7709
7971
|
var import_smol_toml4 = require("smol-toml");
|
|
7710
|
-
var
|
|
7972
|
+
var import_types30 = require("@neat.is/types");
|
|
7711
7973
|
async function readSupabaseConfig(dir) {
|
|
7712
|
-
const relFile =
|
|
7713
|
-
const abs =
|
|
7974
|
+
const relFile = import_node_path41.default.join("supabase", "config.toml");
|
|
7975
|
+
const abs = import_node_path41.default.join(dir, relFile);
|
|
7714
7976
|
if (!await exists(abs)) return null;
|
|
7715
7977
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
7716
7978
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -7724,7 +7986,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7724
7986
|
try {
|
|
7725
7987
|
read = await readSupabaseConfig(service.dir);
|
|
7726
7988
|
} catch (err) {
|
|
7727
|
-
recordExtractionError("infra supabase",
|
|
7989
|
+
recordExtractionError("infra supabase", import_node_path41.default.relative(scanPath, service.dir), err);
|
|
7728
7990
|
continue;
|
|
7729
7991
|
}
|
|
7730
7992
|
if (!read) continue;
|
|
@@ -7739,7 +8001,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7739
8001
|
});
|
|
7740
8002
|
}
|
|
7741
8003
|
const anchorId = service.node.id;
|
|
7742
|
-
const evidenceFile = toPosix2(
|
|
8004
|
+
const evidenceFile = toPosix2(import_node_path41.default.relative(scanPath, import_node_path41.default.join(service.dir, relFile)));
|
|
7743
8005
|
const add = (edgeType, kind, name) => {
|
|
7744
8006
|
if (!name) return;
|
|
7745
8007
|
const result = emitPlatformResourceEdge(
|
|
@@ -7755,10 +8017,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7755
8017
|
nodesAdded += result.nodesAdded;
|
|
7756
8018
|
edgesAdded += result.edgesAdded;
|
|
7757
8019
|
};
|
|
7758
|
-
add(
|
|
7759
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
7760
|
-
if (config.storage) add(
|
|
7761
|
-
if (config.auth) add(
|
|
8020
|
+
add(import_types30.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
8021
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types30.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
8022
|
+
if (config.storage) add(import_types30.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
8023
|
+
if (config.auth) add(import_types30.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
7762
8024
|
}
|
|
7763
8025
|
return { nodesAdded, edgesAdded };
|
|
7764
8026
|
}
|
|
@@ -7780,17 +8042,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
7780
8042
|
}
|
|
7781
8043
|
|
|
7782
8044
|
// src/extract/index.ts
|
|
7783
|
-
var
|
|
8045
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
7784
8046
|
|
|
7785
8047
|
// src/extract/retire.ts
|
|
7786
8048
|
init_cjs_shims();
|
|
7787
8049
|
var import_node_fs24 = require("fs");
|
|
7788
|
-
var
|
|
7789
|
-
var
|
|
8050
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8051
|
+
var import_types31 = require("@neat.is/types");
|
|
7790
8052
|
function dropOrphanedFileNodes(graph) {
|
|
7791
8053
|
const orphans = [];
|
|
7792
8054
|
graph.forEachNode((id, attrs) => {
|
|
7793
|
-
if (attrs.type !==
|
|
8055
|
+
if (attrs.type !== import_types31.NodeType.FileNode) return;
|
|
7794
8056
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
7795
8057
|
orphans.push(id);
|
|
7796
8058
|
}
|
|
@@ -7803,7 +8065,7 @@ function retireEdgesByFile(graph, file) {
|
|
|
7803
8065
|
const toDrop = [];
|
|
7804
8066
|
graph.forEachEdge((id, attrs) => {
|
|
7805
8067
|
const edge = attrs;
|
|
7806
|
-
if (edge.provenance !==
|
|
8068
|
+
if (edge.provenance !== import_types31.Provenance.EXTRACTED) return;
|
|
7807
8069
|
if (!edge.evidence?.file) return;
|
|
7808
8070
|
if (edge.evidence.file === normalized) toDrop.push(id);
|
|
7809
8071
|
});
|
|
@@ -7816,14 +8078,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
7816
8078
|
const bases = [scanPath, ...serviceDirs];
|
|
7817
8079
|
graph.forEachEdge((id, attrs) => {
|
|
7818
8080
|
const edge = attrs;
|
|
7819
|
-
if (edge.provenance !==
|
|
8081
|
+
if (edge.provenance !== import_types31.Provenance.EXTRACTED) return;
|
|
7820
8082
|
const evidenceFile = edge.evidence?.file;
|
|
7821
8083
|
if (!evidenceFile) return;
|
|
7822
|
-
if (
|
|
8084
|
+
if (import_node_path42.default.isAbsolute(evidenceFile)) {
|
|
7823
8085
|
if (!(0, import_node_fs24.existsSync)(evidenceFile)) toDrop.push(id);
|
|
7824
8086
|
return;
|
|
7825
8087
|
}
|
|
7826
|
-
const found = bases.some((base) => (0, import_node_fs24.existsSync)(
|
|
8088
|
+
const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path42.default.join(base, evidenceFile)));
|
|
7827
8089
|
if (!found) toDrop.push(id);
|
|
7828
8090
|
});
|
|
7829
8091
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -7865,7 +8127,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7865
8127
|
}
|
|
7866
8128
|
const droppedEntries = drainDroppedExtracted();
|
|
7867
8129
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
7868
|
-
const rejectedPath =
|
|
8130
|
+
const rejectedPath = import_node_path43.default.join(import_node_path43.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
7869
8131
|
try {
|
|
7870
8132
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
7871
8133
|
} catch (err) {
|
|
@@ -7899,39 +8161,39 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7899
8161
|
|
|
7900
8162
|
// src/divergences.ts
|
|
7901
8163
|
init_cjs_shims();
|
|
7902
|
-
var
|
|
8164
|
+
var import_types32 = require("@neat.is/types");
|
|
7903
8165
|
function bucketKey(source, target, type) {
|
|
7904
8166
|
return `${type}|${source}|${target}`;
|
|
7905
8167
|
}
|
|
7906
8168
|
function bucketSourceFor(graph, edge) {
|
|
7907
|
-
if (edge.type !==
|
|
7908
|
-
const parsed = (0,
|
|
8169
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) return edge.source;
|
|
8170
|
+
const parsed = (0, import_types32.parseFileId)(edge.source);
|
|
7909
8171
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
7910
8172
|
const target = graph.getNodeAttributes(edge.target);
|
|
7911
|
-
if (target.type !==
|
|
7912
|
-
return (0,
|
|
8173
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) return edge.source;
|
|
8174
|
+
return (0, import_types32.serviceId)(parsed.service);
|
|
7913
8175
|
}
|
|
7914
8176
|
function bucketEdges(graph) {
|
|
7915
8177
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
7916
8178
|
graph.forEachEdge((id, attrs) => {
|
|
7917
8179
|
const e = attrs;
|
|
7918
|
-
const parsed = (0,
|
|
8180
|
+
const parsed = (0, import_types32.parseEdgeId)(id);
|
|
7919
8181
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
7920
8182
|
const source = bucketSourceFor(graph, e);
|
|
7921
8183
|
const key = bucketKey(source, e.target, e.type);
|
|
7922
8184
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
7923
8185
|
switch (provenance) {
|
|
7924
|
-
case
|
|
8186
|
+
case import_types32.Provenance.EXTRACTED:
|
|
7925
8187
|
cur.extracted = e;
|
|
7926
8188
|
break;
|
|
7927
|
-
case
|
|
8189
|
+
case import_types32.Provenance.OBSERVED:
|
|
7928
8190
|
cur.observed = e;
|
|
7929
8191
|
break;
|
|
7930
|
-
case
|
|
8192
|
+
case import_types32.Provenance.INFERRED:
|
|
7931
8193
|
cur.inferred = e;
|
|
7932
8194
|
break;
|
|
7933
8195
|
default:
|
|
7934
|
-
if (e.provenance ===
|
|
8196
|
+
if (e.provenance === import_types32.Provenance.STALE) cur.stale = e;
|
|
7935
8197
|
}
|
|
7936
8198
|
buckets2.set(key, cur);
|
|
7937
8199
|
});
|
|
@@ -7940,12 +8202,12 @@ function bucketEdges(graph) {
|
|
|
7940
8202
|
function nodeIsFrontier(graph, nodeId) {
|
|
7941
8203
|
if (!graph.hasNode(nodeId)) return false;
|
|
7942
8204
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7943
|
-
return attrs.type ===
|
|
8205
|
+
return attrs.type === import_types32.NodeType.FrontierNode;
|
|
7944
8206
|
}
|
|
7945
8207
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
7946
8208
|
if (!graph.hasNode(nodeId)) return false;
|
|
7947
8209
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7948
|
-
return attrs.type ===
|
|
8210
|
+
return attrs.type === import_types32.NodeType.WebSocketChannelNode;
|
|
7949
8211
|
}
|
|
7950
8212
|
function clampConfidence(n) {
|
|
7951
8213
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -7965,14 +8227,14 @@ function gradedConfidence(edge) {
|
|
|
7965
8227
|
return clampConfidence(confidenceForEdge(edge));
|
|
7966
8228
|
}
|
|
7967
8229
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
8230
|
+
import_types32.EdgeType.CALLS,
|
|
8231
|
+
import_types32.EdgeType.CONNECTS_TO,
|
|
8232
|
+
import_types32.EdgeType.PUBLISHES_TO,
|
|
8233
|
+
import_types32.EdgeType.CONSUMES_FROM
|
|
7972
8234
|
]);
|
|
7973
8235
|
function detectMissingDivergences(graph, bucket) {
|
|
7974
8236
|
const out = [];
|
|
7975
|
-
if (bucket.type ===
|
|
8237
|
+
if (bucket.type === import_types32.EdgeType.CONTAINS) return out;
|
|
7976
8238
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
7977
8239
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
7978
8240
|
out.push({
|
|
@@ -8013,7 +8275,7 @@ function declaredHostFor(svc) {
|
|
|
8013
8275
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
8014
8276
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8015
8277
|
const e = graph.getEdgeAttributes(edgeId);
|
|
8016
|
-
if (e.type ===
|
|
8278
|
+
if (e.type === import_types32.EdgeType.CONFIGURED_BY && e.provenance === import_types32.Provenance.EXTRACTED) {
|
|
8017
8279
|
return true;
|
|
8018
8280
|
}
|
|
8019
8281
|
}
|
|
@@ -8026,10 +8288,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
8026
8288
|
const out = [];
|
|
8027
8289
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8028
8290
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8029
|
-
if (edge.type !==
|
|
8030
|
-
if (edge.provenance !==
|
|
8291
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) continue;
|
|
8292
|
+
if (edge.provenance !== import_types32.Provenance.OBSERVED) continue;
|
|
8031
8293
|
const target = graph.getNodeAttributes(edge.target);
|
|
8032
|
-
if (target.type !==
|
|
8294
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) continue;
|
|
8033
8295
|
const observedHost = target.host?.trim();
|
|
8034
8296
|
if (!observedHost) continue;
|
|
8035
8297
|
if (observedHost === declaredHost) continue;
|
|
@@ -8051,10 +8313,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
8051
8313
|
const deps = svc.dependencies ?? {};
|
|
8052
8314
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8053
8315
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8054
|
-
if (edge.type !==
|
|
8055
|
-
if (edge.provenance !==
|
|
8316
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) continue;
|
|
8317
|
+
if (edge.provenance !== import_types32.Provenance.OBSERVED) continue;
|
|
8056
8318
|
const target = graph.getNodeAttributes(edge.target);
|
|
8057
|
-
if (target.type !==
|
|
8319
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) continue;
|
|
8058
8320
|
for (const pair of compatPairs()) {
|
|
8059
8321
|
if (pair.engine !== target.engine) continue;
|
|
8060
8322
|
const declared = deps[pair.driver];
|
|
@@ -8113,7 +8375,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
8113
8375
|
for (const d of all) {
|
|
8114
8376
|
if (d.type !== "host-mismatch") continue;
|
|
8115
8377
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
8116
|
-
declaredHalf.add((0,
|
|
8378
|
+
declaredHalf.add((0, import_types32.databaseId)(d.extractedHost));
|
|
8117
8379
|
}
|
|
8118
8380
|
if (observedHalf.size === 0) return all;
|
|
8119
8381
|
return all.filter((d) => {
|
|
@@ -8132,7 +8394,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8132
8394
|
}
|
|
8133
8395
|
graph.forEachNode((nodeId, attrs) => {
|
|
8134
8396
|
const n = attrs;
|
|
8135
|
-
if (n.type !==
|
|
8397
|
+
if (n.type !== import_types32.NodeType.ServiceNode) return;
|
|
8136
8398
|
const svc = n;
|
|
8137
8399
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
8138
8400
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -8166,7 +8428,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8166
8428
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
8167
8429
|
return a.target.localeCompare(b.target);
|
|
8168
8430
|
});
|
|
8169
|
-
return
|
|
8431
|
+
return import_types32.DivergenceResultSchema.parse({
|
|
8170
8432
|
divergences: filtered,
|
|
8171
8433
|
totalAffected: filtered.length,
|
|
8172
8434
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -8176,8 +8438,8 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8176
8438
|
// src/persist.ts
|
|
8177
8439
|
init_cjs_shims();
|
|
8178
8440
|
var import_node_fs25 = require("fs");
|
|
8179
|
-
var
|
|
8180
|
-
var
|
|
8441
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8442
|
+
var import_types33 = require("@neat.is/types");
|
|
8181
8443
|
var SCHEMA_VERSION = 4;
|
|
8182
8444
|
function migrateV1ToV2(payload) {
|
|
8183
8445
|
const nodes = payload.graph.nodes;
|
|
@@ -8199,12 +8461,12 @@ function migrateV2ToV3(payload) {
|
|
|
8199
8461
|
for (const edge of edges) {
|
|
8200
8462
|
const attrs = edge.attributes;
|
|
8201
8463
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
8202
|
-
attrs.provenance =
|
|
8464
|
+
attrs.provenance = import_types33.Provenance.OBSERVED;
|
|
8203
8465
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
8204
8466
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
8205
8467
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
8206
8468
|
if (type && source && target) {
|
|
8207
|
-
const newId = (0,
|
|
8469
|
+
const newId = (0, import_types33.observedEdgeId)(source, target, type);
|
|
8208
8470
|
attrs.id = newId;
|
|
8209
8471
|
if (edge.key) edge.key = newId;
|
|
8210
8472
|
}
|
|
@@ -8213,7 +8475,7 @@ function migrateV2ToV3(payload) {
|
|
|
8213
8475
|
return { ...payload, schemaVersion: 3 };
|
|
8214
8476
|
}
|
|
8215
8477
|
async function ensureDir(filePath) {
|
|
8216
|
-
await import_node_fs25.promises.mkdir(
|
|
8478
|
+
await import_node_fs25.promises.mkdir(import_node_path44.default.dirname(filePath), { recursive: true });
|
|
8217
8479
|
}
|
|
8218
8480
|
async function saveGraphToDisk(graph, outPath) {
|
|
8219
8481
|
await ensureDir(outPath);
|
|
@@ -8295,7 +8557,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
8295
8557
|
// src/gitignore.ts
|
|
8296
8558
|
init_cjs_shims();
|
|
8297
8559
|
var import_node_fs26 = require("fs");
|
|
8298
|
-
var
|
|
8560
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8299
8561
|
var NEAT_OUT_LINE = "neat-out/";
|
|
8300
8562
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
8301
8563
|
function isNeatOutLine(line) {
|
|
@@ -8303,7 +8565,7 @@ function isNeatOutLine(line) {
|
|
|
8303
8565
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
8304
8566
|
}
|
|
8305
8567
|
async function ensureNeatOutIgnored(projectDir) {
|
|
8306
|
-
const file =
|
|
8568
|
+
const file = import_node_path45.default.join(projectDir, ".gitignore");
|
|
8307
8569
|
let existing = null;
|
|
8308
8570
|
try {
|
|
8309
8571
|
existing = await import_node_fs26.promises.readFile(file, "utf8");
|
|
@@ -8330,7 +8592,7 @@ ${NEAT_OUT_LINE}
|
|
|
8330
8592
|
|
|
8331
8593
|
// src/summary.ts
|
|
8332
8594
|
init_cjs_shims();
|
|
8333
|
-
var
|
|
8595
|
+
var import_types34 = require("@neat.is/types");
|
|
8334
8596
|
function renderOtelEnvBlock() {
|
|
8335
8597
|
return [
|
|
8336
8598
|
"for prod OTel routing, set these in your deploy platform's env:",
|
|
@@ -8340,19 +8602,19 @@ function renderOtelEnvBlock() {
|
|
|
8340
8602
|
}
|
|
8341
8603
|
function findIncompatServices(nodes) {
|
|
8342
8604
|
return nodes.filter(
|
|
8343
|
-
(n) => n.type ===
|
|
8605
|
+
(n) => n.type === import_types34.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
|
|
8344
8606
|
);
|
|
8345
8607
|
}
|
|
8346
8608
|
function servicesWithoutObserved(nodes, edges) {
|
|
8347
8609
|
const seen = /* @__PURE__ */ new Set();
|
|
8348
8610
|
for (const e of edges) {
|
|
8349
|
-
if (e.provenance ===
|
|
8611
|
+
if (e.provenance === import_types34.Provenance.OBSERVED) {
|
|
8350
8612
|
seen.add(e.source);
|
|
8351
8613
|
seen.add(e.target);
|
|
8352
8614
|
}
|
|
8353
8615
|
}
|
|
8354
8616
|
return nodes.filter(
|
|
8355
|
-
(n) => n.type ===
|
|
8617
|
+
(n) => n.type === import_types34.NodeType.ServiceNode && !seen.has(n.id)
|
|
8356
8618
|
);
|
|
8357
8619
|
}
|
|
8358
8620
|
function formatDivergence(d) {
|
|
@@ -8427,26 +8689,26 @@ function formatIncompat(inc) {
|
|
|
8427
8689
|
// src/watch.ts
|
|
8428
8690
|
init_cjs_shims();
|
|
8429
8691
|
var import_node_fs35 = __toESM(require("fs"), 1);
|
|
8430
|
-
var
|
|
8692
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
8431
8693
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
8432
8694
|
|
|
8433
8695
|
// src/api.ts
|
|
8434
8696
|
init_cjs_shims();
|
|
8435
8697
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
8436
8698
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
8437
|
-
var
|
|
8699
|
+
var import_types36 = require("@neat.is/types");
|
|
8438
8700
|
|
|
8439
8701
|
// src/extend/index.ts
|
|
8440
8702
|
init_cjs_shims();
|
|
8441
8703
|
var import_node_fs28 = require("fs");
|
|
8442
|
-
var
|
|
8704
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
8443
8705
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
8444
8706
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
8445
8707
|
|
|
8446
8708
|
// src/installers/package-manager.ts
|
|
8447
8709
|
init_cjs_shims();
|
|
8448
8710
|
var import_node_fs27 = require("fs");
|
|
8449
|
-
var
|
|
8711
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8450
8712
|
var import_node_child_process = require("child_process");
|
|
8451
8713
|
var LOCKFILE_PRIORITY = [
|
|
8452
8714
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -8468,22 +8730,22 @@ async function exists2(p) {
|
|
|
8468
8730
|
}
|
|
8469
8731
|
}
|
|
8470
8732
|
async function detectPackageManager(serviceDir) {
|
|
8471
|
-
let dir =
|
|
8733
|
+
let dir = import_node_path46.default.resolve(serviceDir);
|
|
8472
8734
|
const stops = /* @__PURE__ */ new Set();
|
|
8473
8735
|
for (let i = 0; i < 64; i++) {
|
|
8474
8736
|
if (stops.has(dir)) break;
|
|
8475
8737
|
stops.add(dir);
|
|
8476
8738
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
8477
|
-
const lockPath =
|
|
8739
|
+
const lockPath = import_node_path46.default.join(dir, candidate.lockfile);
|
|
8478
8740
|
if (await exists2(lockPath)) {
|
|
8479
8741
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
8480
8742
|
}
|
|
8481
8743
|
}
|
|
8482
|
-
const parent =
|
|
8744
|
+
const parent = import_node_path46.default.dirname(dir);
|
|
8483
8745
|
if (parent === dir) break;
|
|
8484
8746
|
dir = parent;
|
|
8485
8747
|
}
|
|
8486
|
-
return { pm: "npm", cwd:
|
|
8748
|
+
return { pm: "npm", cwd: import_node_path46.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
8487
8749
|
}
|
|
8488
8750
|
async function runPackageManagerInstall(cmd) {
|
|
8489
8751
|
return new Promise((resolve) => {
|
|
@@ -8532,7 +8794,7 @@ async function fileExists2(p) {
|
|
|
8532
8794
|
}
|
|
8533
8795
|
}
|
|
8534
8796
|
async function readPackageJson(scanPath) {
|
|
8535
|
-
const pkgPath =
|
|
8797
|
+
const pkgPath = import_node_path47.default.join(scanPath, "package.json");
|
|
8536
8798
|
const raw = await import_node_fs28.promises.readFile(pkgPath, "utf8");
|
|
8537
8799
|
return JSON.parse(raw);
|
|
8538
8800
|
}
|
|
@@ -8546,27 +8808,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
8546
8808
|
]);
|
|
8547
8809
|
async function findHookFiles(scanPath) {
|
|
8548
8810
|
const found = [];
|
|
8549
|
-
const
|
|
8811
|
+
const walk4 = async (dir) => {
|
|
8550
8812
|
const entries = await import_node_fs28.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
8551
8813
|
for (const entry2 of entries) {
|
|
8552
8814
|
if (entry2.isDirectory()) {
|
|
8553
8815
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
8554
|
-
await
|
|
8816
|
+
await walk4(import_node_path47.default.join(dir, entry2.name));
|
|
8555
8817
|
} else if (entry2.isFile()) {
|
|
8556
8818
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
8557
|
-
const rel =
|
|
8558
|
-
found.push(rel.split(
|
|
8819
|
+
const rel = import_node_path47.default.relative(scanPath, import_node_path47.default.join(dir, entry2.name));
|
|
8820
|
+
found.push(rel.split(import_node_path47.default.sep).join("/"));
|
|
8559
8821
|
}
|
|
8560
8822
|
}
|
|
8561
8823
|
}
|
|
8562
8824
|
};
|
|
8563
|
-
await
|
|
8825
|
+
await walk4(scanPath);
|
|
8564
8826
|
return found.sort();
|
|
8565
8827
|
}
|
|
8566
8828
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
8567
8829
|
let fallback = null;
|
|
8568
8830
|
for (const file of hookFiles) {
|
|
8569
|
-
const content = await import_node_fs28.promises.readFile(
|
|
8831
|
+
const content = await import_node_fs28.promises.readFile(import_node_path47.default.join(scanPath, file), "utf8");
|
|
8570
8832
|
const patched = splicedContent(content, snippet2);
|
|
8571
8833
|
if (patched !== null) return { file, content, patched };
|
|
8572
8834
|
if (fallback === null) fallback = { file, content };
|
|
@@ -8574,11 +8836,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
8574
8836
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
8575
8837
|
}
|
|
8576
8838
|
function extendLogPath() {
|
|
8577
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
8839
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path47.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
8578
8840
|
}
|
|
8579
8841
|
async function appendExtendLog(entry2) {
|
|
8580
8842
|
const logPath = extendLogPath();
|
|
8581
|
-
await import_node_fs28.promises.mkdir(
|
|
8843
|
+
await import_node_fs28.promises.mkdir(import_node_path47.default.dirname(logPath), { recursive: true });
|
|
8582
8844
|
await import_node_fs28.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
8583
8845
|
}
|
|
8584
8846
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -8637,7 +8899,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
8637
8899
|
}
|
|
8638
8900
|
async function describeProjectInstrumentation(ctx) {
|
|
8639
8901
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
8640
|
-
const envNeat = await fileExists2(
|
|
8902
|
+
const envNeat = await fileExists2(import_node_path47.default.join(ctx.scanPath, ".env.neat"));
|
|
8641
8903
|
const registryInstrPackages = new Set(
|
|
8642
8904
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
8643
8905
|
);
|
|
@@ -8659,7 +8921,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
8659
8921
|
);
|
|
8660
8922
|
}
|
|
8661
8923
|
for (const file of hookFiles) {
|
|
8662
|
-
const content = await import_node_fs28.promises.readFile(
|
|
8924
|
+
const content = await import_node_fs28.promises.readFile(import_node_path47.default.join(ctx.scanPath, file), "utf8");
|
|
8663
8925
|
if (content.includes(args.registration_snippet)) {
|
|
8664
8926
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
8665
8927
|
}
|
|
@@ -8671,10 +8933,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
8671
8933
|
);
|
|
8672
8934
|
}
|
|
8673
8935
|
const primaryFile = primary.file;
|
|
8674
|
-
const primaryPath =
|
|
8936
|
+
const primaryPath = import_node_path47.default.join(ctx.scanPath, primaryFile);
|
|
8675
8937
|
const filesTouched = [];
|
|
8676
8938
|
const depsAdded = [];
|
|
8677
|
-
const pkgPath =
|
|
8939
|
+
const pkgPath = import_node_path47.default.join(ctx.scanPath, "package.json");
|
|
8678
8940
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8679
8941
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
8680
8942
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -8713,7 +8975,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
8713
8975
|
};
|
|
8714
8976
|
}
|
|
8715
8977
|
for (const file of hookFiles) {
|
|
8716
|
-
const content = await import_node_fs28.promises.readFile(
|
|
8978
|
+
const content = await import_node_fs28.promises.readFile(import_node_path47.default.join(ctx.scanPath, file), "utf8");
|
|
8717
8979
|
if (content.includes(args.registration_snippet)) {
|
|
8718
8980
|
return {
|
|
8719
8981
|
library: args.library,
|
|
@@ -8754,7 +9016,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8754
9016
|
if (!match) {
|
|
8755
9017
|
return { undone: false, message: "no apply found for library" };
|
|
8756
9018
|
}
|
|
8757
|
-
const pkgPath =
|
|
9019
|
+
const pkgPath = import_node_path47.default.join(ctx.scanPath, "package.json");
|
|
8758
9020
|
if (await fileExists2(pkgPath)) {
|
|
8759
9021
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8760
9022
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -8765,7 +9027,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8765
9027
|
}
|
|
8766
9028
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
8767
9029
|
for (const file of hookFiles) {
|
|
8768
|
-
const filePath =
|
|
9030
|
+
const filePath = import_node_path47.default.join(ctx.scanPath, file);
|
|
8769
9031
|
const content = await import_node_fs28.promises.readFile(filePath, "utf8");
|
|
8770
9032
|
if (content.includes(match.registration_snippet)) {
|
|
8771
9033
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -8903,23 +9165,23 @@ function canonicalJson(value) {
|
|
|
8903
9165
|
|
|
8904
9166
|
// src/projects.ts
|
|
8905
9167
|
init_cjs_shims();
|
|
8906
|
-
var
|
|
9168
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
8907
9169
|
function pathsForProject(project, baseDir) {
|
|
8908
9170
|
if (project === DEFAULT_PROJECT) {
|
|
8909
9171
|
return {
|
|
8910
|
-
snapshotPath:
|
|
8911
|
-
errorsPath:
|
|
8912
|
-
staleEventsPath:
|
|
8913
|
-
embeddingsCachePath:
|
|
8914
|
-
policyViolationsPath:
|
|
9172
|
+
snapshotPath: import_node_path48.default.join(baseDir, "graph.json"),
|
|
9173
|
+
errorsPath: import_node_path48.default.join(baseDir, "errors.ndjson"),
|
|
9174
|
+
staleEventsPath: import_node_path48.default.join(baseDir, "stale-events.ndjson"),
|
|
9175
|
+
embeddingsCachePath: import_node_path48.default.join(baseDir, "embeddings.json"),
|
|
9176
|
+
policyViolationsPath: import_node_path48.default.join(baseDir, "policy-violations.ndjson")
|
|
8915
9177
|
};
|
|
8916
9178
|
}
|
|
8917
9179
|
return {
|
|
8918
|
-
snapshotPath:
|
|
8919
|
-
errorsPath:
|
|
8920
|
-
staleEventsPath:
|
|
8921
|
-
embeddingsCachePath:
|
|
8922
|
-
policyViolationsPath:
|
|
9180
|
+
snapshotPath: import_node_path48.default.join(baseDir, `${project}.json`),
|
|
9181
|
+
errorsPath: import_node_path48.default.join(baseDir, `errors.${project}.ndjson`),
|
|
9182
|
+
staleEventsPath: import_node_path48.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
9183
|
+
embeddingsCachePath: import_node_path48.default.join(baseDir, `embeddings.${project}.json`),
|
|
9184
|
+
policyViolationsPath: import_node_path48.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
8923
9185
|
};
|
|
8924
9186
|
}
|
|
8925
9187
|
var Projects = class {
|
|
@@ -8957,26 +9219,26 @@ var Projects = class {
|
|
|
8957
9219
|
init_cjs_shims();
|
|
8958
9220
|
var import_node_fs30 = require("fs");
|
|
8959
9221
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
8960
|
-
var
|
|
8961
|
-
var
|
|
9222
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9223
|
+
var import_types35 = require("@neat.is/types");
|
|
8962
9224
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
8963
9225
|
var LOCK_RETRY_MS = 50;
|
|
8964
9226
|
function neatHome() {
|
|
8965
9227
|
const override = process.env.NEAT_HOME;
|
|
8966
|
-
if (override && override.length > 0) return
|
|
8967
|
-
return
|
|
9228
|
+
if (override && override.length > 0) return import_node_path49.default.resolve(override);
|
|
9229
|
+
return import_node_path49.default.join(import_node_os3.default.homedir(), ".neat");
|
|
8968
9230
|
}
|
|
8969
9231
|
function registryPath() {
|
|
8970
|
-
return
|
|
9232
|
+
return import_node_path49.default.join(neatHome(), "projects.json");
|
|
8971
9233
|
}
|
|
8972
9234
|
function registryLockPath() {
|
|
8973
|
-
return
|
|
9235
|
+
return import_node_path49.default.join(neatHome(), "projects.json.lock");
|
|
8974
9236
|
}
|
|
8975
9237
|
function daemonPidPath() {
|
|
8976
|
-
return
|
|
9238
|
+
return import_node_path49.default.join(neatHome(), "neatd.pid");
|
|
8977
9239
|
}
|
|
8978
9240
|
function daemonsDir() {
|
|
8979
|
-
return
|
|
9241
|
+
return import_node_path49.default.join(neatHome(), "daemons");
|
|
8980
9242
|
}
|
|
8981
9243
|
function isFiniteInt(v) {
|
|
8982
9244
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -9017,7 +9279,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
9017
9279
|
const out = [];
|
|
9018
9280
|
for (const name of names) {
|
|
9019
9281
|
if (!name.endsWith(".json")) continue;
|
|
9020
|
-
const file =
|
|
9282
|
+
const file = import_node_path49.default.join(dir, name);
|
|
9021
9283
|
let raw;
|
|
9022
9284
|
try {
|
|
9023
9285
|
raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
@@ -9138,7 +9400,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
9138
9400
|
}
|
|
9139
9401
|
}
|
|
9140
9402
|
async function normalizeProjectPath(input) {
|
|
9141
|
-
const resolved =
|
|
9403
|
+
const resolved = import_node_path49.default.resolve(input);
|
|
9142
9404
|
try {
|
|
9143
9405
|
return await import_node_fs30.promises.realpath(resolved);
|
|
9144
9406
|
} catch {
|
|
@@ -9146,7 +9408,7 @@ async function normalizeProjectPath(input) {
|
|
|
9146
9408
|
}
|
|
9147
9409
|
}
|
|
9148
9410
|
async function writeAtomically(target, contents) {
|
|
9149
|
-
await import_node_fs30.promises.mkdir(
|
|
9411
|
+
await import_node_fs30.promises.mkdir(import_node_path49.default.dirname(target), { recursive: true });
|
|
9150
9412
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
9151
9413
|
const fd = await import_node_fs30.promises.open(tmp, "w");
|
|
9152
9414
|
try {
|
|
@@ -9159,7 +9421,7 @@ async function writeAtomically(target, contents) {
|
|
|
9159
9421
|
}
|
|
9160
9422
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
9161
9423
|
const deadline = Date.now() + timeoutMs;
|
|
9162
|
-
await import_node_fs30.promises.mkdir(
|
|
9424
|
+
await import_node_fs30.promises.mkdir(import_node_path49.default.dirname(lockPath), { recursive: true });
|
|
9163
9425
|
let probedHolder = false;
|
|
9164
9426
|
while (true) {
|
|
9165
9427
|
try {
|
|
@@ -9212,10 +9474,10 @@ async function readRegistry() {
|
|
|
9212
9474
|
throw err;
|
|
9213
9475
|
}
|
|
9214
9476
|
const parsed = JSON.parse(raw);
|
|
9215
|
-
return
|
|
9477
|
+
return import_types35.RegistryFileSchema.parse(parsed);
|
|
9216
9478
|
}
|
|
9217
9479
|
async function writeRegistry(reg) {
|
|
9218
|
-
const validated =
|
|
9480
|
+
const validated = import_types35.RegistryFileSchema.parse(reg);
|
|
9219
9481
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
9220
9482
|
}
|
|
9221
9483
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -9401,7 +9663,7 @@ init_auth();
|
|
|
9401
9663
|
// src/connectors-config.ts
|
|
9402
9664
|
init_cjs_shims();
|
|
9403
9665
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
9404
|
-
var
|
|
9666
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9405
9667
|
var import_node_fs31 = require("fs");
|
|
9406
9668
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
9407
9669
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -9416,11 +9678,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
9416
9678
|
};
|
|
9417
9679
|
function neatHome2() {
|
|
9418
9680
|
const override = process.env.NEAT_HOME;
|
|
9419
|
-
if (override && override.length > 0) return
|
|
9420
|
-
return
|
|
9681
|
+
if (override && override.length > 0) return import_node_path50.default.resolve(override);
|
|
9682
|
+
return import_node_path50.default.join(import_node_os4.default.homedir(), ".neat");
|
|
9421
9683
|
}
|
|
9422
9684
|
function connectorsConfigPath(home = neatHome2()) {
|
|
9423
|
-
return
|
|
9685
|
+
return import_node_path50.default.join(home, "connectors.json");
|
|
9424
9686
|
}
|
|
9425
9687
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
9426
9688
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -9551,7 +9813,7 @@ function connectorMatchesProject(entry2, project) {
|
|
|
9551
9813
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
9552
9814
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
9553
9815
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
9554
|
-
return
|
|
9816
|
+
return import_node_path50.default.join(home, "connectors.json.lock");
|
|
9555
9817
|
}
|
|
9556
9818
|
function isEnvRef(value) {
|
|
9557
9819
|
return value.length > 1 && value.startsWith("$");
|
|
@@ -9564,7 +9826,7 @@ function redactCredentialRef(ref) {
|
|
|
9564
9826
|
return out;
|
|
9565
9827
|
}
|
|
9566
9828
|
async function writeConfigAtomically0600(file, contents) {
|
|
9567
|
-
await import_node_fs31.promises.mkdir(
|
|
9829
|
+
await import_node_fs31.promises.mkdir(import_node_path50.default.dirname(file), { recursive: true });
|
|
9568
9830
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
9569
9831
|
const fd = await import_node_fs31.promises.open(tmp, "w", 384);
|
|
9570
9832
|
try {
|
|
@@ -9578,7 +9840,7 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
9578
9840
|
}
|
|
9579
9841
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
9580
9842
|
const deadline = Date.now() + timeoutMs;
|
|
9581
|
-
await import_node_fs31.promises.mkdir(
|
|
9843
|
+
await import_node_fs31.promises.mkdir(import_node_path50.default.dirname(lockPath), { recursive: true });
|
|
9582
9844
|
for (; ; ) {
|
|
9583
9845
|
try {
|
|
9584
9846
|
const fd = await import_node_fs31.promises.open(lockPath, "wx");
|
|
@@ -9861,11 +10123,11 @@ function registerRoutes(scope, ctx) {
|
|
|
9861
10123
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
9862
10124
|
const parsed = [];
|
|
9863
10125
|
for (const c of candidates) {
|
|
9864
|
-
const r =
|
|
10126
|
+
const r = import_types36.DivergenceTypeSchema.safeParse(c);
|
|
9865
10127
|
if (!r.success) {
|
|
9866
10128
|
return reply.code(400).send({
|
|
9867
10129
|
error: `unknown divergence type "${c}"`,
|
|
9868
|
-
allowed:
|
|
10130
|
+
allowed: import_types36.DivergenceTypeSchema.options
|
|
9869
10131
|
});
|
|
9870
10132
|
}
|
|
9871
10133
|
parsed.push(r.data);
|
|
@@ -10136,7 +10398,7 @@ function registerRoutes(scope, ctx) {
|
|
|
10136
10398
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
10137
10399
|
let violations = await log.readAll();
|
|
10138
10400
|
if (req.query.severity) {
|
|
10139
|
-
const sev =
|
|
10401
|
+
const sev = import_types36.PolicySeveritySchema.safeParse(req.query.severity);
|
|
10140
10402
|
if (!sev.success) {
|
|
10141
10403
|
return reply.code(400).send({
|
|
10142
10404
|
error: "invalid severity",
|
|
@@ -10175,7 +10437,7 @@ function registerRoutes(scope, ctx) {
|
|
|
10175
10437
|
scope.post("/policies/check", async (req, reply) => {
|
|
10176
10438
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
10177
10439
|
if (!proj) return;
|
|
10178
|
-
const parsed =
|
|
10440
|
+
const parsed = import_types36.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
10179
10441
|
if (!parsed.success) {
|
|
10180
10442
|
return reply.code(400).send({
|
|
10181
10443
|
error: "invalid /policies/check body",
|
|
@@ -10477,13 +10739,13 @@ init_otel();
|
|
|
10477
10739
|
// src/daemon.ts
|
|
10478
10740
|
init_cjs_shims();
|
|
10479
10741
|
var import_node_fs33 = require("fs");
|
|
10480
|
-
var
|
|
10742
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
10481
10743
|
var import_node_module = require("module");
|
|
10482
10744
|
init_otel();
|
|
10483
10745
|
|
|
10484
10746
|
// src/connectors/index.ts
|
|
10485
10747
|
init_cjs_shims();
|
|
10486
|
-
var
|
|
10748
|
+
var import_types37 = require("@neat.is/types");
|
|
10487
10749
|
|
|
10488
10750
|
// src/connectors/registry.ts
|
|
10489
10751
|
init_cjs_shims();
|
|
@@ -10858,10 +11120,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
10858
11120
|
// src/connectors/supabase/map.ts
|
|
10859
11121
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
10860
11122
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
10861
|
-
function targetFromRestPath(
|
|
10862
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
11123
|
+
function targetFromRestPath(path64) {
|
|
11124
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path64);
|
|
10863
11125
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
10864
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
11126
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path64);
|
|
10865
11127
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
10866
11128
|
return null;
|
|
10867
11129
|
}
|
|
@@ -10970,23 +11232,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
10970
11232
|
|
|
10971
11233
|
// src/connectors/supabase/resolve.ts
|
|
10972
11234
|
init_cjs_shims();
|
|
10973
|
-
var
|
|
11235
|
+
var import_types39 = require("@neat.is/types");
|
|
10974
11236
|
function createSupabaseResolveTarget(graph, config) {
|
|
10975
11237
|
return (signal, _ctx) => {
|
|
10976
11238
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
10977
11239
|
return null;
|
|
10978
11240
|
}
|
|
10979
|
-
const subResourceId = (0,
|
|
11241
|
+
const subResourceId = (0, import_types39.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
10980
11242
|
if (graph.hasNode(subResourceId)) {
|
|
10981
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
11243
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types39.EdgeType.CALLS };
|
|
10982
11244
|
}
|
|
10983
|
-
const bareResourceId = (0,
|
|
11245
|
+
const bareResourceId = (0, import_types39.infraId)(signal.targetKind, signal.targetName);
|
|
10984
11246
|
if (graph.hasNode(bareResourceId)) {
|
|
10985
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
11247
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types39.EdgeType.CALLS };
|
|
10986
11248
|
}
|
|
10987
|
-
const projectLevelId = (0,
|
|
11249
|
+
const projectLevelId = (0, import_types39.infraId)("supabase", config.nodeRef);
|
|
10988
11250
|
if (graph.hasNode(projectLevelId)) {
|
|
10989
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
11251
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types39.EdgeType.CALLS };
|
|
10990
11252
|
}
|
|
10991
11253
|
return null;
|
|
10992
11254
|
};
|
|
@@ -11079,7 +11341,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
11079
11341
|
|
|
11080
11342
|
// src/connectors/railway/index.ts
|
|
11081
11343
|
init_cjs_shims();
|
|
11082
|
-
var
|
|
11344
|
+
var import_types43 = require("@neat.is/types");
|
|
11083
11345
|
|
|
11084
11346
|
// src/connectors/railway/client.ts
|
|
11085
11347
|
init_cjs_shims();
|
|
@@ -11205,7 +11467,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
11205
11467
|
const out = [];
|
|
11206
11468
|
graph.forEachNode((_id, attrs) => {
|
|
11207
11469
|
const node = attrs;
|
|
11208
|
-
if (node.type !==
|
|
11470
|
+
if (node.type !== import_types43.NodeType.RouteNode) return;
|
|
11209
11471
|
const route = attrs;
|
|
11210
11472
|
if (route.service !== serviceName) return;
|
|
11211
11473
|
out.push({
|
|
@@ -11309,12 +11571,12 @@ function createRailwayResolveTarget(config) {
|
|
|
11309
11571
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
11310
11572
|
if (!serviceName) return null;
|
|
11311
11573
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
11312
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
11574
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types43.EdgeType.CALLS };
|
|
11313
11575
|
}
|
|
11314
11576
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
11315
11577
|
const peerName = config.serviceNameById[signal.targetName];
|
|
11316
11578
|
if (!peerName) return null;
|
|
11317
|
-
return { targetNodeId: (0,
|
|
11579
|
+
return { targetNodeId: (0, import_types43.serviceId)(peerName), serviceName, edgeType: import_types43.EdgeType.CONNECTS_TO };
|
|
11318
11580
|
}
|
|
11319
11581
|
return null;
|
|
11320
11582
|
};
|
|
@@ -11438,9 +11700,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
11438
11700
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
11439
11701
|
if (secondSep === -1) return null;
|
|
11440
11702
|
const method = rest.slice(0, secondSep);
|
|
11441
|
-
const
|
|
11442
|
-
if (!resourceName || !method || !
|
|
11443
|
-
return { resourceName, method, path:
|
|
11703
|
+
const path64 = rest.slice(secondSep + 1);
|
|
11704
|
+
if (!resourceName || !method || !path64) return null;
|
|
11705
|
+
return { resourceName, method, path: path64 };
|
|
11444
11706
|
}
|
|
11445
11707
|
function resourceNameFor(type, labels) {
|
|
11446
11708
|
if (!labels) return null;
|
|
@@ -11478,14 +11740,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
11478
11740
|
if (!req) return null;
|
|
11479
11741
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
11480
11742
|
const method = req.requestMethod.toUpperCase();
|
|
11481
|
-
const
|
|
11482
|
-
if (
|
|
11743
|
+
const path64 = pathFromRequestUrl(req.requestUrl);
|
|
11744
|
+
if (path64 === null) return null;
|
|
11483
11745
|
const timestamp = entry2.timestamp;
|
|
11484
11746
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
11485
11747
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
11486
11748
|
return {
|
|
11487
11749
|
targetKind: resourceType,
|
|
11488
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
11750
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path64 }),
|
|
11489
11751
|
callCount: 1,
|
|
11490
11752
|
errorCount: isError ? 1 : 0,
|
|
11491
11753
|
lastObservedIso: timestamp
|
|
@@ -11502,7 +11764,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
11502
11764
|
|
|
11503
11765
|
// src/connectors/firebase/resolve.ts
|
|
11504
11766
|
init_cjs_shims();
|
|
11505
|
-
var
|
|
11767
|
+
var import_types44 = require("@neat.is/types");
|
|
11506
11768
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
11507
11769
|
switch (resourceType) {
|
|
11508
11770
|
case "cloud_function":
|
|
@@ -11517,7 +11779,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
11517
11779
|
const entries = [];
|
|
11518
11780
|
graph.forEachNode((_id, attrs) => {
|
|
11519
11781
|
const node = attrs;
|
|
11520
|
-
if (node.type !==
|
|
11782
|
+
if (node.type !== import_types44.NodeType.RouteNode) return;
|
|
11521
11783
|
const route = attrs;
|
|
11522
11784
|
if (route.service !== serviceName) return;
|
|
11523
11785
|
entries.push({
|
|
@@ -11549,7 +11811,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
11549
11811
|
return {
|
|
11550
11812
|
targetNodeId: match.routeNodeId,
|
|
11551
11813
|
serviceName,
|
|
11552
|
-
edgeType:
|
|
11814
|
+
edgeType: import_types44.EdgeType.CALLS
|
|
11553
11815
|
};
|
|
11554
11816
|
};
|
|
11555
11817
|
}
|
|
@@ -11576,7 +11838,7 @@ init_cjs_shims();
|
|
|
11576
11838
|
|
|
11577
11839
|
// src/connectors/cloudflare/connector.ts
|
|
11578
11840
|
init_cjs_shims();
|
|
11579
|
-
var
|
|
11841
|
+
var import_types46 = require("@neat.is/types");
|
|
11580
11842
|
|
|
11581
11843
|
// src/connectors/cloudflare/client.ts
|
|
11582
11844
|
init_cjs_shims();
|
|
@@ -11692,7 +11954,7 @@ function mapEventToSignal(event) {
|
|
|
11692
11954
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
11693
11955
|
const statusCode = metadata?.statusCode;
|
|
11694
11956
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
11695
|
-
const
|
|
11957
|
+
const path64 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
11696
11958
|
return {
|
|
11697
11959
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
11698
11960
|
targetName: scriptName,
|
|
@@ -11700,7 +11962,7 @@ function mapEventToSignal(event) {
|
|
|
11700
11962
|
errorCount: isError ? 1 : 0,
|
|
11701
11963
|
lastObservedIso: observedAt.toISOString(),
|
|
11702
11964
|
method,
|
|
11703
|
-
...
|
|
11965
|
+
...path64 ? { path: path64 } : {},
|
|
11704
11966
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
11705
11967
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
11706
11968
|
};
|
|
@@ -11740,19 +12002,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
11740
12002
|
graph.forEachNode((id, attrs) => {
|
|
11741
12003
|
if (found) return;
|
|
11742
12004
|
const a = attrs;
|
|
11743
|
-
if (a.type ===
|
|
12005
|
+
if (a.type === import_types46.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
11744
12006
|
found = id;
|
|
11745
12007
|
}
|
|
11746
12008
|
});
|
|
11747
12009
|
return found;
|
|
11748
12010
|
}
|
|
11749
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
11750
|
-
const normalizedPath = normalizePathTemplate(
|
|
12011
|
+
function findMatchingRouteNode(graph, serviceName, method, path64) {
|
|
12012
|
+
const normalizedPath = normalizePathTemplate(path64);
|
|
11751
12013
|
let found = null;
|
|
11752
12014
|
graph.forEachNode((id, attrs) => {
|
|
11753
12015
|
if (found) return;
|
|
11754
12016
|
const a = attrs;
|
|
11755
|
-
if (a.type !==
|
|
12017
|
+
if (a.type !== import_types46.NodeType.RouteNode || a.service !== serviceName) return;
|
|
11756
12018
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
11757
12019
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
11758
12020
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -11764,18 +12026,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
11764
12026
|
return (signal) => {
|
|
11765
12027
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
11766
12028
|
const scriptName = signal.targetName;
|
|
11767
|
-
const { method, path:
|
|
12029
|
+
const { method, path: path64 } = signal;
|
|
11768
12030
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
11769
|
-
if (!method || !
|
|
11770
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
12031
|
+
if (!method || !path64) return wholeFileId;
|
|
12032
|
+
return findMatchingRouteNode(graph, serviceName, method, path64) ?? wholeFileId;
|
|
11771
12033
|
};
|
|
11772
12034
|
const mapping = config.workers?.[scriptName];
|
|
11773
12035
|
if (mapping) {
|
|
11774
|
-
const wholeFileId = (0,
|
|
12036
|
+
const wholeFileId = (0, import_types46.fileId)(mapping.service, mapping.entryFile);
|
|
11775
12037
|
return {
|
|
11776
12038
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
11777
12039
|
serviceName: mapping.service,
|
|
11778
|
-
edgeType:
|
|
12040
|
+
edgeType: import_types46.EdgeType.CALLS
|
|
11779
12041
|
};
|
|
11780
12042
|
}
|
|
11781
12043
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -11784,13 +12046,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
11784
12046
|
return {
|
|
11785
12047
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
11786
12048
|
serviceName: fileNode.service,
|
|
11787
|
-
edgeType:
|
|
12049
|
+
edgeType: import_types46.EdgeType.CALLS
|
|
11788
12050
|
};
|
|
11789
12051
|
}
|
|
11790
12052
|
return {
|
|
11791
|
-
targetNodeId: (0,
|
|
12053
|
+
targetNodeId: (0, import_types46.infraId)("cloudflare-worker", scriptName),
|
|
11792
12054
|
serviceName: scriptName,
|
|
11793
|
-
edgeType:
|
|
12055
|
+
edgeType: import_types46.EdgeType.CALLS,
|
|
11794
12056
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
11795
12057
|
};
|
|
11796
12058
|
};
|
|
@@ -12249,28 +12511,28 @@ init_auth();
|
|
|
12249
12511
|
// src/unrouted.ts
|
|
12250
12512
|
init_cjs_shims();
|
|
12251
12513
|
var import_node_fs32 = require("fs");
|
|
12252
|
-
var
|
|
12514
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
12253
12515
|
|
|
12254
12516
|
// src/daemon.ts
|
|
12255
|
-
var
|
|
12517
|
+
var import_types49 = require("@neat.is/types");
|
|
12256
12518
|
function daemonJsonPath(scanPath) {
|
|
12257
|
-
return
|
|
12519
|
+
return import_node_path54.default.join(scanPath, "neat-out", "daemon.json");
|
|
12258
12520
|
}
|
|
12259
12521
|
function daemonsDiscoveryDir(home) {
|
|
12260
12522
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
12261
|
-
return
|
|
12523
|
+
return import_node_path54.default.join(base, "daemons");
|
|
12262
12524
|
}
|
|
12263
12525
|
function daemonDiscoveryPath(project, home) {
|
|
12264
|
-
return
|
|
12526
|
+
return import_node_path54.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
12265
12527
|
}
|
|
12266
12528
|
function sanitizeDiscoveryName(project) {
|
|
12267
12529
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
12268
12530
|
}
|
|
12269
12531
|
function neatHomeFromEnv() {
|
|
12270
12532
|
const env = process.env.NEAT_HOME;
|
|
12271
|
-
if (env && env.length > 0) return
|
|
12533
|
+
if (env && env.length > 0) return import_node_path54.default.resolve(env);
|
|
12272
12534
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
12273
|
-
return
|
|
12535
|
+
return import_node_path54.default.join(home, ".neat");
|
|
12274
12536
|
}
|
|
12275
12537
|
async function readDaemonRecord(scanPath) {
|
|
12276
12538
|
try {
|
|
@@ -12341,7 +12603,7 @@ init_otel_grpc();
|
|
|
12341
12603
|
// src/search.ts
|
|
12342
12604
|
init_cjs_shims();
|
|
12343
12605
|
var import_node_fs34 = require("fs");
|
|
12344
|
-
var
|
|
12606
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
12345
12607
|
var import_node_crypto4 = require("crypto");
|
|
12346
12608
|
var DEFAULT_LIMIT = 10;
|
|
12347
12609
|
var NOMIC_DIM = 768;
|
|
@@ -12504,7 +12766,7 @@ async function readCache(cachePath) {
|
|
|
12504
12766
|
}
|
|
12505
12767
|
}
|
|
12506
12768
|
async function writeCache(cachePath, cache) {
|
|
12507
|
-
await import_node_fs34.promises.mkdir(
|
|
12769
|
+
await import_node_fs34.promises.mkdir(import_node_path55.default.dirname(cachePath), { recursive: true });
|
|
12508
12770
|
await import_node_fs34.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
12509
12771
|
}
|
|
12510
12772
|
var VectorIndex = class {
|
|
@@ -12662,8 +12924,8 @@ var ALL_PHASES = [
|
|
|
12662
12924
|
];
|
|
12663
12925
|
function classifyChange(relPath) {
|
|
12664
12926
|
const phases = /* @__PURE__ */ new Set();
|
|
12665
|
-
const base =
|
|
12666
|
-
const segments = relPath.split(
|
|
12927
|
+
const base = import_node_path56.default.basename(relPath).toLowerCase();
|
|
12928
|
+
const segments = relPath.split(import_node_path56.default.sep).map((s) => s.toLowerCase());
|
|
12667
12929
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
12668
12930
|
phases.add("services");
|
|
12669
12931
|
phases.add("aliases");
|
|
@@ -12791,9 +13053,9 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
12791
13053
|
for (const e of entries) {
|
|
12792
13054
|
if (count >= limit) return;
|
|
12793
13055
|
if (!e.isDirectory()) continue;
|
|
12794
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
13056
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path56.default.join(dir, e.name) + import_node_path56.default.sep))) continue;
|
|
12795
13057
|
count++;
|
|
12796
|
-
if (depth < 2) visit(
|
|
13058
|
+
if (depth < 2) visit(import_node_path56.default.join(dir, e.name), depth + 1);
|
|
12797
13059
|
}
|
|
12798
13060
|
};
|
|
12799
13061
|
visit(scanPath, 0);
|
|
@@ -12811,8 +13073,8 @@ async function startWatch(graph, opts) {
|
|
|
12811
13073
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
12812
13074
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
12813
13075
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
12814
|
-
const policyFilePath =
|
|
12815
|
-
const policyViolationsPath =
|
|
13076
|
+
const policyFilePath = import_node_path56.default.join(opts.scanPath, "policy.json");
|
|
13077
|
+
const policyViolationsPath = import_node_path56.default.join(import_node_path56.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
12816
13078
|
let policies = [];
|
|
12817
13079
|
try {
|
|
12818
13080
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -12863,7 +13125,7 @@ async function startWatch(graph, opts) {
|
|
|
12863
13125
|
assertBindAuthority(host, auth.authToken);
|
|
12864
13126
|
const port = opts.port ?? 8080;
|
|
12865
13127
|
const otelPort = opts.otelPort ?? 4318;
|
|
12866
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
13128
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path56.default.join(import_node_path56.default.dirname(opts.outPath), "embeddings.json");
|
|
12867
13129
|
let searchIndex;
|
|
12868
13130
|
try {
|
|
12869
13131
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -12881,7 +13143,7 @@ async function startWatch(graph, opts) {
|
|
|
12881
13143
|
// Paths are derived from the explicit options the watch caller passes
|
|
12882
13144
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
12883
13145
|
// fields so the registry shape is complete.
|
|
12884
|
-
...pathsForProject(projectName,
|
|
13146
|
+
...pathsForProject(projectName, import_node_path56.default.dirname(opts.outPath)),
|
|
12885
13147
|
snapshotPath: opts.outPath,
|
|
12886
13148
|
errorsPath: opts.errorsPath,
|
|
12887
13149
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -12999,9 +13261,9 @@ async function startWatch(graph, opts) {
|
|
|
12999
13261
|
};
|
|
13000
13262
|
const onPath = (absPath) => {
|
|
13001
13263
|
if (shouldIgnore(absPath)) return;
|
|
13002
|
-
const rel =
|
|
13264
|
+
const rel = import_node_path56.default.relative(opts.scanPath, absPath);
|
|
13003
13265
|
if (!rel || rel.startsWith("..")) return;
|
|
13004
|
-
pendingPaths.add(rel.split(
|
|
13266
|
+
pendingPaths.add(rel.split(import_node_path56.default.sep).join("/"));
|
|
13005
13267
|
const phases = classifyChange(rel);
|
|
13006
13268
|
if (phases.size === 0) {
|
|
13007
13269
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -13058,7 +13320,7 @@ async function startWatch(graph, opts) {
|
|
|
13058
13320
|
// src/deploy/detect.ts
|
|
13059
13321
|
init_cjs_shims();
|
|
13060
13322
|
var import_node_fs36 = require("fs");
|
|
13061
|
-
var
|
|
13323
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
13062
13324
|
var import_node_child_process2 = require("child_process");
|
|
13063
13325
|
var import_node_crypto5 = require("crypto");
|
|
13064
13326
|
function generateToken() {
|
|
@@ -13158,7 +13420,7 @@ async function runDeploy(opts = {}) {
|
|
|
13158
13420
|
const token = generateToken();
|
|
13159
13421
|
switch (substrate) {
|
|
13160
13422
|
case "docker-compose": {
|
|
13161
|
-
const artifactPath =
|
|
13423
|
+
const artifactPath = import_node_path57.default.join(cwd, "docker-compose.neat.yml");
|
|
13162
13424
|
const contents = emitDockerCompose(cwd);
|
|
13163
13425
|
await import_node_fs36.promises.writeFile(artifactPath, contents, "utf8");
|
|
13164
13426
|
return {
|
|
@@ -13166,11 +13428,11 @@ async function runDeploy(opts = {}) {
|
|
|
13166
13428
|
artifactPath,
|
|
13167
13429
|
token,
|
|
13168
13430
|
contents,
|
|
13169
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
13431
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path57.default.basename(artifactPath)} up -d`
|
|
13170
13432
|
};
|
|
13171
13433
|
}
|
|
13172
13434
|
case "systemd": {
|
|
13173
|
-
const artifactPath =
|
|
13435
|
+
const artifactPath = import_node_path57.default.join(cwd, "neat.service");
|
|
13174
13436
|
const contents = emitSystemdUnit(cwd);
|
|
13175
13437
|
await import_node_fs36.promises.writeFile(artifactPath, contents, "utf8");
|
|
13176
13438
|
return {
|
|
@@ -13206,7 +13468,7 @@ init_cjs_shims();
|
|
|
13206
13468
|
// src/installers/javascript.ts
|
|
13207
13469
|
init_cjs_shims();
|
|
13208
13470
|
var import_node_fs37 = require("fs");
|
|
13209
|
-
var
|
|
13471
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13210
13472
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
13211
13473
|
|
|
13212
13474
|
// src/installers/templates.ts
|
|
@@ -13859,11 +14121,11 @@ var OTEL_ENV = {
|
|
|
13859
14121
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
13860
14122
|
};
|
|
13861
14123
|
function serviceNodeName(pkg, serviceDir) {
|
|
13862
|
-
return pkg.name ??
|
|
14124
|
+
return pkg.name ?? import_node_path58.default.basename(serviceDir);
|
|
13863
14125
|
}
|
|
13864
14126
|
function projectToken(pkg, serviceDir, project) {
|
|
13865
14127
|
if (project && project.length > 0) return project;
|
|
13866
|
-
return pkg.name ??
|
|
14128
|
+
return pkg.name ?? import_node_path58.default.basename(serviceDir);
|
|
13867
14129
|
}
|
|
13868
14130
|
async function readJsonFile(p) {
|
|
13869
14131
|
try {
|
|
@@ -13876,16 +14138,16 @@ async function readJsonFile(p) {
|
|
|
13876
14138
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
13877
14139
|
const deps = allDeps(pkg);
|
|
13878
14140
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
13879
|
-
const appJson = await readJsonFile(
|
|
14141
|
+
const appJson = await readJsonFile(import_node_path58.default.join(pkgRoot, "app.json"));
|
|
13880
14142
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
13881
14143
|
return "react-native";
|
|
13882
14144
|
}
|
|
13883
|
-
if (await exists3(
|
|
14145
|
+
if (await exists3(import_node_path58.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path58.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path58.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
13884
14146
|
return "browser-bundle";
|
|
13885
14147
|
}
|
|
13886
|
-
if (await exists3(
|
|
13887
|
-
if (await exists3(
|
|
13888
|
-
if (await exists3(
|
|
14148
|
+
if (await exists3(import_node_path58.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
14149
|
+
if (await exists3(import_node_path58.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
14150
|
+
if (await exists3(import_node_path58.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path58.default.join(pkgRoot, "deno.lock"))) {
|
|
13889
14151
|
return "deno";
|
|
13890
14152
|
}
|
|
13891
14153
|
const engines = pkg.engines ?? {};
|
|
@@ -13894,7 +14156,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
13894
14156
|
}
|
|
13895
14157
|
async function readPackageJson2(serviceDir) {
|
|
13896
14158
|
try {
|
|
13897
|
-
const raw = await import_node_fs37.promises.readFile(
|
|
14159
|
+
const raw = await import_node_fs37.promises.readFile(import_node_path58.default.join(serviceDir, "package.json"), "utf8");
|
|
13898
14160
|
return JSON.parse(raw);
|
|
13899
14161
|
} catch {
|
|
13900
14162
|
return null;
|
|
@@ -13938,7 +14200,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
13938
14200
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
13939
14201
|
async function findNextConfig(serviceDir) {
|
|
13940
14202
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
13941
|
-
const candidate =
|
|
14203
|
+
const candidate = import_node_path58.default.join(serviceDir, name);
|
|
13942
14204
|
if (await exists3(candidate)) return candidate;
|
|
13943
14205
|
}
|
|
13944
14206
|
return null;
|
|
@@ -14007,7 +14269,7 @@ function hasRemixDependency(pkg) {
|
|
|
14007
14269
|
}
|
|
14008
14270
|
async function findRemixEntry(serviceDir) {
|
|
14009
14271
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
14010
|
-
const candidate =
|
|
14272
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14011
14273
|
if (await exists3(candidate)) return candidate;
|
|
14012
14274
|
}
|
|
14013
14275
|
return null;
|
|
@@ -14019,14 +14281,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
14019
14281
|
}
|
|
14020
14282
|
async function findSvelteKitHooks(serviceDir) {
|
|
14021
14283
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
14022
|
-
const candidate =
|
|
14284
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14023
14285
|
if (await exists3(candidate)) return candidate;
|
|
14024
14286
|
}
|
|
14025
14287
|
return null;
|
|
14026
14288
|
}
|
|
14027
14289
|
async function findSvelteKitConfig(serviceDir) {
|
|
14028
14290
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
14029
|
-
const candidate =
|
|
14291
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14030
14292
|
if (await exists3(candidate)) return candidate;
|
|
14031
14293
|
}
|
|
14032
14294
|
return null;
|
|
@@ -14037,7 +14299,7 @@ function hasNuxtDependency(pkg) {
|
|
|
14037
14299
|
}
|
|
14038
14300
|
async function findNuxtConfig(serviceDir) {
|
|
14039
14301
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
14040
|
-
const candidate =
|
|
14302
|
+
const candidate = import_node_path58.default.join(serviceDir, name);
|
|
14041
14303
|
if (await exists3(candidate)) return candidate;
|
|
14042
14304
|
}
|
|
14043
14305
|
return null;
|
|
@@ -14048,7 +14310,7 @@ function hasAstroDependency(pkg) {
|
|
|
14048
14310
|
}
|
|
14049
14311
|
async function findAstroConfig(serviceDir) {
|
|
14050
14312
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
14051
|
-
const candidate =
|
|
14313
|
+
const candidate = import_node_path58.default.join(serviceDir, name);
|
|
14052
14314
|
if (await exists3(candidate)) return candidate;
|
|
14053
14315
|
}
|
|
14054
14316
|
return null;
|
|
@@ -14062,7 +14324,7 @@ function parseNextMajor(range) {
|
|
|
14062
14324
|
return Number.isFinite(n) ? n : null;
|
|
14063
14325
|
}
|
|
14064
14326
|
async function isTypeScriptProject(serviceDir) {
|
|
14065
|
-
return exists3(
|
|
14327
|
+
return exists3(import_node_path58.default.join(serviceDir, "tsconfig.json"));
|
|
14066
14328
|
}
|
|
14067
14329
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
14068
14330
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -14111,7 +14373,7 @@ function entryFromScript(script) {
|
|
|
14111
14373
|
}
|
|
14112
14374
|
async function resolveEntry(serviceDir, pkg) {
|
|
14113
14375
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
14114
|
-
const candidate =
|
|
14376
|
+
const candidate = import_node_path58.default.resolve(serviceDir, pkg.main);
|
|
14115
14377
|
if (await exists3(candidate)) return candidate;
|
|
14116
14378
|
}
|
|
14117
14379
|
if (pkg.bin) {
|
|
@@ -14125,40 +14387,40 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
14125
14387
|
if (typeof first === "string") binEntry = first;
|
|
14126
14388
|
}
|
|
14127
14389
|
if (binEntry) {
|
|
14128
|
-
const candidate =
|
|
14390
|
+
const candidate = import_node_path58.default.resolve(serviceDir, binEntry);
|
|
14129
14391
|
if (await exists3(candidate)) return candidate;
|
|
14130
14392
|
}
|
|
14131
14393
|
}
|
|
14132
14394
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
14133
14395
|
if (startEntry) {
|
|
14134
|
-
const candidate =
|
|
14396
|
+
const candidate = import_node_path58.default.resolve(serviceDir, startEntry);
|
|
14135
14397
|
if (await exists3(candidate)) return candidate;
|
|
14136
14398
|
}
|
|
14137
14399
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
14138
14400
|
if (devEntry) {
|
|
14139
|
-
const candidate =
|
|
14401
|
+
const candidate = import_node_path58.default.resolve(serviceDir, devEntry);
|
|
14140
14402
|
if (await exists3(candidate)) return candidate;
|
|
14141
14403
|
}
|
|
14142
14404
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
14143
|
-
const candidate =
|
|
14405
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14144
14406
|
if (await exists3(candidate)) return candidate;
|
|
14145
14407
|
}
|
|
14146
14408
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
14147
|
-
const candidate =
|
|
14409
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14148
14410
|
if (await exists3(candidate)) return candidate;
|
|
14149
14411
|
}
|
|
14150
14412
|
for (const rel of ROOT_NAMED_CANDIDATES) {
|
|
14151
|
-
const candidate =
|
|
14413
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14152
14414
|
if (await exists3(candidate)) return candidate;
|
|
14153
14415
|
}
|
|
14154
14416
|
for (const name of INDEX_CANDIDATES) {
|
|
14155
|
-
const candidate =
|
|
14417
|
+
const candidate = import_node_path58.default.join(serviceDir, name);
|
|
14156
14418
|
if (await exists3(candidate)) return candidate;
|
|
14157
14419
|
}
|
|
14158
14420
|
return null;
|
|
14159
14421
|
}
|
|
14160
14422
|
function dispatchEntry(entryFile, pkg) {
|
|
14161
|
-
const ext =
|
|
14423
|
+
const ext = import_node_path58.default.extname(entryFile).toLowerCase();
|
|
14162
14424
|
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
14163
14425
|
if (ext === ".mjs") return "esm";
|
|
14164
14426
|
if (ext === ".cjs") return "cjs";
|
|
@@ -14175,9 +14437,9 @@ function otelInitContents(flavor) {
|
|
|
14175
14437
|
return OTEL_INIT_CJS;
|
|
14176
14438
|
}
|
|
14177
14439
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
14178
|
-
let rel =
|
|
14440
|
+
let rel = import_node_path58.default.relative(import_node_path58.default.dirname(entryFile), otelInitFile);
|
|
14179
14441
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
14180
|
-
rel = rel.split(
|
|
14442
|
+
rel = rel.split(import_node_path58.default.sep).join("/");
|
|
14181
14443
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
14182
14444
|
if (flavor === "esm") return `import '${rel}'`;
|
|
14183
14445
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -14190,27 +14452,27 @@ function lineIsOtelInjection(line) {
|
|
|
14190
14452
|
}
|
|
14191
14453
|
async function detectsSrcLayout(serviceDir) {
|
|
14192
14454
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
14193
|
-
exists3(
|
|
14194
|
-
exists3(
|
|
14195
|
-
exists3(
|
|
14196
|
-
exists3(
|
|
14455
|
+
exists3(import_node_path58.default.join(serviceDir, "src", "app")),
|
|
14456
|
+
exists3(import_node_path58.default.join(serviceDir, "src", "pages")),
|
|
14457
|
+
exists3(import_node_path58.default.join(serviceDir, "app")),
|
|
14458
|
+
exists3(import_node_path58.default.join(serviceDir, "pages"))
|
|
14197
14459
|
]);
|
|
14198
14460
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
14199
14461
|
}
|
|
14200
14462
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
14201
14463
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
14202
14464
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
14203
|
-
const baseDir = srcLayout ?
|
|
14204
|
-
const instrumentationFile =
|
|
14205
|
-
const instrumentationNodeFile =
|
|
14465
|
+
const baseDir = srcLayout ? import_node_path58.default.join(serviceDir, "src") : serviceDir;
|
|
14466
|
+
const instrumentationFile = import_node_path58.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
14467
|
+
const instrumentationNodeFile = import_node_path58.default.join(
|
|
14206
14468
|
baseDir,
|
|
14207
14469
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
14208
14470
|
);
|
|
14209
|
-
const instrumentationEdgeFile =
|
|
14471
|
+
const instrumentationEdgeFile = import_node_path58.default.join(
|
|
14210
14472
|
baseDir,
|
|
14211
14473
|
useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
|
|
14212
14474
|
);
|
|
14213
|
-
const envNeatFile =
|
|
14475
|
+
const envNeatFile = import_node_path58.default.join(baseDir, ".env.neat");
|
|
14214
14476
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
14215
14477
|
const dependencyEdits = [];
|
|
14216
14478
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -14335,7 +14597,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
14335
14597
|
return edits;
|
|
14336
14598
|
}
|
|
14337
14599
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
14338
|
-
const envNeatFile =
|
|
14600
|
+
const envNeatFile = import_node_path58.default.join(serviceDir, ".env.neat");
|
|
14339
14601
|
if (!await exists3(envNeatFile)) {
|
|
14340
14602
|
generatedFiles.push({
|
|
14341
14603
|
file: envNeatFile,
|
|
@@ -14370,7 +14632,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
14370
14632
|
}
|
|
14371
14633
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
14372
14634
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
14373
|
-
const otelServerFile =
|
|
14635
|
+
const otelServerFile = import_node_path58.default.join(
|
|
14374
14636
|
serviceDir,
|
|
14375
14637
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
14376
14638
|
);
|
|
@@ -14427,11 +14689,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
14427
14689
|
}
|
|
14428
14690
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
14429
14691
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
14430
|
-
const otelInitFile =
|
|
14692
|
+
const otelInitFile = import_node_path58.default.join(
|
|
14431
14693
|
serviceDir,
|
|
14432
14694
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
14433
14695
|
);
|
|
14434
|
-
const resolvedHooksFile = hooksFile ??
|
|
14696
|
+
const resolvedHooksFile = hooksFile ?? import_node_path58.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
14435
14697
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
14436
14698
|
const generatedFiles = [];
|
|
14437
14699
|
const entrypointEdits = [];
|
|
@@ -14493,11 +14755,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
14493
14755
|
}
|
|
14494
14756
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
14495
14757
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
14496
|
-
const otelPluginFile =
|
|
14758
|
+
const otelPluginFile = import_node_path58.default.join(
|
|
14497
14759
|
serviceDir,
|
|
14498
14760
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
14499
14761
|
);
|
|
14500
|
-
const otelInitFile =
|
|
14762
|
+
const otelInitFile = import_node_path58.default.join(
|
|
14501
14763
|
serviceDir,
|
|
14502
14764
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
14503
14765
|
);
|
|
@@ -14548,19 +14810,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
14548
14810
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
14549
14811
|
async function findAstroMiddleware(serviceDir) {
|
|
14550
14812
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
14551
|
-
const candidate =
|
|
14813
|
+
const candidate = import_node_path58.default.join(serviceDir, rel);
|
|
14552
14814
|
if (await exists3(candidate)) return candidate;
|
|
14553
14815
|
}
|
|
14554
14816
|
return null;
|
|
14555
14817
|
}
|
|
14556
14818
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
14557
14819
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
14558
|
-
const otelInitFile =
|
|
14820
|
+
const otelInitFile = import_node_path58.default.join(
|
|
14559
14821
|
serviceDir,
|
|
14560
14822
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
14561
14823
|
);
|
|
14562
14824
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
14563
|
-
const middlewareFile = existingMiddleware ??
|
|
14825
|
+
const middlewareFile = existingMiddleware ?? import_node_path58.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
14564
14826
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
14565
14827
|
const generatedFiles = [];
|
|
14566
14828
|
const entrypointEdits = [];
|
|
@@ -14656,7 +14918,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
14656
14918
|
}
|
|
14657
14919
|
async function plan(serviceDir, opts) {
|
|
14658
14920
|
const pkg = await readPackageJson2(serviceDir);
|
|
14659
|
-
const manifestPath =
|
|
14921
|
+
const manifestPath = import_node_path58.default.join(serviceDir, "package.json");
|
|
14660
14922
|
const project = opts?.project;
|
|
14661
14923
|
const empty = {
|
|
14662
14924
|
language: "javascript",
|
|
@@ -14691,8 +14953,8 @@ async function plan(serviceDir, opts) {
|
|
|
14691
14953
|
return { ...empty, libOnly: true };
|
|
14692
14954
|
}
|
|
14693
14955
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
14694
|
-
const otelInitFile =
|
|
14695
|
-
const envNeatFile =
|
|
14956
|
+
const otelInitFile = import_node_path58.default.join(import_node_path58.default.dirname(entryFile), otelInitFilename(flavor));
|
|
14957
|
+
const envNeatFile = import_node_path58.default.join(serviceDir, ".env.neat");
|
|
14696
14958
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
14697
14959
|
const dependencyEdits = [];
|
|
14698
14960
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -14761,13 +15023,13 @@ async function plan(serviceDir, opts) {
|
|
|
14761
15023
|
};
|
|
14762
15024
|
}
|
|
14763
15025
|
function isAllowedWritePath(serviceDir, target) {
|
|
14764
|
-
const rel =
|
|
15026
|
+
const rel = import_node_path58.default.relative(serviceDir, target);
|
|
14765
15027
|
if (rel.startsWith("..")) return false;
|
|
14766
|
-
const base =
|
|
15028
|
+
const base = import_node_path58.default.basename(target);
|
|
14767
15029
|
if (base === "package.json") return true;
|
|
14768
15030
|
if (base === ".env.neat") return true;
|
|
14769
15031
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
14770
|
-
const relPosix = rel.split(
|
|
15032
|
+
const relPosix = rel.split(import_node_path58.default.sep).join("/");
|
|
14771
15033
|
if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
14772
15034
|
if (relPosix === base) return true;
|
|
14773
15035
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -14784,7 +15046,7 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
14784
15046
|
return false;
|
|
14785
15047
|
}
|
|
14786
15048
|
async function writeAtomic(file, contents) {
|
|
14787
|
-
await import_node_fs37.promises.mkdir(
|
|
15049
|
+
await import_node_fs37.promises.mkdir(import_node_path58.default.dirname(file), { recursive: true });
|
|
14788
15050
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
14789
15051
|
await import_node_fs37.promises.writeFile(tmp, contents, "utf8");
|
|
14790
15052
|
await import_node_fs37.promises.rename(tmp, file);
|
|
@@ -14968,7 +15230,7 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
14968
15230
|
...removed.map((f) => `removed: ${f}`),
|
|
14969
15231
|
""
|
|
14970
15232
|
];
|
|
14971
|
-
const rollbackPath =
|
|
15233
|
+
const rollbackPath = import_node_path58.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
14972
15234
|
await import_node_fs37.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
14973
15235
|
}
|
|
14974
15236
|
function injectInstrumentationHook(raw) {
|
|
@@ -14999,7 +15261,7 @@ var javascriptInstaller = {
|
|
|
14999
15261
|
// src/installers/python.ts
|
|
15000
15262
|
init_cjs_shims();
|
|
15001
15263
|
var import_node_fs38 = require("fs");
|
|
15002
|
-
var
|
|
15264
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
15003
15265
|
var SDK_PACKAGES2 = [
|
|
15004
15266
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
15005
15267
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -15020,7 +15282,7 @@ async function exists4(p) {
|
|
|
15020
15282
|
async function detect2(serviceDir) {
|
|
15021
15283
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
15022
15284
|
for (const m of markers) {
|
|
15023
|
-
if (await exists4(
|
|
15285
|
+
if (await exists4(import_node_path59.default.join(serviceDir, m))) return true;
|
|
15024
15286
|
}
|
|
15025
15287
|
return false;
|
|
15026
15288
|
}
|
|
@@ -15030,7 +15292,7 @@ function reqPackageName(line) {
|
|
|
15030
15292
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
15031
15293
|
}
|
|
15032
15294
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
15033
|
-
const file =
|
|
15295
|
+
const file = import_node_path59.default.join(serviceDir, "requirements.txt");
|
|
15034
15296
|
if (!await exists4(file)) return null;
|
|
15035
15297
|
const raw = await import_node_fs38.promises.readFile(file, "utf8");
|
|
15036
15298
|
const presentNames = new Set(
|
|
@@ -15040,7 +15302,7 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
15040
15302
|
return { manifest: file, missing: [...missing] };
|
|
15041
15303
|
}
|
|
15042
15304
|
async function planProcfileEdits(serviceDir) {
|
|
15043
|
-
const procfile =
|
|
15305
|
+
const procfile = import_node_path59.default.join(serviceDir, "Procfile");
|
|
15044
15306
|
if (!await exists4(procfile)) return [];
|
|
15045
15307
|
const raw = await import_node_fs38.promises.readFile(procfile, "utf8");
|
|
15046
15308
|
const edits = [];
|
|
@@ -15129,7 +15391,7 @@ async function apply2(installPlan) {
|
|
|
15129
15391
|
if (raw === void 0) {
|
|
15130
15392
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
15131
15393
|
}
|
|
15132
|
-
const base =
|
|
15394
|
+
const base = import_node_path59.default.basename(file);
|
|
15133
15395
|
if (base === "requirements.txt") {
|
|
15134
15396
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
15135
15397
|
if (edits.length > 0) {
|
|
@@ -15168,7 +15430,7 @@ async function rollback2(installPlan, originals) {
|
|
|
15168
15430
|
...restored.map((f) => `restored: ${f}`),
|
|
15169
15431
|
""
|
|
15170
15432
|
];
|
|
15171
|
-
const rollbackPath =
|
|
15433
|
+
const rollbackPath = import_node_path59.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
15172
15434
|
await import_node_fs38.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
15173
15435
|
}
|
|
15174
15436
|
var pythonInstaller = {
|
|
@@ -15295,7 +15557,7 @@ init_cjs_shims();
|
|
|
15295
15557
|
var import_node_fs39 = require("fs");
|
|
15296
15558
|
var import_node_http = __toESM(require("http"), 1);
|
|
15297
15559
|
var import_node_net = __toESM(require("net"), 1);
|
|
15298
|
-
var
|
|
15560
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
15299
15561
|
var import_node_url4 = require("url");
|
|
15300
15562
|
var import_node_child_process3 = require("child_process");
|
|
15301
15563
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
@@ -15305,7 +15567,7 @@ async function extractAndPersist(opts) {
|
|
|
15305
15567
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
15306
15568
|
resetGraph(graphKey);
|
|
15307
15569
|
const graph = getGraph(graphKey);
|
|
15308
|
-
const projectPaths = pathsForProject(graphKey,
|
|
15570
|
+
const projectPaths = pathsForProject(graphKey, import_node_path60.default.join(opts.scanPath, "neat-out"));
|
|
15309
15571
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
15310
15572
|
errorsPath: projectPaths.errorsPath
|
|
15311
15573
|
});
|
|
@@ -15357,7 +15619,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15357
15619
|
libOnly++;
|
|
15358
15620
|
const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
|
|
15359
15621
|
if (appDeps.length > 0) {
|
|
15360
|
-
const svcName =
|
|
15622
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15361
15623
|
const list = appDeps.join(", ");
|
|
15362
15624
|
console.warn(
|
|
15363
15625
|
`neat: runtime layer won't engage for ${svcName}: no entry point found.
|
|
@@ -15370,7 +15632,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15370
15632
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
15371
15633
|
} else if (outcome.outcome === "react-native") {
|
|
15372
15634
|
reactNative++;
|
|
15373
|
-
const svcName =
|
|
15635
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15374
15636
|
console.log(
|
|
15375
15637
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
15376
15638
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -15381,7 +15643,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15381
15643
|
);
|
|
15382
15644
|
} else if (outcome.outcome === "bun") {
|
|
15383
15645
|
bun++;
|
|
15384
|
-
const svcName =
|
|
15646
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15385
15647
|
console.log(
|
|
15386
15648
|
`neat: ${svc.dir} detected as Bun
|
|
15387
15649
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -15392,7 +15654,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15392
15654
|
);
|
|
15393
15655
|
} else if (outcome.outcome === "deno") {
|
|
15394
15656
|
deno++;
|
|
15395
|
-
const svcName =
|
|
15657
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15396
15658
|
console.log(
|
|
15397
15659
|
`neat: ${svc.dir} detected as Deno
|
|
15398
15660
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -15403,7 +15665,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15403
15665
|
);
|
|
15404
15666
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
15405
15667
|
cloudflareWorkers++;
|
|
15406
|
-
const svcName =
|
|
15668
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15407
15669
|
console.log(
|
|
15408
15670
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
15409
15671
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -15414,7 +15676,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15414
15676
|
);
|
|
15415
15677
|
} else if (outcome.outcome === "electron") {
|
|
15416
15678
|
electron++;
|
|
15417
|
-
const svcName =
|
|
15679
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15418
15680
|
console.log(
|
|
15419
15681
|
`neat: ${svc.dir} detected as Electron
|
|
15420
15682
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -15427,7 +15689,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
15427
15689
|
if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
|
|
15428
15690
|
const gaps = uninstrumentedLibraries(svc.pkg);
|
|
15429
15691
|
if (gaps.length > 0) {
|
|
15430
|
-
const svcName =
|
|
15692
|
+
const svcName = import_node_path60.default.basename(svc.dir);
|
|
15431
15693
|
const list = gaps.join(", ");
|
|
15432
15694
|
const subject = gaps.length === 1 ? "this library" : "these libraries";
|
|
15433
15695
|
const aux = gaps.length === 1 ? "isn't" : "aren't";
|
|
@@ -15633,8 +15895,8 @@ async function persistedPortsFor(scanPath) {
|
|
|
15633
15895
|
return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
|
|
15634
15896
|
}
|
|
15635
15897
|
async function acquireSpawnLock(scanPath) {
|
|
15636
|
-
const lockPath =
|
|
15637
|
-
await import_node_fs39.promises.mkdir(
|
|
15898
|
+
const lockPath = import_node_path60.default.join(scanPath, "neat-out", "daemon.spawn.lock");
|
|
15899
|
+
await import_node_fs39.promises.mkdir(import_node_path60.default.dirname(lockPath), { recursive: true });
|
|
15638
15900
|
const STALE_LOCK_MS = 6e4;
|
|
15639
15901
|
try {
|
|
15640
15902
|
const fd = await import_node_fs39.promises.open(lockPath, "wx");
|
|
@@ -15679,13 +15941,13 @@ async function healthIsForProject(restPort, project) {
|
|
|
15679
15941
|
return false;
|
|
15680
15942
|
}
|
|
15681
15943
|
function daemonLogPath(projectPath2) {
|
|
15682
|
-
return
|
|
15944
|
+
return import_node_path60.default.join(projectPath2, "neat-out", "daemon.log");
|
|
15683
15945
|
}
|
|
15684
15946
|
function spawnDaemonDetached(spec) {
|
|
15685
|
-
const here =
|
|
15947
|
+
const here = import_node_path60.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
|
|
15686
15948
|
const candidates = [
|
|
15687
|
-
|
|
15688
|
-
|
|
15949
|
+
import_node_path60.default.join(here, "neatd.cjs"),
|
|
15950
|
+
import_node_path60.default.join(here, "neatd.js")
|
|
15689
15951
|
];
|
|
15690
15952
|
let entry2 = null;
|
|
15691
15953
|
const fsSync = require("fs");
|
|
@@ -15715,7 +15977,7 @@ function spawnDaemonDetached(spec) {
|
|
|
15715
15977
|
let logFd = null;
|
|
15716
15978
|
if (spec) {
|
|
15717
15979
|
const logPath = daemonLogPath(spec.projectPath);
|
|
15718
|
-
fsSync.mkdirSync(
|
|
15980
|
+
fsSync.mkdirSync(import_node_path60.default.dirname(logPath), { recursive: true });
|
|
15719
15981
|
logFd = fsSync.openSync(logPath, "a");
|
|
15720
15982
|
}
|
|
15721
15983
|
const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
|
|
@@ -15914,7 +16176,7 @@ async function runOrchestrator(opts) {
|
|
|
15914
16176
|
result.steps.browser = openBrowser(dashboardUrl);
|
|
15915
16177
|
}
|
|
15916
16178
|
const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
|
|
15917
|
-
const daemonLog = daemonRunning ?
|
|
16179
|
+
const daemonLog = daemonRunning ? import_node_path60.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
|
|
15918
16180
|
printSummary(result, graph, dashboardUrl, daemonLog);
|
|
15919
16181
|
return result;
|
|
15920
16182
|
}
|
|
@@ -16371,7 +16633,7 @@ async function runConnectorCommand(rawArgs, deps = {}) {
|
|
|
16371
16633
|
|
|
16372
16634
|
// src/hooks-cli.ts
|
|
16373
16635
|
init_cjs_shims();
|
|
16374
|
-
var
|
|
16636
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
16375
16637
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
16376
16638
|
var import_node_fs40 = require("fs");
|
|
16377
16639
|
var import_node_url5 = require("url");
|
|
@@ -16380,14 +16642,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
|
|
|
16380
16642
|
var GUIDE_INSTALL_NAME = "neat-graph-first.md";
|
|
16381
16643
|
var HOOK_MATCHER = "Grep|Glob|Bash";
|
|
16382
16644
|
function moduleDir() {
|
|
16383
|
-
return typeof __dirname !== "undefined" ? __dirname :
|
|
16645
|
+
return typeof __dirname !== "undefined" ? __dirname : import_node_path61.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
|
|
16384
16646
|
}
|
|
16385
16647
|
async function readSkillAsset(rel) {
|
|
16386
16648
|
const here = moduleDir();
|
|
16387
16649
|
const candidates = [
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16650
|
+
import_node_path61.default.resolve(here, "../../claude-skill", rel),
|
|
16651
|
+
import_node_path61.default.resolve(here, "../../../claude-skill", rel),
|
|
16652
|
+
import_node_path61.default.resolve(here, "../claude-skill", rel)
|
|
16391
16653
|
];
|
|
16392
16654
|
for (const candidate of candidates) {
|
|
16393
16655
|
try {
|
|
@@ -16401,17 +16663,17 @@ async function readSkillAsset(rel) {
|
|
|
16401
16663
|
}
|
|
16402
16664
|
function neatHome3() {
|
|
16403
16665
|
const override = process.env.NEAT_HOME;
|
|
16404
|
-
if (override && override.length > 0) return
|
|
16405
|
-
return
|
|
16666
|
+
if (override && override.length > 0) return import_node_path61.default.resolve(override);
|
|
16667
|
+
return import_node_path61.default.join(import_node_os5.default.homedir(), ".neat");
|
|
16406
16668
|
}
|
|
16407
16669
|
function claudeSettingsPath() {
|
|
16408
16670
|
const override = process.env.NEAT_CLAUDE_SETTINGS;
|
|
16409
|
-
if (override && override.length > 0) return
|
|
16671
|
+
if (override && override.length > 0) return import_node_path61.default.resolve(override);
|
|
16410
16672
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os5.default.homedir();
|
|
16411
|
-
return
|
|
16673
|
+
return import_node_path61.default.join(home, ".claude", "settings.json");
|
|
16412
16674
|
}
|
|
16413
16675
|
function installedHookPath() {
|
|
16414
|
-
return
|
|
16676
|
+
return import_node_path61.default.join(neatHome3(), "hooks", HOOK_FILENAME);
|
|
16415
16677
|
}
|
|
16416
16678
|
function isNeatSearchEntry(entry2) {
|
|
16417
16679
|
return (entry2.hooks ?? []).some(
|
|
@@ -16444,9 +16706,9 @@ async function runHooks(opts) {
|
|
|
16444
16706
|
const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
|
|
16445
16707
|
const guide = await readSkillAsset(GUIDE_FILENAME);
|
|
16446
16708
|
const scriptPath = installedHookPath();
|
|
16447
|
-
await import_node_fs40.promises.mkdir(
|
|
16709
|
+
await import_node_fs40.promises.mkdir(import_node_path61.default.dirname(scriptPath), { recursive: true });
|
|
16448
16710
|
await import_node_fs40.promises.writeFile(scriptPath, hookScript, { mode: 493 });
|
|
16449
|
-
const guidePath =
|
|
16711
|
+
const guidePath = import_node_path61.default.join(neatHome3(), GUIDE_INSTALL_NAME);
|
|
16450
16712
|
await import_node_fs40.promises.writeFile(guidePath, guide, "utf8");
|
|
16451
16713
|
const settingsFile = claudeSettingsPath();
|
|
16452
16714
|
let settings = {};
|
|
@@ -16473,7 +16735,7 @@ async function runHooks(opts) {
|
|
|
16473
16735
|
...settings,
|
|
16474
16736
|
hooks: { ...hooks, PreToolUse: preToolUse }
|
|
16475
16737
|
};
|
|
16476
|
-
await import_node_fs40.promises.mkdir(
|
|
16738
|
+
await import_node_fs40.promises.mkdir(import_node_path61.default.dirname(settingsFile), { recursive: true });
|
|
16477
16739
|
await import_node_fs40.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
16478
16740
|
console.log(`neat hooks: installed the search-nudge hook`);
|
|
16479
16741
|
console.log(` script: ${scriptPath}`);
|
|
@@ -16545,11 +16807,11 @@ async function runHooksCommand(args) {
|
|
|
16545
16807
|
|
|
16546
16808
|
// src/cli-verbs.ts
|
|
16547
16809
|
init_cjs_shims();
|
|
16548
|
-
var
|
|
16810
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
16549
16811
|
|
|
16550
16812
|
// src/cli-client.ts
|
|
16551
16813
|
init_cjs_shims();
|
|
16552
|
-
var
|
|
16814
|
+
var import_types50 = require("@neat.is/types");
|
|
16553
16815
|
var HttpError = class extends Error {
|
|
16554
16816
|
constructor(status2, message, responseBody = "") {
|
|
16555
16817
|
super(message);
|
|
@@ -16574,10 +16836,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
16574
16836
|
const root = baseUrl.replace(/\/$/, "");
|
|
16575
16837
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
16576
16838
|
return {
|
|
16577
|
-
async get(
|
|
16839
|
+
async get(path64) {
|
|
16578
16840
|
let res;
|
|
16579
16841
|
try {
|
|
16580
|
-
res = await fetch(`${root}${
|
|
16842
|
+
res = await fetch(`${root}${path64}`, {
|
|
16581
16843
|
headers: { ...authHeader }
|
|
16582
16844
|
});
|
|
16583
16845
|
} catch (err) {
|
|
@@ -16589,16 +16851,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
16589
16851
|
const body = await res.text().catch(() => "");
|
|
16590
16852
|
throw new HttpError(
|
|
16591
16853
|
res.status,
|
|
16592
|
-
`${res.status} ${res.statusText} on GET ${
|
|
16854
|
+
`${res.status} ${res.statusText} on GET ${path64}: ${body}`,
|
|
16593
16855
|
body
|
|
16594
16856
|
);
|
|
16595
16857
|
}
|
|
16596
16858
|
return await res.json();
|
|
16597
16859
|
},
|
|
16598
|
-
async post(
|
|
16860
|
+
async post(path64, body) {
|
|
16599
16861
|
let res;
|
|
16600
16862
|
try {
|
|
16601
|
-
res = await fetch(`${root}${
|
|
16863
|
+
res = await fetch(`${root}${path64}`, {
|
|
16602
16864
|
method: "POST",
|
|
16603
16865
|
headers: { "content-type": "application/json", ...authHeader },
|
|
16604
16866
|
body: JSON.stringify(body)
|
|
@@ -16612,7 +16874,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
16612
16874
|
const text = await res.text().catch(() => "");
|
|
16613
16875
|
throw new HttpError(
|
|
16614
16876
|
res.status,
|
|
16615
|
-
`${res.status} ${res.statusText} on POST ${
|
|
16877
|
+
`${res.status} ${res.statusText} on POST ${path64}: ${text}`,
|
|
16616
16878
|
text
|
|
16617
16879
|
);
|
|
16618
16880
|
}
|
|
@@ -16626,12 +16888,12 @@ function projectPath(project, suffix) {
|
|
|
16626
16888
|
}
|
|
16627
16889
|
async function runRootCause(client, input) {
|
|
16628
16890
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
16629
|
-
const
|
|
16891
|
+
const path64 = projectPath(
|
|
16630
16892
|
input.project,
|
|
16631
16893
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
16632
16894
|
);
|
|
16633
16895
|
try {
|
|
16634
|
-
const result = await client.get(
|
|
16896
|
+
const result = await client.get(path64);
|
|
16635
16897
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
16636
16898
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
16637
16899
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -16657,12 +16919,12 @@ async function runRootCause(client, input) {
|
|
|
16657
16919
|
}
|
|
16658
16920
|
async function runBlastRadius(client, input) {
|
|
16659
16921
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
16660
|
-
const
|
|
16922
|
+
const path64 = projectPath(
|
|
16661
16923
|
input.project,
|
|
16662
16924
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
16663
16925
|
);
|
|
16664
16926
|
try {
|
|
16665
|
-
const result = await client.get(
|
|
16927
|
+
const result = await client.get(path64);
|
|
16666
16928
|
if (result.totalAffected === 0) {
|
|
16667
16929
|
return {
|
|
16668
16930
|
summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
|
|
@@ -16691,17 +16953,17 @@ async function runBlastRadius(client, input) {
|
|
|
16691
16953
|
}
|
|
16692
16954
|
}
|
|
16693
16955
|
function formatBlastEntry(n) {
|
|
16694
|
-
const tag = n.edgeProvenance ===
|
|
16956
|
+
const tag = n.edgeProvenance === import_types50.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
16695
16957
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
16696
16958
|
}
|
|
16697
16959
|
async function runDependencies(client, input) {
|
|
16698
16960
|
const depth = input.depth ?? 3;
|
|
16699
|
-
const
|
|
16961
|
+
const path64 = projectPath(
|
|
16700
16962
|
input.project,
|
|
16701
16963
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
16702
16964
|
);
|
|
16703
16965
|
try {
|
|
16704
|
-
const result = await client.get(
|
|
16966
|
+
const result = await client.get(path64);
|
|
16705
16967
|
if (result.total === 0) {
|
|
16706
16968
|
return {
|
|
16707
16969
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -16748,7 +17010,7 @@ async function runObservedDependencies(client, input) {
|
|
|
16748
17010
|
if (result.observed) {
|
|
16749
17011
|
return {
|
|
16750
17012
|
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.`,
|
|
16751
|
-
provenance:
|
|
17013
|
+
provenance: import_types50.Provenance.OBSERVED
|
|
16752
17014
|
};
|
|
16753
17015
|
}
|
|
16754
17016
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -16758,7 +17020,7 @@ async function runObservedDependencies(client, input) {
|
|
|
16758
17020
|
return {
|
|
16759
17021
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
16760
17022
|
block: blockLines.join("\n"),
|
|
16761
|
-
provenance:
|
|
17023
|
+
provenance: import_types50.Provenance.OBSERVED
|
|
16762
17024
|
};
|
|
16763
17025
|
} catch (err) {
|
|
16764
17026
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -16793,9 +17055,9 @@ function formatDuration(ms) {
|
|
|
16793
17055
|
return `${Math.round(h / 24)}d`;
|
|
16794
17056
|
}
|
|
16795
17057
|
async function runIncidents(client, input) {
|
|
16796
|
-
const
|
|
17058
|
+
const path64 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
16797
17059
|
try {
|
|
16798
|
-
const body = await client.get(
|
|
17060
|
+
const body = await client.get(path64);
|
|
16799
17061
|
const events = body.events;
|
|
16800
17062
|
if (events.length === 0) {
|
|
16801
17063
|
return {
|
|
@@ -16812,7 +17074,7 @@ async function runIncidents(client, input) {
|
|
|
16812
17074
|
return {
|
|
16813
17075
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
16814
17076
|
block: blockLines.join("\n"),
|
|
16815
|
-
provenance:
|
|
17077
|
+
provenance: import_types50.Provenance.OBSERVED
|
|
16816
17078
|
};
|
|
16817
17079
|
} catch (err) {
|
|
16818
17080
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -16921,7 +17183,7 @@ async function runStaleEdges(client, input) {
|
|
|
16921
17183
|
return {
|
|
16922
17184
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
16923
17185
|
block: blockLines.join("\n"),
|
|
16924
|
-
provenance:
|
|
17186
|
+
provenance: import_types50.Provenance.STALE
|
|
16925
17187
|
};
|
|
16926
17188
|
}
|
|
16927
17189
|
async function runPolicies(client, input) {
|
|
@@ -17085,7 +17347,7 @@ async function resolveProjectEntry(opts) {
|
|
|
17085
17347
|
const cwd = opts.cwd ?? process.cwd();
|
|
17086
17348
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
17087
17349
|
for (const entry2 of entries) {
|
|
17088
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
17350
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path62.default.sep}`)) {
|
|
17089
17351
|
return entry2;
|
|
17090
17352
|
}
|
|
17091
17353
|
}
|
|
@@ -17238,7 +17500,7 @@ async function runSync(opts) {
|
|
|
17238
17500
|
}
|
|
17239
17501
|
|
|
17240
17502
|
// src/cli.ts
|
|
17241
|
-
var
|
|
17503
|
+
var import_types51 = require("@neat.is/types");
|
|
17242
17504
|
function isNpxInvocation() {
|
|
17243
17505
|
if (process.env.npm_command === "exec") return true;
|
|
17244
17506
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -17549,12 +17811,12 @@ async function runInit(opts) {
|
|
|
17549
17811
|
printDiscoveryReport(opts, services);
|
|
17550
17812
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
17551
17813
|
const patch = renderPatch(sections);
|
|
17552
|
-
const patchPath =
|
|
17814
|
+
const patchPath = import_node_path63.default.join(opts.scanPath, "neat.patch");
|
|
17553
17815
|
if (opts.dryRun) {
|
|
17554
17816
|
await import_node_fs41.promises.writeFile(patchPath, patch, "utf8");
|
|
17555
17817
|
written.push(patchPath);
|
|
17556
17818
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
17557
|
-
const gitignorePath =
|
|
17819
|
+
const gitignorePath = import_node_path63.default.join(opts.scanPath, ".gitignore");
|
|
17558
17820
|
const gitignoreExists = await import_node_fs41.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
17559
17821
|
const verb = gitignoreExists ? "append" : "create";
|
|
17560
17822
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
@@ -17566,9 +17828,9 @@ async function runInit(opts) {
|
|
|
17566
17828
|
const graph = getGraph(graphKey);
|
|
17567
17829
|
const projectPaths = pathsForProject(
|
|
17568
17830
|
graphKey,
|
|
17569
|
-
|
|
17831
|
+
import_node_path63.default.join(opts.scanPath, "neat-out")
|
|
17570
17832
|
);
|
|
17571
|
-
const errorsPath =
|
|
17833
|
+
const errorsPath = import_node_path63.default.join(import_node_path63.default.dirname(opts.outPath), import_node_path63.default.basename(projectPaths.errorsPath));
|
|
17572
17834
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
17573
17835
|
await saveGraphToDisk(graph, opts.outPath);
|
|
17574
17836
|
written.push(opts.outPath);
|
|
@@ -17687,9 +17949,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
17687
17949
|
};
|
|
17688
17950
|
function claudeConfigPath() {
|
|
17689
17951
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
17690
|
-
if (override && override.length > 0) return
|
|
17952
|
+
if (override && override.length > 0) return import_node_path63.default.resolve(override);
|
|
17691
17953
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17692
|
-
return
|
|
17954
|
+
return import_node_path63.default.join(home, ".claude.json");
|
|
17693
17955
|
}
|
|
17694
17956
|
async function runSkill(opts) {
|
|
17695
17957
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -17713,7 +17975,7 @@ async function runSkill(opts) {
|
|
|
17713
17975
|
...existing,
|
|
17714
17976
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
17715
17977
|
};
|
|
17716
|
-
await import_node_fs41.promises.mkdir(
|
|
17978
|
+
await import_node_fs41.promises.mkdir(import_node_path63.default.dirname(target), { recursive: true });
|
|
17717
17979
|
await import_node_fs41.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
17718
17980
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
17719
17981
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
@@ -17779,12 +18041,12 @@ async function main() {
|
|
|
17779
18041
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
17780
18042
|
process.exit(2);
|
|
17781
18043
|
}
|
|
17782
|
-
const scanPath =
|
|
18044
|
+
const scanPath = import_node_path63.default.resolve(target);
|
|
17783
18045
|
const projectExplicit = parsed.project !== null;
|
|
17784
|
-
const projectName = projectExplicit ? project :
|
|
18046
|
+
const projectName = projectExplicit ? project : import_node_path63.default.basename(scanPath);
|
|
17785
18047
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
17786
|
-
const fallback = pathsForProject(projectKey,
|
|
17787
|
-
const outPath =
|
|
18048
|
+
const fallback = pathsForProject(projectKey, import_node_path63.default.join(scanPath, "neat-out")).snapshotPath;
|
|
18049
|
+
const outPath = import_node_path63.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
17788
18050
|
const result = await runInit({
|
|
17789
18051
|
scanPath,
|
|
17790
18052
|
outPath,
|
|
@@ -17805,21 +18067,21 @@ async function main() {
|
|
|
17805
18067
|
usage2();
|
|
17806
18068
|
process.exit(2);
|
|
17807
18069
|
}
|
|
17808
|
-
const scanPath =
|
|
18070
|
+
const scanPath = import_node_path63.default.resolve(target);
|
|
17809
18071
|
const stat = await import_node_fs41.promises.stat(scanPath).catch(() => null);
|
|
17810
18072
|
if (!stat || !stat.isDirectory()) {
|
|
17811
18073
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
17812
18074
|
process.exit(2);
|
|
17813
18075
|
}
|
|
17814
|
-
const projectPaths = pathsForProject(project,
|
|
17815
|
-
const outPath =
|
|
17816
|
-
const errorsPath =
|
|
17817
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
18076
|
+
const projectPaths = pathsForProject(project, import_node_path63.default.join(scanPath, "neat-out"));
|
|
18077
|
+
const outPath = import_node_path63.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
18078
|
+
const errorsPath = import_node_path63.default.resolve(
|
|
18079
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path63.default.join(import_node_path63.default.dirname(outPath), import_node_path63.default.basename(projectPaths.errorsPath))
|
|
17818
18080
|
);
|
|
17819
|
-
const staleEventsPath =
|
|
17820
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
18081
|
+
const staleEventsPath = import_node_path63.default.resolve(
|
|
18082
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path63.default.join(import_node_path63.default.dirname(outPath), import_node_path63.default.basename(projectPaths.staleEventsPath))
|
|
17821
18083
|
);
|
|
17822
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
18084
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path63.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
17823
18085
|
const handle = await startWatch(getGraph(project), {
|
|
17824
18086
|
scanPath,
|
|
17825
18087
|
outPath,
|
|
@@ -18002,11 +18264,11 @@ async function main() {
|
|
|
18002
18264
|
process.exit(1);
|
|
18003
18265
|
}
|
|
18004
18266
|
async function tryOrchestrator(cmd, parsed) {
|
|
18005
|
-
const scanPath =
|
|
18267
|
+
const scanPath = import_node_path63.default.resolve(cmd);
|
|
18006
18268
|
const stat = await import_node_fs41.promises.stat(scanPath).catch(() => null);
|
|
18007
18269
|
if (!stat || !stat.isDirectory()) return null;
|
|
18008
18270
|
const projectExplicit = parsed.project !== null;
|
|
18009
|
-
const projectName = projectExplicit ? parsed.project :
|
|
18271
|
+
const projectName = projectExplicit ? parsed.project : import_node_path63.default.basename(scanPath);
|
|
18010
18272
|
const result = await runOrchestrator({
|
|
18011
18273
|
scanPath,
|
|
18012
18274
|
project: projectName,
|
|
@@ -18195,10 +18457,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
18195
18457
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
18196
18458
|
const out = [];
|
|
18197
18459
|
for (const p of parts) {
|
|
18198
|
-
const r =
|
|
18460
|
+
const r = import_types51.DivergenceTypeSchema.safeParse(p);
|
|
18199
18461
|
if (!r.success) {
|
|
18200
18462
|
console.error(
|
|
18201
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
18463
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types51.DivergenceTypeSchema.options.join(", ")}`
|
|
18202
18464
|
);
|
|
18203
18465
|
return 2;
|
|
18204
18466
|
}
|