@neat.is/core 0.7.6 → 0.7.8
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-6H757ZNM.js → chunk-4GCV46AP.js} +2 -2
- package/dist/{chunk-XT4NNFH6.js → chunk-LN75Z624.js} +866 -216
- package/dist/chunk-LN75Z624.js.map +1 -0
- package/dist/{chunk-XHSK4BGL.js → chunk-OVRVDSUO.js} +3 -3
- package/dist/{chunk-P2ZEKJ35.js → chunk-Y43UCVZS.js} +9 -6
- package/dist/chunk-Y43UCVZS.js.map +1 -0
- package/dist/cli.cjs +1244 -590
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +1046 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +1055 -401
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-APVZSB6W.js → otel-grpc-DPSAGRUU.js} +3 -3
- package/dist/server.cjs +978 -324
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-P2ZEKJ35.js.map +0 -1
- package/dist/chunk-XT4NNFH6.js.map +0 -1
- /package/dist/{chunk-6H757ZNM.js.map → chunk-4GCV46AP.js.map} +0 -0
- /package/dist/{chunk-XHSK4BGL.js.map → chunk-OVRVDSUO.js.map} +0 -0
- /package/dist/{otel-grpc-APVZSB6W.js.map → otel-grpc-DPSAGRUU.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 path82 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path82) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path82)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -343,7 +343,7 @@ function pickEnv(spanAttrs, resourceAttrs) {
|
|
|
343
343
|
return ENV_FALLBACK;
|
|
344
344
|
}
|
|
345
345
|
function normalizeDbSystem(attrs) {
|
|
346
|
-
const raw = attrs["db.system"];
|
|
346
|
+
const raw = attrs["db.system"] ?? attrs["db.system.name"];
|
|
347
347
|
if (typeof raw !== "string") return void 0;
|
|
348
348
|
return raw === "mongoose" ? "mongodb" : raw;
|
|
349
349
|
}
|
|
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
415
415
|
const v = attrs[key];
|
|
416
416
|
if (typeof v === "string" && v.length > 0) {
|
|
417
417
|
const q = v.indexOf("?");
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
418
|
+
const path82 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path82.length > 0) return path82;
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
return void 0;
|
|
@@ -435,6 +435,9 @@ function parseOtlpRequest(body) {
|
|
|
435
435
|
for (const ss of rs.scopeSpans ?? []) {
|
|
436
436
|
for (const span of ss.spans ?? []) {
|
|
437
437
|
const attrs = attrsToRecord(span.attributes);
|
|
438
|
+
const dbSqlText = typeof attrs["db.statement"] === "string" ? attrs["db.statement"] : typeof attrs["db.query.text"] === "string" ? attrs["db.query.text"] : void 0;
|
|
439
|
+
const dbSystemName = normalizeDbSystem(attrs);
|
|
440
|
+
const directDbTable = typeof attrs["db.sql.table"] === "string" ? attrs["db.sql.table"] : dbSystemName !== "mongodb" && typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : void 0;
|
|
438
441
|
const parsed = {
|
|
439
442
|
service,
|
|
440
443
|
resourceServiceNamePresent,
|
|
@@ -449,11 +452,11 @@ function parseOtlpRequest(body) {
|
|
|
449
452
|
durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
|
|
450
453
|
env: pickEnv(attrs, resourceAttrs),
|
|
451
454
|
attributes: attrs,
|
|
452
|
-
dbSystem:
|
|
455
|
+
dbSystem: dbSystemName,
|
|
453
456
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
454
457
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
455
|
-
dbTable:
|
|
456
|
-
dbColumns:
|
|
458
|
+
dbTable: directDbTable ?? (dbSqlText ? tableFromSqlStatement(dbSqlText) ?? void 0 : void 0),
|
|
459
|
+
dbColumns: dbSqlText ? columnsFromSqlStatement(dbSqlText) : void 0,
|
|
457
460
|
httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
|
|
458
461
|
httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
|
|
459
462
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
@@ -752,7 +755,7 @@ __export(cli_exports, {
|
|
|
752
755
|
});
|
|
753
756
|
module.exports = __toCommonJS(cli_exports);
|
|
754
757
|
init_cjs_shims();
|
|
755
|
-
var
|
|
758
|
+
var import_node_path81 = __toESM(require("path"), 1);
|
|
756
759
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
757
760
|
var import_node_fs46 = require("fs");
|
|
758
761
|
|
|
@@ -1322,19 +1325,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1322
1325
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1323
1326
|
let best = { path: [start], edges: [] };
|
|
1324
1327
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1325
|
-
function step(node,
|
|
1326
|
-
if (
|
|
1327
|
-
best = { path: [...
|
|
1328
|
+
function step(node, path82, edges) {
|
|
1329
|
+
if (path82.length > best.path.length) {
|
|
1330
|
+
best = { path: [...path82], edges: [...edges] };
|
|
1328
1331
|
}
|
|
1329
|
-
if (
|
|
1332
|
+
if (path82.length - 1 >= maxDepth) return;
|
|
1330
1333
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1331
1334
|
for (const [srcId, edge] of incoming) {
|
|
1332
1335
|
if (visited.has(srcId)) continue;
|
|
1333
1336
|
visited.add(srcId);
|
|
1334
|
-
|
|
1337
|
+
path82.push(srcId);
|
|
1335
1338
|
edges.push(edge);
|
|
1336
|
-
step(srcId,
|
|
1337
|
-
|
|
1339
|
+
step(srcId, path82, edges);
|
|
1340
|
+
path82.pop();
|
|
1338
1341
|
edges.pop();
|
|
1339
1342
|
visited.delete(srcId);
|
|
1340
1343
|
}
|
|
@@ -1342,11 +1345,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1342
1345
|
step(start, [start], []);
|
|
1343
1346
|
return best;
|
|
1344
1347
|
}
|
|
1345
|
-
function databaseRootCauseShape(graph, origin,
|
|
1348
|
+
function databaseRootCauseShape(graph, origin, walk9) {
|
|
1346
1349
|
const targetDb = origin;
|
|
1347
1350
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1348
1351
|
if (candidatePairs.length === 0) return null;
|
|
1349
|
-
for (const id of
|
|
1352
|
+
for (const id of walk9.path) {
|
|
1350
1353
|
const owner = resolveOwningService(graph, id);
|
|
1351
1354
|
if (!owner) continue;
|
|
1352
1355
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1373,8 +1376,8 @@ function databaseRootCauseShape(graph, origin, walk8) {
|
|
|
1373
1376
|
}
|
|
1374
1377
|
return null;
|
|
1375
1378
|
}
|
|
1376
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1377
|
-
for (const id of
|
|
1379
|
+
function serviceRootCauseShape(graph, _origin, walk9) {
|
|
1380
|
+
for (const id of walk9.path) {
|
|
1378
1381
|
const owner = resolveOwningService(graph, id);
|
|
1379
1382
|
if (!owner) continue;
|
|
1380
1383
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1410,15 +1413,15 @@ function serviceRootCauseShape(graph, _origin, walk8) {
|
|
|
1410
1413
|
}
|
|
1411
1414
|
return null;
|
|
1412
1415
|
}
|
|
1413
|
-
function fileRootCauseShape(graph, origin,
|
|
1416
|
+
function fileRootCauseShape(graph, origin, walk9) {
|
|
1414
1417
|
const owner = resolveOwningService(graph, origin.id);
|
|
1415
1418
|
if (!owner) return null;
|
|
1416
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1419
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1417
1420
|
}
|
|
1418
|
-
function symbolRootCauseShape(graph, origin,
|
|
1421
|
+
function symbolRootCauseShape(graph, origin, walk9) {
|
|
1419
1422
|
const owner = resolveOwningService(graph, origin.id);
|
|
1420
1423
|
if (!owner) return null;
|
|
1421
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1424
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1422
1425
|
}
|
|
1423
1426
|
var rootCauseShapes = {
|
|
1424
1427
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1431,16 +1434,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1431
1434
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1432
1435
|
const shape = rootCauseShapes[origin.type];
|
|
1433
1436
|
if (shape) {
|
|
1434
|
-
const
|
|
1435
|
-
const match = shape(graph, origin,
|
|
1437
|
+
const walk9 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1438
|
+
const match = shape(graph, origin, walk9);
|
|
1436
1439
|
if (match) {
|
|
1437
1440
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1438
1441
|
return import_types.RootCauseResultSchema.parse({
|
|
1439
1442
|
rootCauseNode: match.rootCauseNode,
|
|
1440
1443
|
rootCauseReason: reason,
|
|
1441
|
-
traversalPath:
|
|
1442
|
-
edgeProvenances:
|
|
1443
|
-
confidence: confidenceFromMix(
|
|
1444
|
+
traversalPath: walk9.path,
|
|
1445
|
+
edgeProvenances: walk9.edges.map((e) => e.provenance),
|
|
1446
|
+
confidence: confidenceFromMix(walk9.edges),
|
|
1444
1447
|
fixRecommendation: match.fixRecommendation
|
|
1445
1448
|
});
|
|
1446
1449
|
}
|
|
@@ -1541,26 +1544,26 @@ function dominantFailingCall(graph, serviceId9, visited) {
|
|
|
1541
1544
|
return best;
|
|
1542
1545
|
}
|
|
1543
1546
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1544
|
-
const
|
|
1547
|
+
const path82 = [originServiceId];
|
|
1545
1548
|
const edges = [];
|
|
1546
1549
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1547
1550
|
let current = originServiceId;
|
|
1548
1551
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1549
1552
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1550
1553
|
if (!hop) break;
|
|
1551
|
-
|
|
1554
|
+
path82.push(hop.nextService);
|
|
1552
1555
|
edges.push(hop.edge);
|
|
1553
1556
|
visited.add(hop.nextService);
|
|
1554
1557
|
current = hop.nextService;
|
|
1555
1558
|
}
|
|
1556
1559
|
if (edges.length === 0) return null;
|
|
1557
|
-
return { path:
|
|
1560
|
+
return { path: path82, edges, culprit: current };
|
|
1558
1561
|
}
|
|
1559
1562
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1560
1563
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1561
1564
|
if (!chain) return null;
|
|
1562
1565
|
const culprit = chain.culprit;
|
|
1563
|
-
const
|
|
1566
|
+
const path82 = [...chain.path];
|
|
1564
1567
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1565
1568
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1566
1569
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1568,14 +1571,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1568
1571
|
if (loc) {
|
|
1569
1572
|
let rootCauseNode = culprit;
|
|
1570
1573
|
if (loc.fileNode) {
|
|
1571
|
-
|
|
1574
|
+
path82.push(loc.fileNode);
|
|
1572
1575
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1573
1576
|
rootCauseNode = loc.fileNode;
|
|
1574
1577
|
}
|
|
1575
1578
|
return import_types.RootCauseResultSchema.parse({
|
|
1576
1579
|
rootCauseNode,
|
|
1577
1580
|
rootCauseReason: loc.rootCauseReason,
|
|
1578
|
-
traversalPath:
|
|
1581
|
+
traversalPath: path82,
|
|
1579
1582
|
edgeProvenances,
|
|
1580
1583
|
confidence,
|
|
1581
1584
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1587,7 +1590,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1587
1590
|
return import_types.RootCauseResultSchema.parse({
|
|
1588
1591
|
rootCauseNode: culprit,
|
|
1589
1592
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1590
|
-
traversalPath:
|
|
1593
|
+
traversalPath: path82,
|
|
1591
1594
|
edgeProvenances,
|
|
1592
1595
|
confidence,
|
|
1593
1596
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2534,14 +2537,14 @@ function buildServiceHostIndex(services) {
|
|
|
2534
2537
|
}
|
|
2535
2538
|
async function walkSourceFiles(dir) {
|
|
2536
2539
|
const out = [];
|
|
2537
|
-
async function
|
|
2540
|
+
async function walk9(current) {
|
|
2538
2541
|
const entries = await import_node_fs6.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2539
2542
|
for (const entry2 of entries) {
|
|
2540
2543
|
const full = import_node_path6.default.join(current, entry2.name);
|
|
2541
2544
|
if (entry2.isDirectory()) {
|
|
2542
2545
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
2543
2546
|
if (await isPythonVenvDir(full)) continue;
|
|
2544
|
-
await
|
|
2547
|
+
await walk9(full);
|
|
2545
2548
|
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path6.default.extname(entry2.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
2546
2549
|
// would attribute our instrumentation imports to the user's service.
|
|
2547
2550
|
!isNeatAuthoredSourceFile(entry2.name)) {
|
|
@@ -2549,7 +2552,7 @@ async function walkSourceFiles(dir) {
|
|
|
2549
2552
|
}
|
|
2550
2553
|
}
|
|
2551
2554
|
}
|
|
2552
|
-
await
|
|
2555
|
+
await walk9(dir);
|
|
2553
2556
|
return out;
|
|
2554
2557
|
}
|
|
2555
2558
|
async function loadSourceFiles(dir) {
|
|
@@ -3062,8 +3065,9 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
3062
3065
|
"all"
|
|
3063
3066
|
]);
|
|
3064
3067
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3068
|
+
var NET_HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3065
3069
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
3066
|
-
function
|
|
3070
|
+
function goRouterRoutesFromSource(source, parser, framework) {
|
|
3067
3071
|
const tree = parseSource2(parser, source);
|
|
3068
3072
|
const prefixes = /* @__PURE__ */ new Map();
|
|
3069
3073
|
const out = [];
|
|
@@ -3073,10 +3077,12 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3073
3077
|
const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
|
|
3074
3078
|
if (name && value?.type === "call_expression") {
|
|
3075
3079
|
const fn2 = value.childForFieldName("function");
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
+
if (fn2?.childForFieldName("field")?.text === "Group") {
|
|
3081
|
+
const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
|
|
3082
|
+
if (leaf2 !== null) {
|
|
3083
|
+
const parent = fn2.childForFieldName("operand")?.text ?? "";
|
|
3084
|
+
prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
|
|
3085
|
+
}
|
|
3080
3086
|
}
|
|
3081
3087
|
}
|
|
3082
3088
|
return;
|
|
@@ -3087,18 +3093,127 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3087
3093
|
const method = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
3088
3094
|
if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
|
|
3089
3095
|
const receiver = fn.childForFieldName("operand")?.text ?? "";
|
|
3090
|
-
const
|
|
3091
|
-
if (
|
|
3092
|
-
const leaf = first.text.slice(1, -1);
|
|
3096
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3097
|
+
if (leaf === null) return;
|
|
3093
3098
|
out.push({
|
|
3094
|
-
method
|
|
3099
|
+
method,
|
|
3095
3100
|
pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
|
|
3096
3101
|
line: node.startPosition.row + 1,
|
|
3097
|
-
framework
|
|
3102
|
+
framework
|
|
3098
3103
|
});
|
|
3099
3104
|
});
|
|
3100
3105
|
return out;
|
|
3101
3106
|
}
|
|
3107
|
+
function goStringLiteral(node) {
|
|
3108
|
+
if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
|
|
3109
|
+
return node.text.slice(1, -1);
|
|
3110
|
+
}
|
|
3111
|
+
return null;
|
|
3112
|
+
}
|
|
3113
|
+
function ginRoutesFromSource(source, parser) {
|
|
3114
|
+
return goRouterRoutesFromSource(source, parser, "gin");
|
|
3115
|
+
}
|
|
3116
|
+
function echoRoutesFromSource(source, parser) {
|
|
3117
|
+
return goRouterRoutesFromSource(source, parser, "echo");
|
|
3118
|
+
}
|
|
3119
|
+
function fiberRoutesFromSource(source, parser) {
|
|
3120
|
+
return goRouterRoutesFromSource(source, parser, "fiber");
|
|
3121
|
+
}
|
|
3122
|
+
function chiRoutesFromSource(source, parser) {
|
|
3123
|
+
const tree = parseSource2(parser, source);
|
|
3124
|
+
const out = [];
|
|
3125
|
+
chiWalk(tree.rootNode, "", out);
|
|
3126
|
+
return out;
|
|
3127
|
+
}
|
|
3128
|
+
function stripChiRegex(path82) {
|
|
3129
|
+
return path82.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3130
|
+
}
|
|
3131
|
+
function chiWalk(node, prefix, out) {
|
|
3132
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3133
|
+
const child = node.namedChild(i);
|
|
3134
|
+
if (child) chiHandle(child, prefix, out);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
function chiHandle(node, prefix, out) {
|
|
3138
|
+
if (node.type === "call_expression") {
|
|
3139
|
+
const fn = node.childForFieldName("function");
|
|
3140
|
+
if (fn?.type === "selector_expression") {
|
|
3141
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3142
|
+
const args = node.childForFieldName("arguments");
|
|
3143
|
+
if (field === "Route") {
|
|
3144
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3145
|
+
const closure = args?.namedChild(1);
|
|
3146
|
+
if (leaf !== null && closure?.type === "func_literal") {
|
|
3147
|
+
const body = closure.childForFieldName("body");
|
|
3148
|
+
if (body) chiWalk(body, prefix + leaf, out);
|
|
3149
|
+
}
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
if (field === "Group") {
|
|
3153
|
+
const closure = args?.namedChild(0);
|
|
3154
|
+
if (closure?.type === "func_literal") {
|
|
3155
|
+
const body = closure.childForFieldName("body");
|
|
3156
|
+
if (body) chiWalk(body, prefix, out);
|
|
3157
|
+
}
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
if (field === "Mount") {
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
if (field && ROUTER_METHODS.has(field.toLowerCase())) {
|
|
3164
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3165
|
+
if (leaf !== null) {
|
|
3166
|
+
out.push({
|
|
3167
|
+
method: field.toUpperCase(),
|
|
3168
|
+
pathTemplate: canonicalizeTemplate(stripChiRegex(prefix + leaf)),
|
|
3169
|
+
line: node.startPosition.row + 1,
|
|
3170
|
+
framework: "chi"
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
chiWalk(node, prefix, out);
|
|
3178
|
+
}
|
|
3179
|
+
function netHttpRoutesFromSource(source, parser) {
|
|
3180
|
+
const tree = parseSource2(parser, source);
|
|
3181
|
+
if (!goImportsNetHttp(tree.rootNode)) return [];
|
|
3182
|
+
const out = [];
|
|
3183
|
+
walk(tree.rootNode, (node) => {
|
|
3184
|
+
if (node.type !== "call_expression") return;
|
|
3185
|
+
const fn = node.childForFieldName("function");
|
|
3186
|
+
if (fn?.type !== "selector_expression") return;
|
|
3187
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3188
|
+
if (field !== "HandleFunc" && field !== "Handle") return;
|
|
3189
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3190
|
+
if (leaf === null) return;
|
|
3191
|
+
const sp = leaf.indexOf(" ");
|
|
3192
|
+
if (sp < 0) return;
|
|
3193
|
+
const method = leaf.slice(0, sp);
|
|
3194
|
+
const rest = leaf.slice(sp + 1);
|
|
3195
|
+
if (!NET_HTTP_METHODS.has(method)) return;
|
|
3196
|
+
if (!rest.startsWith("/")) return;
|
|
3197
|
+
out.push({
|
|
3198
|
+
method,
|
|
3199
|
+
pathTemplate: canonicalizeTemplate(rest),
|
|
3200
|
+
line: node.startPosition.row + 1,
|
|
3201
|
+
framework: "net/http"
|
|
3202
|
+
});
|
|
3203
|
+
});
|
|
3204
|
+
return out;
|
|
3205
|
+
}
|
|
3206
|
+
function goImportsNetHttp(root) {
|
|
3207
|
+
let found = false;
|
|
3208
|
+
walk(root, (node) => {
|
|
3209
|
+
if (found || node.type !== "import_spec") return;
|
|
3210
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3211
|
+
const child = node.namedChild(i);
|
|
3212
|
+
if (goStringLiteral(child) === "net/http") found = true;
|
|
3213
|
+
}
|
|
3214
|
+
});
|
|
3215
|
+
return found;
|
|
3216
|
+
}
|
|
3102
3217
|
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
3103
3218
|
var NESTJS_METHODS = /* @__PURE__ */ new Map([
|
|
3104
3219
|
["Get", "GET"],
|
|
@@ -3683,9 +3798,9 @@ function rubyRocketRoute(args) {
|
|
|
3683
3798
|
if (!pair || pair.type !== "pair") continue;
|
|
3684
3799
|
const k = pair.childForFieldName("key");
|
|
3685
3800
|
if (k?.type !== "string") continue;
|
|
3686
|
-
const
|
|
3687
|
-
if (
|
|
3688
|
-
return { path:
|
|
3801
|
+
const path82 = rubyLiteral(k);
|
|
3802
|
+
if (path82 === null) continue;
|
|
3803
|
+
return { path: path82, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3689
3804
|
}
|
|
3690
3805
|
return null;
|
|
3691
3806
|
}
|
|
@@ -4362,9 +4477,13 @@ async function addRoutes(graph, services) {
|
|
|
4362
4477
|
const hasFlask = deps["flask"] !== void 0;
|
|
4363
4478
|
const hasDjango = deps["django"] !== void 0;
|
|
4364
4479
|
const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
|
|
4480
|
+
const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
|
|
4481
|
+
const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
|
|
4482
|
+
const hasChi = deps["github.com/go-chi/chi/v5"] !== void 0 || deps["github.com/go-chi/chi"] !== void 0;
|
|
4483
|
+
const isGoService = service.node.language === "go";
|
|
4365
4484
|
const hasRails = deps["rails"] !== void 0;
|
|
4366
4485
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4367
|
-
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
|
|
4486
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel)
|
|
4368
4487
|
continue;
|
|
4369
4488
|
const files = await loadSourceFiles(service.dir);
|
|
4370
4489
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4388,7 +4507,12 @@ async function addRoutes(graph, services) {
|
|
|
4388
4507
|
} else if (isRb) {
|
|
4389
4508
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4390
4509
|
} else if (isGo) {
|
|
4391
|
-
routes =
|
|
4510
|
+
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4511
|
+
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
4512
|
+
else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
|
|
4513
|
+
else if (hasChi) routes = chiRoutesFromSource(file.content, goParser);
|
|
4514
|
+
else routes = [];
|
|
4515
|
+
routes = routes.concat(netHttpRoutesFromSource(file.content, goParser));
|
|
4392
4516
|
} else if (isPy) {
|
|
4393
4517
|
routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
|
|
4394
4518
|
if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
|
|
@@ -5998,6 +6122,13 @@ function parseGoMod(source) {
|
|
|
5998
6122
|
}
|
|
5999
6123
|
return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
|
|
6000
6124
|
}
|
|
6125
|
+
function goFramework(deps) {
|
|
6126
|
+
if (deps["github.com/gin-gonic/gin"]) return "gin";
|
|
6127
|
+
if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
|
|
6128
|
+
if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
|
|
6129
|
+
if (deps["github.com/go-chi/chi/v5"] || deps["github.com/go-chi/chi"]) return "chi";
|
|
6130
|
+
return void 0;
|
|
6131
|
+
}
|
|
6001
6132
|
async function discoverGoService(scanPath, dir) {
|
|
6002
6133
|
let raw;
|
|
6003
6134
|
try {
|
|
@@ -6009,6 +6140,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
6009
6140
|
if (!mod) return null;
|
|
6010
6141
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
6011
6142
|
const pkg = { name, dependencies: mod.dependencies };
|
|
6143
|
+
const framework = goFramework(mod.dependencies);
|
|
6012
6144
|
const node = {
|
|
6013
6145
|
id: (0, import_types9.serviceId)(name),
|
|
6014
6146
|
type: import_types9.NodeType.ServiceNode,
|
|
@@ -6016,7 +6148,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
6016
6148
|
language: "go",
|
|
6017
6149
|
dependencies: mod.dependencies,
|
|
6018
6150
|
repoPath: import_node_path11.default.relative(scanPath, dir),
|
|
6019
|
-
...
|
|
6151
|
+
...framework ? { framework } : {}
|
|
6020
6152
|
};
|
|
6021
6153
|
return { pkg, dir, node };
|
|
6022
6154
|
}
|
|
@@ -6916,7 +7048,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6916
7048
|
return best;
|
|
6917
7049
|
};
|
|
6918
7050
|
const requests = [];
|
|
6919
|
-
const
|
|
7051
|
+
const walk9 = (node) => {
|
|
6920
7052
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
6921
7053
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
6922
7054
|
if (self && self.kind === "class") {
|
|
@@ -6962,10 +7094,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
6962
7094
|
}
|
|
6963
7095
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6964
7096
|
const child = node.namedChild(i);
|
|
6965
|
-
if (child)
|
|
7097
|
+
if (child) walk9(child);
|
|
6966
7098
|
}
|
|
6967
7099
|
};
|
|
6968
|
-
|
|
7100
|
+
walk9(root);
|
|
6969
7101
|
for (const req of requests) {
|
|
6970
7102
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
6971
7103
|
if (!targetSid) continue;
|
|
@@ -7978,20 +8110,20 @@ var import_node_path29 = __toESM(require("path"), 1);
|
|
|
7978
8110
|
var import_types18 = require("@neat.is/types");
|
|
7979
8111
|
async function walkConfigFiles(dir) {
|
|
7980
8112
|
const out = [];
|
|
7981
|
-
async function
|
|
8113
|
+
async function walk9(current) {
|
|
7982
8114
|
const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true });
|
|
7983
8115
|
for (const entry2 of entries) {
|
|
7984
8116
|
const full = import_node_path29.default.join(current, entry2.name);
|
|
7985
8117
|
if (entry2.isDirectory()) {
|
|
7986
8118
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
7987
8119
|
if (await isPythonVenvDir(full)) continue;
|
|
7988
|
-
await
|
|
8120
|
+
await walk9(full);
|
|
7989
8121
|
} else if (entry2.isFile() && isConfigFile(entry2.name).match) {
|
|
7990
8122
|
out.push(full);
|
|
7991
8123
|
}
|
|
7992
8124
|
}
|
|
7993
8125
|
}
|
|
7994
|
-
await
|
|
8126
|
+
await walk9(dir);
|
|
7995
8127
|
return out;
|
|
7996
8128
|
}
|
|
7997
8129
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -8081,20 +8213,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
8081
8213
|
}
|
|
8082
8214
|
async function walkProtoFiles(dir) {
|
|
8083
8215
|
const out = [];
|
|
8084
|
-
async function
|
|
8216
|
+
async function walk9(current) {
|
|
8085
8217
|
const entries = await import_node_fs18.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8086
8218
|
for (const entry2 of entries) {
|
|
8087
8219
|
const full = import_node_path30.default.join(current, entry2.name);
|
|
8088
8220
|
if (entry2.isDirectory()) {
|
|
8089
8221
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
8090
8222
|
if (await isPythonVenvDir(full)) continue;
|
|
8091
|
-
await
|
|
8223
|
+
await walk9(full);
|
|
8092
8224
|
} else if (entry2.isFile() && import_node_path30.default.extname(entry2.name) === PROTO_EXTENSION) {
|
|
8093
8225
|
out.push(full);
|
|
8094
8226
|
}
|
|
8095
8227
|
}
|
|
8096
8228
|
}
|
|
8097
|
-
await
|
|
8229
|
+
await walk9(dir);
|
|
8098
8230
|
return out;
|
|
8099
8231
|
}
|
|
8100
8232
|
async function addGrpcMethods(graph, services) {
|
|
@@ -8162,7 +8294,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
8162
8294
|
|
|
8163
8295
|
// src/extract/calls/index.ts
|
|
8164
8296
|
init_cjs_shims();
|
|
8165
|
-
var
|
|
8297
|
+
var import_types37 = require("@neat.is/types");
|
|
8166
8298
|
|
|
8167
8299
|
// src/extract/calls/http.ts
|
|
8168
8300
|
init_cjs_shims();
|
|
@@ -8916,7 +9048,7 @@ function isFirestoreClientFactory(node) {
|
|
|
8916
9048
|
}
|
|
8917
9049
|
function firestoreClientVars(root) {
|
|
8918
9050
|
const vars = /* @__PURE__ */ new Set();
|
|
8919
|
-
const
|
|
9051
|
+
const walk9 = (node) => {
|
|
8920
9052
|
if (node.type === "variable_declarator") {
|
|
8921
9053
|
const name = node.childForFieldName("name");
|
|
8922
9054
|
let value = node.childForFieldName("value");
|
|
@@ -8925,9 +9057,9 @@ function firestoreClientVars(root) {
|
|
|
8925
9057
|
vars.add(name.text);
|
|
8926
9058
|
}
|
|
8927
9059
|
}
|
|
8928
|
-
for (const c of namedChildren(node))
|
|
9060
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
8929
9061
|
};
|
|
8930
|
-
|
|
9062
|
+
walk9(root);
|
|
8931
9063
|
return vars;
|
|
8932
9064
|
}
|
|
8933
9065
|
function isClientExpr(node, clientVars) {
|
|
@@ -9082,7 +9214,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9082
9214
|
}
|
|
9083
9215
|
s.add(field);
|
|
9084
9216
|
};
|
|
9085
|
-
const
|
|
9217
|
+
const walk9 = (node) => {
|
|
9086
9218
|
if (node.type === "call_expression") {
|
|
9087
9219
|
const fn = node.childForFieldName("function");
|
|
9088
9220
|
const line = node.startPosition.row + 1;
|
|
@@ -9122,9 +9254,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9122
9254
|
}
|
|
9123
9255
|
}
|
|
9124
9256
|
}
|
|
9125
|
-
for (const c of namedChildren(node))
|
|
9257
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
9126
9258
|
};
|
|
9127
|
-
|
|
9259
|
+
walk9(tree.rootNode);
|
|
9128
9260
|
const out = [];
|
|
9129
9261
|
for (const [collPath, line] of collLine) {
|
|
9130
9262
|
const byField = writes.get(collPath);
|
|
@@ -9919,7 +10051,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9919
10051
|
const tree = parseSource3(parserForExt2(import_node_path42.default.extname(file.path)), file.content);
|
|
9920
10052
|
const out = [];
|
|
9921
10053
|
const seen = /* @__PURE__ */ new Set();
|
|
9922
|
-
const
|
|
10054
|
+
const walk9 = (node) => {
|
|
9923
10055
|
if (node.type === "call_expression") {
|
|
9924
10056
|
const fn = node.childForFieldName("function");
|
|
9925
10057
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9947,9 +10079,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9947
10079
|
}
|
|
9948
10080
|
}
|
|
9949
10081
|
}
|
|
9950
|
-
for (const c of namedChildren4(node))
|
|
10082
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9951
10083
|
};
|
|
9952
|
-
|
|
10084
|
+
walk9(tree.rootNode);
|
|
9953
10085
|
return out;
|
|
9954
10086
|
}
|
|
9955
10087
|
function enclosingVarName(call) {
|
|
@@ -9971,7 +10103,7 @@ function enclosingVarName(call) {
|
|
|
9971
10103
|
function collectDrizzleTables(root) {
|
|
9972
10104
|
const tables = [];
|
|
9973
10105
|
const varToTable = /* @__PURE__ */ new Map();
|
|
9974
|
-
const
|
|
10106
|
+
const walk9 = (node) => {
|
|
9975
10107
|
if (node.type === "call_expression") {
|
|
9976
10108
|
const fn = node.childForFieldName("function");
|
|
9977
10109
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9986,9 +10118,9 @@ function collectDrizzleTables(root) {
|
|
|
9986
10118
|
}
|
|
9987
10119
|
}
|
|
9988
10120
|
}
|
|
9989
|
-
for (const c of namedChildren4(node))
|
|
10121
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9990
10122
|
};
|
|
9991
|
-
|
|
10123
|
+
walk9(root);
|
|
9992
10124
|
return { tables, varToTable };
|
|
9993
10125
|
}
|
|
9994
10126
|
function referencesTargetVar(call) {
|
|
@@ -10011,7 +10143,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
10011
10143
|
const seen = /* @__PURE__ */ new Set();
|
|
10012
10144
|
for (const table of tables) {
|
|
10013
10145
|
if (!table.object) continue;
|
|
10014
|
-
const
|
|
10146
|
+
const walk9 = (node) => {
|
|
10015
10147
|
if (node.type === "call_expression") {
|
|
10016
10148
|
const targetVar = referencesTargetVar(node);
|
|
10017
10149
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -10032,9 +10164,9 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
10032
10164
|
}
|
|
10033
10165
|
}
|
|
10034
10166
|
}
|
|
10035
|
-
for (const c of namedChildren4(node))
|
|
10167
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
10036
10168
|
};
|
|
10037
|
-
|
|
10169
|
+
walk9(table.object);
|
|
10038
10170
|
}
|
|
10039
10171
|
return out;
|
|
10040
10172
|
}
|
|
@@ -11114,15 +11246,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
11114
11246
|
return out;
|
|
11115
11247
|
}
|
|
11116
11248
|
|
|
11249
|
+
// src/extract/calls/gorm.ts
|
|
11250
|
+
init_cjs_shims();
|
|
11251
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11252
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
11253
|
+
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
11254
|
+
var import_types36 = require("@neat.is/types");
|
|
11255
|
+
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
11256
|
+
var PARSE_CHUNK11 = 16384;
|
|
11257
|
+
function makeGoParser3() {
|
|
11258
|
+
const p = new import_tree_sitter15.default();
|
|
11259
|
+
p.setLanguage(import_tree_sitter_go4.default);
|
|
11260
|
+
return p;
|
|
11261
|
+
}
|
|
11262
|
+
function parseSource10(parser, source) {
|
|
11263
|
+
return parser.parse(
|
|
11264
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
11265
|
+
);
|
|
11266
|
+
}
|
|
11267
|
+
function walk8(node, visit) {
|
|
11268
|
+
visit(node);
|
|
11269
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11270
|
+
const c = node.namedChild(i);
|
|
11271
|
+
if (c) walk8(c, visit);
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
var COMMON_INITIALISMS = [
|
|
11275
|
+
"ASCII",
|
|
11276
|
+
"HTTPS",
|
|
11277
|
+
"UTF8",
|
|
11278
|
+
"XSRF",
|
|
11279
|
+
"HTML",
|
|
11280
|
+
"HTTP",
|
|
11281
|
+
"JSON",
|
|
11282
|
+
"UUID",
|
|
11283
|
+
"XMPP",
|
|
11284
|
+
"ACL",
|
|
11285
|
+
"API",
|
|
11286
|
+
"CPU",
|
|
11287
|
+
"CSS",
|
|
11288
|
+
"DNS",
|
|
11289
|
+
"EOF",
|
|
11290
|
+
"GUID",
|
|
11291
|
+
"LHS",
|
|
11292
|
+
"QPS",
|
|
11293
|
+
"RAM",
|
|
11294
|
+
"RHS",
|
|
11295
|
+
"RPC",
|
|
11296
|
+
"SLA",
|
|
11297
|
+
"SQL",
|
|
11298
|
+
"SSH",
|
|
11299
|
+
"TCP",
|
|
11300
|
+
"TLS",
|
|
11301
|
+
"TTL",
|
|
11302
|
+
"UDP",
|
|
11303
|
+
"UID",
|
|
11304
|
+
"URI",
|
|
11305
|
+
"URL",
|
|
11306
|
+
"UID",
|
|
11307
|
+
"XSS",
|
|
11308
|
+
"ID",
|
|
11309
|
+
"IP",
|
|
11310
|
+
"UI",
|
|
11311
|
+
"VM",
|
|
11312
|
+
"XML"
|
|
11313
|
+
].sort((a, b) => b.length - a.length);
|
|
11314
|
+
function titleCase(word) {
|
|
11315
|
+
return word.charAt(0) + word.slice(1).toLowerCase();
|
|
11316
|
+
}
|
|
11317
|
+
function replaceInitialisms(name) {
|
|
11318
|
+
let out = "";
|
|
11319
|
+
let i = 0;
|
|
11320
|
+
while (i < name.length) {
|
|
11321
|
+
let matched = false;
|
|
11322
|
+
for (const init of COMMON_INITIALISMS) {
|
|
11323
|
+
if (name.startsWith(init, i)) {
|
|
11324
|
+
out += titleCase(init);
|
|
11325
|
+
i += init.length;
|
|
11326
|
+
matched = true;
|
|
11327
|
+
break;
|
|
11328
|
+
}
|
|
11329
|
+
}
|
|
11330
|
+
if (!matched) {
|
|
11331
|
+
out += name[i];
|
|
11332
|
+
i++;
|
|
11333
|
+
}
|
|
11334
|
+
}
|
|
11335
|
+
return out;
|
|
11336
|
+
}
|
|
11337
|
+
var isUpper = (c) => c >= "A" && c <= "Z";
|
|
11338
|
+
var isDigit = (c) => c >= "0" && c <= "9";
|
|
11339
|
+
function toDBName(name) {
|
|
11340
|
+
if (name === "") return "";
|
|
11341
|
+
const value = replaceInitialisms(name);
|
|
11342
|
+
if (value.length === 1) return value.toLowerCase();
|
|
11343
|
+
let buf = "";
|
|
11344
|
+
let lastCase = false;
|
|
11345
|
+
let curCase = isUpper(value[0]);
|
|
11346
|
+
for (let i = 0; i < value.length - 1; i++) {
|
|
11347
|
+
const v = value[i];
|
|
11348
|
+
const nextCase = isUpper(value[i + 1]);
|
|
11349
|
+
const nextNumber = isDigit(value[i + 1]);
|
|
11350
|
+
if (curCase) {
|
|
11351
|
+
if (lastCase && (nextCase || nextNumber)) {
|
|
11352
|
+
buf += v.toLowerCase();
|
|
11353
|
+
} else {
|
|
11354
|
+
if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
|
|
11355
|
+
buf += v.toLowerCase();
|
|
11356
|
+
}
|
|
11357
|
+
} else {
|
|
11358
|
+
buf += v;
|
|
11359
|
+
}
|
|
11360
|
+
lastCase = curCase;
|
|
11361
|
+
curCase = nextCase;
|
|
11362
|
+
}
|
|
11363
|
+
const last = value[value.length - 1];
|
|
11364
|
+
if (curCase) {
|
|
11365
|
+
if (!lastCase && value.length > 1) buf += "_";
|
|
11366
|
+
buf += last.toLowerCase();
|
|
11367
|
+
} else {
|
|
11368
|
+
buf += last;
|
|
11369
|
+
}
|
|
11370
|
+
return buf;
|
|
11371
|
+
}
|
|
11372
|
+
var UNCOUNTABLE = /* @__PURE__ */ new Set([
|
|
11373
|
+
"equipment",
|
|
11374
|
+
"information",
|
|
11375
|
+
"rice",
|
|
11376
|
+
"money",
|
|
11377
|
+
"species",
|
|
11378
|
+
"series",
|
|
11379
|
+
"fish",
|
|
11380
|
+
"sheep",
|
|
11381
|
+
"jeans",
|
|
11382
|
+
"police"
|
|
11383
|
+
]);
|
|
11384
|
+
var IRREGULAR = [
|
|
11385
|
+
["person", "people"],
|
|
11386
|
+
["man", "men"],
|
|
11387
|
+
["child", "children"],
|
|
11388
|
+
["sex", "sexes"],
|
|
11389
|
+
["move", "moves"]
|
|
11390
|
+
];
|
|
11391
|
+
var PLURAL_RULES = [
|
|
11392
|
+
[/(quiz)$/i, "$1zes"],
|
|
11393
|
+
[/^(ox)$/i, "$1en"],
|
|
11394
|
+
[/([ml])ouse$/i, "$1ice"],
|
|
11395
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
|
|
11396
|
+
[/(x|ch|ss|sh)$/i, "$1es"],
|
|
11397
|
+
[/([^aeiouy]|qu)y$/i, "$1ies"],
|
|
11398
|
+
[/(hive)$/i, "$1s"],
|
|
11399
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
|
11400
|
+
[/sis$/i, "ses"],
|
|
11401
|
+
[/([ti])um$/i, "$1a"],
|
|
11402
|
+
[/([ti])a$/i, "$1a"],
|
|
11403
|
+
[/(buffal|tomat)o$/i, "$1oes"],
|
|
11404
|
+
[/(bu)s$/i, "$1ses"],
|
|
11405
|
+
[/(alias|status)$/i, "$1es"],
|
|
11406
|
+
[/(octop|vir)i$/i, "$1i"],
|
|
11407
|
+
[/(octop|vir)us$/i, "$1i"],
|
|
11408
|
+
[/(ax|test)is$/i, "$1es"],
|
|
11409
|
+
[/s$/i, "s"]
|
|
11410
|
+
];
|
|
11411
|
+
function pluralize3(word) {
|
|
11412
|
+
if (word === "") return word;
|
|
11413
|
+
const lower = word.toLowerCase();
|
|
11414
|
+
for (const u of UNCOUNTABLE) {
|
|
11415
|
+
if (lower === u || lower.endsWith("_" + u)) return word;
|
|
11416
|
+
}
|
|
11417
|
+
for (const [sing, plur] of IRREGULAR) {
|
|
11418
|
+
const re = new RegExp(sing + "$", "i");
|
|
11419
|
+
if (re.test(word)) return word.replace(re, plur);
|
|
11420
|
+
}
|
|
11421
|
+
for (const [re, rep] of PLURAL_RULES) {
|
|
11422
|
+
if (re.test(word)) return word.replace(re, rep);
|
|
11423
|
+
}
|
|
11424
|
+
return word + "s";
|
|
11425
|
+
}
|
|
11426
|
+
function deriveTableName(structName) {
|
|
11427
|
+
return pluralize3(toDBName(structName));
|
|
11428
|
+
}
|
|
11429
|
+
function stringLiteralValue(node) {
|
|
11430
|
+
if (!node) return null;
|
|
11431
|
+
if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
|
|
11432
|
+
const t = node.text;
|
|
11433
|
+
return t.length >= 2 ? t.slice(1, -1) : "";
|
|
11434
|
+
}
|
|
11435
|
+
return null;
|
|
11436
|
+
}
|
|
11437
|
+
function parseGormTag(tagNode) {
|
|
11438
|
+
const tag = {};
|
|
11439
|
+
if (!tagNode) return tag;
|
|
11440
|
+
let inner = tagNode.text;
|
|
11441
|
+
if (inner.length >= 2) inner = inner.slice(1, -1);
|
|
11442
|
+
if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
|
|
11443
|
+
const m = inner.match(/gorm:"([^"]*)"/);
|
|
11444
|
+
if (!m) return tag;
|
|
11445
|
+
for (const part of m[1].split(";")) {
|
|
11446
|
+
if (part === "") continue;
|
|
11447
|
+
const idx = part.indexOf(":");
|
|
11448
|
+
const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
|
|
11449
|
+
const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
|
|
11450
|
+
if (key === "-") tag.skip = true;
|
|
11451
|
+
else if (key === "column") tag.column = value;
|
|
11452
|
+
else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
|
|
11453
|
+
else if (key === "foreignkey") tag.foreignKey = value;
|
|
11454
|
+
else if (key === "many2many") tag.many2many = value;
|
|
11455
|
+
else if (key === "embedded") tag.embedded = true;
|
|
11456
|
+
else if (key === "embeddedprefix") tag.embeddedPrefix = value;
|
|
11457
|
+
}
|
|
11458
|
+
return tag;
|
|
11459
|
+
}
|
|
11460
|
+
function unwrapType(typeNode) {
|
|
11461
|
+
let isSlice = false;
|
|
11462
|
+
let isPointer = false;
|
|
11463
|
+
let n = typeNode;
|
|
11464
|
+
while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
|
|
11465
|
+
if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
|
|
11466
|
+
if (n.type === "pointer_type") isPointer = true;
|
|
11467
|
+
n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
|
|
11468
|
+
}
|
|
11469
|
+
if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11470
|
+
if (n.type === "type_identifier") {
|
|
11471
|
+
return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11472
|
+
}
|
|
11473
|
+
if (n.type === "qualified_type") {
|
|
11474
|
+
const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
|
|
11475
|
+
const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
|
|
11476
|
+
return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
|
|
11477
|
+
}
|
|
11478
|
+
return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11479
|
+
}
|
|
11480
|
+
function readField(fieldDecl) {
|
|
11481
|
+
const names = [];
|
|
11482
|
+
let tagNode = null;
|
|
11483
|
+
for (let i = 0; i < fieldDecl.namedChildCount; i++) {
|
|
11484
|
+
const c = fieldDecl.namedChild(i);
|
|
11485
|
+
if (!c) continue;
|
|
11486
|
+
if (c.type === "field_identifier") names.push(c.text);
|
|
11487
|
+
else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
|
|
11488
|
+
}
|
|
11489
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
11490
|
+
const t = unwrapType(typeNode);
|
|
11491
|
+
return {
|
|
11492
|
+
names,
|
|
11493
|
+
typeName: t.name,
|
|
11494
|
+
qualifier: t.qualifier,
|
|
11495
|
+
isSlice: t.isSlice,
|
|
11496
|
+
isPointer: t.isPointer,
|
|
11497
|
+
isQualified: t.isQualified,
|
|
11498
|
+
tag: parseGormTag(tagNode),
|
|
11499
|
+
line: fieldDecl.startPosition.row + 1
|
|
11500
|
+
};
|
|
11501
|
+
}
|
|
11502
|
+
function collectStructs(tree) {
|
|
11503
|
+
const structs = /* @__PURE__ */ new Map();
|
|
11504
|
+
walk8(tree.rootNode, (node) => {
|
|
11505
|
+
if (node.type !== "type_spec") return;
|
|
11506
|
+
const nameNode = node.childForFieldName("name");
|
|
11507
|
+
const typeNode = node.childForFieldName("type");
|
|
11508
|
+
if (!nameNode || typeNode?.type !== "struct_type") return;
|
|
11509
|
+
const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
|
|
11510
|
+
const fields = [];
|
|
11511
|
+
if (list && list.type === "field_declaration_list") {
|
|
11512
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
11513
|
+
const fd = list.namedChild(i);
|
|
11514
|
+
if (fd?.type === "field_declaration") fields.push(readField(fd));
|
|
11515
|
+
}
|
|
11516
|
+
}
|
|
11517
|
+
structs.set(nameNode.text, {
|
|
11518
|
+
name: nameNode.text,
|
|
11519
|
+
fields,
|
|
11520
|
+
line: node.startPosition.row + 1
|
|
11521
|
+
});
|
|
11522
|
+
});
|
|
11523
|
+
return structs;
|
|
11524
|
+
}
|
|
11525
|
+
var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
11526
|
+
"AutoMigrate",
|
|
11527
|
+
"Model",
|
|
11528
|
+
"Create",
|
|
11529
|
+
"Find",
|
|
11530
|
+
"First",
|
|
11531
|
+
"Take",
|
|
11532
|
+
"Last",
|
|
11533
|
+
"Save",
|
|
11534
|
+
"Delete",
|
|
11535
|
+
"Where",
|
|
11536
|
+
"FirstOrCreate",
|
|
11537
|
+
"FirstOrInit"
|
|
11538
|
+
]);
|
|
11539
|
+
function compositeStructName(arg) {
|
|
11540
|
+
let n = arg;
|
|
11541
|
+
if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
|
|
11542
|
+
if (!n || n.type !== "composite_literal") return null;
|
|
11543
|
+
const typeNode = n.childForFieldName("type");
|
|
11544
|
+
if (!typeNode) return null;
|
|
11545
|
+
if (typeNode.type === "type_identifier") return typeNode.text;
|
|
11546
|
+
if (typeNode.type === "qualified_type") {
|
|
11547
|
+
return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
|
|
11548
|
+
}
|
|
11549
|
+
return null;
|
|
11550
|
+
}
|
|
11551
|
+
function collectCallModels(tree) {
|
|
11552
|
+
const models = /* @__PURE__ */ new Set();
|
|
11553
|
+
walk8(tree.rootNode, (node) => {
|
|
11554
|
+
if (node.type !== "call_expression") return;
|
|
11555
|
+
const fn = node.childForFieldName("function");
|
|
11556
|
+
if (fn?.type !== "selector_expression") return;
|
|
11557
|
+
const method = fn.childForFieldName("field")?.text;
|
|
11558
|
+
if (!method || !GORM_MODEL_METHODS.has(method)) return;
|
|
11559
|
+
const args = node.childForFieldName("arguments");
|
|
11560
|
+
if (!args) return;
|
|
11561
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
11562
|
+
const arg = args.namedChild(i);
|
|
11563
|
+
if (!arg) continue;
|
|
11564
|
+
const name = compositeStructName(arg);
|
|
11565
|
+
if (name) models.add(name);
|
|
11566
|
+
}
|
|
11567
|
+
});
|
|
11568
|
+
return models;
|
|
11569
|
+
}
|
|
11570
|
+
function collectTableNameOverrides(tree) {
|
|
11571
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
11572
|
+
const declarers = /* @__PURE__ */ new Set();
|
|
11573
|
+
walk8(tree.rootNode, (node) => {
|
|
11574
|
+
if (node.type !== "method_declaration") return;
|
|
11575
|
+
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
11576
|
+
const receiver = node.childForFieldName("receiver");
|
|
11577
|
+
if (!receiver) return;
|
|
11578
|
+
let recvType = null;
|
|
11579
|
+
for (let i = 0; i < receiver.namedChildCount; i++) {
|
|
11580
|
+
const pd = receiver.namedChild(i);
|
|
11581
|
+
if (pd?.type !== "parameter_declaration") continue;
|
|
11582
|
+
const t = unwrapType(pd.childForFieldName("type"));
|
|
11583
|
+
recvType = t.name;
|
|
11584
|
+
}
|
|
11585
|
+
if (!recvType) return;
|
|
11586
|
+
declarers.add(recvType);
|
|
11587
|
+
const body = node.childForFieldName("body");
|
|
11588
|
+
if (!body) return;
|
|
11589
|
+
let literal = null;
|
|
11590
|
+
walk8(body, (n) => {
|
|
11591
|
+
if (literal !== null) return;
|
|
11592
|
+
if (n.type !== "return_statement") return;
|
|
11593
|
+
const exprList = n.namedChild(0);
|
|
11594
|
+
const first = exprList?.namedChild(0) ?? exprList;
|
|
11595
|
+
const v = stringLiteralValue(first);
|
|
11596
|
+
if (v) literal = v;
|
|
11597
|
+
});
|
|
11598
|
+
if (literal !== null) overrides.set(recvType, literal);
|
|
11599
|
+
});
|
|
11600
|
+
return { overrides, declarers };
|
|
11601
|
+
}
|
|
11602
|
+
function isRelationField(field, structs) {
|
|
11603
|
+
if (field.names.length === 0) return false;
|
|
11604
|
+
if (field.isQualified) return false;
|
|
11605
|
+
if (!field.typeName) return false;
|
|
11606
|
+
return structs.has(field.typeName);
|
|
11607
|
+
}
|
|
11608
|
+
function isGormModelEmbed(field) {
|
|
11609
|
+
return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
|
|
11610
|
+
}
|
|
11611
|
+
function analyze(tree) {
|
|
11612
|
+
const structs = collectStructs(tree);
|
|
11613
|
+
const { overrides, declarers } = collectTableNameOverrides(tree);
|
|
11614
|
+
const callModels = collectCallModels(tree);
|
|
11615
|
+
const models = /* @__PURE__ */ new Set();
|
|
11616
|
+
for (const [name, info] of structs) {
|
|
11617
|
+
if (info.fields.some(isGormModelEmbed)) models.add(name);
|
|
11618
|
+
}
|
|
11619
|
+
for (const name of callModels) if (structs.has(name)) models.add(name);
|
|
11620
|
+
for (const name of declarers) if (structs.has(name)) models.add(name);
|
|
11621
|
+
let grew = true;
|
|
11622
|
+
while (grew) {
|
|
11623
|
+
grew = false;
|
|
11624
|
+
for (const name of Array.from(models)) {
|
|
11625
|
+
const info = structs.get(name);
|
|
11626
|
+
if (!info) continue;
|
|
11627
|
+
for (const field of info.fields) {
|
|
11628
|
+
if (!isRelationField(field, structs)) continue;
|
|
11629
|
+
const target = field.typeName;
|
|
11630
|
+
if (!models.has(target) && structs.has(target)) {
|
|
11631
|
+
models.add(target);
|
|
11632
|
+
grew = true;
|
|
11633
|
+
}
|
|
11634
|
+
}
|
|
11635
|
+
}
|
|
11636
|
+
}
|
|
11637
|
+
const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
|
|
11638
|
+
return { structs, models, tableFor };
|
|
11639
|
+
}
|
|
11640
|
+
function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
11641
|
+
if (seen.has(struct.name)) return;
|
|
11642
|
+
seen.add(struct.name);
|
|
11643
|
+
const add = (col) => {
|
|
11644
|
+
const full = prefix + col;
|
|
11645
|
+
if (!emitted.has(full)) {
|
|
11646
|
+
emitted.add(full);
|
|
11647
|
+
out.push(full);
|
|
11648
|
+
}
|
|
11649
|
+
};
|
|
11650
|
+
for (const field of struct.fields) {
|
|
11651
|
+
if (field.tag.skip) continue;
|
|
11652
|
+
if (field.names.length === 0) {
|
|
11653
|
+
if (isGormModelEmbed(field)) {
|
|
11654
|
+
add("id");
|
|
11655
|
+
add("created_at");
|
|
11656
|
+
add("updated_at");
|
|
11657
|
+
add("deleted_at");
|
|
11658
|
+
} else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11659
|
+
collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
|
|
11660
|
+
}
|
|
11661
|
+
continue;
|
|
11662
|
+
}
|
|
11663
|
+
if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11664
|
+
collectColumns(
|
|
11665
|
+
structs.get(field.typeName),
|
|
11666
|
+
structs,
|
|
11667
|
+
seen,
|
|
11668
|
+
prefix + (field.tag.embeddedPrefix ?? ""),
|
|
11669
|
+
out,
|
|
11670
|
+
emitted
|
|
11671
|
+
);
|
|
11672
|
+
continue;
|
|
11673
|
+
}
|
|
11674
|
+
if (isRelationField(field, structs)) continue;
|
|
11675
|
+
if (field.names.length === 1 && field.tag.column) {
|
|
11676
|
+
add(field.tag.column);
|
|
11677
|
+
} else {
|
|
11678
|
+
for (const n of field.names) add(toDBName(n));
|
|
11679
|
+
}
|
|
11680
|
+
}
|
|
11681
|
+
seen.delete(struct.name);
|
|
11682
|
+
}
|
|
11683
|
+
function gormEndpointsFromFile(file, serviceDir) {
|
|
11684
|
+
if (import_node_path49.default.extname(file.path) !== ".go") return [];
|
|
11685
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11686
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11687
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11688
|
+
const out = [];
|
|
11689
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
11690
|
+
for (const name of models) {
|
|
11691
|
+
const struct = structs.get(name);
|
|
11692
|
+
if (!struct) continue;
|
|
11693
|
+
const table = tableFor(name);
|
|
11694
|
+
if (seenTables.has(table)) continue;
|
|
11695
|
+
seenTables.add(table);
|
|
11696
|
+
const columns = [];
|
|
11697
|
+
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
11698
|
+
out.push({
|
|
11699
|
+
infraId: (0, import_types36.infraId)("sql-table", table),
|
|
11700
|
+
name: table,
|
|
11701
|
+
kind: "sql-table",
|
|
11702
|
+
edgeType: "CALLS",
|
|
11703
|
+
confidenceKind: "structural",
|
|
11704
|
+
...columns.length > 0 ? { columns } : {},
|
|
11705
|
+
evidence: {
|
|
11706
|
+
file: toPosix(import_node_path49.default.relative(serviceDir, file.path)),
|
|
11707
|
+
line: struct.line,
|
|
11708
|
+
snippet: snippet(file.content, struct.line)
|
|
11709
|
+
}
|
|
11710
|
+
});
|
|
11711
|
+
}
|
|
11712
|
+
return out;
|
|
11713
|
+
}
|
|
11714
|
+
function gormForeignKeys(file, serviceDir) {
|
|
11715
|
+
if (import_node_path49.default.extname(file.path) !== ".go") return [];
|
|
11716
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11717
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11718
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11719
|
+
const out = [];
|
|
11720
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11721
|
+
const emit = (childTable, parentTable, line) => {
|
|
11722
|
+
if (!childTable || !parentTable || childTable === parentTable) return;
|
|
11723
|
+
const key = `${childTable}->${parentTable}`;
|
|
11724
|
+
if (seen.has(key)) return;
|
|
11725
|
+
seen.add(key);
|
|
11726
|
+
out.push({
|
|
11727
|
+
childTable,
|
|
11728
|
+
parentTable,
|
|
11729
|
+
evidence: {
|
|
11730
|
+
file: toPosix(import_node_path49.default.relative(serviceDir, file.path)),
|
|
11731
|
+
line,
|
|
11732
|
+
snippet: snippet(file.content, line)
|
|
11733
|
+
}
|
|
11734
|
+
});
|
|
11735
|
+
};
|
|
11736
|
+
for (const name of models) {
|
|
11737
|
+
const struct = structs.get(name);
|
|
11738
|
+
if (!struct) continue;
|
|
11739
|
+
const thisTable = tableFor(name);
|
|
11740
|
+
const scalarNames = new Set(
|
|
11741
|
+
struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
|
|
11742
|
+
);
|
|
11743
|
+
for (const field of struct.fields) {
|
|
11744
|
+
if (field.tag.skip) continue;
|
|
11745
|
+
if (!isRelationField(field, structs)) continue;
|
|
11746
|
+
const relTable = tableFor(field.typeName);
|
|
11747
|
+
if (field.tag.many2many) {
|
|
11748
|
+
emit(field.tag.many2many, thisTable, field.line);
|
|
11749
|
+
emit(field.tag.many2many, relTable, field.line);
|
|
11750
|
+
continue;
|
|
11751
|
+
}
|
|
11752
|
+
if (field.isSlice) {
|
|
11753
|
+
emit(relTable, thisTable, field.line);
|
|
11754
|
+
continue;
|
|
11755
|
+
}
|
|
11756
|
+
const convFk = field.names[0] + "ID";
|
|
11757
|
+
const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
|
|
11758
|
+
if (belongsTo) emit(thisTable, relTable, field.line);
|
|
11759
|
+
else emit(relTable, thisTable, field.line);
|
|
11760
|
+
}
|
|
11761
|
+
}
|
|
11762
|
+
return out;
|
|
11763
|
+
}
|
|
11764
|
+
|
|
11117
11765
|
// src/extract/calls/index.ts
|
|
11118
11766
|
function edgeTypeFromEndpoint(ep) {
|
|
11119
11767
|
switch (ep.edgeType) {
|
|
11120
11768
|
case "PUBLISHES_TO":
|
|
11121
|
-
return
|
|
11769
|
+
return import_types37.EdgeType.PUBLISHES_TO;
|
|
11122
11770
|
case "CONSUMES_FROM":
|
|
11123
|
-
return
|
|
11771
|
+
return import_types37.EdgeType.CONSUMES_FROM;
|
|
11124
11772
|
default:
|
|
11125
|
-
return
|
|
11773
|
+
return import_types37.EdgeType.CALLS;
|
|
11126
11774
|
}
|
|
11127
11775
|
}
|
|
11128
11776
|
function isAwsKind(kind) {
|
|
@@ -11155,6 +11803,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11155
11803
|
} catch (err) {
|
|
11156
11804
|
recordExtractionError("go SQL call extraction", file.path, err);
|
|
11157
11805
|
}
|
|
11806
|
+
try {
|
|
11807
|
+
endpoints.push(...gormEndpointsFromFile(file, service.dir));
|
|
11808
|
+
} catch (err) {
|
|
11809
|
+
recordExtractionError("gorm data-axis extraction", file.path, err);
|
|
11810
|
+
}
|
|
11158
11811
|
try {
|
|
11159
11812
|
endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
|
|
11160
11813
|
endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
|
|
@@ -11177,7 +11830,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11177
11830
|
if (!graph.hasNode(ep.infraId)) {
|
|
11178
11831
|
const node = {
|
|
11179
11832
|
id: ep.infraId,
|
|
11180
|
-
type:
|
|
11833
|
+
type: import_types37.NodeType.InfraNode,
|
|
11181
11834
|
name: ep.name,
|
|
11182
11835
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
11183
11836
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -11190,21 +11843,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11190
11843
|
}
|
|
11191
11844
|
if (ep.columns && ep.columns.length > 0) {
|
|
11192
11845
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11193
|
-
if (node.type ===
|
|
11846
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11194
11847
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11195
11848
|
...node,
|
|
11196
11849
|
columns: foldColumns(
|
|
11197
11850
|
node.columns,
|
|
11198
11851
|
ep.columns,
|
|
11199
|
-
|
|
11200
|
-
(0,
|
|
11852
|
+
import_types37.Provenance.EXTRACTED,
|
|
11853
|
+
(0, import_types37.confidenceForExtracted)(ep.confidenceKind)
|
|
11201
11854
|
)
|
|
11202
11855
|
});
|
|
11203
11856
|
}
|
|
11204
11857
|
}
|
|
11205
11858
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
11206
11859
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11207
|
-
if (node.type ===
|
|
11860
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11208
11861
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11209
11862
|
...node,
|
|
11210
11863
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -11212,7 +11865,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11212
11865
|
}
|
|
11213
11866
|
}
|
|
11214
11867
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
11215
|
-
const confidence = (0,
|
|
11868
|
+
const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
|
|
11216
11869
|
const relFile = toPosix(ep.evidence.file);
|
|
11217
11870
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
11218
11871
|
graph,
|
|
@@ -11222,7 +11875,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11222
11875
|
);
|
|
11223
11876
|
nodesAdded += n;
|
|
11224
11877
|
edgesAdded += e;
|
|
11225
|
-
if (!(0,
|
|
11878
|
+
if (!(0, import_types37.passesExtractedFloor)(confidence)) {
|
|
11226
11879
|
noteExtractedDropped({
|
|
11227
11880
|
source: fileNodeId,
|
|
11228
11881
|
target: ep.infraId,
|
|
@@ -11242,7 +11895,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11242
11895
|
source: fileNodeId,
|
|
11243
11896
|
target: ep.infraId,
|
|
11244
11897
|
type: edgeType,
|
|
11245
|
-
provenance:
|
|
11898
|
+
provenance: import_types37.Provenance.EXTRACTED,
|
|
11246
11899
|
confidence,
|
|
11247
11900
|
evidence: ep.evidence
|
|
11248
11901
|
};
|
|
@@ -11265,7 +11918,7 @@ async function addCallEdges(graph, services) {
|
|
|
11265
11918
|
|
|
11266
11919
|
// src/extract/table-edges.ts
|
|
11267
11920
|
init_cjs_shims();
|
|
11268
|
-
var
|
|
11921
|
+
var import_types38 = require("@neat.is/types");
|
|
11269
11922
|
async function addTableEdges(graph, services) {
|
|
11270
11923
|
let nodesAdded = 0;
|
|
11271
11924
|
let edgesAdded = 0;
|
|
@@ -11279,6 +11932,7 @@ async function addTableEdges(graph, services) {
|
|
|
11279
11932
|
refs.push(...sqlalchemyForeignKeys(file, service.dir));
|
|
11280
11933
|
refs.push(...railsSchemaForeignKeys(file, service.dir));
|
|
11281
11934
|
refs.push(...laravelMigrationForeignKeys(file, service.dir));
|
|
11935
|
+
refs.push(...gormForeignKeys(file, service.dir));
|
|
11282
11936
|
modelRefs.push(...railsModelForeignKeys(file, service.dir));
|
|
11283
11937
|
modelRefs.push(...laravelModelForeignKeys(file, service.dir));
|
|
11284
11938
|
} catch (err) {
|
|
@@ -11292,20 +11946,20 @@ async function addTableEdges(graph, services) {
|
|
|
11292
11946
|
}
|
|
11293
11947
|
refs.push(...modelRefs);
|
|
11294
11948
|
for (const ref of refs) {
|
|
11295
|
-
const childId = (0,
|
|
11296
|
-
const parentId = (0,
|
|
11949
|
+
const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
|
|
11950
|
+
const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
|
|
11297
11951
|
if (childId === parentId) continue;
|
|
11298
11952
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
11299
11953
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
11300
|
-
const edgeId = (0,
|
|
11954
|
+
const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
|
|
11301
11955
|
if (graph.hasEdge(edgeId)) continue;
|
|
11302
11956
|
const edge = {
|
|
11303
11957
|
id: edgeId,
|
|
11304
11958
|
source: childId,
|
|
11305
11959
|
target: parentId,
|
|
11306
|
-
type:
|
|
11307
|
-
provenance:
|
|
11308
|
-
confidence: (0,
|
|
11960
|
+
type: import_types38.EdgeType.REFERENCES,
|
|
11961
|
+
provenance: import_types38.Provenance.EXTRACTED,
|
|
11962
|
+
confidence: (0, import_types38.confidenceForExtracted)("structural"),
|
|
11309
11963
|
evidence: ref.evidence
|
|
11310
11964
|
};
|
|
11311
11965
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -11318,7 +11972,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
11318
11972
|
if (graph.hasNode(id)) return 0;
|
|
11319
11973
|
const node = {
|
|
11320
11974
|
id,
|
|
11321
|
-
type:
|
|
11975
|
+
type: import_types38.NodeType.InfraNode,
|
|
11322
11976
|
name,
|
|
11323
11977
|
provider: "self",
|
|
11324
11978
|
kind: "sql-table"
|
|
@@ -11332,16 +11986,16 @@ init_cjs_shims();
|
|
|
11332
11986
|
|
|
11333
11987
|
// src/extract/infra/docker-compose.ts
|
|
11334
11988
|
init_cjs_shims();
|
|
11335
|
-
var
|
|
11336
|
-
var
|
|
11989
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11990
|
+
var import_types40 = require("@neat.is/types");
|
|
11337
11991
|
|
|
11338
11992
|
// src/extract/infra/shared.ts
|
|
11339
11993
|
init_cjs_shims();
|
|
11340
|
-
var
|
|
11994
|
+
var import_types39 = require("@neat.is/types");
|
|
11341
11995
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
11342
11996
|
return {
|
|
11343
|
-
id: (0,
|
|
11344
|
-
type:
|
|
11997
|
+
id: (0, import_types39.infraId)(kind, name),
|
|
11998
|
+
type: import_types39.NodeType.InfraNode,
|
|
11345
11999
|
name,
|
|
11346
12000
|
provider,
|
|
11347
12001
|
kind,
|
|
@@ -11385,8 +12039,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
11385
12039
|
source: anchorId,
|
|
11386
12040
|
target: node.id,
|
|
11387
12041
|
type: edgeType,
|
|
11388
|
-
provenance:
|
|
11389
|
-
confidence: (0,
|
|
12042
|
+
provenance: import_types39.Provenance.EXTRACTED,
|
|
12043
|
+
confidence: (0, import_types39.confidenceForExtracted)("structural"),
|
|
11390
12044
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11391
12045
|
};
|
|
11392
12046
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11403,7 +12057,7 @@ function dependsOnList(value) {
|
|
|
11403
12057
|
}
|
|
11404
12058
|
function serviceNameToServiceNode(name, services) {
|
|
11405
12059
|
for (const s of services) {
|
|
11406
|
-
if (s.node.name === name ||
|
|
12060
|
+
if (s.node.name === name || import_node_path50.default.basename(s.dir) === name) return s.node.id;
|
|
11407
12061
|
}
|
|
11408
12062
|
return null;
|
|
11409
12063
|
}
|
|
@@ -11412,7 +12066,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11412
12066
|
let edgesAdded = 0;
|
|
11413
12067
|
let composePath = null;
|
|
11414
12068
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
11415
|
-
const abs =
|
|
12069
|
+
const abs = import_node_path50.default.join(scanPath, name);
|
|
11416
12070
|
if (await exists(abs)) {
|
|
11417
12071
|
composePath = abs;
|
|
11418
12072
|
break;
|
|
@@ -11425,13 +12079,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11425
12079
|
} catch (err) {
|
|
11426
12080
|
recordExtractionError(
|
|
11427
12081
|
"infra docker-compose",
|
|
11428
|
-
|
|
12082
|
+
import_node_path50.default.relative(scanPath, composePath),
|
|
11429
12083
|
err
|
|
11430
12084
|
);
|
|
11431
12085
|
return { nodesAdded, edgesAdded };
|
|
11432
12086
|
}
|
|
11433
12087
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
11434
|
-
const evidenceFile =
|
|
12088
|
+
const evidenceFile = import_node_path50.default.relative(scanPath, composePath).split(import_node_path50.default.sep).join("/");
|
|
11435
12089
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
11436
12090
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
11437
12091
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -11453,15 +12107,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11453
12107
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
11454
12108
|
const targetId = composeNameToNodeId.get(dep);
|
|
11455
12109
|
if (!targetId) continue;
|
|
11456
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
12110
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
|
|
11457
12111
|
if (graph.hasEdge(edgeId)) continue;
|
|
11458
12112
|
const edge = {
|
|
11459
12113
|
id: edgeId,
|
|
11460
12114
|
source: sourceId,
|
|
11461
12115
|
target: targetId,
|
|
11462
|
-
type:
|
|
11463
|
-
provenance:
|
|
11464
|
-
confidence: (0,
|
|
12116
|
+
type: import_types40.EdgeType.DEPENDS_ON,
|
|
12117
|
+
provenance: import_types40.Provenance.EXTRACTED,
|
|
12118
|
+
confidence: (0, import_types40.confidenceForExtracted)("structural"),
|
|
11465
12119
|
evidence: { file: evidenceFile }
|
|
11466
12120
|
};
|
|
11467
12121
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11473,9 +12127,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11473
12127
|
|
|
11474
12128
|
// src/extract/infra/dockerfile.ts
|
|
11475
12129
|
init_cjs_shims();
|
|
11476
|
-
var
|
|
12130
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
11477
12131
|
var import_node_fs19 = require("fs");
|
|
11478
|
-
var
|
|
12132
|
+
var import_types41 = require("@neat.is/types");
|
|
11479
12133
|
function readDockerfile(content) {
|
|
11480
12134
|
let image = null;
|
|
11481
12135
|
const ports = [];
|
|
@@ -11504,7 +12158,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11504
12158
|
let nodesAdded = 0;
|
|
11505
12159
|
let edgesAdded = 0;
|
|
11506
12160
|
for (const service of services) {
|
|
11507
|
-
const dockerfilePath =
|
|
12161
|
+
const dockerfilePath = import_node_path51.default.join(service.dir, "Dockerfile");
|
|
11508
12162
|
if (!await exists(dockerfilePath)) continue;
|
|
11509
12163
|
let content;
|
|
11510
12164
|
try {
|
|
@@ -11512,7 +12166,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11512
12166
|
} catch (err) {
|
|
11513
12167
|
recordExtractionError(
|
|
11514
12168
|
"infra dockerfile",
|
|
11515
|
-
|
|
12169
|
+
import_node_path51.default.relative(scanPath, dockerfilePath),
|
|
11516
12170
|
err
|
|
11517
12171
|
);
|
|
11518
12172
|
continue;
|
|
@@ -11524,8 +12178,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11524
12178
|
graph.addNode(node.id, node);
|
|
11525
12179
|
nodesAdded++;
|
|
11526
12180
|
}
|
|
11527
|
-
const relDockerfile = toPosix(
|
|
11528
|
-
const evidenceFile = toPosix(
|
|
12181
|
+
const relDockerfile = toPosix(import_node_path51.default.relative(service.dir, dockerfilePath));
|
|
12182
|
+
const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, dockerfilePath));
|
|
11529
12183
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11530
12184
|
graph,
|
|
11531
12185
|
service.pkg.name,
|
|
@@ -11534,15 +12188,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11534
12188
|
);
|
|
11535
12189
|
nodesAdded += fn;
|
|
11536
12190
|
edgesAdded += fe;
|
|
11537
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
12191
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
|
|
11538
12192
|
if (!graph.hasEdge(edgeId)) {
|
|
11539
12193
|
const edge = {
|
|
11540
12194
|
id: edgeId,
|
|
11541
12195
|
source: fileNodeId,
|
|
11542
12196
|
target: node.id,
|
|
11543
|
-
type:
|
|
11544
|
-
provenance:
|
|
11545
|
-
confidence: (0,
|
|
12197
|
+
type: import_types41.EdgeType.RUNS_ON,
|
|
12198
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12199
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11546
12200
|
evidence: {
|
|
11547
12201
|
file: evidenceFile,
|
|
11548
12202
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -11557,15 +12211,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11557
12211
|
graph.addNode(portNode.id, portNode);
|
|
11558
12212
|
nodesAdded++;
|
|
11559
12213
|
}
|
|
11560
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
12214
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
|
|
11561
12215
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
11562
12216
|
const portEdge = {
|
|
11563
12217
|
id: portEdgeId,
|
|
11564
12218
|
source: fileNodeId,
|
|
11565
12219
|
target: portNode.id,
|
|
11566
|
-
type:
|
|
11567
|
-
provenance:
|
|
11568
|
-
confidence: (0,
|
|
12220
|
+
type: import_types41.EdgeType.CONNECTS_TO,
|
|
12221
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12222
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11569
12223
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
11570
12224
|
};
|
|
11571
12225
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -11578,8 +12232,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11578
12232
|
// src/extract/infra/terraform.ts
|
|
11579
12233
|
init_cjs_shims();
|
|
11580
12234
|
var import_node_fs20 = require("fs");
|
|
11581
|
-
var
|
|
11582
|
-
var
|
|
12235
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
12236
|
+
var import_types42 = require("@neat.is/types");
|
|
11583
12237
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
11584
12238
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
11585
12239
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -11589,11 +12243,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
11589
12243
|
for (const entry2 of entries) {
|
|
11590
12244
|
if (entry2.isDirectory()) {
|
|
11591
12245
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
11592
|
-
const child =
|
|
12246
|
+
const child = import_node_path52.default.join(start, entry2.name);
|
|
11593
12247
|
if (await isPythonVenvDir(child)) continue;
|
|
11594
12248
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
11595
12249
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
11596
|
-
out.push(
|
|
12250
|
+
out.push(import_node_path52.default.join(start, entry2.name));
|
|
11597
12251
|
}
|
|
11598
12252
|
}
|
|
11599
12253
|
return out;
|
|
@@ -11625,7 +12279,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11625
12279
|
const files = await walkTfFiles(scanPath);
|
|
11626
12280
|
for (const file of files) {
|
|
11627
12281
|
const content = await import_node_fs20.promises.readFile(file, "utf8");
|
|
11628
|
-
const evidenceFile = toPosix(
|
|
12282
|
+
const evidenceFile = toPosix(import_node_path52.default.relative(scanPath, file));
|
|
11629
12283
|
const resources = [];
|
|
11630
12284
|
const byKey = /* @__PURE__ */ new Map();
|
|
11631
12285
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -11660,16 +12314,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11660
12314
|
if (!target) continue;
|
|
11661
12315
|
if (seen.has(target.nodeId)) continue;
|
|
11662
12316
|
seen.add(target.nodeId);
|
|
11663
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
12317
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
|
|
11664
12318
|
if (graph.hasEdge(edgeId)) continue;
|
|
11665
12319
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
11666
12320
|
const edge = {
|
|
11667
12321
|
id: edgeId,
|
|
11668
12322
|
source: resource.nodeId,
|
|
11669
12323
|
target: target.nodeId,
|
|
11670
|
-
type:
|
|
11671
|
-
provenance:
|
|
11672
|
-
confidence: (0,
|
|
12324
|
+
type: import_types42.EdgeType.DEPENDS_ON,
|
|
12325
|
+
provenance: import_types42.Provenance.EXTRACTED,
|
|
12326
|
+
confidence: (0, import_types42.confidenceForExtracted)("structural"),
|
|
11673
12327
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
11674
12328
|
};
|
|
11675
12329
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11683,7 +12337,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11683
12337
|
// src/extract/infra/k8s.ts
|
|
11684
12338
|
init_cjs_shims();
|
|
11685
12339
|
var import_node_fs21 = require("fs");
|
|
11686
|
-
var
|
|
12340
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11687
12341
|
var import_yaml3 = require("yaml");
|
|
11688
12342
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
11689
12343
|
Service: "k8s-service",
|
|
@@ -11701,11 +12355,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
11701
12355
|
for (const entry2 of entries) {
|
|
11702
12356
|
if (entry2.isDirectory()) {
|
|
11703
12357
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
11704
|
-
const child =
|
|
12358
|
+
const child = import_node_path53.default.join(start, entry2.name);
|
|
11705
12359
|
if (await isPythonVenvDir(child)) continue;
|
|
11706
12360
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
11707
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
11708
|
-
out.push(
|
|
12361
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path53.default.extname(entry2.name))) {
|
|
12362
|
+
out.push(import_node_path53.default.join(start, entry2.name));
|
|
11709
12363
|
}
|
|
11710
12364
|
}
|
|
11711
12365
|
return out;
|
|
@@ -11739,13 +12393,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
11739
12393
|
// src/extract/infra/cloudflare.ts
|
|
11740
12394
|
init_cjs_shims();
|
|
11741
12395
|
var import_node_fs22 = require("fs");
|
|
11742
|
-
var
|
|
12396
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
11743
12397
|
var import_smol_toml2 = require("smol-toml");
|
|
11744
|
-
var
|
|
12398
|
+
var import_types43 = require("@neat.is/types");
|
|
11745
12399
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
11746
12400
|
async function readWranglerConfig(dir) {
|
|
11747
12401
|
for (const filename of WRANGLER_FILENAMES) {
|
|
11748
|
-
const abs =
|
|
12402
|
+
const abs = import_node_path54.default.join(dir, filename);
|
|
11749
12403
|
if (!await exists(abs)) continue;
|
|
11750
12404
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
11751
12405
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11789,8 +12443,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
11789
12443
|
source: anchorId,
|
|
11790
12444
|
target: node.id,
|
|
11791
12445
|
type: edgeType,
|
|
11792
|
-
provenance:
|
|
11793
|
-
confidence: (0,
|
|
12446
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12447
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11794
12448
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11795
12449
|
};
|
|
11796
12450
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11808,11 +12462,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11808
12462
|
try {
|
|
11809
12463
|
read = await readWranglerConfig(service.dir);
|
|
11810
12464
|
} catch (err) {
|
|
11811
|
-
recordExtractionError("infra cloudflare",
|
|
12465
|
+
recordExtractionError("infra cloudflare", import_node_path54.default.relative(scanPath, service.dir), err);
|
|
11812
12466
|
continue;
|
|
11813
12467
|
}
|
|
11814
12468
|
if (!read || !read.config.name) continue;
|
|
11815
|
-
const evidenceFile = toPosix(
|
|
12469
|
+
const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, read.relFile)));
|
|
11816
12470
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
11817
12471
|
}
|
|
11818
12472
|
for (const worker of discovered) {
|
|
@@ -11824,7 +12478,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11824
12478
|
}
|
|
11825
12479
|
let anchorId = service.node.id;
|
|
11826
12480
|
if (config.main) {
|
|
11827
|
-
const entryRelPath = toPosix(
|
|
12481
|
+
const entryRelPath = toPosix(import_node_path54.default.normalize(config.main));
|
|
11828
12482
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11829
12483
|
graph,
|
|
11830
12484
|
service.pkg.name,
|
|
@@ -11851,15 +12505,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11851
12505
|
nodesAdded++;
|
|
11852
12506
|
}
|
|
11853
12507
|
if (runtimeNode.id !== anchorId) {
|
|
11854
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
12508
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
|
|
11855
12509
|
if (!graph.hasEdge(runsOnId)) {
|
|
11856
12510
|
const edge = {
|
|
11857
12511
|
id: runsOnId,
|
|
11858
12512
|
source: anchorId,
|
|
11859
12513
|
target: runtimeNode.id,
|
|
11860
|
-
type:
|
|
11861
|
-
provenance:
|
|
11862
|
-
confidence: (0,
|
|
12514
|
+
type: import_types43.EdgeType.RUNS_ON,
|
|
12515
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12516
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11863
12517
|
evidence: {
|
|
11864
12518
|
file: evidenceFile,
|
|
11865
12519
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -11873,7 +12527,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11873
12527
|
const result = addResourceEdge(
|
|
11874
12528
|
graph,
|
|
11875
12529
|
anchorId,
|
|
11876
|
-
|
|
12530
|
+
import_types43.EdgeType.CONNECTS_TO,
|
|
11877
12531
|
"cloudflare-route",
|
|
11878
12532
|
route,
|
|
11879
12533
|
evidenceFile,
|
|
@@ -11897,7 +12551,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11897
12551
|
const result = addResourceEdge(
|
|
11898
12552
|
graph,
|
|
11899
12553
|
anchorId,
|
|
11900
|
-
|
|
12554
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11901
12555
|
group.kind,
|
|
11902
12556
|
name,
|
|
11903
12557
|
evidenceFile,
|
|
@@ -11911,7 +12565,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11911
12565
|
const result = addResourceEdge(
|
|
11912
12566
|
graph,
|
|
11913
12567
|
anchorId,
|
|
11914
|
-
|
|
12568
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11915
12569
|
"cloudflare-cron",
|
|
11916
12570
|
cron,
|
|
11917
12571
|
evidenceFile,
|
|
@@ -11924,7 +12578,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11924
12578
|
const result = addResourceEdge(
|
|
11925
12579
|
graph,
|
|
11926
12580
|
anchorId,
|
|
11927
|
-
|
|
12581
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11928
12582
|
"cloudflare-env-var",
|
|
11929
12583
|
varName,
|
|
11930
12584
|
evidenceFile,
|
|
@@ -11937,15 +12591,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11937
12591
|
if (!svc.service) continue;
|
|
11938
12592
|
const target = workerIndex.get(svc.service);
|
|
11939
12593
|
if (target && target.anchorId !== anchorId) {
|
|
11940
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
12594
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
|
|
11941
12595
|
if (!graph.hasEdge(edgeId)) {
|
|
11942
12596
|
const edge = {
|
|
11943
12597
|
id: edgeId,
|
|
11944
12598
|
source: anchorId,
|
|
11945
12599
|
target: target.anchorId,
|
|
11946
|
-
type:
|
|
11947
|
-
provenance:
|
|
11948
|
-
confidence: (0,
|
|
12600
|
+
type: import_types43.EdgeType.CALLS,
|
|
12601
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12602
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11949
12603
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
11950
12604
|
};
|
|
11951
12605
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11956,7 +12610,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11956
12610
|
const result = addResourceEdge(
|
|
11957
12611
|
graph,
|
|
11958
12612
|
anchorId,
|
|
11959
|
-
|
|
12613
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11960
12614
|
"cloudflare-service-binding",
|
|
11961
12615
|
svc.service,
|
|
11962
12616
|
evidenceFile,
|
|
@@ -11972,12 +12626,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11972
12626
|
// src/extract/infra/vercel.ts
|
|
11973
12627
|
init_cjs_shims();
|
|
11974
12628
|
var import_node_fs23 = require("fs");
|
|
11975
|
-
var
|
|
11976
|
-
var
|
|
12629
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
12630
|
+
var import_types44 = require("@neat.is/types");
|
|
11977
12631
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
11978
12632
|
async function readVercelConfig(dir) {
|
|
11979
12633
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
11980
|
-
const abs =
|
|
12634
|
+
const abs = import_node_path55.default.join(dir, filename);
|
|
11981
12635
|
if (!await exists(abs)) continue;
|
|
11982
12636
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
11983
12637
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11986,7 +12640,7 @@ async function readVercelConfig(dir) {
|
|
|
11986
12640
|
return null;
|
|
11987
12641
|
}
|
|
11988
12642
|
async function readLinkedProjectName(dir) {
|
|
11989
|
-
const abs =
|
|
12643
|
+
const abs = import_node_path55.default.join(dir, ".vercel", "project.json");
|
|
11990
12644
|
if (!await exists(abs)) return void 0;
|
|
11991
12645
|
const parsed = JSON.parse(await import_node_fs23.promises.readFile(abs, "utf8"));
|
|
11992
12646
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -12004,7 +12658,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12004
12658
|
read = await readVercelConfig(service.dir);
|
|
12005
12659
|
projectName = await readLinkedProjectName(service.dir);
|
|
12006
12660
|
} catch (err) {
|
|
12007
|
-
recordExtractionError("infra vercel",
|
|
12661
|
+
recordExtractionError("infra vercel", import_node_path55.default.relative(scanPath, service.dir), err);
|
|
12008
12662
|
continue;
|
|
12009
12663
|
}
|
|
12010
12664
|
if (!read && !projectName) continue;
|
|
@@ -12020,7 +12674,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12020
12674
|
const anchorId = service.node.id;
|
|
12021
12675
|
if (!read) continue;
|
|
12022
12676
|
const { config, relFile, raw } = read;
|
|
12023
|
-
const evidenceFile = toPosix(
|
|
12677
|
+
const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
|
|
12024
12678
|
const add = (edgeType, kind, name) => {
|
|
12025
12679
|
if (!name) return;
|
|
12026
12680
|
const result = emitPlatformResourceEdge(
|
|
@@ -12036,12 +12690,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12036
12690
|
nodesAdded += result.nodesAdded;
|
|
12037
12691
|
edgesAdded += result.edgesAdded;
|
|
12038
12692
|
};
|
|
12039
|
-
add(
|
|
12040
|
-
for (const cron of config.crons ?? []) add(
|
|
12041
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
12042
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
12693
|
+
add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
12694
|
+
for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
12695
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12696
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12043
12697
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
12044
|
-
add(
|
|
12698
|
+
add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
12045
12699
|
}
|
|
12046
12700
|
}
|
|
12047
12701
|
return { nodesAdded, edgesAdded };
|
|
@@ -12050,13 +12704,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12050
12704
|
// src/extract/infra/railway.ts
|
|
12051
12705
|
init_cjs_shims();
|
|
12052
12706
|
var import_node_fs24 = require("fs");
|
|
12053
|
-
var
|
|
12707
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
12054
12708
|
var import_smol_toml3 = require("smol-toml");
|
|
12055
|
-
var
|
|
12709
|
+
var import_types45 = require("@neat.is/types");
|
|
12056
12710
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
12057
12711
|
async function readRailwayConfig(dir) {
|
|
12058
12712
|
for (const filename of RAILWAY_FILENAMES) {
|
|
12059
|
-
const abs =
|
|
12713
|
+
const abs = import_node_path56.default.join(dir, filename);
|
|
12060
12714
|
if (!await exists(abs)) continue;
|
|
12061
12715
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
12062
12716
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -12072,7 +12726,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12072
12726
|
try {
|
|
12073
12727
|
read = await readRailwayConfig(service.dir);
|
|
12074
12728
|
} catch (err) {
|
|
12075
|
-
recordExtractionError("infra railway",
|
|
12729
|
+
recordExtractionError("infra railway", import_node_path56.default.relative(scanPath, service.dir), err);
|
|
12076
12730
|
continue;
|
|
12077
12731
|
}
|
|
12078
12732
|
if (!read) continue;
|
|
@@ -12082,7 +12736,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12082
12736
|
}
|
|
12083
12737
|
const anchorId = service.node.id;
|
|
12084
12738
|
const { config, relFile, raw } = read;
|
|
12085
|
-
const evidenceFile = toPosix(
|
|
12739
|
+
const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
|
|
12086
12740
|
const add = (edgeType, kind, name) => {
|
|
12087
12741
|
if (!name) return;
|
|
12088
12742
|
const result = emitPlatformResourceEdge(
|
|
@@ -12098,9 +12752,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12098
12752
|
nodesAdded += result.nodesAdded;
|
|
12099
12753
|
edgesAdded += result.edgesAdded;
|
|
12100
12754
|
};
|
|
12101
|
-
add(
|
|
12102
|
-
add(
|
|
12103
|
-
add(
|
|
12755
|
+
add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
|
|
12756
|
+
add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
12757
|
+
add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
12104
12758
|
}
|
|
12105
12759
|
return { nodesAdded, edgesAdded };
|
|
12106
12760
|
}
|
|
@@ -12108,12 +12762,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12108
12762
|
// src/extract/infra/supabase.ts
|
|
12109
12763
|
init_cjs_shims();
|
|
12110
12764
|
var import_node_fs25 = require("fs");
|
|
12111
|
-
var
|
|
12765
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
12112
12766
|
var import_smol_toml4 = require("smol-toml");
|
|
12113
|
-
var
|
|
12767
|
+
var import_types46 = require("@neat.is/types");
|
|
12114
12768
|
async function readSupabaseConfig(dir) {
|
|
12115
|
-
const relFile =
|
|
12116
|
-
const abs =
|
|
12769
|
+
const relFile = import_node_path57.default.join("supabase", "config.toml");
|
|
12770
|
+
const abs = import_node_path57.default.join(dir, relFile);
|
|
12117
12771
|
if (!await exists(abs)) return null;
|
|
12118
12772
|
const raw = await import_node_fs25.promises.readFile(abs, "utf8");
|
|
12119
12773
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -12127,7 +12781,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12127
12781
|
try {
|
|
12128
12782
|
read = await readSupabaseConfig(service.dir);
|
|
12129
12783
|
} catch (err) {
|
|
12130
|
-
recordExtractionError("infra supabase",
|
|
12784
|
+
recordExtractionError("infra supabase", import_node_path57.default.relative(scanPath, service.dir), err);
|
|
12131
12785
|
continue;
|
|
12132
12786
|
}
|
|
12133
12787
|
if (!read) continue;
|
|
@@ -12142,7 +12796,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12142
12796
|
});
|
|
12143
12797
|
}
|
|
12144
12798
|
const anchorId = service.node.id;
|
|
12145
|
-
const evidenceFile = toPosix(
|
|
12799
|
+
const evidenceFile = toPosix(import_node_path57.default.relative(scanPath, import_node_path57.default.join(service.dir, relFile)));
|
|
12146
12800
|
const add = (edgeType, kind, name) => {
|
|
12147
12801
|
if (!name) return;
|
|
12148
12802
|
const result = emitPlatformResourceEdge(
|
|
@@ -12158,10 +12812,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12158
12812
|
nodesAdded += result.nodesAdded;
|
|
12159
12813
|
edgesAdded += result.edgesAdded;
|
|
12160
12814
|
};
|
|
12161
|
-
add(
|
|
12162
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
12163
|
-
if (config.storage) add(
|
|
12164
|
-
if (config.auth) add(
|
|
12815
|
+
add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
12816
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
12817
|
+
if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
12818
|
+
if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
12165
12819
|
}
|
|
12166
12820
|
return { nodesAdded, edgesAdded };
|
|
12167
12821
|
}
|
|
@@ -12184,14 +12838,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
12184
12838
|
|
|
12185
12839
|
// src/extract/zod-shapes.ts
|
|
12186
12840
|
init_cjs_shims();
|
|
12187
|
-
var
|
|
12188
|
-
var
|
|
12841
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
12842
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
12189
12843
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12190
|
-
var
|
|
12844
|
+
var import_types47 = require("@neat.is/types");
|
|
12191
12845
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12192
12846
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12193
12847
|
function parserForExt3(ext) {
|
|
12194
|
-
const p = new
|
|
12848
|
+
const p = new import_tree_sitter16.default();
|
|
12195
12849
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12196
12850
|
return p;
|
|
12197
12851
|
}
|
|
@@ -12279,7 +12933,7 @@ function topLevelSchemas(root) {
|
|
|
12279
12933
|
}
|
|
12280
12934
|
function zodShapesFromFile(file, serviceDir) {
|
|
12281
12935
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12282
|
-
const tree = parseSource3(parserForExt3(
|
|
12936
|
+
const tree = parseSource3(parserForExt3(import_node_path58.default.extname(file.path)), file.content);
|
|
12283
12937
|
const out = [];
|
|
12284
12938
|
const seen = /* @__PURE__ */ new Set();
|
|
12285
12939
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -12293,11 +12947,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
12293
12947
|
seen.add(name);
|
|
12294
12948
|
const line = call.startPosition.row + 1;
|
|
12295
12949
|
out.push({
|
|
12296
|
-
infraId: (0,
|
|
12950
|
+
infraId: (0, import_types47.infraId)("zod-schema", name),
|
|
12297
12951
|
name,
|
|
12298
12952
|
fields,
|
|
12299
12953
|
evidence: {
|
|
12300
|
-
file:
|
|
12954
|
+
file: import_node_path58.default.relative(serviceDir, file.path),
|
|
12301
12955
|
line,
|
|
12302
12956
|
snippet: snippet(file.content, line)
|
|
12303
12957
|
}
|
|
@@ -12328,7 +12982,7 @@ async function addZodShapes(graph, services) {
|
|
|
12328
12982
|
if (!graph.hasNode(shape.infraId)) {
|
|
12329
12983
|
const node = {
|
|
12330
12984
|
id: shape.infraId,
|
|
12331
|
-
type:
|
|
12985
|
+
type: import_types47.NodeType.InfraNode,
|
|
12332
12986
|
name: shape.name,
|
|
12333
12987
|
provider: "self",
|
|
12334
12988
|
kind: "zod-schema"
|
|
@@ -12338,14 +12992,14 @@ async function addZodShapes(graph, services) {
|
|
|
12338
12992
|
}
|
|
12339
12993
|
if (shape.fields.length > 0) {
|
|
12340
12994
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
12341
|
-
if (node.type ===
|
|
12995
|
+
if (node.type === import_types47.NodeType.InfraNode) {
|
|
12342
12996
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
12343
12997
|
...node,
|
|
12344
12998
|
columns: foldColumns(
|
|
12345
12999
|
node.columns,
|
|
12346
13000
|
shape.fields,
|
|
12347
|
-
|
|
12348
|
-
(0,
|
|
13001
|
+
import_types47.Provenance.EXTRACTED,
|
|
13002
|
+
(0, import_types47.confidenceForExtracted)("structural")
|
|
12349
13003
|
)
|
|
12350
13004
|
});
|
|
12351
13005
|
}
|
|
@@ -12359,15 +13013,15 @@ async function addZodShapes(graph, services) {
|
|
|
12359
13013
|
);
|
|
12360
13014
|
nodesAdded += n;
|
|
12361
13015
|
edgesAdded += e;
|
|
12362
|
-
const edgeId = (0,
|
|
13016
|
+
const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
|
|
12363
13017
|
if (!graph.hasEdge(edgeId)) {
|
|
12364
13018
|
const edge = {
|
|
12365
13019
|
id: edgeId,
|
|
12366
13020
|
source: fileNodeId,
|
|
12367
13021
|
target: shape.infraId,
|
|
12368
|
-
type:
|
|
12369
|
-
provenance:
|
|
12370
|
-
confidence: (0,
|
|
13022
|
+
type: import_types47.EdgeType.CONTAINS,
|
|
13023
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
13024
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
12371
13025
|
evidence: shape.evidence
|
|
12372
13026
|
};
|
|
12373
13027
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -12381,7 +13035,7 @@ async function addZodShapes(graph, services) {
|
|
|
12381
13035
|
|
|
12382
13036
|
// src/extract/firestore-rules.ts
|
|
12383
13037
|
init_cjs_shims();
|
|
12384
|
-
var
|
|
13038
|
+
var import_types48 = require("@neat.is/types");
|
|
12385
13039
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
12386
13040
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
12387
13041
|
function stripComments(src) {
|
|
@@ -12521,7 +13175,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
12521
13175
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
12522
13176
|
graph.forEachNode((id, attrs) => {
|
|
12523
13177
|
const node = attrs;
|
|
12524
|
-
if (node.type !==
|
|
13178
|
+
if (node.type !== import_types48.NodeType.InfraNode) return;
|
|
12525
13179
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
12526
13180
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
12527
13181
|
if (!fields || fields.size === 0) return;
|
|
@@ -12534,17 +13188,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
12534
13188
|
}
|
|
12535
13189
|
|
|
12536
13190
|
// src/extract/index.ts
|
|
12537
|
-
var
|
|
13191
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
12538
13192
|
|
|
12539
13193
|
// src/extract/retire.ts
|
|
12540
13194
|
init_cjs_shims();
|
|
12541
13195
|
var import_node_fs26 = require("fs");
|
|
12542
|
-
var
|
|
12543
|
-
var
|
|
13196
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
13197
|
+
var import_types49 = require("@neat.is/types");
|
|
12544
13198
|
function dropOrphanedFileNodes(graph) {
|
|
12545
13199
|
const orphans = [];
|
|
12546
13200
|
graph.forEachNode((id, attrs) => {
|
|
12547
|
-
if (attrs.type !==
|
|
13201
|
+
if (attrs.type !== import_types49.NodeType.FileNode) return;
|
|
12548
13202
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
12549
13203
|
orphans.push(id);
|
|
12550
13204
|
}
|
|
@@ -12557,7 +13211,7 @@ function retireEdgesByFile(graph, file) {
|
|
|
12557
13211
|
const toDrop = [];
|
|
12558
13212
|
graph.forEachEdge((id, attrs) => {
|
|
12559
13213
|
const edge = attrs;
|
|
12560
|
-
if (edge.provenance !==
|
|
13214
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12561
13215
|
if (!edge.evidence?.file) return;
|
|
12562
13216
|
if (edge.evidence.file === normalized) toDrop.push(id);
|
|
12563
13217
|
});
|
|
@@ -12570,14 +13224,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
12570
13224
|
const bases = [scanPath, ...serviceDirs];
|
|
12571
13225
|
graph.forEachEdge((id, attrs) => {
|
|
12572
13226
|
const edge = attrs;
|
|
12573
|
-
if (edge.provenance !==
|
|
13227
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12574
13228
|
const evidenceFile = edge.evidence?.file;
|
|
12575
13229
|
if (!evidenceFile) return;
|
|
12576
|
-
if (
|
|
13230
|
+
if (import_node_path59.default.isAbsolute(evidenceFile)) {
|
|
12577
13231
|
if (!(0, import_node_fs26.existsSync)(evidenceFile)) toDrop.push(id);
|
|
12578
13232
|
return;
|
|
12579
13233
|
}
|
|
12580
|
-
const found = bases.some((base) => (0, import_node_fs26.existsSync)(
|
|
13234
|
+
const found = bases.some((base) => (0, import_node_fs26.existsSync)(import_node_path59.default.join(base, evidenceFile)));
|
|
12581
13235
|
if (!found) toDrop.push(id);
|
|
12582
13236
|
});
|
|
12583
13237
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -12634,7 +13288,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12634
13288
|
}
|
|
12635
13289
|
const droppedEntries = drainDroppedExtracted();
|
|
12636
13290
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
12637
|
-
const rejectedPath =
|
|
13291
|
+
const rejectedPath = import_node_path60.default.join(import_node_path60.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
12638
13292
|
try {
|
|
12639
13293
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
12640
13294
|
} catch (err) {
|
|
@@ -12668,39 +13322,39 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12668
13322
|
|
|
12669
13323
|
// src/divergences.ts
|
|
12670
13324
|
init_cjs_shims();
|
|
12671
|
-
var
|
|
13325
|
+
var import_types50 = require("@neat.is/types");
|
|
12672
13326
|
function bucketKey(source, target, type) {
|
|
12673
13327
|
return `${type}|${source}|${target}`;
|
|
12674
13328
|
}
|
|
12675
13329
|
function bucketSourceFor(graph, edge) {
|
|
12676
|
-
if (edge.type !==
|
|
12677
|
-
const parsed = (0,
|
|
13330
|
+
if (edge.type !== import_types50.EdgeType.CONNECTS_TO) return edge.source;
|
|
13331
|
+
const parsed = (0, import_types50.parseFileId)(edge.source);
|
|
12678
13332
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
12679
13333
|
const target = graph.getNodeAttributes(edge.target);
|
|
12680
|
-
if (target.type !==
|
|
12681
|
-
return (0,
|
|
13334
|
+
if (target.type !== import_types50.NodeType.DatabaseNode) return edge.source;
|
|
13335
|
+
return (0, import_types50.serviceId)(parsed.service);
|
|
12682
13336
|
}
|
|
12683
13337
|
function bucketEdges(graph) {
|
|
12684
13338
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
12685
13339
|
graph.forEachEdge((id, attrs) => {
|
|
12686
13340
|
const e = attrs;
|
|
12687
|
-
const parsed = (0,
|
|
13341
|
+
const parsed = (0, import_types50.parseEdgeId)(id);
|
|
12688
13342
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
12689
13343
|
const source = bucketSourceFor(graph, e);
|
|
12690
13344
|
const key = bucketKey(source, e.target, e.type);
|
|
12691
13345
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
12692
13346
|
switch (provenance) {
|
|
12693
|
-
case
|
|
13347
|
+
case import_types50.Provenance.EXTRACTED:
|
|
12694
13348
|
cur.extracted = e;
|
|
12695
13349
|
break;
|
|
12696
|
-
case
|
|
13350
|
+
case import_types50.Provenance.OBSERVED:
|
|
12697
13351
|
cur.observed = e;
|
|
12698
13352
|
break;
|
|
12699
|
-
case
|
|
13353
|
+
case import_types50.Provenance.INFERRED:
|
|
12700
13354
|
cur.inferred = e;
|
|
12701
13355
|
break;
|
|
12702
13356
|
default:
|
|
12703
|
-
if (e.provenance ===
|
|
13357
|
+
if (e.provenance === import_types50.Provenance.STALE) cur.stale = e;
|
|
12704
13358
|
}
|
|
12705
13359
|
buckets2.set(key, cur);
|
|
12706
13360
|
});
|
|
@@ -12709,22 +13363,22 @@ function bucketEdges(graph) {
|
|
|
12709
13363
|
function nodeIsFrontier(graph, nodeId) {
|
|
12710
13364
|
if (!graph.hasNode(nodeId)) return false;
|
|
12711
13365
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
12712
|
-
return attrs.type ===
|
|
13366
|
+
return attrs.type === import_types50.NodeType.FrontierNode;
|
|
12713
13367
|
}
|
|
12714
13368
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
12715
13369
|
if (!graph.hasNode(nodeId)) return false;
|
|
12716
13370
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
12717
|
-
return attrs.type ===
|
|
13371
|
+
return attrs.type === import_types50.NodeType.WebSocketChannelNode;
|
|
12718
13372
|
}
|
|
12719
13373
|
function nodeIsServerAction(graph, nodeId) {
|
|
12720
13374
|
if (!graph.hasNode(nodeId)) return false;
|
|
12721
13375
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
12722
|
-
return attrs.type ===
|
|
13376
|
+
return attrs.type === import_types50.NodeType.ServerActionNode;
|
|
12723
13377
|
}
|
|
12724
13378
|
function nodeIsSymbol(graph, nodeId) {
|
|
12725
13379
|
if (!graph.hasNode(nodeId)) return false;
|
|
12726
13380
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
12727
|
-
return attrs.type ===
|
|
13381
|
+
return attrs.type === import_types50.NodeType.SymbolNode;
|
|
12728
13382
|
}
|
|
12729
13383
|
function clampConfidence(n) {
|
|
12730
13384
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -12744,14 +13398,14 @@ function gradedConfidence(edge) {
|
|
|
12744
13398
|
return clampConfidence(confidenceForEdge(edge));
|
|
12745
13399
|
}
|
|
12746
13400
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
13401
|
+
import_types50.EdgeType.CALLS,
|
|
13402
|
+
import_types50.EdgeType.CONNECTS_TO,
|
|
13403
|
+
import_types50.EdgeType.PUBLISHES_TO,
|
|
13404
|
+
import_types50.EdgeType.CONSUMES_FROM
|
|
12751
13405
|
]);
|
|
12752
13406
|
function detectMissingDivergences(graph, bucket) {
|
|
12753
13407
|
const out = [];
|
|
12754
|
-
if (bucket.type ===
|
|
13408
|
+
if (bucket.type === import_types50.EdgeType.CONTAINS) return out;
|
|
12755
13409
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
12756
13410
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
12757
13411
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -12793,7 +13447,7 @@ function declaredHostFor(svc) {
|
|
|
12793
13447
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
12794
13448
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
12795
13449
|
const e = graph.getEdgeAttributes(edgeId);
|
|
12796
|
-
if (e.type ===
|
|
13450
|
+
if (e.type === import_types50.EdgeType.CONFIGURED_BY && e.provenance === import_types50.Provenance.EXTRACTED) {
|
|
12797
13451
|
return true;
|
|
12798
13452
|
}
|
|
12799
13453
|
}
|
|
@@ -12806,10 +13460,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
12806
13460
|
const out = [];
|
|
12807
13461
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
12808
13462
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
12809
|
-
if (edge.type !==
|
|
12810
|
-
if (edge.provenance !==
|
|
13463
|
+
if (edge.type !== import_types50.EdgeType.CONNECTS_TO) continue;
|
|
13464
|
+
if (edge.provenance !== import_types50.Provenance.OBSERVED) continue;
|
|
12811
13465
|
const target = graph.getNodeAttributes(edge.target);
|
|
12812
|
-
if (target.type !==
|
|
13466
|
+
if (target.type !== import_types50.NodeType.DatabaseNode) continue;
|
|
12813
13467
|
const observedHost = target.host?.trim();
|
|
12814
13468
|
if (!observedHost) continue;
|
|
12815
13469
|
if (observedHost === declaredHost) continue;
|
|
@@ -12831,10 +13485,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
12831
13485
|
const deps = svc.dependencies ?? {};
|
|
12832
13486
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
12833
13487
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
12834
|
-
if (edge.type !==
|
|
12835
|
-
if (edge.provenance !==
|
|
13488
|
+
if (edge.type !== import_types50.EdgeType.CONNECTS_TO) continue;
|
|
13489
|
+
if (edge.provenance !== import_types50.Provenance.OBSERVED) continue;
|
|
12836
13490
|
const target = graph.getNodeAttributes(edge.target);
|
|
12837
|
-
if (target.type !==
|
|
13491
|
+
if (target.type !== import_types50.NodeType.DatabaseNode) continue;
|
|
12838
13492
|
for (const pair of compatPairs()) {
|
|
12839
13493
|
if (pair.engine !== target.engine) continue;
|
|
12840
13494
|
const declared = deps[pair.driver];
|
|
@@ -12931,7 +13585,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
12931
13585
|
for (const d of all) {
|
|
12932
13586
|
if (d.type !== "host-mismatch") continue;
|
|
12933
13587
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
12934
|
-
declaredHalf.add((0,
|
|
13588
|
+
declaredHalf.add((0, import_types50.databaseId)(d.extractedHost));
|
|
12935
13589
|
}
|
|
12936
13590
|
if (observedHalf.size === 0) return all;
|
|
12937
13591
|
return all.filter((d) => {
|
|
@@ -12950,13 +13604,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
12950
13604
|
}
|
|
12951
13605
|
graph.forEachNode((nodeId, attrs) => {
|
|
12952
13606
|
const n = attrs;
|
|
12953
|
-
if (n.type ===
|
|
13607
|
+
if (n.type === import_types50.NodeType.ServiceNode) {
|
|
12954
13608
|
const svc = n;
|
|
12955
13609
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
12956
13610
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
12957
13611
|
return;
|
|
12958
13612
|
}
|
|
12959
|
-
if (n.type ===
|
|
13613
|
+
if (n.type === import_types50.NodeType.InfraNode && n.kind === "sql-table") {
|
|
12960
13614
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
12961
13615
|
}
|
|
12962
13616
|
});
|
|
@@ -12992,7 +13646,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
12992
13646
|
const bc = "column" in b && b.column ? b.column : "";
|
|
12993
13647
|
return ac.localeCompare(bc);
|
|
12994
13648
|
});
|
|
12995
|
-
return
|
|
13649
|
+
return import_types50.DivergenceResultSchema.parse({
|
|
12996
13650
|
divergences: filtered,
|
|
12997
13651
|
totalAffected: filtered.length,
|
|
12998
13652
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13002,8 +13656,8 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13002
13656
|
// src/persist.ts
|
|
13003
13657
|
init_cjs_shims();
|
|
13004
13658
|
var import_node_fs27 = require("fs");
|
|
13005
|
-
var
|
|
13006
|
-
var
|
|
13659
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
13660
|
+
var import_types51 = require("@neat.is/types");
|
|
13007
13661
|
var SCHEMA_VERSION = 7;
|
|
13008
13662
|
function migrateV1ToV2(payload) {
|
|
13009
13663
|
const nodes = payload.graph.nodes;
|
|
@@ -13027,7 +13681,7 @@ function migrateV5ToV6(payload) {
|
|
|
13027
13681
|
if (Array.isArray(nodes)) {
|
|
13028
13682
|
for (const node of nodes) {
|
|
13029
13683
|
const attrs = node.attributes;
|
|
13030
|
-
if (!attrs || attrs.type !==
|
|
13684
|
+
if (!attrs || attrs.type !== import_types51.NodeType.InfraNode) continue;
|
|
13031
13685
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
13032
13686
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
13033
13687
|
}
|
|
@@ -13043,12 +13697,12 @@ function migrateV2ToV3(payload) {
|
|
|
13043
13697
|
for (const edge of edges) {
|
|
13044
13698
|
const attrs = edge.attributes;
|
|
13045
13699
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
13046
|
-
attrs.provenance =
|
|
13700
|
+
attrs.provenance = import_types51.Provenance.OBSERVED;
|
|
13047
13701
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
13048
13702
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
13049
13703
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
13050
13704
|
if (type && source && target) {
|
|
13051
|
-
const newId = (0,
|
|
13705
|
+
const newId = (0, import_types51.observedEdgeId)(source, target, type);
|
|
13052
13706
|
attrs.id = newId;
|
|
13053
13707
|
if (edge.key) edge.key = newId;
|
|
13054
13708
|
}
|
|
@@ -13057,7 +13711,7 @@ function migrateV2ToV3(payload) {
|
|
|
13057
13711
|
return { ...payload, schemaVersion: 3 };
|
|
13058
13712
|
}
|
|
13059
13713
|
async function ensureDir(filePath) {
|
|
13060
|
-
await import_node_fs27.promises.mkdir(
|
|
13714
|
+
await import_node_fs27.promises.mkdir(import_node_path61.default.dirname(filePath), { recursive: true });
|
|
13061
13715
|
}
|
|
13062
13716
|
async function saveGraphToDisk(graph, outPath) {
|
|
13063
13717
|
await ensureDir(outPath);
|
|
@@ -13148,7 +13802,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
13148
13802
|
// src/gitignore.ts
|
|
13149
13803
|
init_cjs_shims();
|
|
13150
13804
|
var import_node_fs28 = require("fs");
|
|
13151
|
-
var
|
|
13805
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
13152
13806
|
var NEAT_OUT_LINE = "neat-out/";
|
|
13153
13807
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
13154
13808
|
function isNeatOutLine(line) {
|
|
@@ -13156,7 +13810,7 @@ function isNeatOutLine(line) {
|
|
|
13156
13810
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
13157
13811
|
}
|
|
13158
13812
|
async function ensureNeatOutIgnored(projectDir) {
|
|
13159
|
-
const file =
|
|
13813
|
+
const file = import_node_path62.default.join(projectDir, ".gitignore");
|
|
13160
13814
|
let existing = null;
|
|
13161
13815
|
try {
|
|
13162
13816
|
existing = await import_node_fs28.promises.readFile(file, "utf8");
|
|
@@ -13183,7 +13837,7 @@ ${NEAT_OUT_LINE}
|
|
|
13183
13837
|
|
|
13184
13838
|
// src/summary.ts
|
|
13185
13839
|
init_cjs_shims();
|
|
13186
|
-
var
|
|
13840
|
+
var import_types52 = require("@neat.is/types");
|
|
13187
13841
|
function renderOtelEnvBlock() {
|
|
13188
13842
|
return [
|
|
13189
13843
|
"for prod OTel routing, set these in your deploy platform's env:",
|
|
@@ -13193,19 +13847,19 @@ function renderOtelEnvBlock() {
|
|
|
13193
13847
|
}
|
|
13194
13848
|
function findIncompatServices(nodes) {
|
|
13195
13849
|
return nodes.filter(
|
|
13196
|
-
(n) => n.type ===
|
|
13850
|
+
(n) => n.type === import_types52.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
|
|
13197
13851
|
);
|
|
13198
13852
|
}
|
|
13199
13853
|
function servicesWithoutObserved(nodes, edges) {
|
|
13200
13854
|
const seen = /* @__PURE__ */ new Set();
|
|
13201
13855
|
for (const e of edges) {
|
|
13202
|
-
if (e.provenance ===
|
|
13856
|
+
if (e.provenance === import_types52.Provenance.OBSERVED) {
|
|
13203
13857
|
seen.add(e.source);
|
|
13204
13858
|
seen.add(e.target);
|
|
13205
13859
|
}
|
|
13206
13860
|
}
|
|
13207
13861
|
return nodes.filter(
|
|
13208
|
-
(n) => n.type ===
|
|
13862
|
+
(n) => n.type === import_types52.NodeType.ServiceNode && !seen.has(n.id)
|
|
13209
13863
|
);
|
|
13210
13864
|
}
|
|
13211
13865
|
function formatDivergence(d) {
|
|
@@ -13280,26 +13934,26 @@ function formatIncompat(inc) {
|
|
|
13280
13934
|
// src/watch.ts
|
|
13281
13935
|
init_cjs_shims();
|
|
13282
13936
|
var import_node_fs37 = __toESM(require("fs"), 1);
|
|
13283
|
-
var
|
|
13937
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
13284
13938
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
13285
13939
|
|
|
13286
13940
|
// src/api.ts
|
|
13287
13941
|
init_cjs_shims();
|
|
13288
13942
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
13289
13943
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
13290
|
-
var
|
|
13944
|
+
var import_types81 = require("@neat.is/types");
|
|
13291
13945
|
|
|
13292
13946
|
// src/extend/index.ts
|
|
13293
13947
|
init_cjs_shims();
|
|
13294
13948
|
var import_node_fs30 = require("fs");
|
|
13295
|
-
var
|
|
13949
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
13296
13950
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
13297
13951
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
13298
13952
|
|
|
13299
13953
|
// src/installers/package-manager.ts
|
|
13300
13954
|
init_cjs_shims();
|
|
13301
13955
|
var import_node_fs29 = require("fs");
|
|
13302
|
-
var
|
|
13956
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
13303
13957
|
var import_node_child_process = require("child_process");
|
|
13304
13958
|
var LOCKFILE_PRIORITY = [
|
|
13305
13959
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -13321,22 +13975,22 @@ async function exists2(p) {
|
|
|
13321
13975
|
}
|
|
13322
13976
|
}
|
|
13323
13977
|
async function detectPackageManager(serviceDir) {
|
|
13324
|
-
let dir =
|
|
13978
|
+
let dir = import_node_path63.default.resolve(serviceDir);
|
|
13325
13979
|
const stops = /* @__PURE__ */ new Set();
|
|
13326
13980
|
for (let i = 0; i < 64; i++) {
|
|
13327
13981
|
if (stops.has(dir)) break;
|
|
13328
13982
|
stops.add(dir);
|
|
13329
13983
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
13330
|
-
const lockPath =
|
|
13984
|
+
const lockPath = import_node_path63.default.join(dir, candidate.lockfile);
|
|
13331
13985
|
if (await exists2(lockPath)) {
|
|
13332
13986
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
13333
13987
|
}
|
|
13334
13988
|
}
|
|
13335
|
-
const parent =
|
|
13989
|
+
const parent = import_node_path63.default.dirname(dir);
|
|
13336
13990
|
if (parent === dir) break;
|
|
13337
13991
|
dir = parent;
|
|
13338
13992
|
}
|
|
13339
|
-
return { pm: "npm", cwd:
|
|
13993
|
+
return { pm: "npm", cwd: import_node_path63.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
13340
13994
|
}
|
|
13341
13995
|
async function runPackageManagerInstall(cmd) {
|
|
13342
13996
|
return new Promise((resolve) => {
|
|
@@ -13385,7 +14039,7 @@ async function fileExists2(p) {
|
|
|
13385
14039
|
}
|
|
13386
14040
|
}
|
|
13387
14041
|
async function readPackageJson(scanPath) {
|
|
13388
|
-
const pkgPath =
|
|
14042
|
+
const pkgPath = import_node_path64.default.join(scanPath, "package.json");
|
|
13389
14043
|
const raw = await import_node_fs30.promises.readFile(pkgPath, "utf8");
|
|
13390
14044
|
return JSON.parse(raw);
|
|
13391
14045
|
}
|
|
@@ -13399,27 +14053,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
13399
14053
|
]);
|
|
13400
14054
|
async function findHookFiles(scanPath) {
|
|
13401
14055
|
const found = [];
|
|
13402
|
-
const
|
|
14056
|
+
const walk9 = async (dir) => {
|
|
13403
14057
|
const entries = await import_node_fs30.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
13404
14058
|
for (const entry2 of entries) {
|
|
13405
14059
|
if (entry2.isDirectory()) {
|
|
13406
14060
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
13407
|
-
await
|
|
14061
|
+
await walk9(import_node_path64.default.join(dir, entry2.name));
|
|
13408
14062
|
} else if (entry2.isFile()) {
|
|
13409
14063
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
13410
|
-
const rel =
|
|
13411
|
-
found.push(rel.split(
|
|
14064
|
+
const rel = import_node_path64.default.relative(scanPath, import_node_path64.default.join(dir, entry2.name));
|
|
14065
|
+
found.push(rel.split(import_node_path64.default.sep).join("/"));
|
|
13412
14066
|
}
|
|
13413
14067
|
}
|
|
13414
14068
|
}
|
|
13415
14069
|
};
|
|
13416
|
-
await
|
|
14070
|
+
await walk9(scanPath);
|
|
13417
14071
|
return found.sort();
|
|
13418
14072
|
}
|
|
13419
14073
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
13420
14074
|
let fallback = null;
|
|
13421
14075
|
for (const file of hookFiles) {
|
|
13422
|
-
const content = await import_node_fs30.promises.readFile(
|
|
14076
|
+
const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(scanPath, file), "utf8");
|
|
13423
14077
|
const patched = splicedContent(content, snippet2);
|
|
13424
14078
|
if (patched !== null) return { file, content, patched };
|
|
13425
14079
|
if (fallback === null) fallback = { file, content };
|
|
@@ -13427,11 +14081,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
13427
14081
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
13428
14082
|
}
|
|
13429
14083
|
function extendLogPath() {
|
|
13430
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
14084
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path64.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
13431
14085
|
}
|
|
13432
14086
|
async function appendExtendLog(entry2) {
|
|
13433
14087
|
const logPath = extendLogPath();
|
|
13434
|
-
await import_node_fs30.promises.mkdir(
|
|
14088
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(logPath), { recursive: true });
|
|
13435
14089
|
await import_node_fs30.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
13436
14090
|
}
|
|
13437
14091
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -13490,7 +14144,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
13490
14144
|
}
|
|
13491
14145
|
async function describeProjectInstrumentation(ctx) {
|
|
13492
14146
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13493
|
-
const envNeat = await fileExists2(
|
|
14147
|
+
const envNeat = await fileExists2(import_node_path64.default.join(ctx.scanPath, ".env.neat"));
|
|
13494
14148
|
const registryInstrPackages = new Set(
|
|
13495
14149
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
13496
14150
|
);
|
|
@@ -13512,7 +14166,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
13512
14166
|
);
|
|
13513
14167
|
}
|
|
13514
14168
|
for (const file of hookFiles) {
|
|
13515
|
-
const content = await import_node_fs30.promises.readFile(
|
|
14169
|
+
const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(ctx.scanPath, file), "utf8");
|
|
13516
14170
|
if (content.includes(args.registration_snippet)) {
|
|
13517
14171
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
13518
14172
|
}
|
|
@@ -13524,10 +14178,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
13524
14178
|
);
|
|
13525
14179
|
}
|
|
13526
14180
|
const primaryFile = primary.file;
|
|
13527
|
-
const primaryPath =
|
|
14181
|
+
const primaryPath = import_node_path64.default.join(ctx.scanPath, primaryFile);
|
|
13528
14182
|
const filesTouched = [];
|
|
13529
14183
|
const depsAdded = [];
|
|
13530
|
-
const pkgPath =
|
|
14184
|
+
const pkgPath = import_node_path64.default.join(ctx.scanPath, "package.json");
|
|
13531
14185
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13532
14186
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
13533
14187
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -13566,7 +14220,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
13566
14220
|
};
|
|
13567
14221
|
}
|
|
13568
14222
|
for (const file of hookFiles) {
|
|
13569
|
-
const content = await import_node_fs30.promises.readFile(
|
|
14223
|
+
const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(ctx.scanPath, file), "utf8");
|
|
13570
14224
|
if (content.includes(args.registration_snippet)) {
|
|
13571
14225
|
return {
|
|
13572
14226
|
library: args.library,
|
|
@@ -13607,7 +14261,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13607
14261
|
if (!match) {
|
|
13608
14262
|
return { undone: false, message: "no apply found for library" };
|
|
13609
14263
|
}
|
|
13610
|
-
const pkgPath =
|
|
14264
|
+
const pkgPath = import_node_path64.default.join(ctx.scanPath, "package.json");
|
|
13611
14265
|
if (await fileExists2(pkgPath)) {
|
|
13612
14266
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13613
14267
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -13618,7 +14272,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13618
14272
|
}
|
|
13619
14273
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13620
14274
|
for (const file of hookFiles) {
|
|
13621
|
-
const filePath =
|
|
14275
|
+
const filePath = import_node_path64.default.join(ctx.scanPath, file);
|
|
13622
14276
|
const content = await import_node_fs30.promises.readFile(filePath, "utf8");
|
|
13623
14277
|
if (content.includes(match.registration_snippet)) {
|
|
13624
14278
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -13756,23 +14410,23 @@ function canonicalJson(value) {
|
|
|
13756
14410
|
|
|
13757
14411
|
// src/projects.ts
|
|
13758
14412
|
init_cjs_shims();
|
|
13759
|
-
var
|
|
14413
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
13760
14414
|
function pathsForProject(project, baseDir) {
|
|
13761
14415
|
if (project === DEFAULT_PROJECT) {
|
|
13762
14416
|
return {
|
|
13763
|
-
snapshotPath:
|
|
13764
|
-
errorsPath:
|
|
13765
|
-
staleEventsPath:
|
|
13766
|
-
embeddingsCachePath:
|
|
13767
|
-
policyViolationsPath:
|
|
14417
|
+
snapshotPath: import_node_path65.default.join(baseDir, "graph.json"),
|
|
14418
|
+
errorsPath: import_node_path65.default.join(baseDir, "errors.ndjson"),
|
|
14419
|
+
staleEventsPath: import_node_path65.default.join(baseDir, "stale-events.ndjson"),
|
|
14420
|
+
embeddingsCachePath: import_node_path65.default.join(baseDir, "embeddings.json"),
|
|
14421
|
+
policyViolationsPath: import_node_path65.default.join(baseDir, "policy-violations.ndjson")
|
|
13768
14422
|
};
|
|
13769
14423
|
}
|
|
13770
14424
|
return {
|
|
13771
|
-
snapshotPath:
|
|
13772
|
-
errorsPath:
|
|
13773
|
-
staleEventsPath:
|
|
13774
|
-
embeddingsCachePath:
|
|
13775
|
-
policyViolationsPath:
|
|
14425
|
+
snapshotPath: import_node_path65.default.join(baseDir, `${project}.json`),
|
|
14426
|
+
errorsPath: import_node_path65.default.join(baseDir, `errors.${project}.ndjson`),
|
|
14427
|
+
staleEventsPath: import_node_path65.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
14428
|
+
embeddingsCachePath: import_node_path65.default.join(baseDir, `embeddings.${project}.json`),
|
|
14429
|
+
policyViolationsPath: import_node_path65.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
13776
14430
|
};
|
|
13777
14431
|
}
|
|
13778
14432
|
var Projects = class {
|
|
@@ -13810,26 +14464,26 @@ var Projects = class {
|
|
|
13810
14464
|
init_cjs_shims();
|
|
13811
14465
|
var import_node_fs32 = require("fs");
|
|
13812
14466
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
13813
|
-
var
|
|
13814
|
-
var
|
|
14467
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
14468
|
+
var import_types53 = require("@neat.is/types");
|
|
13815
14469
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
13816
14470
|
var LOCK_RETRY_MS = 50;
|
|
13817
14471
|
function neatHome() {
|
|
13818
14472
|
const override = process.env.NEAT_HOME;
|
|
13819
|
-
if (override && override.length > 0) return
|
|
13820
|
-
return
|
|
14473
|
+
if (override && override.length > 0) return import_node_path66.default.resolve(override);
|
|
14474
|
+
return import_node_path66.default.join(import_node_os3.default.homedir(), ".neat");
|
|
13821
14475
|
}
|
|
13822
14476
|
function registryPath() {
|
|
13823
|
-
return
|
|
14477
|
+
return import_node_path66.default.join(neatHome(), "projects.json");
|
|
13824
14478
|
}
|
|
13825
14479
|
function registryLockPath() {
|
|
13826
|
-
return
|
|
14480
|
+
return import_node_path66.default.join(neatHome(), "projects.json.lock");
|
|
13827
14481
|
}
|
|
13828
14482
|
function daemonPidPath() {
|
|
13829
|
-
return
|
|
14483
|
+
return import_node_path66.default.join(neatHome(), "neatd.pid");
|
|
13830
14484
|
}
|
|
13831
14485
|
function daemonsDir() {
|
|
13832
|
-
return
|
|
14486
|
+
return import_node_path66.default.join(neatHome(), "daemons");
|
|
13833
14487
|
}
|
|
13834
14488
|
function isFiniteInt(v) {
|
|
13835
14489
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -13870,7 +14524,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
13870
14524
|
const out = [];
|
|
13871
14525
|
for (const name of names) {
|
|
13872
14526
|
if (!name.endsWith(".json")) continue;
|
|
13873
|
-
const file =
|
|
14527
|
+
const file = import_node_path66.default.join(dir, name);
|
|
13874
14528
|
let raw;
|
|
13875
14529
|
try {
|
|
13876
14530
|
raw = await import_node_fs32.promises.readFile(file, "utf8");
|
|
@@ -13991,7 +14645,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
13991
14645
|
}
|
|
13992
14646
|
}
|
|
13993
14647
|
async function normalizeProjectPath(input) {
|
|
13994
|
-
const resolved =
|
|
14648
|
+
const resolved = import_node_path66.default.resolve(input);
|
|
13995
14649
|
try {
|
|
13996
14650
|
return await import_node_fs32.promises.realpath(resolved);
|
|
13997
14651
|
} catch {
|
|
@@ -13999,7 +14653,7 @@ async function normalizeProjectPath(input) {
|
|
|
13999
14653
|
}
|
|
14000
14654
|
}
|
|
14001
14655
|
async function writeAtomically(target, contents) {
|
|
14002
|
-
await import_node_fs32.promises.mkdir(
|
|
14656
|
+
await import_node_fs32.promises.mkdir(import_node_path66.default.dirname(target), { recursive: true });
|
|
14003
14657
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
14004
14658
|
const fd = await import_node_fs32.promises.open(tmp, "w");
|
|
14005
14659
|
try {
|
|
@@ -14012,7 +14666,7 @@ async function writeAtomically(target, contents) {
|
|
|
14012
14666
|
}
|
|
14013
14667
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
14014
14668
|
const deadline = Date.now() + timeoutMs;
|
|
14015
|
-
await import_node_fs32.promises.mkdir(
|
|
14669
|
+
await import_node_fs32.promises.mkdir(import_node_path66.default.dirname(lockPath), { recursive: true });
|
|
14016
14670
|
let probedHolder = false;
|
|
14017
14671
|
while (true) {
|
|
14018
14672
|
try {
|
|
@@ -14065,10 +14719,10 @@ async function readRegistry() {
|
|
|
14065
14719
|
throw err;
|
|
14066
14720
|
}
|
|
14067
14721
|
const parsed = JSON.parse(raw);
|
|
14068
|
-
return
|
|
14722
|
+
return import_types53.RegistryFileSchema.parse(parsed);
|
|
14069
14723
|
}
|
|
14070
14724
|
async function writeRegistry(reg) {
|
|
14071
|
-
const validated =
|
|
14725
|
+
const validated = import_types53.RegistryFileSchema.parse(reg);
|
|
14072
14726
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
14073
14727
|
}
|
|
14074
14728
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -14254,7 +14908,7 @@ init_auth();
|
|
|
14254
14908
|
// src/connectors-config.ts
|
|
14255
14909
|
init_cjs_shims();
|
|
14256
14910
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
14257
|
-
var
|
|
14911
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
14258
14912
|
var import_node_fs33 = require("fs");
|
|
14259
14913
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
14260
14914
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -14269,11 +14923,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
14269
14923
|
};
|
|
14270
14924
|
function neatHome2() {
|
|
14271
14925
|
const override = process.env.NEAT_HOME;
|
|
14272
|
-
if (override && override.length > 0) return
|
|
14273
|
-
return
|
|
14926
|
+
if (override && override.length > 0) return import_node_path67.default.resolve(override);
|
|
14927
|
+
return import_node_path67.default.join(import_node_os4.default.homedir(), ".neat");
|
|
14274
14928
|
}
|
|
14275
14929
|
function connectorsConfigPath(home = neatHome2()) {
|
|
14276
|
-
return
|
|
14930
|
+
return import_node_path67.default.join(home, "connectors.json");
|
|
14277
14931
|
}
|
|
14278
14932
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
14279
14933
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -14404,7 +15058,7 @@ function connectorMatchesProject(entry2, project) {
|
|
|
14404
15058
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
14405
15059
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
14406
15060
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
14407
|
-
return
|
|
15061
|
+
return import_node_path67.default.join(home, "connectors.json.lock");
|
|
14408
15062
|
}
|
|
14409
15063
|
function isEnvRef(value) {
|
|
14410
15064
|
return value.length > 1 && value.startsWith("$");
|
|
@@ -14417,7 +15071,7 @@ function redactCredentialRef(ref) {
|
|
|
14417
15071
|
return out;
|
|
14418
15072
|
}
|
|
14419
15073
|
async function writeConfigAtomically0600(file, contents) {
|
|
14420
|
-
await import_node_fs33.promises.mkdir(
|
|
15074
|
+
await import_node_fs33.promises.mkdir(import_node_path67.default.dirname(file), { recursive: true });
|
|
14421
15075
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
14422
15076
|
const fd = await import_node_fs33.promises.open(tmp, "w", 384);
|
|
14423
15077
|
try {
|
|
@@ -14431,7 +15085,7 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
14431
15085
|
}
|
|
14432
15086
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
14433
15087
|
const deadline = Date.now() + timeoutMs;
|
|
14434
|
-
await import_node_fs33.promises.mkdir(
|
|
15088
|
+
await import_node_fs33.promises.mkdir(import_node_path67.default.dirname(lockPath), { recursive: true });
|
|
14435
15089
|
for (; ; ) {
|
|
14436
15090
|
try {
|
|
14437
15091
|
const fd = await import_node_fs33.promises.open(lockPath, "wx");
|
|
@@ -14581,15 +15235,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
14581
15235
|
|
|
14582
15236
|
// src/connectors/index.ts
|
|
14583
15237
|
init_cjs_shims();
|
|
14584
|
-
var
|
|
15238
|
+
var import_types54 = require("@neat.is/types");
|
|
14585
15239
|
var NO_ENV = "unknown";
|
|
14586
15240
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
14587
15241
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14588
15242
|
const sites = [];
|
|
14589
15243
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
14590
15244
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
14591
|
-
if (edge.provenance !==
|
|
14592
|
-
const parsed = (0,
|
|
15245
|
+
if (edge.provenance !== import_types54.Provenance.EXTRACTED) continue;
|
|
15246
|
+
const parsed = (0, import_types54.parseFileId)(edge.source);
|
|
14593
15247
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
14594
15248
|
const site = { relPath: edge.evidence.file };
|
|
14595
15249
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -14600,7 +15254,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
14600
15254
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
14601
15255
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14602
15256
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
14603
|
-
if (attrs.type !==
|
|
15257
|
+
if (attrs.type !== import_types54.NodeType.RouteNode || !attrs.path) return void 0;
|
|
14604
15258
|
const site = { relPath: attrs.path };
|
|
14605
15259
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
14606
15260
|
return site;
|
|
@@ -15081,10 +15735,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
15081
15735
|
// src/connectors/supabase/map.ts
|
|
15082
15736
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
15083
15737
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
15084
|
-
function targetFromRestPath(
|
|
15085
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
15738
|
+
function targetFromRestPath(path82) {
|
|
15739
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path82);
|
|
15086
15740
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
15087
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
15741
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path82);
|
|
15088
15742
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
15089
15743
|
return null;
|
|
15090
15744
|
}
|
|
@@ -15195,23 +15849,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
15195
15849
|
|
|
15196
15850
|
// src/connectors/supabase/resolve.ts
|
|
15197
15851
|
init_cjs_shims();
|
|
15198
|
-
var
|
|
15852
|
+
var import_types56 = require("@neat.is/types");
|
|
15199
15853
|
function createSupabaseResolveTarget(graph, config) {
|
|
15200
15854
|
return (signal, _ctx) => {
|
|
15201
15855
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
15202
15856
|
return null;
|
|
15203
15857
|
}
|
|
15204
|
-
const subResourceId = (0,
|
|
15858
|
+
const subResourceId = (0, import_types56.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
15205
15859
|
if (graph.hasNode(subResourceId)) {
|
|
15206
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
15860
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
|
|
15207
15861
|
}
|
|
15208
|
-
const bareResourceId = (0,
|
|
15862
|
+
const bareResourceId = (0, import_types56.infraId)(signal.targetKind, signal.targetName);
|
|
15209
15863
|
if (graph.hasNode(bareResourceId)) {
|
|
15210
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
15864
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
|
|
15211
15865
|
}
|
|
15212
|
-
const projectLevelId = (0,
|
|
15866
|
+
const projectLevelId = (0, import_types56.infraId)("supabase", config.nodeRef);
|
|
15213
15867
|
if (graph.hasNode(projectLevelId)) {
|
|
15214
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
15868
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
|
|
15215
15869
|
}
|
|
15216
15870
|
return null;
|
|
15217
15871
|
};
|
|
@@ -15304,7 +15958,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
15304
15958
|
|
|
15305
15959
|
// src/connectors/railway/index.ts
|
|
15306
15960
|
init_cjs_shims();
|
|
15307
|
-
var
|
|
15961
|
+
var import_types60 = require("@neat.is/types");
|
|
15308
15962
|
|
|
15309
15963
|
// src/connectors/railway/client.ts
|
|
15310
15964
|
init_cjs_shims();
|
|
@@ -15455,7 +16109,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
15455
16109
|
const out = [];
|
|
15456
16110
|
graph.forEachNode((_id, attrs) => {
|
|
15457
16111
|
const node = attrs;
|
|
15458
|
-
if (node.type !==
|
|
16112
|
+
if (node.type !== import_types60.NodeType.RouteNode) return;
|
|
15459
16113
|
const route = attrs;
|
|
15460
16114
|
if (route.service !== serviceName) return;
|
|
15461
16115
|
out.push({
|
|
@@ -15559,12 +16213,12 @@ function createRailwayResolveTarget(config) {
|
|
|
15559
16213
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
15560
16214
|
if (!serviceName) return null;
|
|
15561
16215
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
15562
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
16216
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types60.EdgeType.CALLS };
|
|
15563
16217
|
}
|
|
15564
16218
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
15565
16219
|
const peerName = config.serviceNameById[signal.targetName];
|
|
15566
16220
|
if (!peerName) return null;
|
|
15567
|
-
return { targetNodeId: (0,
|
|
16221
|
+
return { targetNodeId: (0, import_types60.serviceId)(peerName), serviceName, edgeType: import_types60.EdgeType.CONNECTS_TO };
|
|
15568
16222
|
}
|
|
15569
16223
|
return null;
|
|
15570
16224
|
};
|
|
@@ -15688,9 +16342,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
15688
16342
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
15689
16343
|
if (secondSep === -1) return null;
|
|
15690
16344
|
const method = rest.slice(0, secondSep);
|
|
15691
|
-
const
|
|
15692
|
-
if (!resourceName || !method || !
|
|
15693
|
-
return { resourceName, method, path:
|
|
16345
|
+
const path82 = rest.slice(secondSep + 1);
|
|
16346
|
+
if (!resourceName || !method || !path82) return null;
|
|
16347
|
+
return { resourceName, method, path: path82 };
|
|
15694
16348
|
}
|
|
15695
16349
|
function resourceNameFor(type, labels) {
|
|
15696
16350
|
if (!labels) return null;
|
|
@@ -15728,14 +16382,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
15728
16382
|
if (!req) return null;
|
|
15729
16383
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
15730
16384
|
const method = req.requestMethod.toUpperCase();
|
|
15731
|
-
const
|
|
15732
|
-
if (
|
|
16385
|
+
const path82 = pathFromRequestUrl(req.requestUrl);
|
|
16386
|
+
if (path82 === null) return null;
|
|
15733
16387
|
const timestamp = entry2.timestamp;
|
|
15734
16388
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15735
16389
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
15736
16390
|
return {
|
|
15737
16391
|
targetKind: resourceType,
|
|
15738
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
16392
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path82 }),
|
|
15739
16393
|
callCount: 1,
|
|
15740
16394
|
errorCount: isError ? 1 : 0,
|
|
15741
16395
|
lastObservedIso: timestamp
|
|
@@ -15752,7 +16406,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
15752
16406
|
|
|
15753
16407
|
// src/connectors/firebase/resolve.ts
|
|
15754
16408
|
init_cjs_shims();
|
|
15755
|
-
var
|
|
16409
|
+
var import_types61 = require("@neat.is/types");
|
|
15756
16410
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
15757
16411
|
switch (resourceType) {
|
|
15758
16412
|
case "cloud_function":
|
|
@@ -15767,7 +16421,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
15767
16421
|
const entries = [];
|
|
15768
16422
|
graph.forEachNode((_id, attrs) => {
|
|
15769
16423
|
const node = attrs;
|
|
15770
|
-
if (node.type !==
|
|
16424
|
+
if (node.type !== import_types61.NodeType.RouteNode) return;
|
|
15771
16425
|
const route = attrs;
|
|
15772
16426
|
if (route.service !== serviceName) return;
|
|
15773
16427
|
entries.push({
|
|
@@ -15799,7 +16453,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
15799
16453
|
return {
|
|
15800
16454
|
targetNodeId: match.routeNodeId,
|
|
15801
16455
|
serviceName,
|
|
15802
|
-
edgeType:
|
|
16456
|
+
edgeType: import_types61.EdgeType.CALLS
|
|
15803
16457
|
};
|
|
15804
16458
|
};
|
|
15805
16459
|
}
|
|
@@ -15826,7 +16480,7 @@ init_cjs_shims();
|
|
|
15826
16480
|
|
|
15827
16481
|
// src/connectors/cloudflare/connector.ts
|
|
15828
16482
|
init_cjs_shims();
|
|
15829
|
-
var
|
|
16483
|
+
var import_types63 = require("@neat.is/types");
|
|
15830
16484
|
|
|
15831
16485
|
// src/connectors/cloudflare/client.ts
|
|
15832
16486
|
init_cjs_shims();
|
|
@@ -15942,7 +16596,7 @@ function mapEventToSignal(event) {
|
|
|
15942
16596
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
15943
16597
|
const statusCode = metadata?.statusCode;
|
|
15944
16598
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
15945
|
-
const
|
|
16599
|
+
const path82 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
15946
16600
|
return {
|
|
15947
16601
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
15948
16602
|
targetName: scriptName,
|
|
@@ -15950,7 +16604,7 @@ function mapEventToSignal(event) {
|
|
|
15950
16604
|
errorCount: isError ? 1 : 0,
|
|
15951
16605
|
lastObservedIso: observedAt.toISOString(),
|
|
15952
16606
|
method,
|
|
15953
|
-
...
|
|
16607
|
+
...path82 ? { path: path82 } : {},
|
|
15954
16608
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
15955
16609
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
15956
16610
|
};
|
|
@@ -15990,19 +16644,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
15990
16644
|
graph.forEachNode((id, attrs) => {
|
|
15991
16645
|
if (found) return;
|
|
15992
16646
|
const a = attrs;
|
|
15993
|
-
if (a.type ===
|
|
16647
|
+
if (a.type === import_types63.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
15994
16648
|
found = id;
|
|
15995
16649
|
}
|
|
15996
16650
|
});
|
|
15997
16651
|
return found;
|
|
15998
16652
|
}
|
|
15999
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
16000
|
-
const normalizedPath = normalizePathTemplate(
|
|
16653
|
+
function findMatchingRouteNode(graph, serviceName, method, path82) {
|
|
16654
|
+
const normalizedPath = normalizePathTemplate(path82);
|
|
16001
16655
|
let found = null;
|
|
16002
16656
|
graph.forEachNode((id, attrs) => {
|
|
16003
16657
|
if (found) return;
|
|
16004
16658
|
const a = attrs;
|
|
16005
|
-
if (a.type !==
|
|
16659
|
+
if (a.type !== import_types63.NodeType.RouteNode || a.service !== serviceName) return;
|
|
16006
16660
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
16007
16661
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
16008
16662
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -16014,18 +16668,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
16014
16668
|
return (signal) => {
|
|
16015
16669
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
16016
16670
|
const scriptName = signal.targetName;
|
|
16017
|
-
const { method, path:
|
|
16671
|
+
const { method, path: path82 } = signal;
|
|
16018
16672
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
16019
|
-
if (!method || !
|
|
16020
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
16673
|
+
if (!method || !path82) return wholeFileId;
|
|
16674
|
+
return findMatchingRouteNode(graph, serviceName, method, path82) ?? wholeFileId;
|
|
16021
16675
|
};
|
|
16022
16676
|
const mapping = config.workers?.[scriptName];
|
|
16023
16677
|
if (mapping) {
|
|
16024
|
-
const wholeFileId = (0,
|
|
16678
|
+
const wholeFileId = (0, import_types63.fileId)(mapping.service, mapping.entryFile);
|
|
16025
16679
|
return {
|
|
16026
16680
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
16027
16681
|
serviceName: mapping.service,
|
|
16028
|
-
edgeType:
|
|
16682
|
+
edgeType: import_types63.EdgeType.CALLS
|
|
16029
16683
|
};
|
|
16030
16684
|
}
|
|
16031
16685
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -16034,13 +16688,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
16034
16688
|
return {
|
|
16035
16689
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
16036
16690
|
serviceName: fileNode.service,
|
|
16037
|
-
edgeType:
|
|
16691
|
+
edgeType: import_types63.EdgeType.CALLS
|
|
16038
16692
|
};
|
|
16039
16693
|
}
|
|
16040
16694
|
return {
|
|
16041
|
-
targetNodeId: (0,
|
|
16695
|
+
targetNodeId: (0, import_types63.infraId)("cloudflare-worker", scriptName),
|
|
16042
16696
|
serviceName: scriptName,
|
|
16043
|
-
edgeType:
|
|
16697
|
+
edgeType: import_types63.EdgeType.CALLS,
|
|
16044
16698
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
16045
16699
|
};
|
|
16046
16700
|
};
|
|
@@ -16236,14 +16890,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
16236
16890
|
|
|
16237
16891
|
// src/connectors/neon/resolve.ts
|
|
16238
16892
|
init_cjs_shims();
|
|
16239
|
-
var
|
|
16893
|
+
var import_types67 = require("@neat.is/types");
|
|
16240
16894
|
function createNeonResolveTarget(config) {
|
|
16241
16895
|
return (signal) => {
|
|
16242
16896
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16243
16897
|
return {
|
|
16244
|
-
targetNodeId: (0,
|
|
16898
|
+
targetNodeId: (0, import_types67.infraId)("sql-table", signal.targetName),
|
|
16245
16899
|
serviceName: config.serviceName,
|
|
16246
|
-
edgeType:
|
|
16900
|
+
edgeType: import_types67.EdgeType.CALLS,
|
|
16247
16901
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
16248
16902
|
};
|
|
16249
16903
|
};
|
|
@@ -16369,9 +17023,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
16369
17023
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
16370
17024
|
if (secondSep === -1) return null;
|
|
16371
17025
|
const method = rest.slice(0, secondSep);
|
|
16372
|
-
const
|
|
16373
|
-
if (!serviceName || !method || !
|
|
16374
|
-
return { serviceName, method, path:
|
|
17026
|
+
const path82 = rest.slice(secondSep + 1);
|
|
17027
|
+
if (!serviceName || !method || !path82) return null;
|
|
17028
|
+
return { serviceName, method, path: path82 };
|
|
16375
17029
|
}
|
|
16376
17030
|
|
|
16377
17031
|
// src/connectors/cloud-run/map.ts
|
|
@@ -16400,14 +17054,14 @@ function mapLogEntryToSignal2(entry2) {
|
|
|
16400
17054
|
if (!req) return null;
|
|
16401
17055
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
16402
17056
|
const method = req.requestMethod.toUpperCase();
|
|
16403
|
-
const
|
|
16404
|
-
if (
|
|
17057
|
+
const path82 = pathFromRequestUrl2(req.requestUrl);
|
|
17058
|
+
if (path82 === null) return null;
|
|
16405
17059
|
const timestamp = entry2.timestamp;
|
|
16406
17060
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
16407
17061
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
16408
17062
|
return {
|
|
16409
17063
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
16410
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
17064
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path82 }),
|
|
16411
17065
|
callCount: 1,
|
|
16412
17066
|
errorCount: isError ? 1 : 0,
|
|
16413
17067
|
lastObservedIso: timestamp
|
|
@@ -16424,14 +17078,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
16424
17078
|
|
|
16425
17079
|
// src/connectors/cloud-run/resolve.ts
|
|
16426
17080
|
init_cjs_shims();
|
|
16427
|
-
var
|
|
17081
|
+
var import_types71 = require("@neat.is/types");
|
|
16428
17082
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
16429
17083
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
16430
17084
|
let found = null;
|
|
16431
17085
|
graph.forEachNode((_id, attrs) => {
|
|
16432
17086
|
if (found) return;
|
|
16433
17087
|
const node = attrs;
|
|
16434
|
-
if (node.type !==
|
|
17088
|
+
if (node.type !== import_types71.NodeType.RouteNode) return;
|
|
16435
17089
|
const route = attrs;
|
|
16436
17090
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
16437
17091
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -16446,23 +17100,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
16446
17100
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
16447
17101
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
16448
17102
|
if (!identity) return null;
|
|
16449
|
-
const { serviceName: gcpServiceName, method, path:
|
|
17103
|
+
const { serviceName: gcpServiceName, method, path: path82 } = identity;
|
|
16450
17104
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
16451
17105
|
if (mappedService) {
|
|
16452
17106
|
const routeNodeId = findMatchingRouteNode2(
|
|
16453
17107
|
graph,
|
|
16454
17108
|
mappedService,
|
|
16455
17109
|
method,
|
|
16456
|
-
normalizePathTemplate(
|
|
17110
|
+
normalizePathTemplate(path82)
|
|
16457
17111
|
);
|
|
16458
17112
|
if (routeNodeId) {
|
|
16459
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
17113
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types71.EdgeType.CALLS };
|
|
16460
17114
|
}
|
|
16461
17115
|
}
|
|
16462
17116
|
return {
|
|
16463
|
-
targetNodeId: (0,
|
|
17117
|
+
targetNodeId: (0, import_types71.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
16464
17118
|
serviceName: mappedService ?? gcpServiceName,
|
|
16465
|
-
edgeType:
|
|
17119
|
+
edgeType: import_types71.EdgeType.CALLS,
|
|
16466
17120
|
ensureInfraNode: {
|
|
16467
17121
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
16468
17122
|
name: gcpServiceName,
|
|
@@ -16503,7 +17157,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
16503
17157
|
|
|
16504
17158
|
// src/connectors/render/index.ts
|
|
16505
17159
|
init_cjs_shims();
|
|
16506
|
-
var
|
|
17160
|
+
var import_types74 = require("@neat.is/types");
|
|
16507
17161
|
|
|
16508
17162
|
// src/connectors/render/types.ts
|
|
16509
17163
|
init_cjs_shims();
|
|
@@ -16581,7 +17235,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
16581
17235
|
const out = [];
|
|
16582
17236
|
graph.forEachNode((_id, attrs) => {
|
|
16583
17237
|
const node = attrs;
|
|
16584
|
-
if (node.type !==
|
|
17238
|
+
if (node.type !== import_types74.NodeType.RouteNode) return;
|
|
16585
17239
|
const route = attrs;
|
|
16586
17240
|
if (route.service !== serviceName) return;
|
|
16587
17241
|
out.push({
|
|
@@ -16666,7 +17320,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
16666
17320
|
function createRenderResolveTarget(config) {
|
|
16667
17321
|
return (signal) => {
|
|
16668
17322
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
16669
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
17323
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types74.EdgeType.CALLS };
|
|
16670
17324
|
}
|
|
16671
17325
|
return null;
|
|
16672
17326
|
};
|
|
@@ -16804,21 +17458,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
16804
17458
|
|
|
16805
17459
|
// src/connectors/planetscale/resolve.ts
|
|
16806
17460
|
init_cjs_shims();
|
|
16807
|
-
var
|
|
17461
|
+
var import_types78 = require("@neat.is/types");
|
|
16808
17462
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
16809
17463
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
16810
17464
|
const databaseName = `${config.organization}/${config.database}`;
|
|
16811
17465
|
return (signal, _ctx) => {
|
|
16812
17466
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16813
|
-
const tableId = (0,
|
|
17467
|
+
const tableId = (0, import_types78.infraId)("sql-table", signal.targetName);
|
|
16814
17468
|
if (graph.hasNode(tableId)) {
|
|
16815
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
17469
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types78.EdgeType.CALLS };
|
|
16816
17470
|
}
|
|
16817
|
-
const providerId = (0,
|
|
17471
|
+
const providerId = (0, import_types78.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
16818
17472
|
return {
|
|
16819
17473
|
targetNodeId: providerId,
|
|
16820
17474
|
serviceName: config.serviceName,
|
|
16821
|
-
edgeType:
|
|
17475
|
+
edgeType: import_types78.EdgeType.CALLS,
|
|
16822
17476
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
16823
17477
|
};
|
|
16824
17478
|
};
|
|
@@ -17567,11 +18221,11 @@ function registerRoutes(scope, ctx) {
|
|
|
17567
18221
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17568
18222
|
const parsed = [];
|
|
17569
18223
|
for (const c of candidates) {
|
|
17570
|
-
const r =
|
|
18224
|
+
const r = import_types81.DivergenceTypeSchema.safeParse(c);
|
|
17571
18225
|
if (!r.success) {
|
|
17572
18226
|
return reply.code(400).send({
|
|
17573
18227
|
error: `unknown divergence type "${c}"`,
|
|
17574
|
-
allowed:
|
|
18228
|
+
allowed: import_types81.DivergenceTypeSchema.options
|
|
17575
18229
|
});
|
|
17576
18230
|
}
|
|
17577
18231
|
parsed.push(r.data);
|
|
@@ -17880,7 +18534,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17880
18534
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
17881
18535
|
let violations = await log.readAll();
|
|
17882
18536
|
if (req.query.severity) {
|
|
17883
|
-
const sev =
|
|
18537
|
+
const sev = import_types81.PolicySeveritySchema.safeParse(req.query.severity);
|
|
17884
18538
|
if (!sev.success) {
|
|
17885
18539
|
return reply.code(400).send({
|
|
17886
18540
|
error: "invalid severity",
|
|
@@ -17919,7 +18573,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17919
18573
|
scope.post("/policies/check", async (req, reply) => {
|
|
17920
18574
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
17921
18575
|
if (!proj) return;
|
|
17922
|
-
const parsed =
|
|
18576
|
+
const parsed = import_types81.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
17923
18577
|
if (!parsed.success) {
|
|
17924
18578
|
return reply.code(400).send({
|
|
17925
18579
|
error: "invalid /policies/check body",
|
|
@@ -18241,7 +18895,7 @@ init_otel();
|
|
|
18241
18895
|
// src/daemon.ts
|
|
18242
18896
|
init_cjs_shims();
|
|
18243
18897
|
var import_node_fs35 = require("fs");
|
|
18244
|
-
var
|
|
18898
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
18245
18899
|
var import_node_module = require("module");
|
|
18246
18900
|
init_otel();
|
|
18247
18901
|
init_auth();
|
|
@@ -18249,28 +18903,28 @@ init_auth();
|
|
|
18249
18903
|
// src/unrouted.ts
|
|
18250
18904
|
init_cjs_shims();
|
|
18251
18905
|
var import_node_fs34 = require("fs");
|
|
18252
|
-
var
|
|
18906
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
18253
18907
|
|
|
18254
18908
|
// src/daemon.ts
|
|
18255
|
-
var
|
|
18909
|
+
var import_types82 = require("@neat.is/types");
|
|
18256
18910
|
function daemonJsonPath(scanPath) {
|
|
18257
|
-
return
|
|
18911
|
+
return import_node_path69.default.join(scanPath, "neat-out", "daemon.json");
|
|
18258
18912
|
}
|
|
18259
18913
|
function daemonsDiscoveryDir(home) {
|
|
18260
18914
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
18261
|
-
return
|
|
18915
|
+
return import_node_path69.default.join(base, "daemons");
|
|
18262
18916
|
}
|
|
18263
18917
|
function daemonDiscoveryPath(project, home) {
|
|
18264
|
-
return
|
|
18918
|
+
return import_node_path69.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
18265
18919
|
}
|
|
18266
18920
|
function sanitizeDiscoveryName(project) {
|
|
18267
18921
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
18268
18922
|
}
|
|
18269
18923
|
function neatHomeFromEnv() {
|
|
18270
18924
|
const env = process.env.NEAT_HOME;
|
|
18271
|
-
if (env && env.length > 0) return
|
|
18925
|
+
if (env && env.length > 0) return import_node_path69.default.resolve(env);
|
|
18272
18926
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
18273
|
-
return
|
|
18927
|
+
return import_node_path69.default.join(home, ".neat");
|
|
18274
18928
|
}
|
|
18275
18929
|
async function readDaemonRecord(scanPath) {
|
|
18276
18930
|
try {
|
|
@@ -18341,7 +18995,7 @@ init_otel_grpc();
|
|
|
18341
18995
|
// src/search.ts
|
|
18342
18996
|
init_cjs_shims();
|
|
18343
18997
|
var import_node_fs36 = require("fs");
|
|
18344
|
-
var
|
|
18998
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
18345
18999
|
var import_node_crypto4 = require("crypto");
|
|
18346
19000
|
var DEFAULT_LIMIT = 10;
|
|
18347
19001
|
var NOMIC_DIM = 768;
|
|
@@ -18504,7 +19158,7 @@ async function readCache(cachePath) {
|
|
|
18504
19158
|
}
|
|
18505
19159
|
}
|
|
18506
19160
|
async function writeCache(cachePath, cache) {
|
|
18507
|
-
await import_node_fs36.promises.mkdir(
|
|
19161
|
+
await import_node_fs36.promises.mkdir(import_node_path70.default.dirname(cachePath), { recursive: true });
|
|
18508
19162
|
await import_node_fs36.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
18509
19163
|
}
|
|
18510
19164
|
var VectorIndex = class {
|
|
@@ -18664,8 +19318,8 @@ var ALL_PHASES = [
|
|
|
18664
19318
|
];
|
|
18665
19319
|
function classifyChange(relPath) {
|
|
18666
19320
|
const phases = /* @__PURE__ */ new Set();
|
|
18667
|
-
const base =
|
|
18668
|
-
const segments = relPath.split(
|
|
19321
|
+
const base = import_node_path71.default.basename(relPath).toLowerCase();
|
|
19322
|
+
const segments = relPath.split(import_node_path71.default.sep).map((s) => s.toLowerCase());
|
|
18669
19323
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
18670
19324
|
phases.add("services");
|
|
18671
19325
|
phases.add("aliases");
|
|
@@ -18805,9 +19459,9 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
18805
19459
|
for (const e of entries) {
|
|
18806
19460
|
if (count >= limit) return;
|
|
18807
19461
|
if (!e.isDirectory()) continue;
|
|
18808
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
19462
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path71.default.join(dir, e.name) + import_node_path71.default.sep))) continue;
|
|
18809
19463
|
count++;
|
|
18810
|
-
if (depth < 2) visit(
|
|
19464
|
+
if (depth < 2) visit(import_node_path71.default.join(dir, e.name), depth + 1);
|
|
18811
19465
|
}
|
|
18812
19466
|
};
|
|
18813
19467
|
visit(scanPath, 0);
|
|
@@ -18825,8 +19479,8 @@ async function startWatch(graph, opts) {
|
|
|
18825
19479
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
18826
19480
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
18827
19481
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
18828
|
-
const policyFilePath =
|
|
18829
|
-
const policyViolationsPath =
|
|
19482
|
+
const policyFilePath = import_node_path71.default.join(opts.scanPath, "policy.json");
|
|
19483
|
+
const policyViolationsPath = import_node_path71.default.join(import_node_path71.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
18830
19484
|
let policies = [];
|
|
18831
19485
|
try {
|
|
18832
19486
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -18886,7 +19540,7 @@ async function startWatch(graph, opts) {
|
|
|
18886
19540
|
assertBindAuthority(host, auth.authToken);
|
|
18887
19541
|
const port = opts.port ?? 8080;
|
|
18888
19542
|
const otelPort = opts.otelPort ?? 4318;
|
|
18889
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
19543
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path71.default.join(import_node_path71.default.dirname(opts.outPath), "embeddings.json");
|
|
18890
19544
|
let searchIndex;
|
|
18891
19545
|
try {
|
|
18892
19546
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -18904,7 +19558,7 @@ async function startWatch(graph, opts) {
|
|
|
18904
19558
|
// Paths are derived from the explicit options the watch caller passes
|
|
18905
19559
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
18906
19560
|
// fields so the registry shape is complete.
|
|
18907
|
-
...pathsForProject(projectName,
|
|
19561
|
+
...pathsForProject(projectName, import_node_path71.default.dirname(opts.outPath)),
|
|
18908
19562
|
snapshotPath: opts.outPath,
|
|
18909
19563
|
errorsPath: opts.errorsPath,
|
|
18910
19564
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -19022,9 +19676,9 @@ async function startWatch(graph, opts) {
|
|
|
19022
19676
|
};
|
|
19023
19677
|
const onPath = (absPath) => {
|
|
19024
19678
|
if (shouldIgnore(absPath)) return;
|
|
19025
|
-
const rel =
|
|
19679
|
+
const rel = import_node_path71.default.relative(opts.scanPath, absPath);
|
|
19026
19680
|
if (!rel || rel.startsWith("..")) return;
|
|
19027
|
-
pendingPaths.add(rel.split(
|
|
19681
|
+
pendingPaths.add(rel.split(import_node_path71.default.sep).join("/"));
|
|
19028
19682
|
const phases = classifyChange(rel);
|
|
19029
19683
|
if (phases.size === 0) {
|
|
19030
19684
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -19082,7 +19736,7 @@ async function startWatch(graph, opts) {
|
|
|
19082
19736
|
// src/deploy/detect.ts
|
|
19083
19737
|
init_cjs_shims();
|
|
19084
19738
|
var import_node_fs38 = require("fs");
|
|
19085
|
-
var
|
|
19739
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
19086
19740
|
var import_node_child_process2 = require("child_process");
|
|
19087
19741
|
var import_node_crypto5 = require("crypto");
|
|
19088
19742
|
function generateToken() {
|
|
@@ -19182,7 +19836,7 @@ async function runDeploy(opts = {}) {
|
|
|
19182
19836
|
const token = generateToken();
|
|
19183
19837
|
switch (substrate) {
|
|
19184
19838
|
case "docker-compose": {
|
|
19185
|
-
const artifactPath =
|
|
19839
|
+
const artifactPath = import_node_path72.default.join(cwd, "docker-compose.neat.yml");
|
|
19186
19840
|
const contents = emitDockerCompose(cwd);
|
|
19187
19841
|
await import_node_fs38.promises.writeFile(artifactPath, contents, "utf8");
|
|
19188
19842
|
return {
|
|
@@ -19190,11 +19844,11 @@ async function runDeploy(opts = {}) {
|
|
|
19190
19844
|
artifactPath,
|
|
19191
19845
|
token,
|
|
19192
19846
|
contents,
|
|
19193
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
19847
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path72.default.basename(artifactPath)} up -d`
|
|
19194
19848
|
};
|
|
19195
19849
|
}
|
|
19196
19850
|
case "systemd": {
|
|
19197
|
-
const artifactPath =
|
|
19851
|
+
const artifactPath = import_node_path72.default.join(cwd, "neat.service");
|
|
19198
19852
|
const contents = emitSystemdUnit(cwd);
|
|
19199
19853
|
await import_node_fs38.promises.writeFile(artifactPath, contents, "utf8");
|
|
19200
19854
|
return {
|
|
@@ -19230,7 +19884,7 @@ init_cjs_shims();
|
|
|
19230
19884
|
// src/installers/javascript.ts
|
|
19231
19885
|
init_cjs_shims();
|
|
19232
19886
|
var import_node_fs39 = require("fs");
|
|
19233
|
-
var
|
|
19887
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
19234
19888
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
19235
19889
|
|
|
19236
19890
|
// src/installers/templates.ts
|
|
@@ -19897,11 +20551,11 @@ var OTEL_ENV = {
|
|
|
19897
20551
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
19898
20552
|
};
|
|
19899
20553
|
function serviceNodeName(pkg, serviceDir) {
|
|
19900
|
-
return pkg.name ??
|
|
20554
|
+
return pkg.name ?? import_node_path73.default.basename(serviceDir);
|
|
19901
20555
|
}
|
|
19902
20556
|
function projectToken(pkg, serviceDir, project) {
|
|
19903
20557
|
if (project && project.length > 0) return project;
|
|
19904
|
-
return pkg.name ??
|
|
20558
|
+
return pkg.name ?? import_node_path73.default.basename(serviceDir);
|
|
19905
20559
|
}
|
|
19906
20560
|
async function readJsonFile(p) {
|
|
19907
20561
|
try {
|
|
@@ -19914,16 +20568,16 @@ async function readJsonFile(p) {
|
|
|
19914
20568
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
19915
20569
|
const deps = allDeps(pkg);
|
|
19916
20570
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
19917
|
-
const appJson = await readJsonFile(
|
|
20571
|
+
const appJson = await readJsonFile(import_node_path73.default.join(pkgRoot, "app.json"));
|
|
19918
20572
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
19919
20573
|
return "react-native";
|
|
19920
20574
|
}
|
|
19921
|
-
if (await exists3(
|
|
20575
|
+
if (await exists3(import_node_path73.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path73.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path73.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
19922
20576
|
return "browser-bundle";
|
|
19923
20577
|
}
|
|
19924
|
-
if (await exists3(
|
|
19925
|
-
if (await exists3(
|
|
19926
|
-
if (await exists3(
|
|
20578
|
+
if (await exists3(import_node_path73.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
20579
|
+
if (await exists3(import_node_path73.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
20580
|
+
if (await exists3(import_node_path73.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path73.default.join(pkgRoot, "deno.lock"))) {
|
|
19927
20581
|
return "deno";
|
|
19928
20582
|
}
|
|
19929
20583
|
const engines = pkg.engines ?? {};
|
|
@@ -19932,7 +20586,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
19932
20586
|
}
|
|
19933
20587
|
async function readPackageJson2(serviceDir) {
|
|
19934
20588
|
try {
|
|
19935
|
-
const raw = await import_node_fs39.promises.readFile(
|
|
20589
|
+
const raw = await import_node_fs39.promises.readFile(import_node_path73.default.join(serviceDir, "package.json"), "utf8");
|
|
19936
20590
|
return JSON.parse(raw);
|
|
19937
20591
|
} catch {
|
|
19938
20592
|
return null;
|
|
@@ -19976,7 +20630,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
19976
20630
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
19977
20631
|
async function findNextConfig(serviceDir) {
|
|
19978
20632
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
19979
|
-
const candidate =
|
|
20633
|
+
const candidate = import_node_path73.default.join(serviceDir, name);
|
|
19980
20634
|
if (await exists3(candidate)) return candidate;
|
|
19981
20635
|
}
|
|
19982
20636
|
return null;
|
|
@@ -20045,7 +20699,7 @@ function hasRemixDependency(pkg) {
|
|
|
20045
20699
|
}
|
|
20046
20700
|
async function findRemixEntry(serviceDir) {
|
|
20047
20701
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
20048
|
-
const candidate =
|
|
20702
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20049
20703
|
if (await exists3(candidate)) return candidate;
|
|
20050
20704
|
}
|
|
20051
20705
|
return null;
|
|
@@ -20057,14 +20711,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
20057
20711
|
}
|
|
20058
20712
|
async function findSvelteKitHooks(serviceDir) {
|
|
20059
20713
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
20060
|
-
const candidate =
|
|
20714
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20061
20715
|
if (await exists3(candidate)) return candidate;
|
|
20062
20716
|
}
|
|
20063
20717
|
return null;
|
|
20064
20718
|
}
|
|
20065
20719
|
async function findSvelteKitConfig(serviceDir) {
|
|
20066
20720
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
20067
|
-
const candidate =
|
|
20721
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20068
20722
|
if (await exists3(candidate)) return candidate;
|
|
20069
20723
|
}
|
|
20070
20724
|
return null;
|
|
@@ -20075,7 +20729,7 @@ function hasNuxtDependency(pkg) {
|
|
|
20075
20729
|
}
|
|
20076
20730
|
async function findNuxtConfig(serviceDir) {
|
|
20077
20731
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
20078
|
-
const candidate =
|
|
20732
|
+
const candidate = import_node_path73.default.join(serviceDir, name);
|
|
20079
20733
|
if (await exists3(candidate)) return candidate;
|
|
20080
20734
|
}
|
|
20081
20735
|
return null;
|
|
@@ -20086,7 +20740,7 @@ function hasAstroDependency(pkg) {
|
|
|
20086
20740
|
}
|
|
20087
20741
|
async function findAstroConfig(serviceDir) {
|
|
20088
20742
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
20089
|
-
const candidate =
|
|
20743
|
+
const candidate = import_node_path73.default.join(serviceDir, name);
|
|
20090
20744
|
if (await exists3(candidate)) return candidate;
|
|
20091
20745
|
}
|
|
20092
20746
|
return null;
|
|
@@ -20100,7 +20754,7 @@ function parseNextMajor(range) {
|
|
|
20100
20754
|
return Number.isFinite(n) ? n : null;
|
|
20101
20755
|
}
|
|
20102
20756
|
async function isTypeScriptProject(serviceDir) {
|
|
20103
|
-
return exists3(
|
|
20757
|
+
return exists3(import_node_path73.default.join(serviceDir, "tsconfig.json"));
|
|
20104
20758
|
}
|
|
20105
20759
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
20106
20760
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -20149,7 +20803,7 @@ function entryFromScript(script) {
|
|
|
20149
20803
|
}
|
|
20150
20804
|
async function resolveEntry(serviceDir, pkg) {
|
|
20151
20805
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
20152
|
-
const candidate =
|
|
20806
|
+
const candidate = import_node_path73.default.resolve(serviceDir, pkg.main);
|
|
20153
20807
|
if (await exists3(candidate)) return candidate;
|
|
20154
20808
|
}
|
|
20155
20809
|
if (pkg.bin) {
|
|
@@ -20163,40 +20817,40 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
20163
20817
|
if (typeof first === "string") binEntry = first;
|
|
20164
20818
|
}
|
|
20165
20819
|
if (binEntry) {
|
|
20166
|
-
const candidate =
|
|
20820
|
+
const candidate = import_node_path73.default.resolve(serviceDir, binEntry);
|
|
20167
20821
|
if (await exists3(candidate)) return candidate;
|
|
20168
20822
|
}
|
|
20169
20823
|
}
|
|
20170
20824
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
20171
20825
|
if (startEntry) {
|
|
20172
|
-
const candidate =
|
|
20826
|
+
const candidate = import_node_path73.default.resolve(serviceDir, startEntry);
|
|
20173
20827
|
if (await exists3(candidate)) return candidate;
|
|
20174
20828
|
}
|
|
20175
20829
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
20176
20830
|
if (devEntry) {
|
|
20177
|
-
const candidate =
|
|
20831
|
+
const candidate = import_node_path73.default.resolve(serviceDir, devEntry);
|
|
20178
20832
|
if (await exists3(candidate)) return candidate;
|
|
20179
20833
|
}
|
|
20180
20834
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
20181
|
-
const candidate =
|
|
20835
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20182
20836
|
if (await exists3(candidate)) return candidate;
|
|
20183
20837
|
}
|
|
20184
20838
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
20185
|
-
const candidate =
|
|
20839
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20186
20840
|
if (await exists3(candidate)) return candidate;
|
|
20187
20841
|
}
|
|
20188
20842
|
for (const rel of ROOT_NAMED_CANDIDATES) {
|
|
20189
|
-
const candidate =
|
|
20843
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20190
20844
|
if (await exists3(candidate)) return candidate;
|
|
20191
20845
|
}
|
|
20192
20846
|
for (const name of INDEX_CANDIDATES) {
|
|
20193
|
-
const candidate =
|
|
20847
|
+
const candidate = import_node_path73.default.join(serviceDir, name);
|
|
20194
20848
|
if (await exists3(candidate)) return candidate;
|
|
20195
20849
|
}
|
|
20196
20850
|
return null;
|
|
20197
20851
|
}
|
|
20198
20852
|
function dispatchEntry(entryFile, pkg) {
|
|
20199
|
-
const ext =
|
|
20853
|
+
const ext = import_node_path73.default.extname(entryFile).toLowerCase();
|
|
20200
20854
|
if (ext === ".ts" || ext === ".tsx") return pkg.type === "module" ? "ts" : "ts-cjs";
|
|
20201
20855
|
if (ext === ".mjs") return "esm";
|
|
20202
20856
|
if (ext === ".cjs") return "cjs";
|
|
@@ -20214,9 +20868,9 @@ function otelInitContents(flavor) {
|
|
|
20214
20868
|
return OTEL_INIT_CJS;
|
|
20215
20869
|
}
|
|
20216
20870
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
20217
|
-
let rel =
|
|
20871
|
+
let rel = import_node_path73.default.relative(import_node_path73.default.dirname(entryFile), otelInitFile);
|
|
20218
20872
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
20219
|
-
rel = rel.split(
|
|
20873
|
+
rel = rel.split(import_node_path73.default.sep).join("/");
|
|
20220
20874
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
20221
20875
|
if (flavor === "esm") return `import '${rel}'`;
|
|
20222
20876
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -20229,27 +20883,27 @@ function lineIsOtelInjection(line) {
|
|
|
20229
20883
|
}
|
|
20230
20884
|
async function detectsSrcLayout(serviceDir) {
|
|
20231
20885
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
20232
|
-
exists3(
|
|
20233
|
-
exists3(
|
|
20234
|
-
exists3(
|
|
20235
|
-
exists3(
|
|
20886
|
+
exists3(import_node_path73.default.join(serviceDir, "src", "app")),
|
|
20887
|
+
exists3(import_node_path73.default.join(serviceDir, "src", "pages")),
|
|
20888
|
+
exists3(import_node_path73.default.join(serviceDir, "app")),
|
|
20889
|
+
exists3(import_node_path73.default.join(serviceDir, "pages"))
|
|
20236
20890
|
]);
|
|
20237
20891
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
20238
20892
|
}
|
|
20239
20893
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
20240
20894
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
20241
20895
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
20242
|
-
const baseDir = srcLayout ?
|
|
20243
|
-
const instrumentationFile =
|
|
20244
|
-
const instrumentationNodeFile =
|
|
20896
|
+
const baseDir = srcLayout ? import_node_path73.default.join(serviceDir, "src") : serviceDir;
|
|
20897
|
+
const instrumentationFile = import_node_path73.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
20898
|
+
const instrumentationNodeFile = import_node_path73.default.join(
|
|
20245
20899
|
baseDir,
|
|
20246
20900
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
20247
20901
|
);
|
|
20248
|
-
const instrumentationEdgeFile =
|
|
20902
|
+
const instrumentationEdgeFile = import_node_path73.default.join(
|
|
20249
20903
|
baseDir,
|
|
20250
20904
|
useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
|
|
20251
20905
|
);
|
|
20252
|
-
const envNeatFile =
|
|
20906
|
+
const envNeatFile = import_node_path73.default.join(baseDir, ".env.neat");
|
|
20253
20907
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
20254
20908
|
const dependencyEdits = [];
|
|
20255
20909
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -20374,7 +21028,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
20374
21028
|
return edits;
|
|
20375
21029
|
}
|
|
20376
21030
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
20377
|
-
const envNeatFile =
|
|
21031
|
+
const envNeatFile = import_node_path73.default.join(serviceDir, ".env.neat");
|
|
20378
21032
|
if (!await exists3(envNeatFile)) {
|
|
20379
21033
|
generatedFiles.push({
|
|
20380
21034
|
file: envNeatFile,
|
|
@@ -20409,7 +21063,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
20409
21063
|
}
|
|
20410
21064
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
20411
21065
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
20412
|
-
const otelServerFile =
|
|
21066
|
+
const otelServerFile = import_node_path73.default.join(
|
|
20413
21067
|
serviceDir,
|
|
20414
21068
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
20415
21069
|
);
|
|
@@ -20466,11 +21120,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
20466
21120
|
}
|
|
20467
21121
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
20468
21122
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
20469
|
-
const otelInitFile =
|
|
21123
|
+
const otelInitFile = import_node_path73.default.join(
|
|
20470
21124
|
serviceDir,
|
|
20471
21125
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
20472
21126
|
);
|
|
20473
|
-
const resolvedHooksFile = hooksFile ??
|
|
21127
|
+
const resolvedHooksFile = hooksFile ?? import_node_path73.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
20474
21128
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
20475
21129
|
const generatedFiles = [];
|
|
20476
21130
|
const entrypointEdits = [];
|
|
@@ -20532,11 +21186,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
20532
21186
|
}
|
|
20533
21187
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
20534
21188
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
20535
|
-
const otelPluginFile =
|
|
21189
|
+
const otelPluginFile = import_node_path73.default.join(
|
|
20536
21190
|
serviceDir,
|
|
20537
21191
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
20538
21192
|
);
|
|
20539
|
-
const otelInitFile =
|
|
21193
|
+
const otelInitFile = import_node_path73.default.join(
|
|
20540
21194
|
serviceDir,
|
|
20541
21195
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
20542
21196
|
);
|
|
@@ -20587,19 +21241,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
20587
21241
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
20588
21242
|
async function findAstroMiddleware(serviceDir) {
|
|
20589
21243
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
20590
|
-
const candidate =
|
|
21244
|
+
const candidate = import_node_path73.default.join(serviceDir, rel);
|
|
20591
21245
|
if (await exists3(candidate)) return candidate;
|
|
20592
21246
|
}
|
|
20593
21247
|
return null;
|
|
20594
21248
|
}
|
|
20595
21249
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
20596
21250
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
20597
|
-
const otelInitFile =
|
|
21251
|
+
const otelInitFile = import_node_path73.default.join(
|
|
20598
21252
|
serviceDir,
|
|
20599
21253
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
20600
21254
|
);
|
|
20601
21255
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
20602
|
-
const middlewareFile = existingMiddleware ??
|
|
21256
|
+
const middlewareFile = existingMiddleware ?? import_node_path73.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
20603
21257
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
20604
21258
|
const generatedFiles = [];
|
|
20605
21259
|
const entrypointEdits = [];
|
|
@@ -20695,7 +21349,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
20695
21349
|
}
|
|
20696
21350
|
async function plan(serviceDir, opts) {
|
|
20697
21351
|
const pkg = await readPackageJson2(serviceDir);
|
|
20698
|
-
const manifestPath =
|
|
21352
|
+
const manifestPath = import_node_path73.default.join(serviceDir, "package.json");
|
|
20699
21353
|
const project = opts?.project;
|
|
20700
21354
|
const empty = {
|
|
20701
21355
|
language: "javascript",
|
|
@@ -20730,8 +21384,8 @@ async function plan(serviceDir, opts) {
|
|
|
20730
21384
|
return { ...empty, libOnly: true };
|
|
20731
21385
|
}
|
|
20732
21386
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
20733
|
-
const otelInitFile =
|
|
20734
|
-
const envNeatFile =
|
|
21387
|
+
const otelInitFile = import_node_path73.default.join(import_node_path73.default.dirname(entryFile), otelInitFilename(flavor));
|
|
21388
|
+
const envNeatFile = import_node_path73.default.join(serviceDir, ".env.neat");
|
|
20735
21389
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
20736
21390
|
const dependencyEdits = [];
|
|
20737
21391
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -20800,13 +21454,13 @@ async function plan(serviceDir, opts) {
|
|
|
20800
21454
|
};
|
|
20801
21455
|
}
|
|
20802
21456
|
function isAllowedWritePath(serviceDir, target) {
|
|
20803
|
-
const rel =
|
|
21457
|
+
const rel = import_node_path73.default.relative(serviceDir, target);
|
|
20804
21458
|
if (rel.startsWith("..")) return false;
|
|
20805
|
-
const base =
|
|
21459
|
+
const base = import_node_path73.default.basename(target);
|
|
20806
21460
|
if (base === "package.json") return true;
|
|
20807
21461
|
if (base === ".env.neat") return true;
|
|
20808
21462
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
20809
|
-
const relPosix = rel.split(
|
|
21463
|
+
const relPosix = rel.split(import_node_path73.default.sep).join("/");
|
|
20810
21464
|
if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
20811
21465
|
if (relPosix === base) return true;
|
|
20812
21466
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -20823,7 +21477,7 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
20823
21477
|
return false;
|
|
20824
21478
|
}
|
|
20825
21479
|
async function writeAtomic(file, contents) {
|
|
20826
|
-
await import_node_fs39.promises.mkdir(
|
|
21480
|
+
await import_node_fs39.promises.mkdir(import_node_path73.default.dirname(file), { recursive: true });
|
|
20827
21481
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
20828
21482
|
await import_node_fs39.promises.writeFile(tmp, contents, "utf8");
|
|
20829
21483
|
await import_node_fs39.promises.rename(tmp, file);
|
|
@@ -21007,7 +21661,7 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
21007
21661
|
...removed.map((f) => `removed: ${f}`),
|
|
21008
21662
|
""
|
|
21009
21663
|
];
|
|
21010
|
-
const rollbackPath =
|
|
21664
|
+
const rollbackPath = import_node_path73.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
21011
21665
|
await import_node_fs39.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
21012
21666
|
}
|
|
21013
21667
|
function injectInstrumentationHook(raw) {
|
|
@@ -21038,7 +21692,7 @@ var javascriptInstaller = {
|
|
|
21038
21692
|
// src/installers/python.ts
|
|
21039
21693
|
init_cjs_shims();
|
|
21040
21694
|
var import_node_fs40 = require("fs");
|
|
21041
|
-
var
|
|
21695
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
21042
21696
|
var SDK_PACKAGES2 = [
|
|
21043
21697
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
21044
21698
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -21136,7 +21790,7 @@ async function writeFileAtomic(file, contents) {
|
|
|
21136
21790
|
await import_node_fs40.promises.rename(tmp, file);
|
|
21137
21791
|
}
|
|
21138
21792
|
async function resolvePyEntrypoint(serviceDir) {
|
|
21139
|
-
const procfile =
|
|
21793
|
+
const procfile = import_node_path74.default.join(serviceDir, "Procfile");
|
|
21140
21794
|
if (await exists4(procfile)) {
|
|
21141
21795
|
const raw = await import_node_fs40.promises.readFile(procfile, "utf8");
|
|
21142
21796
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -21146,20 +21800,20 @@ async function resolvePyEntrypoint(serviceDir) {
|
|
|
21146
21800
|
const asgi = cmd.match(/\b(?:uvicorn|gunicorn|hypercorn|daphne)\s+([\w.]+):/);
|
|
21147
21801
|
if (asgi) {
|
|
21148
21802
|
const modPath = asgi[1].replace(/\./g, "/");
|
|
21149
|
-
const asFile =
|
|
21803
|
+
const asFile = import_node_path74.default.join(serviceDir, `${modPath}.py`);
|
|
21150
21804
|
if (await exists4(asFile)) return asFile;
|
|
21151
|
-
const asPkg =
|
|
21805
|
+
const asPkg = import_node_path74.default.join(serviceDir, modPath, "__init__.py");
|
|
21152
21806
|
if (await exists4(asPkg)) return asPkg;
|
|
21153
21807
|
}
|
|
21154
21808
|
const runFile = cmd.match(/\b(?:python3?|fastapi\s+(?:run|dev))\s+([\w./-]+\.py)\b/);
|
|
21155
21809
|
if (runFile) {
|
|
21156
|
-
const p =
|
|
21810
|
+
const p = import_node_path74.default.join(serviceDir, runFile[1]);
|
|
21157
21811
|
if (await exists4(p)) return p;
|
|
21158
21812
|
}
|
|
21159
21813
|
}
|
|
21160
21814
|
}
|
|
21161
21815
|
for (const name of ["main.py", "app.py", "asgi.py", "wsgi.py", "manage.py", "server.py"]) {
|
|
21162
|
-
const p =
|
|
21816
|
+
const p = import_node_path74.default.join(serviceDir, name);
|
|
21163
21817
|
if (await exists4(p)) return p;
|
|
21164
21818
|
}
|
|
21165
21819
|
return null;
|
|
@@ -21185,7 +21839,7 @@ async function exists4(p) {
|
|
|
21185
21839
|
async function detect2(serviceDir) {
|
|
21186
21840
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
21187
21841
|
for (const m of markers) {
|
|
21188
|
-
if (await exists4(
|
|
21842
|
+
if (await exists4(import_node_path74.default.join(serviceDir, m))) return true;
|
|
21189
21843
|
}
|
|
21190
21844
|
return false;
|
|
21191
21845
|
}
|
|
@@ -21195,7 +21849,7 @@ function reqPackageName(line) {
|
|
|
21195
21849
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
21196
21850
|
}
|
|
21197
21851
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
21198
|
-
const file =
|
|
21852
|
+
const file = import_node_path74.default.join(serviceDir, "requirements.txt");
|
|
21199
21853
|
if (!await exists4(file)) return null;
|
|
21200
21854
|
const raw = await import_node_fs40.promises.readFile(file, "utf8");
|
|
21201
21855
|
const presentNames = new Set(
|
|
@@ -21205,7 +21859,7 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
21205
21859
|
return { manifest: file, missing: [...missing] };
|
|
21206
21860
|
}
|
|
21207
21861
|
async function planProcfileEdits(serviceDir) {
|
|
21208
|
-
const procfile =
|
|
21862
|
+
const procfile = import_node_path74.default.join(serviceDir, "Procfile");
|
|
21209
21863
|
if (!await exists4(procfile)) return [];
|
|
21210
21864
|
const raw = await import_node_fs40.promises.readFile(procfile, "utf8");
|
|
21211
21865
|
const edits = [];
|
|
@@ -21243,7 +21897,7 @@ async function plan2(serviceDir) {
|
|
|
21243
21897
|
}
|
|
21244
21898
|
const entrypointEdits = await planProcfileEdits(serviceDir);
|
|
21245
21899
|
const entryFile = await resolvePyEntrypoint(serviceDir);
|
|
21246
|
-
const generatedFiles = entryFile ? [{ file:
|
|
21900
|
+
const generatedFiles = entryFile ? [{ file: import_node_path74.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
|
|
21247
21901
|
if (dependencyEdits.length === 0 && entrypointEdits.length === 0 && !entryFile) {
|
|
21248
21902
|
return empty;
|
|
21249
21903
|
}
|
|
@@ -21311,7 +21965,7 @@ async function apply2(installPlan) {
|
|
|
21311
21965
|
if (raw === void 0) {
|
|
21312
21966
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
21313
21967
|
}
|
|
21314
|
-
const base =
|
|
21968
|
+
const base = import_node_path74.default.basename(file);
|
|
21315
21969
|
if (base === "requirements.txt") {
|
|
21316
21970
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
21317
21971
|
if (edits.length > 0) {
|
|
@@ -21366,7 +22020,7 @@ async function rollback2(installPlan, originals, createdFiles = []) {
|
|
|
21366
22020
|
...removed.map((f) => `removed: ${f}`),
|
|
21367
22021
|
""
|
|
21368
22022
|
];
|
|
21369
|
-
const rollbackPath =
|
|
22023
|
+
const rollbackPath = import_node_path74.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
21370
22024
|
await import_node_fs40.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
21371
22025
|
}
|
|
21372
22026
|
var pythonInstaller = {
|
|
@@ -21379,7 +22033,7 @@ var pythonInstaller = {
|
|
|
21379
22033
|
// src/installers/go.ts
|
|
21380
22034
|
init_cjs_shims();
|
|
21381
22035
|
var import_node_fs41 = require("fs");
|
|
21382
|
-
var
|
|
22036
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
21383
22037
|
var GO_DEPS = [
|
|
21384
22038
|
{ name: "go.opentelemetry.io/otel", version: "v1.38.0" },
|
|
21385
22039
|
{ name: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp", version: "v1.38.0" },
|
|
@@ -21389,13 +22043,13 @@ async function exists5(file) {
|
|
|
21389
22043
|
return import_node_fs41.promises.stat(file).then(() => true, () => false);
|
|
21390
22044
|
}
|
|
21391
22045
|
async function findMain(serviceDir) {
|
|
21392
|
-
const root =
|
|
22046
|
+
const root = import_node_path75.default.join(serviceDir, "main.go");
|
|
21393
22047
|
if (await exists5(root)) return root;
|
|
21394
|
-
const cmd =
|
|
22048
|
+
const cmd = import_node_path75.default.join(serviceDir, "cmd");
|
|
21395
22049
|
const entries = await import_node_fs41.promises.readdir(cmd, { withFileTypes: true }).catch(() => []);
|
|
21396
22050
|
for (const entry2 of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
21397
22051
|
if (!entry2.isDirectory()) continue;
|
|
21398
|
-
const candidate =
|
|
22052
|
+
const candidate = import_node_path75.default.join(cmd, entry2.name, "main.go");
|
|
21399
22053
|
if (await exists5(candidate)) return candidate;
|
|
21400
22054
|
}
|
|
21401
22055
|
return null;
|
|
@@ -21470,17 +22124,17 @@ func init() {
|
|
|
21470
22124
|
`;
|
|
21471
22125
|
}
|
|
21472
22126
|
async function detect3(serviceDir) {
|
|
21473
|
-
return exists5(
|
|
22127
|
+
return exists5(import_node_path75.default.join(serviceDir, "go.mod"));
|
|
21474
22128
|
}
|
|
21475
22129
|
async function plan3(serviceDir) {
|
|
21476
|
-
const manifest =
|
|
22130
|
+
const manifest = import_node_path75.default.join(serviceDir, "go.mod");
|
|
21477
22131
|
const raw = await import_node_fs41.promises.readFile(manifest, "utf8");
|
|
21478
22132
|
const main2 = await findMain(serviceDir);
|
|
21479
22133
|
const dependencyEdits = GO_DEPS.filter((dep) => !raw.includes(dep.name)).map((dep) => ({ file: manifest, kind: "add", ...dep }));
|
|
21480
22134
|
if (!main2) return { language: "go", serviceDir, dependencyEdits: [], entrypointEdits: [], envEdits: [], libOnly: true };
|
|
21481
22135
|
const source = await import_node_fs41.promises.readFile(main2, "utf8");
|
|
21482
22136
|
const packageName = source.match(/^\s*package\s+(\w+)\s*$/m)?.[1] ?? "main";
|
|
21483
|
-
const generated =
|
|
22137
|
+
const generated = import_node_path75.default.join(import_node_path75.default.dirname(main2), "neat_otel.go");
|
|
21484
22138
|
const generatedFiles = await exists5(generated) ? [] : [{ file: generated, contents: neatOtelGo(packageName) }];
|
|
21485
22139
|
return { language: "go", serviceDir, dependencyEdits, entrypointEdits: [], envEdits: [], generatedFiles, entryFile: main2 };
|
|
21486
22140
|
}
|
|
@@ -21622,7 +22276,7 @@ init_cjs_shims();
|
|
|
21622
22276
|
var import_node_fs42 = require("fs");
|
|
21623
22277
|
var import_node_http = __toESM(require("http"), 1);
|
|
21624
22278
|
var import_node_net = __toESM(require("net"), 1);
|
|
21625
|
-
var
|
|
22279
|
+
var import_node_path76 = __toESM(require("path"), 1);
|
|
21626
22280
|
var import_node_url4 = require("url");
|
|
21627
22281
|
var import_node_child_process3 = require("child_process");
|
|
21628
22282
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
@@ -21632,7 +22286,7 @@ async function extractAndPersist(opts) {
|
|
|
21632
22286
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
21633
22287
|
resetGraph(graphKey);
|
|
21634
22288
|
const graph = getGraph(graphKey);
|
|
21635
|
-
const projectPaths = pathsForProject(graphKey,
|
|
22289
|
+
const projectPaths = pathsForProject(graphKey, import_node_path76.default.join(opts.scanPath, "neat-out"));
|
|
21636
22290
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
21637
22291
|
errorsPath: projectPaths.errorsPath
|
|
21638
22292
|
});
|
|
@@ -21684,7 +22338,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21684
22338
|
libOnly++;
|
|
21685
22339
|
const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
|
|
21686
22340
|
if (appDeps.length > 0) {
|
|
21687
|
-
const svcName =
|
|
22341
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21688
22342
|
const list = appDeps.join(", ");
|
|
21689
22343
|
console.warn(
|
|
21690
22344
|
`neat: runtime layer won't engage for ${svcName}: no entry point found.
|
|
@@ -21697,7 +22351,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21697
22351
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
21698
22352
|
} else if (outcome.outcome === "react-native") {
|
|
21699
22353
|
reactNative++;
|
|
21700
|
-
const svcName =
|
|
22354
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21701
22355
|
console.log(
|
|
21702
22356
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
21703
22357
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -21708,7 +22362,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21708
22362
|
);
|
|
21709
22363
|
} else if (outcome.outcome === "bun") {
|
|
21710
22364
|
bun++;
|
|
21711
|
-
const svcName =
|
|
22365
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21712
22366
|
console.log(
|
|
21713
22367
|
`neat: ${svc.dir} detected as Bun
|
|
21714
22368
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -21719,7 +22373,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21719
22373
|
);
|
|
21720
22374
|
} else if (outcome.outcome === "deno") {
|
|
21721
22375
|
deno++;
|
|
21722
|
-
const svcName =
|
|
22376
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21723
22377
|
console.log(
|
|
21724
22378
|
`neat: ${svc.dir} detected as Deno
|
|
21725
22379
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -21730,7 +22384,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21730
22384
|
);
|
|
21731
22385
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
21732
22386
|
cloudflareWorkers++;
|
|
21733
|
-
const svcName =
|
|
22387
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21734
22388
|
console.log(
|
|
21735
22389
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
21736
22390
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -21741,7 +22395,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21741
22395
|
);
|
|
21742
22396
|
} else if (outcome.outcome === "electron") {
|
|
21743
22397
|
electron++;
|
|
21744
|
-
const svcName =
|
|
22398
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21745
22399
|
console.log(
|
|
21746
22400
|
`neat: ${svc.dir} detected as Electron
|
|
21747
22401
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -21754,7 +22408,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
21754
22408
|
if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
|
|
21755
22409
|
const gaps = uninstrumentedLibraries(svc.pkg);
|
|
21756
22410
|
if (gaps.length > 0) {
|
|
21757
|
-
const svcName =
|
|
22411
|
+
const svcName = import_node_path76.default.basename(svc.dir);
|
|
21758
22412
|
const list = gaps.join(", ");
|
|
21759
22413
|
const subject = gaps.length === 1 ? "this library" : "these libraries";
|
|
21760
22414
|
const aux = gaps.length === 1 ? "isn't" : "aren't";
|
|
@@ -21960,8 +22614,8 @@ async function persistedPortsFor(scanPath) {
|
|
|
21960
22614
|
return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
|
|
21961
22615
|
}
|
|
21962
22616
|
async function acquireSpawnLock(scanPath) {
|
|
21963
|
-
const lockPath =
|
|
21964
|
-
await import_node_fs42.promises.mkdir(
|
|
22617
|
+
const lockPath = import_node_path76.default.join(scanPath, "neat-out", "daemon.spawn.lock");
|
|
22618
|
+
await import_node_fs42.promises.mkdir(import_node_path76.default.dirname(lockPath), { recursive: true });
|
|
21965
22619
|
const STALE_LOCK_MS = 6e4;
|
|
21966
22620
|
try {
|
|
21967
22621
|
const fd = await import_node_fs42.promises.open(lockPath, "wx");
|
|
@@ -22006,13 +22660,13 @@ async function healthIsForProject(restPort, project) {
|
|
|
22006
22660
|
return false;
|
|
22007
22661
|
}
|
|
22008
22662
|
function daemonLogPath(projectPath3) {
|
|
22009
|
-
return
|
|
22663
|
+
return import_node_path76.default.join(projectPath3, "neat-out", "daemon.log");
|
|
22010
22664
|
}
|
|
22011
22665
|
function spawnDaemonDetached(spec) {
|
|
22012
|
-
const here =
|
|
22666
|
+
const here = import_node_path76.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
|
|
22013
22667
|
const candidates = [
|
|
22014
|
-
|
|
22015
|
-
|
|
22668
|
+
import_node_path76.default.join(here, "neatd.cjs"),
|
|
22669
|
+
import_node_path76.default.join(here, "neatd.js")
|
|
22016
22670
|
];
|
|
22017
22671
|
let entry2 = null;
|
|
22018
22672
|
const fsSync = require("fs");
|
|
@@ -22042,7 +22696,7 @@ function spawnDaemonDetached(spec) {
|
|
|
22042
22696
|
let logFd = null;
|
|
22043
22697
|
if (spec) {
|
|
22044
22698
|
const logPath = daemonLogPath(spec.projectPath);
|
|
22045
|
-
fsSync.mkdirSync(
|
|
22699
|
+
fsSync.mkdirSync(import_node_path76.default.dirname(logPath), { recursive: true });
|
|
22046
22700
|
logFd = fsSync.openSync(logPath, "a");
|
|
22047
22701
|
}
|
|
22048
22702
|
const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
|
|
@@ -22241,7 +22895,7 @@ async function runOrchestrator(opts) {
|
|
|
22241
22895
|
result.steps.browser = openBrowser(dashboardUrl);
|
|
22242
22896
|
}
|
|
22243
22897
|
const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
|
|
22244
|
-
const daemonLog = daemonRunning ?
|
|
22898
|
+
const daemonLog = daemonRunning ? import_node_path76.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
|
|
22245
22899
|
printSummary(result, graph, dashboardUrl, daemonLog);
|
|
22246
22900
|
return result;
|
|
22247
22901
|
}
|
|
@@ -22700,7 +23354,7 @@ async function runConnectorCommand(rawArgs, deps = {}) {
|
|
|
22700
23354
|
|
|
22701
23355
|
// src/hooks-cli.ts
|
|
22702
23356
|
init_cjs_shims();
|
|
22703
|
-
var
|
|
23357
|
+
var import_node_path77 = __toESM(require("path"), 1);
|
|
22704
23358
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
22705
23359
|
var import_node_fs43 = require("fs");
|
|
22706
23360
|
var import_node_url5 = require("url");
|
|
@@ -22709,14 +23363,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
|
|
|
22709
23363
|
var GUIDE_INSTALL_NAME = "neat-graph-first.md";
|
|
22710
23364
|
var HOOK_MATCHER = "Grep|Glob|Bash";
|
|
22711
23365
|
function moduleDir() {
|
|
22712
|
-
return typeof __dirname !== "undefined" ? __dirname :
|
|
23366
|
+
return typeof __dirname !== "undefined" ? __dirname : import_node_path77.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
|
|
22713
23367
|
}
|
|
22714
23368
|
async function readSkillAsset(rel) {
|
|
22715
23369
|
const here = moduleDir();
|
|
22716
23370
|
const candidates = [
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
23371
|
+
import_node_path77.default.resolve(here, "../../claude-skill", rel),
|
|
23372
|
+
import_node_path77.default.resolve(here, "../../../claude-skill", rel),
|
|
23373
|
+
import_node_path77.default.resolve(here, "../claude-skill", rel)
|
|
22720
23374
|
];
|
|
22721
23375
|
for (const candidate of candidates) {
|
|
22722
23376
|
try {
|
|
@@ -22730,17 +23384,17 @@ async function readSkillAsset(rel) {
|
|
|
22730
23384
|
}
|
|
22731
23385
|
function neatHome3() {
|
|
22732
23386
|
const override = process.env.NEAT_HOME;
|
|
22733
|
-
if (override && override.length > 0) return
|
|
22734
|
-
return
|
|
23387
|
+
if (override && override.length > 0) return import_node_path77.default.resolve(override);
|
|
23388
|
+
return import_node_path77.default.join(import_node_os5.default.homedir(), ".neat");
|
|
22735
23389
|
}
|
|
22736
23390
|
function claudeSettingsPath() {
|
|
22737
23391
|
const override = process.env.NEAT_CLAUDE_SETTINGS;
|
|
22738
|
-
if (override && override.length > 0) return
|
|
23392
|
+
if (override && override.length > 0) return import_node_path77.default.resolve(override);
|
|
22739
23393
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os5.default.homedir();
|
|
22740
|
-
return
|
|
23394
|
+
return import_node_path77.default.join(home, ".claude", "settings.json");
|
|
22741
23395
|
}
|
|
22742
23396
|
function installedHookPath() {
|
|
22743
|
-
return
|
|
23397
|
+
return import_node_path77.default.join(neatHome3(), "hooks", HOOK_FILENAME);
|
|
22744
23398
|
}
|
|
22745
23399
|
function isNeatSearchEntry(entry2) {
|
|
22746
23400
|
return (entry2.hooks ?? []).some(
|
|
@@ -22773,9 +23427,9 @@ async function runHooks(opts) {
|
|
|
22773
23427
|
const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
|
|
22774
23428
|
const guide = await readSkillAsset(GUIDE_FILENAME);
|
|
22775
23429
|
const scriptPath = installedHookPath();
|
|
22776
|
-
await import_node_fs43.promises.mkdir(
|
|
23430
|
+
await import_node_fs43.promises.mkdir(import_node_path77.default.dirname(scriptPath), { recursive: true });
|
|
22777
23431
|
await import_node_fs43.promises.writeFile(scriptPath, hookScript, { mode: 493 });
|
|
22778
|
-
const guidePath =
|
|
23432
|
+
const guidePath = import_node_path77.default.join(neatHome3(), GUIDE_INSTALL_NAME);
|
|
22779
23433
|
await import_node_fs43.promises.writeFile(guidePath, guide, "utf8");
|
|
22780
23434
|
const settingsFile = claudeSettingsPath();
|
|
22781
23435
|
let settings = {};
|
|
@@ -22802,7 +23456,7 @@ async function runHooks(opts) {
|
|
|
22802
23456
|
...settings,
|
|
22803
23457
|
hooks: { ...hooks, PreToolUse: preToolUse }
|
|
22804
23458
|
};
|
|
22805
|
-
await import_node_fs43.promises.mkdir(
|
|
23459
|
+
await import_node_fs43.promises.mkdir(import_node_path77.default.dirname(settingsFile), { recursive: true });
|
|
22806
23460
|
await import_node_fs43.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
22807
23461
|
console.log(`neat hooks: installed the search-nudge hook`);
|
|
22808
23462
|
console.log(` script: ${scriptPath}`);
|
|
@@ -22874,7 +23528,7 @@ async function runHooksCommand(args) {
|
|
|
22874
23528
|
|
|
22875
23529
|
// src/codex-cli.ts
|
|
22876
23530
|
init_cjs_shims();
|
|
22877
|
-
var
|
|
23531
|
+
var import_node_path78 = __toESM(require("path"), 1);
|
|
22878
23532
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
22879
23533
|
var import_node_fs44 = require("fs");
|
|
22880
23534
|
var import_node_util = require("util");
|
|
@@ -22894,14 +23548,14 @@ var NEAT_GRAPH_FIRST_START = "<!-- neat:graph-first -->";
|
|
|
22894
23548
|
var NEAT_GRAPH_FIRST_END = "<!-- /neat:graph-first -->";
|
|
22895
23549
|
function codexConfigPath() {
|
|
22896
23550
|
const override = process.env.NEAT_CODEX_CONFIG;
|
|
22897
|
-
if (override && override.length > 0) return
|
|
23551
|
+
if (override && override.length > 0) return import_node_path78.default.resolve(override);
|
|
22898
23552
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os6.default.homedir();
|
|
22899
|
-
return
|
|
23553
|
+
return import_node_path78.default.join(home, ".codex", "config.toml");
|
|
22900
23554
|
}
|
|
22901
23555
|
function agentsFilePath() {
|
|
22902
23556
|
const override = process.env.NEAT_CODEX_AGENTS;
|
|
22903
|
-
if (override && override.length > 0) return
|
|
22904
|
-
return
|
|
23557
|
+
if (override && override.length > 0) return import_node_path78.default.resolve(override);
|
|
23558
|
+
return import_node_path78.default.join(process.cwd(), "AGENTS.md");
|
|
22905
23559
|
}
|
|
22906
23560
|
function isTableHeader(line) {
|
|
22907
23561
|
return /^\s*\[\[?[^\]]+\]\]?\s*$/.test(line);
|
|
@@ -23084,14 +23738,14 @@ async function runCodex(opts) {
|
|
|
23084
23738
|
return { exitCode: 0 };
|
|
23085
23739
|
}
|
|
23086
23740
|
if (config.changed) {
|
|
23087
|
-
await import_node_fs44.promises.mkdir(
|
|
23741
|
+
await import_node_fs44.promises.mkdir(import_node_path78.default.dirname(configPath), { recursive: true });
|
|
23088
23742
|
await import_node_fs44.promises.writeFile(configPath, config.text, "utf8");
|
|
23089
23743
|
console.log(`neat codex: wrote [mcp_servers.neat] to ${configPath}`);
|
|
23090
23744
|
} else {
|
|
23091
23745
|
console.log(`neat codex: ${configPath} already has NEAT's MCP server`);
|
|
23092
23746
|
}
|
|
23093
23747
|
if (agents.changed) {
|
|
23094
|
-
await import_node_fs44.promises.mkdir(
|
|
23748
|
+
await import_node_fs44.promises.mkdir(import_node_path78.default.dirname(agentsPath), { recursive: true });
|
|
23095
23749
|
await import_node_fs44.promises.writeFile(agentsPath, agents.text, "utf8");
|
|
23096
23750
|
console.log(`neat codex: wrote the graph-first block to ${agentsPath}`);
|
|
23097
23751
|
} else {
|
|
@@ -23149,7 +23803,7 @@ async function runCodexCommand(args) {
|
|
|
23149
23803
|
|
|
23150
23804
|
// src/editors-cli.ts
|
|
23151
23805
|
init_cjs_shims();
|
|
23152
|
-
var
|
|
23806
|
+
var import_node_path79 = __toESM(require("path"), 1);
|
|
23153
23807
|
var import_node_os7 = __toESM(require("os"), 1);
|
|
23154
23808
|
var import_node_fs45 = require("fs");
|
|
23155
23809
|
var import_node_util2 = require("util");
|
|
@@ -23175,17 +23829,17 @@ function homeDir() {
|
|
|
23175
23829
|
}
|
|
23176
23830
|
function xdgConfigDir() {
|
|
23177
23831
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
23178
|
-
return xdg && xdg.length > 0 ?
|
|
23832
|
+
return xdg && xdg.length > 0 ? import_node_path79.default.resolve(xdg) : import_node_path79.default.join(homeDir(), ".config");
|
|
23179
23833
|
}
|
|
23180
23834
|
function envOverride(name) {
|
|
23181
23835
|
const v = process.env[name];
|
|
23182
|
-
return v && v.length > 0 ?
|
|
23836
|
+
return v && v.length > 0 ? import_node_path79.default.resolve(v) : void 0;
|
|
23183
23837
|
}
|
|
23184
23838
|
var CURSOR_CLIENT = {
|
|
23185
23839
|
id: "cursor",
|
|
23186
23840
|
label: "Cursor",
|
|
23187
23841
|
docsUrl: "https://docs.cursor.com/context/mcp",
|
|
23188
|
-
mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ??
|
|
23842
|
+
mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? import_node_path79.default.join(homeDir(), ".cursor", "mcp.json"),
|
|
23189
23843
|
mcpContainerKey: "mcpServers",
|
|
23190
23844
|
format: "json",
|
|
23191
23845
|
// Cursor still reads a single `.cursorrules` at the project root (the modern
|
|
@@ -23197,7 +23851,7 @@ var DEVIN_CLIENT = {
|
|
|
23197
23851
|
id: "devin",
|
|
23198
23852
|
label: "Devin Desktop (Cascade)",
|
|
23199
23853
|
docsUrl: "https://docs.devin.ai/desktop/cascade/mcp",
|
|
23200
|
-
mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ??
|
|
23854
|
+
mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? import_node_path79.default.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
23201
23855
|
mcpContainerKey: "mcpServers",
|
|
23202
23856
|
format: "json",
|
|
23203
23857
|
rulesFileName: ".windsurfrules"
|
|
@@ -23206,7 +23860,7 @@ var GEMINI_CLIENT = {
|
|
|
23206
23860
|
id: "gemini",
|
|
23207
23861
|
label: "Gemini CLI",
|
|
23208
23862
|
docsUrl: "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
|
|
23209
|
-
mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ??
|
|
23863
|
+
mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? import_node_path79.default.join(homeDir(), ".gemini", "settings.json"),
|
|
23210
23864
|
mcpContainerKey: "mcpServers",
|
|
23211
23865
|
format: "json",
|
|
23212
23866
|
rulesFileName: "GEMINI.md"
|
|
@@ -23215,7 +23869,7 @@ var QWEN_CLIENT = {
|
|
|
23215
23869
|
id: "qwen",
|
|
23216
23870
|
label: "Qwen Code",
|
|
23217
23871
|
docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/",
|
|
23218
|
-
mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ??
|
|
23872
|
+
mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? import_node_path79.default.join(homeDir(), ".qwen", "settings.json"),
|
|
23219
23873
|
mcpContainerKey: "mcpServers",
|
|
23220
23874
|
format: "json",
|
|
23221
23875
|
rulesFileName: "QWEN.md"
|
|
@@ -23224,7 +23878,7 @@ var AMAZONQ_CLIENT = {
|
|
|
23224
23878
|
id: "amazonq",
|
|
23225
23879
|
label: "Amazon Q Developer CLI",
|
|
23226
23880
|
docsUrl: "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html",
|
|
23227
|
-
mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ??
|
|
23881
|
+
mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? import_node_path79.default.join(homeDir(), ".aws", "amazonq", "mcp.json"),
|
|
23228
23882
|
mcpContainerKey: "mcpServers",
|
|
23229
23883
|
format: "json"
|
|
23230
23884
|
};
|
|
@@ -23232,7 +23886,7 @@ var ROOCODE_CLIENT = {
|
|
|
23232
23886
|
id: "roocode",
|
|
23233
23887
|
label: "Roo Code",
|
|
23234
23888
|
docsUrl: "https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo",
|
|
23235
|
-
mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ??
|
|
23889
|
+
mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? import_node_path79.default.join(process.cwd(), ".roo", "mcp.json"),
|
|
23236
23890
|
mcpContainerKey: "mcpServers",
|
|
23237
23891
|
format: "json"
|
|
23238
23892
|
};
|
|
@@ -23245,9 +23899,9 @@ var ZED_CLIENT = {
|
|
|
23245
23899
|
if (override) return override;
|
|
23246
23900
|
if (process.platform === "win32") {
|
|
23247
23901
|
const appData = process.env.APPDATA;
|
|
23248
|
-
if (appData && appData.length > 0) return
|
|
23902
|
+
if (appData && appData.length > 0) return import_node_path79.default.join(appData, "Zed", "settings.json");
|
|
23249
23903
|
}
|
|
23250
|
-
return
|
|
23904
|
+
return import_node_path79.default.join(homeDir(), ".config", "zed", "settings.json");
|
|
23251
23905
|
},
|
|
23252
23906
|
mcpContainerKey: "context_servers",
|
|
23253
23907
|
format: "jsonc",
|
|
@@ -23257,7 +23911,7 @@ var OPENCODE_CLIENT = {
|
|
|
23257
23911
|
id: "opencode",
|
|
23258
23912
|
label: "OpenCode",
|
|
23259
23913
|
docsUrl: "https://opencode.ai/docs/mcp-servers/",
|
|
23260
|
-
mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ??
|
|
23914
|
+
mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? import_node_path79.default.join(xdgConfigDir(), "opencode", "opencode.json"),
|
|
23261
23915
|
mcpContainerKey: "mcp",
|
|
23262
23916
|
format: "json",
|
|
23263
23917
|
serverEntry: NEAT_OPENCODE_SERVER,
|
|
@@ -23267,7 +23921,7 @@ var CRUSH_CLIENT = {
|
|
|
23267
23921
|
id: "crush",
|
|
23268
23922
|
label: "Crush",
|
|
23269
23923
|
docsUrl: "https://charmbracelet-crush.mintlify.app/configuration/mcp",
|
|
23270
|
-
mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ??
|
|
23924
|
+
mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? import_node_path79.default.join(xdgConfigDir(), "crush", "crush.json"),
|
|
23271
23925
|
mcpContainerKey: "mcp",
|
|
23272
23926
|
format: "json",
|
|
23273
23927
|
serverEntry: NEAT_CRUSH_SERVER,
|
|
@@ -23372,7 +24026,7 @@ async function runEditorInstall(client, opts) {
|
|
|
23372
24026
|
const mcpPath = client.mcpConfigPath();
|
|
23373
24027
|
const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER;
|
|
23374
24028
|
const hasRules = typeof client.rulesFileName === "string";
|
|
23375
|
-
const rulesPath = hasRules ?
|
|
24029
|
+
const rulesPath = hasRules ? import_node_path79.default.join(opts.projectDir, client.rulesFileName) : "";
|
|
23376
24030
|
const mcp = await planMcp(client, mcpPath);
|
|
23377
24031
|
if (mcp === null) return { exitCode: 1 };
|
|
23378
24032
|
let existingRules = "";
|
|
@@ -23415,10 +24069,10 @@ async function runEditorInstall(client, opts) {
|
|
|
23415
24069
|
);
|
|
23416
24070
|
return { exitCode: 0 };
|
|
23417
24071
|
}
|
|
23418
|
-
await import_node_fs45.promises.mkdir(
|
|
24072
|
+
await import_node_fs45.promises.mkdir(import_node_path79.default.dirname(mcpPath), { recursive: true });
|
|
23419
24073
|
await import_node_fs45.promises.writeFile(mcpPath, mcp.text, "utf8");
|
|
23420
24074
|
if (hasRules) {
|
|
23421
|
-
await import_node_fs45.promises.mkdir(
|
|
24075
|
+
await import_node_fs45.promises.mkdir(import_node_path79.default.dirname(rulesPath), { recursive: true });
|
|
23422
24076
|
await import_node_fs45.promises.writeFile(rulesPath, newRules, "utf8");
|
|
23423
24077
|
}
|
|
23424
24078
|
console.log(`neat ${client.id}: wired NEAT into ${client.label}`);
|
|
@@ -23482,11 +24136,11 @@ async function runEditorCommand(clientId, args, projectDir = process.cwd()) {
|
|
|
23482
24136
|
|
|
23483
24137
|
// src/monitor.ts
|
|
23484
24138
|
init_cjs_shims();
|
|
23485
|
-
var
|
|
24139
|
+
var import_types84 = require("@neat.is/types");
|
|
23486
24140
|
|
|
23487
24141
|
// src/cli-client.ts
|
|
23488
24142
|
init_cjs_shims();
|
|
23489
|
-
var
|
|
24143
|
+
var import_types83 = require("@neat.is/types");
|
|
23490
24144
|
var HttpError = class extends Error {
|
|
23491
24145
|
constructor(status2, message, responseBody = "") {
|
|
23492
24146
|
super(message);
|
|
@@ -23511,10 +24165,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
23511
24165
|
const root = baseUrl.replace(/\/$/, "");
|
|
23512
24166
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
23513
24167
|
return {
|
|
23514
|
-
async get(
|
|
24168
|
+
async get(path82) {
|
|
23515
24169
|
let res;
|
|
23516
24170
|
try {
|
|
23517
|
-
res = await fetch(`${root}${
|
|
24171
|
+
res = await fetch(`${root}${path82}`, {
|
|
23518
24172
|
headers: { ...authHeader }
|
|
23519
24173
|
});
|
|
23520
24174
|
} catch (err) {
|
|
@@ -23526,16 +24180,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
23526
24180
|
const body = await res.text().catch(() => "");
|
|
23527
24181
|
throw new HttpError(
|
|
23528
24182
|
res.status,
|
|
23529
|
-
`${res.status} ${res.statusText} on GET ${
|
|
24183
|
+
`${res.status} ${res.statusText} on GET ${path82}: ${body}`,
|
|
23530
24184
|
body
|
|
23531
24185
|
);
|
|
23532
24186
|
}
|
|
23533
24187
|
return await res.json();
|
|
23534
24188
|
},
|
|
23535
|
-
async post(
|
|
24189
|
+
async post(path82, body) {
|
|
23536
24190
|
let res;
|
|
23537
24191
|
try {
|
|
23538
|
-
res = await fetch(`${root}${
|
|
24192
|
+
res = await fetch(`${root}${path82}`, {
|
|
23539
24193
|
method: "POST",
|
|
23540
24194
|
headers: { "content-type": "application/json", ...authHeader },
|
|
23541
24195
|
body: JSON.stringify(body)
|
|
@@ -23549,7 +24203,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
23549
24203
|
const text = await res.text().catch(() => "");
|
|
23550
24204
|
throw new HttpError(
|
|
23551
24205
|
res.status,
|
|
23552
|
-
`${res.status} ${res.statusText} on POST ${
|
|
24206
|
+
`${res.status} ${res.statusText} on POST ${path82}: ${text}`,
|
|
23553
24207
|
text
|
|
23554
24208
|
);
|
|
23555
24209
|
}
|
|
@@ -23563,12 +24217,12 @@ function projectPath(project, suffix) {
|
|
|
23563
24217
|
}
|
|
23564
24218
|
async function runRootCause(client, input) {
|
|
23565
24219
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
23566
|
-
const
|
|
24220
|
+
const path82 = projectPath(
|
|
23567
24221
|
input.project,
|
|
23568
24222
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
23569
24223
|
);
|
|
23570
24224
|
try {
|
|
23571
|
-
const result = await client.get(
|
|
24225
|
+
const result = await client.get(path82);
|
|
23572
24226
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
23573
24227
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
23574
24228
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -23594,12 +24248,12 @@ async function runRootCause(client, input) {
|
|
|
23594
24248
|
}
|
|
23595
24249
|
async function runBlastRadius(client, input) {
|
|
23596
24250
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
23597
|
-
const
|
|
24251
|
+
const path82 = projectPath(
|
|
23598
24252
|
input.project,
|
|
23599
24253
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
23600
24254
|
);
|
|
23601
24255
|
try {
|
|
23602
|
-
const result = await client.get(
|
|
24256
|
+
const result = await client.get(path82);
|
|
23603
24257
|
if (result.totalAffected === 0) {
|
|
23604
24258
|
return {
|
|
23605
24259
|
summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
|
|
@@ -23628,17 +24282,17 @@ async function runBlastRadius(client, input) {
|
|
|
23628
24282
|
}
|
|
23629
24283
|
}
|
|
23630
24284
|
function formatBlastEntry(n) {
|
|
23631
|
-
const tag = n.edgeProvenance ===
|
|
24285
|
+
const tag = n.edgeProvenance === import_types83.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
23632
24286
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
23633
24287
|
}
|
|
23634
24288
|
async function runDependencies(client, input) {
|
|
23635
24289
|
const depth = input.depth ?? 3;
|
|
23636
|
-
const
|
|
24290
|
+
const path82 = projectPath(
|
|
23637
24291
|
input.project,
|
|
23638
24292
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
23639
24293
|
);
|
|
23640
24294
|
try {
|
|
23641
|
-
const result = await client.get(
|
|
24295
|
+
const result = await client.get(path82);
|
|
23642
24296
|
if (result.total === 0) {
|
|
23643
24297
|
return {
|
|
23644
24298
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -23685,7 +24339,7 @@ async function runObservedDependencies(client, input) {
|
|
|
23685
24339
|
if (result.observed) {
|
|
23686
24340
|
return {
|
|
23687
24341
|
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.`,
|
|
23688
|
-
provenance:
|
|
24342
|
+
provenance: import_types83.Provenance.OBSERVED
|
|
23689
24343
|
};
|
|
23690
24344
|
}
|
|
23691
24345
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -23695,7 +24349,7 @@ async function runObservedDependencies(client, input) {
|
|
|
23695
24349
|
return {
|
|
23696
24350
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
23697
24351
|
block: blockLines.join("\n"),
|
|
23698
|
-
provenance:
|
|
24352
|
+
provenance: import_types83.Provenance.OBSERVED
|
|
23699
24353
|
};
|
|
23700
24354
|
} catch (err) {
|
|
23701
24355
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -23730,9 +24384,9 @@ function formatDuration(ms) {
|
|
|
23730
24384
|
return `${Math.round(h / 24)}d`;
|
|
23731
24385
|
}
|
|
23732
24386
|
async function runIncidents(client, input) {
|
|
23733
|
-
const
|
|
24387
|
+
const path82 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
23734
24388
|
try {
|
|
23735
|
-
const body = await client.get(
|
|
24389
|
+
const body = await client.get(path82);
|
|
23736
24390
|
const events = body.events;
|
|
23737
24391
|
if (events.length === 0) {
|
|
23738
24392
|
return {
|
|
@@ -23749,7 +24403,7 @@ async function runIncidents(client, input) {
|
|
|
23749
24403
|
return {
|
|
23750
24404
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
23751
24405
|
block: blockLines.join("\n"),
|
|
23752
|
-
provenance:
|
|
24406
|
+
provenance: import_types83.Provenance.OBSERVED
|
|
23753
24407
|
};
|
|
23754
24408
|
} catch (err) {
|
|
23755
24409
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -23858,7 +24512,7 @@ async function runStaleEdges(client, input) {
|
|
|
23858
24512
|
return {
|
|
23859
24513
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
23860
24514
|
block: blockLines.join("\n"),
|
|
23861
|
-
provenance:
|
|
24515
|
+
provenance: import_types83.Provenance.STALE
|
|
23862
24516
|
};
|
|
23863
24517
|
}
|
|
23864
24518
|
async function runPolicies(client, input) {
|
|
@@ -24017,10 +24671,10 @@ async function pushSnapshotToRemote(input) {
|
|
|
24017
24671
|
|
|
24018
24672
|
// src/monitor.ts
|
|
24019
24673
|
var OBSERVED_DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
24020
|
-
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24674
|
+
import_types84.EdgeType.CALLS,
|
|
24675
|
+
import_types84.EdgeType.CONNECTS_TO,
|
|
24676
|
+
import_types84.EdgeType.PUBLISHES_TO,
|
|
24677
|
+
import_types84.EdgeType.CONSUMES_FROM
|
|
24024
24678
|
]);
|
|
24025
24679
|
function divergenceKey(d) {
|
|
24026
24680
|
const column = "column" in d && d.column ? d.column : "";
|
|
@@ -24065,7 +24719,7 @@ function formatDivergenceLine2(d) {
|
|
|
24065
24719
|
}
|
|
24066
24720
|
}
|
|
24067
24721
|
function formatStaleLine(edgeId) {
|
|
24068
|
-
const parsed = (0,
|
|
24722
|
+
const parsed = (0, import_types84.parseEdgeId)(edgeId);
|
|
24069
24723
|
if (parsed) {
|
|
24070
24724
|
return `\u22EF stale ${parsed.source} \u2192 ${parsed.target} (observed edge went quiet)`;
|
|
24071
24725
|
}
|
|
@@ -24078,7 +24732,7 @@ function divergenceJson(d) {
|
|
|
24078
24732
|
return JSON.stringify({ kind: "divergence", ...d });
|
|
24079
24733
|
}
|
|
24080
24734
|
function staleJson(edgeId) {
|
|
24081
|
-
const parsed = (0,
|
|
24735
|
+
const parsed = (0, import_types84.parseEdgeId)(edgeId);
|
|
24082
24736
|
return JSON.stringify({
|
|
24083
24737
|
kind: "stale",
|
|
24084
24738
|
edgeId,
|
|
@@ -24148,7 +24802,7 @@ var MonitorEmitter = class {
|
|
|
24148
24802
|
// ignores non-OBSERVED edges and non-dependency edge types (structural
|
|
24149
24803
|
// ownership), so only real runtime dependencies reach stdout.
|
|
24150
24804
|
emitObservedEdge(edge) {
|
|
24151
|
-
if (edge.provenance !==
|
|
24805
|
+
if (edge.provenance !== import_types84.Provenance.OBSERVED) return false;
|
|
24152
24806
|
if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false;
|
|
24153
24807
|
const key = `edge|${edge.id}`;
|
|
24154
24808
|
if (this.seen.has(key)) return false;
|
|
@@ -24306,7 +24960,7 @@ async function runMonitor(opts) {
|
|
|
24306
24960
|
case "edge-added": {
|
|
24307
24961
|
const payload = safeParse(frame.data);
|
|
24308
24962
|
const edge = payload?.edge;
|
|
24309
|
-
if (edge && edge.provenance ===
|
|
24963
|
+
if (edge && edge.provenance === import_types84.Provenance.OBSERVED) {
|
|
24310
24964
|
emitter.emitObservedEdge(edge);
|
|
24311
24965
|
divergences.schedule();
|
|
24312
24966
|
}
|
|
@@ -24386,7 +25040,7 @@ function sleep(ms, signal) {
|
|
|
24386
25040
|
|
|
24387
25041
|
// src/cli-verbs.ts
|
|
24388
25042
|
init_cjs_shims();
|
|
24389
|
-
var
|
|
25043
|
+
var import_node_path80 = __toESM(require("path"), 1);
|
|
24390
25044
|
async function resolveProjectEntry(opts) {
|
|
24391
25045
|
const entries = await listProjects();
|
|
24392
25046
|
if (opts.project) {
|
|
@@ -24396,7 +25050,7 @@ async function resolveProjectEntry(opts) {
|
|
|
24396
25050
|
const cwd = opts.cwd ?? process.cwd();
|
|
24397
25051
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
24398
25052
|
for (const entry2 of entries) {
|
|
24399
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
25053
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path80.default.sep}`)) {
|
|
24400
25054
|
return entry2;
|
|
24401
25055
|
}
|
|
24402
25056
|
}
|
|
@@ -24549,7 +25203,7 @@ async function runSync(opts) {
|
|
|
24549
25203
|
}
|
|
24550
25204
|
|
|
24551
25205
|
// src/cli.ts
|
|
24552
|
-
var
|
|
25206
|
+
var import_types85 = require("@neat.is/types");
|
|
24553
25207
|
function isNpxInvocation() {
|
|
24554
25208
|
if (process.env.npm_command === "exec") return true;
|
|
24555
25209
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -24920,12 +25574,12 @@ async function runInit(opts) {
|
|
|
24920
25574
|
printDiscoveryReport(opts, services);
|
|
24921
25575
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
24922
25576
|
const patch = renderPatch(sections);
|
|
24923
|
-
const patchPath =
|
|
25577
|
+
const patchPath = import_node_path81.default.join(opts.scanPath, "neat.patch");
|
|
24924
25578
|
if (opts.dryRun) {
|
|
24925
25579
|
await import_node_fs46.promises.writeFile(patchPath, patch, "utf8");
|
|
24926
25580
|
written.push(patchPath);
|
|
24927
25581
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
24928
|
-
const gitignorePath =
|
|
25582
|
+
const gitignorePath = import_node_path81.default.join(opts.scanPath, ".gitignore");
|
|
24929
25583
|
const gitignoreExists = await import_node_fs46.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
24930
25584
|
const verb = gitignoreExists ? "append" : "create";
|
|
24931
25585
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
@@ -24937,9 +25591,9 @@ async function runInit(opts) {
|
|
|
24937
25591
|
const graph = getGraph(graphKey);
|
|
24938
25592
|
const projectPaths = pathsForProject(
|
|
24939
25593
|
graphKey,
|
|
24940
|
-
|
|
25594
|
+
import_node_path81.default.join(opts.scanPath, "neat-out")
|
|
24941
25595
|
);
|
|
24942
|
-
const errorsPath =
|
|
25596
|
+
const errorsPath = import_node_path81.default.join(import_node_path81.default.dirname(opts.outPath), import_node_path81.default.basename(projectPaths.errorsPath));
|
|
24943
25597
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
24944
25598
|
await saveGraphToDisk(graph, opts.outPath);
|
|
24945
25599
|
written.push(opts.outPath);
|
|
@@ -25058,9 +25712,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
25058
25712
|
};
|
|
25059
25713
|
function claudeConfigPath() {
|
|
25060
25714
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
25061
|
-
if (override && override.length > 0) return
|
|
25715
|
+
if (override && override.length > 0) return import_node_path81.default.resolve(override);
|
|
25062
25716
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
25063
|
-
return
|
|
25717
|
+
return import_node_path81.default.join(home, ".claude.json");
|
|
25064
25718
|
}
|
|
25065
25719
|
async function runSkill(opts) {
|
|
25066
25720
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -25084,7 +25738,7 @@ async function runSkill(opts) {
|
|
|
25084
25738
|
...existing,
|
|
25085
25739
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
25086
25740
|
};
|
|
25087
|
-
await import_node_fs46.promises.mkdir(
|
|
25741
|
+
await import_node_fs46.promises.mkdir(import_node_path81.default.dirname(target), { recursive: true });
|
|
25088
25742
|
await import_node_fs46.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
25089
25743
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
25090
25744
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
@@ -25171,12 +25825,12 @@ async function main() {
|
|
|
25171
25825
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
25172
25826
|
process.exit(2);
|
|
25173
25827
|
}
|
|
25174
|
-
const scanPath =
|
|
25828
|
+
const scanPath = import_node_path81.default.resolve(target);
|
|
25175
25829
|
const projectExplicit = parsed.project !== null;
|
|
25176
|
-
const projectName = projectExplicit ? project :
|
|
25830
|
+
const projectName = projectExplicit ? project : import_node_path81.default.basename(scanPath);
|
|
25177
25831
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
25178
|
-
const fallback = pathsForProject(projectKey,
|
|
25179
|
-
const outPath =
|
|
25832
|
+
const fallback = pathsForProject(projectKey, import_node_path81.default.join(scanPath, "neat-out")).snapshotPath;
|
|
25833
|
+
const outPath = import_node_path81.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
25180
25834
|
const result = await runInit({
|
|
25181
25835
|
scanPath,
|
|
25182
25836
|
outPath,
|
|
@@ -25197,21 +25851,21 @@ async function main() {
|
|
|
25197
25851
|
usage4();
|
|
25198
25852
|
process.exit(2);
|
|
25199
25853
|
}
|
|
25200
|
-
const scanPath =
|
|
25854
|
+
const scanPath = import_node_path81.default.resolve(target);
|
|
25201
25855
|
const stat = await import_node_fs46.promises.stat(scanPath).catch(() => null);
|
|
25202
25856
|
if (!stat || !stat.isDirectory()) {
|
|
25203
25857
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
25204
25858
|
process.exit(2);
|
|
25205
25859
|
}
|
|
25206
|
-
const projectPaths = pathsForProject(project,
|
|
25207
|
-
const outPath =
|
|
25208
|
-
const errorsPath =
|
|
25209
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
25860
|
+
const projectPaths = pathsForProject(project, import_node_path81.default.join(scanPath, "neat-out"));
|
|
25861
|
+
const outPath = import_node_path81.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
25862
|
+
const errorsPath = import_node_path81.default.resolve(
|
|
25863
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path81.default.join(import_node_path81.default.dirname(outPath), import_node_path81.default.basename(projectPaths.errorsPath))
|
|
25210
25864
|
);
|
|
25211
|
-
const staleEventsPath =
|
|
25212
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
25865
|
+
const staleEventsPath = import_node_path81.default.resolve(
|
|
25866
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path81.default.join(import_node_path81.default.dirname(outPath), import_node_path81.default.basename(projectPaths.staleEventsPath))
|
|
25213
25867
|
);
|
|
25214
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
25868
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path81.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
25215
25869
|
const handle = await startWatch(getGraph(project), {
|
|
25216
25870
|
scanPath,
|
|
25217
25871
|
outPath,
|
|
@@ -25220,7 +25874,7 @@ async function main() {
|
|
|
25220
25874
|
project,
|
|
25221
25875
|
// Resolve NEAT_HOME so a `neat watch` picks up connectors added to
|
|
25222
25876
|
// ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
|
|
25223
|
-
neatHome: process.env.NEAT_HOME ?
|
|
25877
|
+
neatHome: process.env.NEAT_HOME ? import_node_path81.default.resolve(process.env.NEAT_HOME) : import_node_path81.default.join(import_node_os8.default.homedir(), ".neat"),
|
|
25224
25878
|
...embeddingsCachePath ? { embeddingsCachePath } : {},
|
|
25225
25879
|
host: process.env.HOST ?? "0.0.0.0",
|
|
25226
25880
|
port: Number(process.env.PORT ?? 8080),
|
|
@@ -25402,11 +26056,11 @@ async function main() {
|
|
|
25402
26056
|
process.exit(1);
|
|
25403
26057
|
}
|
|
25404
26058
|
async function tryOrchestrator(cmd, parsed) {
|
|
25405
|
-
const scanPath =
|
|
26059
|
+
const scanPath = import_node_path81.default.resolve(cmd);
|
|
25406
26060
|
const stat = await import_node_fs46.promises.stat(scanPath).catch(() => null);
|
|
25407
26061
|
if (!stat || !stat.isDirectory()) return null;
|
|
25408
26062
|
const projectExplicit = parsed.project !== null;
|
|
25409
|
-
const projectName = projectExplicit ? parsed.project :
|
|
26063
|
+
const projectName = projectExplicit ? parsed.project : import_node_path81.default.basename(scanPath);
|
|
25410
26064
|
const result = await runOrchestrator({
|
|
25411
26065
|
scanPath,
|
|
25412
26066
|
project: projectName,
|
|
@@ -25595,10 +26249,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
25595
26249
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
25596
26250
|
const out = [];
|
|
25597
26251
|
for (const p of parts) {
|
|
25598
|
-
const r =
|
|
26252
|
+
const r = import_types85.DivergenceTypeSchema.safeParse(p);
|
|
25599
26253
|
if (!r.success) {
|
|
25600
26254
|
console.error(
|
|
25601
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
26255
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types85.DivergenceTypeSchema.options.join(", ")}`
|
|
25602
26256
|
);
|
|
25603
26257
|
return 2;
|
|
25604
26258
|
}
|