@neat.is/core 0.4.12 → 0.4.13
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-WDG4QEFO.js → chunk-5W7H35JJ.js} +557 -232
- package/dist/chunk-5W7H35JJ.js.map +1 -0
- package/dist/{chunk-7JY6F7BY.js → chunk-TWNJX26R.js} +2 -2
- package/dist/cli.cjs +784 -455
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +9 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +606 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +613 -291
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +531 -209
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-WDG4QEFO.js.map +0 -1
- /package/dist/{chunk-7JY6F7BY.js.map → chunk-TWNJX26R.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -58,9 +58,9 @@ function mountBearerAuth(app, opts) {
|
|
|
58
58
|
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
59
59
|
const publicRead = opts.publicRead === true;
|
|
60
60
|
app.addHook("preHandler", (req, reply, done) => {
|
|
61
|
-
const
|
|
61
|
+
const path49 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
62
62
|
for (const suffix of suffixes) {
|
|
63
|
-
if (
|
|
63
|
+
if (path49 === suffix || path49.endsWith(suffix)) {
|
|
64
64
|
done();
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -186,8 +186,8 @@ function reshapeGrpcRequest(req) {
|
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
function resolveProtoRoot() {
|
|
189
|
-
const here =
|
|
190
|
-
return
|
|
189
|
+
const here = import_node_path39.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
190
|
+
return import_node_path39.default.resolve(here, "..", "proto");
|
|
191
191
|
}
|
|
192
192
|
function loadTraceService() {
|
|
193
193
|
const protoRoot = resolveProtoRoot();
|
|
@@ -255,13 +255,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
255
255
|
})
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
|
-
var import_node_url,
|
|
258
|
+
var import_node_url, import_node_path39, import_node_crypto2, grpc, protoLoader;
|
|
259
259
|
var init_otel_grpc = __esm({
|
|
260
260
|
"src/otel-grpc.ts"() {
|
|
261
261
|
"use strict";
|
|
262
262
|
init_cjs_shims();
|
|
263
263
|
import_node_url = require("url");
|
|
264
|
-
|
|
264
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
265
265
|
import_node_crypto2 = require("crypto");
|
|
266
266
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
267
267
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -371,10 +371,10 @@ function parseOtlpRequest(body) {
|
|
|
371
371
|
return out;
|
|
372
372
|
}
|
|
373
373
|
function loadProtoRoot() {
|
|
374
|
-
const here =
|
|
375
|
-
const protoRoot =
|
|
374
|
+
const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
375
|
+
const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
|
|
376
376
|
const root = new import_protobufjs.default.Root();
|
|
377
|
-
root.resolvePath = (_origin, target) =>
|
|
377
|
+
root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
|
|
378
378
|
root.loadSync(
|
|
379
379
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
380
380
|
{ keepCase: true }
|
|
@@ -567,12 +567,12 @@ async function buildOtelReceiver(opts) {
|
|
|
567
567
|
};
|
|
568
568
|
return decorated;
|
|
569
569
|
}
|
|
570
|
-
var
|
|
570
|
+
var import_node_path40, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
571
571
|
var init_otel = __esm({
|
|
572
572
|
"src/otel.ts"() {
|
|
573
573
|
"use strict";
|
|
574
574
|
init_cjs_shims();
|
|
575
|
-
|
|
575
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
576
576
|
import_node_url2 = require("url");
|
|
577
577
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
578
578
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -600,8 +600,8 @@ __export(cli_exports, {
|
|
|
600
600
|
});
|
|
601
601
|
module.exports = __toCommonJS(cli_exports);
|
|
602
602
|
init_cjs_shims();
|
|
603
|
-
var
|
|
604
|
-
var
|
|
603
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
604
|
+
var import_node_fs31 = require("fs");
|
|
605
605
|
var import_node_url3 = require("url");
|
|
606
606
|
|
|
607
607
|
// src/graph.ts
|
|
@@ -1131,19 +1131,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1131
1131
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1132
1132
|
let best = { path: [start], edges: [] };
|
|
1133
1133
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1134
|
-
function step(node,
|
|
1135
|
-
if (
|
|
1136
|
-
best = { path: [...
|
|
1134
|
+
function step(node, path49, edges) {
|
|
1135
|
+
if (path49.length > best.path.length) {
|
|
1136
|
+
best = { path: [...path49], edges: [...edges] };
|
|
1137
1137
|
}
|
|
1138
|
-
if (
|
|
1138
|
+
if (path49.length - 1 >= maxDepth) return;
|
|
1139
1139
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1140
1140
|
for (const [srcId, edge] of incoming) {
|
|
1141
1141
|
if (visited.has(srcId)) continue;
|
|
1142
1142
|
visited.add(srcId);
|
|
1143
|
-
|
|
1143
|
+
path49.push(srcId);
|
|
1144
1144
|
edges.push(edge);
|
|
1145
|
-
step(srcId,
|
|
1146
|
-
|
|
1145
|
+
step(srcId, path49, edges);
|
|
1146
|
+
path49.pop();
|
|
1147
1147
|
edges.pop();
|
|
1148
1148
|
visited.delete(srcId);
|
|
1149
1149
|
}
|
|
@@ -3115,10 +3115,8 @@ async function addServiceAliases(graph, scanPath, services) {
|
|
|
3115
3115
|
await collectK8sAliases(graph, scanPath, byName);
|
|
3116
3116
|
}
|
|
3117
3117
|
|
|
3118
|
-
// src/extract/
|
|
3118
|
+
// src/extract/files.ts
|
|
3119
3119
|
init_cjs_shims();
|
|
3120
|
-
var import_node_path18 = __toESM(require("path"), 1);
|
|
3121
|
-
var import_types8 = require("@neat.is/types");
|
|
3122
3120
|
|
|
3123
3121
|
// src/extract/calls/shared.ts
|
|
3124
3122
|
init_cjs_shims();
|
|
@@ -3217,11 +3215,333 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
|
3217
3215
|
return { fileNodeId, nodesAdded, edgesAdded };
|
|
3218
3216
|
}
|
|
3219
3217
|
|
|
3218
|
+
// src/extract/files.ts
|
|
3219
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
3220
|
+
async function addFiles(graph, services) {
|
|
3221
|
+
let nodesAdded = 0;
|
|
3222
|
+
let edgesAdded = 0;
|
|
3223
|
+
for (const service of services) {
|
|
3224
|
+
const filePaths = await walkSourceFiles(service.dir);
|
|
3225
|
+
for (const filePath of filePaths) {
|
|
3226
|
+
const relPath = toPosix2(import_node_path11.default.relative(service.dir, filePath));
|
|
3227
|
+
const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
3228
|
+
graph,
|
|
3229
|
+
service.pkg.name,
|
|
3230
|
+
service.node.id,
|
|
3231
|
+
relPath
|
|
3232
|
+
);
|
|
3233
|
+
nodesAdded += n;
|
|
3234
|
+
edgesAdded += e;
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
return { nodesAdded, edgesAdded };
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
// src/extract/imports.ts
|
|
3241
|
+
init_cjs_shims();
|
|
3242
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
3243
|
+
var import_node_fs11 = require("fs");
|
|
3244
|
+
var import_tree_sitter = __toESM(require("tree-sitter"), 1);
|
|
3245
|
+
var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
|
|
3246
|
+
var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
|
|
3247
|
+
var import_types8 = require("@neat.is/types");
|
|
3248
|
+
var PARSE_CHUNK = 16384;
|
|
3249
|
+
function parseSource(parser, source) {
|
|
3250
|
+
return parser.parse(
|
|
3251
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK)
|
|
3252
|
+
);
|
|
3253
|
+
}
|
|
3254
|
+
function makeJsParser() {
|
|
3255
|
+
const p = new import_tree_sitter.default();
|
|
3256
|
+
p.setLanguage(import_tree_sitter_javascript.default);
|
|
3257
|
+
return p;
|
|
3258
|
+
}
|
|
3259
|
+
function makePyParser() {
|
|
3260
|
+
const p = new import_tree_sitter.default();
|
|
3261
|
+
p.setLanguage(import_tree_sitter_python.default);
|
|
3262
|
+
return p;
|
|
3263
|
+
}
|
|
3264
|
+
function stringLiteralText(node) {
|
|
3265
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3266
|
+
const child = node.child(i);
|
|
3267
|
+
if (child?.type === "string_fragment") return child.text;
|
|
3268
|
+
}
|
|
3269
|
+
const raw = node.text;
|
|
3270
|
+
if (raw.length >= 2) return raw.slice(1, -1);
|
|
3271
|
+
return raw.length === 0 ? null : "";
|
|
3272
|
+
}
|
|
3273
|
+
function clipSnippet(text) {
|
|
3274
|
+
const oneLine = text.split("\n")[0] ?? text;
|
|
3275
|
+
return oneLine.length > 120 ? oneLine.slice(0, 120) : oneLine;
|
|
3276
|
+
}
|
|
3277
|
+
function collectJsImports(node, out) {
|
|
3278
|
+
if (node.type === "import_statement") {
|
|
3279
|
+
const source = node.childForFieldName("source");
|
|
3280
|
+
if (source) {
|
|
3281
|
+
const specifier = stringLiteralText(source);
|
|
3282
|
+
if (specifier) {
|
|
3283
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
return;
|
|
3287
|
+
}
|
|
3288
|
+
if (node.type === "call_expression") {
|
|
3289
|
+
const fn = node.childForFieldName("function");
|
|
3290
|
+
if (fn?.type === "identifier" && fn.text === "require") {
|
|
3291
|
+
const args = node.childForFieldName("arguments");
|
|
3292
|
+
const firstArg = args?.namedChild(0);
|
|
3293
|
+
if (firstArg?.type === "string") {
|
|
3294
|
+
const specifier = stringLiteralText(firstArg);
|
|
3295
|
+
if (specifier) {
|
|
3296
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3302
|
+
const child = node.namedChild(i);
|
|
3303
|
+
if (child) collectJsImports(child, out);
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
function collectPyImports(node, out) {
|
|
3307
|
+
if (node.type === "import_from_statement") {
|
|
3308
|
+
let level = 0;
|
|
3309
|
+
let modulePath = "";
|
|
3310
|
+
let pastFrom = false;
|
|
3311
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3312
|
+
const child = node.child(i);
|
|
3313
|
+
if (!child) continue;
|
|
3314
|
+
if (!pastFrom) {
|
|
3315
|
+
if (child.type === "from") pastFrom = true;
|
|
3316
|
+
continue;
|
|
3317
|
+
}
|
|
3318
|
+
if (child.type === "import") break;
|
|
3319
|
+
if (child.type === "relative_import") {
|
|
3320
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
3321
|
+
const rc = child.child(j);
|
|
3322
|
+
if (!rc) continue;
|
|
3323
|
+
if (rc.type === "import_prefix") {
|
|
3324
|
+
for (let k = 0; k < rc.childCount; k++) {
|
|
3325
|
+
if (rc.child(k)?.type === ".") level++;
|
|
3326
|
+
}
|
|
3327
|
+
} else if (rc.type === "dotted_name") modulePath = rc.text;
|
|
3328
|
+
}
|
|
3329
|
+
break;
|
|
3330
|
+
}
|
|
3331
|
+
if (child.type === "dotted_name") {
|
|
3332
|
+
modulePath = child.text;
|
|
3333
|
+
break;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
if (level > 0 || modulePath) {
|
|
3337
|
+
out.push({ modulePath, level, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3341
|
+
const child = node.namedChild(i);
|
|
3342
|
+
if (child) collectPyImports(child, out);
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
async function fileExists(p) {
|
|
3346
|
+
try {
|
|
3347
|
+
await import_node_fs11.promises.access(p);
|
|
3348
|
+
return true;
|
|
3349
|
+
} catch {
|
|
3350
|
+
return false;
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
function isWithinServiceDir(candidate, serviceDir) {
|
|
3354
|
+
const rel = import_node_path12.default.relative(serviceDir, candidate);
|
|
3355
|
+
return rel !== "" && !rel.startsWith("..") && !import_node_path12.default.isAbsolute(rel);
|
|
3356
|
+
}
|
|
3357
|
+
var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
3358
|
+
var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
|
|
3359
|
+
async function firstExistingCandidate(base, serviceDir) {
|
|
3360
|
+
for (const ext of JS_EXTENSIONS) {
|
|
3361
|
+
const candidate = base + ext;
|
|
3362
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3363
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
for (const indexFile of JS_INDEX_FILES) {
|
|
3367
|
+
const candidate = import_node_path12.default.join(base, indexFile);
|
|
3368
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3369
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
return null;
|
|
3373
|
+
}
|
|
3374
|
+
async function loadTsPathConfig(serviceDir) {
|
|
3375
|
+
const tsconfigPath = import_node_path12.default.join(serviceDir, "tsconfig.json");
|
|
3376
|
+
let raw;
|
|
3377
|
+
try {
|
|
3378
|
+
raw = await import_node_fs11.promises.readFile(tsconfigPath, "utf8");
|
|
3379
|
+
} catch {
|
|
3380
|
+
return null;
|
|
3381
|
+
}
|
|
3382
|
+
try {
|
|
3383
|
+
const parsed = JSON.parse(raw);
|
|
3384
|
+
const paths = parsed.compilerOptions?.paths;
|
|
3385
|
+
if (!paths || Object.keys(paths).length === 0) return null;
|
|
3386
|
+
const baseUrl = parsed.compilerOptions?.baseUrl;
|
|
3387
|
+
return { paths, baseDir: baseUrl ? import_node_path12.default.resolve(serviceDir, baseUrl) : serviceDir };
|
|
3388
|
+
} catch (err) {
|
|
3389
|
+
recordExtractionError("import alias resolution", tsconfigPath, err);
|
|
3390
|
+
return null;
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
async function resolveTsAlias(specifier, config, serviceDir) {
|
|
3394
|
+
for (const [pattern, targets] of Object.entries(config.paths)) {
|
|
3395
|
+
let suffix = null;
|
|
3396
|
+
if (pattern === specifier) {
|
|
3397
|
+
suffix = "";
|
|
3398
|
+
} else if (pattern.endsWith("/*")) {
|
|
3399
|
+
const prefix = pattern.slice(0, -1);
|
|
3400
|
+
if (specifier.startsWith(prefix)) suffix = specifier.slice(prefix.length);
|
|
3401
|
+
}
|
|
3402
|
+
if (suffix === null) continue;
|
|
3403
|
+
for (const target of targets) {
|
|
3404
|
+
const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
|
|
3405
|
+
const resolvedBase = import_node_path12.default.resolve(config.baseDir, targetBase, suffix);
|
|
3406
|
+
const hit = await firstExistingCandidate(resolvedBase, serviceDir);
|
|
3407
|
+
if (hit) return hit;
|
|
3408
|
+
if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists(resolvedBase)) {
|
|
3409
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, resolvedBase));
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
return null;
|
|
3414
|
+
}
|
|
3415
|
+
async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
|
|
3416
|
+
if (!specifier) return null;
|
|
3417
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
3418
|
+
const base = import_node_path12.default.resolve(importerDir, specifier);
|
|
3419
|
+
const ext = import_node_path12.default.extname(specifier);
|
|
3420
|
+
if (ext) {
|
|
3421
|
+
if (ext === ".js" || ext === ".jsx") {
|
|
3422
|
+
const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
|
|
3423
|
+
const tsSibling = base.slice(0, -ext.length) + tsExt;
|
|
3424
|
+
if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists(tsSibling)) {
|
|
3425
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, tsSibling));
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
if (isWithinServiceDir(base, serviceDir) && await fileExists(base)) {
|
|
3429
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, base));
|
|
3430
|
+
}
|
|
3431
|
+
return null;
|
|
3432
|
+
}
|
|
3433
|
+
return firstExistingCandidate(base, serviceDir);
|
|
3434
|
+
}
|
|
3435
|
+
if (tsPaths) return resolveTsAlias(specifier, tsPaths, serviceDir);
|
|
3436
|
+
return null;
|
|
3437
|
+
}
|
|
3438
|
+
async function resolvePyImport(imp, importerPath, serviceDir) {
|
|
3439
|
+
if (!imp.modulePath) return null;
|
|
3440
|
+
const relPath = imp.modulePath.split(".").join("/");
|
|
3441
|
+
let baseDir;
|
|
3442
|
+
if (imp.level > 0) {
|
|
3443
|
+
baseDir = import_node_path12.default.dirname(importerPath);
|
|
3444
|
+
for (let i = 1; i < imp.level; i++) baseDir = import_node_path12.default.dirname(baseDir);
|
|
3445
|
+
} else {
|
|
3446
|
+
baseDir = serviceDir;
|
|
3447
|
+
}
|
|
3448
|
+
const candidates = [import_node_path12.default.join(baseDir, `${relPath}.py`), import_node_path12.default.join(baseDir, relPath, "__init__.py")];
|
|
3449
|
+
for (const candidate of candidates) {
|
|
3450
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3451
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
return null;
|
|
3455
|
+
}
|
|
3456
|
+
function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
|
|
3457
|
+
const importeeFileId = (0, import_types8.fileId)(serviceName, importeeRelPath);
|
|
3458
|
+
if (!graph.hasNode(importeeFileId)) return 0;
|
|
3459
|
+
const edgeId = (0, import_types8.extractedEdgeId)(importerFileId, importeeFileId, import_types8.EdgeType.IMPORTS);
|
|
3460
|
+
if (graph.hasEdge(edgeId)) return 0;
|
|
3461
|
+
const edge = {
|
|
3462
|
+
id: edgeId,
|
|
3463
|
+
source: importerFileId,
|
|
3464
|
+
target: importeeFileId,
|
|
3465
|
+
type: import_types8.EdgeType.IMPORTS,
|
|
3466
|
+
provenance: import_types8.Provenance.EXTRACTED,
|
|
3467
|
+
confidence: (0, import_types8.confidenceForExtracted)("structural"),
|
|
3468
|
+
evidence: { file: importerRelPath, line, snippet: snippet2 }
|
|
3469
|
+
};
|
|
3470
|
+
graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge);
|
|
3471
|
+
return 1;
|
|
3472
|
+
}
|
|
3473
|
+
async function addImports(graph, services) {
|
|
3474
|
+
const jsParser = makeJsParser();
|
|
3475
|
+
const pyParser = makePyParser();
|
|
3476
|
+
let edgesAdded = 0;
|
|
3477
|
+
for (const service of services) {
|
|
3478
|
+
const tsPaths = await loadTsPathConfig(service.dir);
|
|
3479
|
+
const files = await loadSourceFiles(service.dir);
|
|
3480
|
+
for (const file of files) {
|
|
3481
|
+
if (isTestPath(file.path)) continue;
|
|
3482
|
+
const relFile = toPosix2(import_node_path12.default.relative(service.dir, file.path));
|
|
3483
|
+
const importerFileId = (0, import_types8.fileId)(service.pkg.name, relFile);
|
|
3484
|
+
const isPython = import_node_path12.default.extname(file.path) === ".py";
|
|
3485
|
+
if (isPython) {
|
|
3486
|
+
let pyImports = [];
|
|
3487
|
+
try {
|
|
3488
|
+
const tree = parseSource(pyParser, file.content);
|
|
3489
|
+
collectPyImports(tree.rootNode, pyImports);
|
|
3490
|
+
} catch (err) {
|
|
3491
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3492
|
+
continue;
|
|
3493
|
+
}
|
|
3494
|
+
for (const imp of pyImports) {
|
|
3495
|
+
const resolved = await resolvePyImport(imp, file.path, service.dir);
|
|
3496
|
+
if (!resolved) continue;
|
|
3497
|
+
edgesAdded += emitImportEdge(
|
|
3498
|
+
graph,
|
|
3499
|
+
service.pkg.name,
|
|
3500
|
+
importerFileId,
|
|
3501
|
+
relFile,
|
|
3502
|
+
resolved,
|
|
3503
|
+
imp.line,
|
|
3504
|
+
imp.snippet
|
|
3505
|
+
);
|
|
3506
|
+
}
|
|
3507
|
+
continue;
|
|
3508
|
+
}
|
|
3509
|
+
let jsImports = [];
|
|
3510
|
+
try {
|
|
3511
|
+
const tree = parseSource(jsParser, file.content);
|
|
3512
|
+
collectJsImports(tree.rootNode, jsImports);
|
|
3513
|
+
} catch (err) {
|
|
3514
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3515
|
+
continue;
|
|
3516
|
+
}
|
|
3517
|
+
for (const imp of jsImports) {
|
|
3518
|
+
const resolved = await resolveJsImport(imp.specifier, import_node_path12.default.dirname(file.path), service.dir, tsPaths);
|
|
3519
|
+
if (!resolved) continue;
|
|
3520
|
+
edgesAdded += emitImportEdge(
|
|
3521
|
+
graph,
|
|
3522
|
+
service.pkg.name,
|
|
3523
|
+
importerFileId,
|
|
3524
|
+
relFile,
|
|
3525
|
+
resolved,
|
|
3526
|
+
imp.line,
|
|
3527
|
+
imp.snippet
|
|
3528
|
+
);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
return { nodesAdded: 0, edgesAdded };
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
// src/extract/databases/index.ts
|
|
3536
|
+
init_cjs_shims();
|
|
3537
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
3538
|
+
var import_types9 = require("@neat.is/types");
|
|
3539
|
+
|
|
3220
3540
|
// src/extract/databases/db-config-yaml.ts
|
|
3221
3541
|
init_cjs_shims();
|
|
3222
|
-
var
|
|
3542
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
3223
3543
|
async function parse(serviceDir) {
|
|
3224
|
-
const yamlPath =
|
|
3544
|
+
const yamlPath = import_node_path13.default.join(serviceDir, "db-config.yaml");
|
|
3225
3545
|
if (!await exists(yamlPath)) return [];
|
|
3226
3546
|
const raw = await readYaml(yamlPath);
|
|
3227
3547
|
return [
|
|
@@ -3239,13 +3559,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
|
|
|
3239
3559
|
|
|
3240
3560
|
// src/extract/databases/dotenv.ts
|
|
3241
3561
|
init_cjs_shims();
|
|
3242
|
-
var
|
|
3243
|
-
var
|
|
3562
|
+
var import_node_fs13 = require("fs");
|
|
3563
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3244
3564
|
|
|
3245
3565
|
// src/extract/databases/shared.ts
|
|
3246
3566
|
init_cjs_shims();
|
|
3247
|
-
var
|
|
3248
|
-
var
|
|
3567
|
+
var import_node_fs12 = require("fs");
|
|
3568
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3249
3569
|
function schemeToEngine(scheme) {
|
|
3250
3570
|
const s = scheme.toLowerCase().split("+")[0];
|
|
3251
3571
|
switch (s) {
|
|
@@ -3284,14 +3604,14 @@ function parseConnectionString(url) {
|
|
|
3284
3604
|
}
|
|
3285
3605
|
async function readIfExists(filePath) {
|
|
3286
3606
|
try {
|
|
3287
|
-
return await
|
|
3607
|
+
return await import_node_fs12.promises.readFile(filePath, "utf8");
|
|
3288
3608
|
} catch {
|
|
3289
3609
|
return null;
|
|
3290
3610
|
}
|
|
3291
3611
|
}
|
|
3292
3612
|
async function findFirst(serviceDir, candidates) {
|
|
3293
3613
|
for (const rel of candidates) {
|
|
3294
|
-
const abs =
|
|
3614
|
+
const abs = import_node_path14.default.join(serviceDir, rel);
|
|
3295
3615
|
const content = await readIfExists(abs);
|
|
3296
3616
|
if (content !== null) return abs;
|
|
3297
3617
|
}
|
|
@@ -3342,15 +3662,15 @@ function parseDotenvLine(line) {
|
|
|
3342
3662
|
return { key, value };
|
|
3343
3663
|
}
|
|
3344
3664
|
async function parse2(serviceDir) {
|
|
3345
|
-
const entries = await
|
|
3665
|
+
const entries = await import_node_fs13.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
3346
3666
|
const configs = [];
|
|
3347
3667
|
const seen = /* @__PURE__ */ new Set();
|
|
3348
3668
|
for (const entry2 of entries) {
|
|
3349
3669
|
if (!entry2.isFile()) continue;
|
|
3350
3670
|
const match = isConfigFile(entry2.name);
|
|
3351
3671
|
if (!match.match || match.fileType !== "env") continue;
|
|
3352
|
-
const filePath =
|
|
3353
|
-
const content = await
|
|
3672
|
+
const filePath = import_node_path15.default.join(serviceDir, entry2.name);
|
|
3673
|
+
const content = await import_node_fs13.promises.readFile(filePath, "utf8");
|
|
3354
3674
|
for (const line of content.split("\n")) {
|
|
3355
3675
|
const parsed = parseDotenvLine(line);
|
|
3356
3676
|
if (!parsed) continue;
|
|
@@ -3369,9 +3689,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
|
|
|
3369
3689
|
|
|
3370
3690
|
// src/extract/databases/prisma.ts
|
|
3371
3691
|
init_cjs_shims();
|
|
3372
|
-
var
|
|
3692
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3373
3693
|
async function parse3(serviceDir) {
|
|
3374
|
-
const schemaPath =
|
|
3694
|
+
const schemaPath = import_node_path16.default.join(serviceDir, "prisma", "schema.prisma");
|
|
3375
3695
|
const content = await readIfExists(schemaPath);
|
|
3376
3696
|
if (!content) return [];
|
|
3377
3697
|
const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
|
|
@@ -3503,10 +3823,10 @@ var knexParser = { name: "knex", parse: parse5 };
|
|
|
3503
3823
|
|
|
3504
3824
|
// src/extract/databases/ormconfig.ts
|
|
3505
3825
|
init_cjs_shims();
|
|
3506
|
-
var
|
|
3826
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
3507
3827
|
async function parse6(serviceDir) {
|
|
3508
3828
|
for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
|
|
3509
|
-
const abs =
|
|
3829
|
+
const abs = import_node_path17.default.join(serviceDir, candidate);
|
|
3510
3830
|
if (!await exists(abs)) continue;
|
|
3511
3831
|
const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
|
|
3512
3832
|
const entries = Array.isArray(raw) ? raw : [raw];
|
|
@@ -3566,9 +3886,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
|
|
|
3566
3886
|
|
|
3567
3887
|
// src/extract/databases/sequelize.ts
|
|
3568
3888
|
init_cjs_shims();
|
|
3569
|
-
var
|
|
3889
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
3570
3890
|
async function parse8(serviceDir) {
|
|
3571
|
-
const configPath =
|
|
3891
|
+
const configPath = import_node_path18.default.join(serviceDir, "config", "config.json");
|
|
3572
3892
|
if (!await exists(configPath)) return [];
|
|
3573
3893
|
const raw = await readJson(configPath);
|
|
3574
3894
|
const out = [];
|
|
@@ -3595,7 +3915,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
|
3595
3915
|
|
|
3596
3916
|
// src/extract/databases/docker-compose.ts
|
|
3597
3917
|
init_cjs_shims();
|
|
3598
|
-
var
|
|
3918
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
3599
3919
|
function portFromService(svc) {
|
|
3600
3920
|
for (const raw of svc.ports ?? []) {
|
|
3601
3921
|
const str = String(raw);
|
|
@@ -3622,7 +3942,7 @@ function databaseFromEnv(svc) {
|
|
|
3622
3942
|
}
|
|
3623
3943
|
async function parse9(serviceDir) {
|
|
3624
3944
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
3625
|
-
const abs =
|
|
3945
|
+
const abs = import_node_path19.default.join(serviceDir, name);
|
|
3626
3946
|
if (!await exists(abs)) continue;
|
|
3627
3947
|
const raw = await readYaml(abs);
|
|
3628
3948
|
if (!raw?.services) return [];
|
|
@@ -3663,8 +3983,8 @@ function compatibleDriversFor(engine) {
|
|
|
3663
3983
|
}
|
|
3664
3984
|
function toDatabaseNode(config) {
|
|
3665
3985
|
return {
|
|
3666
|
-
id: (0,
|
|
3667
|
-
type:
|
|
3986
|
+
id: (0, import_types9.databaseId)(config.host),
|
|
3987
|
+
type: import_types9.NodeType.DatabaseNode,
|
|
3668
3988
|
name: config.database || config.host,
|
|
3669
3989
|
engine: config.engine,
|
|
3670
3990
|
engineVersion: config.engineVersion,
|
|
@@ -3794,7 +4114,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3794
4114
|
discoveredVia: mergedDiscoveredVia
|
|
3795
4115
|
});
|
|
3796
4116
|
}
|
|
3797
|
-
const relConfigFile = toPosix2(
|
|
4117
|
+
const relConfigFile = toPosix2(import_node_path20.default.relative(service.dir, config.sourceFile));
|
|
3798
4118
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3799
4119
|
graph,
|
|
3800
4120
|
service.pkg.name,
|
|
@@ -3803,14 +4123,14 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3803
4123
|
);
|
|
3804
4124
|
nodesAdded += fn;
|
|
3805
4125
|
edgesAdded += fe;
|
|
3806
|
-
const evidenceFile = toPosix2(
|
|
4126
|
+
const evidenceFile = toPosix2(import_node_path20.default.relative(scanPath, config.sourceFile));
|
|
3807
4127
|
const edge = {
|
|
3808
|
-
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id,
|
|
4128
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id, import_types9.EdgeType.CONNECTS_TO),
|
|
3809
4129
|
source: fileNodeId,
|
|
3810
4130
|
target: dbNode.id,
|
|
3811
|
-
type:
|
|
3812
|
-
provenance:
|
|
3813
|
-
confidence: (0,
|
|
4131
|
+
type: import_types9.EdgeType.CONNECTS_TO,
|
|
4132
|
+
provenance: import_types9.Provenance.EXTRACTED,
|
|
4133
|
+
confidence: (0, import_types9.confidenceForExtracted)("structural"),
|
|
3814
4134
|
evidence: { file: evidenceFile }
|
|
3815
4135
|
};
|
|
3816
4136
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -3837,15 +4157,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3837
4157
|
|
|
3838
4158
|
// src/extract/configs.ts
|
|
3839
4159
|
init_cjs_shims();
|
|
3840
|
-
var
|
|
3841
|
-
var
|
|
3842
|
-
var
|
|
4160
|
+
var import_node_fs14 = require("fs");
|
|
4161
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
4162
|
+
var import_types10 = require("@neat.is/types");
|
|
3843
4163
|
async function walkConfigFiles(dir) {
|
|
3844
4164
|
const out = [];
|
|
3845
4165
|
async function walk(current) {
|
|
3846
|
-
const entries = await
|
|
4166
|
+
const entries = await import_node_fs14.promises.readdir(current, { withFileTypes: true });
|
|
3847
4167
|
for (const entry2 of entries) {
|
|
3848
|
-
const full =
|
|
4168
|
+
const full = import_node_path21.default.join(current, entry2.name);
|
|
3849
4169
|
if (entry2.isDirectory()) {
|
|
3850
4170
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3851
4171
|
if (await isPythonVenvDir(full)) continue;
|
|
@@ -3864,19 +4184,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3864
4184
|
for (const service of services) {
|
|
3865
4185
|
const configFiles = await walkConfigFiles(service.dir);
|
|
3866
4186
|
for (const file of configFiles) {
|
|
3867
|
-
const relPath =
|
|
4187
|
+
const relPath = import_node_path21.default.relative(scanPath, file);
|
|
3868
4188
|
const node = {
|
|
3869
|
-
id: (0,
|
|
3870
|
-
type:
|
|
3871
|
-
name:
|
|
4189
|
+
id: (0, import_types10.configId)(relPath),
|
|
4190
|
+
type: import_types10.NodeType.ConfigNode,
|
|
4191
|
+
name: import_node_path21.default.basename(file),
|
|
3872
4192
|
path: relPath,
|
|
3873
|
-
fileType: isConfigFile(
|
|
4193
|
+
fileType: isConfigFile(import_node_path21.default.basename(file)).fileType
|
|
3874
4194
|
};
|
|
3875
4195
|
if (!graph.hasNode(node.id)) {
|
|
3876
4196
|
graph.addNode(node.id, node);
|
|
3877
4197
|
nodesAdded++;
|
|
3878
4198
|
}
|
|
3879
|
-
const relToService = toPosix2(
|
|
4199
|
+
const relToService = toPosix2(import_node_path21.default.relative(service.dir, file));
|
|
3880
4200
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3881
4201
|
graph,
|
|
3882
4202
|
service.pkg.name,
|
|
@@ -3886,13 +4206,13 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3886
4206
|
nodesAdded += fn;
|
|
3887
4207
|
edgesAdded += fe;
|
|
3888
4208
|
const edge = {
|
|
3889
|
-
id: (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
4209
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types10.EdgeType.CONFIGURED_BY),
|
|
3890
4210
|
source: fileNodeId,
|
|
3891
4211
|
target: node.id,
|
|
3892
|
-
type:
|
|
3893
|
-
provenance:
|
|
3894
|
-
confidence: (0,
|
|
3895
|
-
evidence: { file: relPath.split(
|
|
4212
|
+
type: import_types10.EdgeType.CONFIGURED_BY,
|
|
4213
|
+
provenance: import_types10.Provenance.EXTRACTED,
|
|
4214
|
+
confidence: (0, import_types10.confidenceForExtracted)("structural"),
|
|
4215
|
+
evidence: { file: relPath.split(import_node_path21.default.sep).join("/") }
|
|
3896
4216
|
};
|
|
3897
4217
|
if (!graph.hasEdge(edge.id)) {
|
|
3898
4218
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -3905,15 +4225,15 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3905
4225
|
|
|
3906
4226
|
// src/extract/calls/index.ts
|
|
3907
4227
|
init_cjs_shims();
|
|
3908
|
-
var
|
|
4228
|
+
var import_types16 = require("@neat.is/types");
|
|
3909
4229
|
|
|
3910
4230
|
// src/extract/calls/http.ts
|
|
3911
4231
|
init_cjs_shims();
|
|
3912
|
-
var
|
|
3913
|
-
var
|
|
3914
|
-
var
|
|
3915
|
-
var
|
|
3916
|
-
var
|
|
4232
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
4233
|
+
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
4234
|
+
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
4235
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
4236
|
+
var import_types11 = require("@neat.is/types");
|
|
3917
4237
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
3918
4238
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
3919
4239
|
function isInsideJsxExternalLink(node) {
|
|
@@ -3941,14 +4261,14 @@ function collectStringLiterals(node, out) {
|
|
|
3941
4261
|
if (child) collectStringLiterals(child, out);
|
|
3942
4262
|
}
|
|
3943
4263
|
}
|
|
3944
|
-
var
|
|
3945
|
-
function
|
|
4264
|
+
var PARSE_CHUNK2 = 16384;
|
|
4265
|
+
function parseSource2(parser, source) {
|
|
3946
4266
|
return parser.parse(
|
|
3947
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
4267
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK2)
|
|
3948
4268
|
);
|
|
3949
4269
|
}
|
|
3950
4270
|
function callsFromSource(source, parser, knownHosts) {
|
|
3951
|
-
const tree =
|
|
4271
|
+
const tree = parseSource2(parser, source);
|
|
3952
4272
|
const literals = [];
|
|
3953
4273
|
collectStringLiterals(tree.rootNode, literals);
|
|
3954
4274
|
const out = [];
|
|
@@ -3962,25 +4282,25 @@ function callsFromSource(source, parser, knownHosts) {
|
|
|
3962
4282
|
}
|
|
3963
4283
|
return out;
|
|
3964
4284
|
}
|
|
3965
|
-
function
|
|
3966
|
-
const p = new
|
|
3967
|
-
p.setLanguage(
|
|
4285
|
+
function makeJsParser2() {
|
|
4286
|
+
const p = new import_tree_sitter2.default();
|
|
4287
|
+
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
3968
4288
|
return p;
|
|
3969
4289
|
}
|
|
3970
|
-
function
|
|
3971
|
-
const p = new
|
|
3972
|
-
p.setLanguage(
|
|
4290
|
+
function makePyParser2() {
|
|
4291
|
+
const p = new import_tree_sitter2.default();
|
|
4292
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
3973
4293
|
return p;
|
|
3974
4294
|
}
|
|
3975
4295
|
async function addHttpCallEdges(graph, services) {
|
|
3976
|
-
const jsParser =
|
|
3977
|
-
const pyParser =
|
|
4296
|
+
const jsParser = makeJsParser2();
|
|
4297
|
+
const pyParser = makePyParser2();
|
|
3978
4298
|
const knownHosts = /* @__PURE__ */ new Set();
|
|
3979
4299
|
const hostToNodeId = /* @__PURE__ */ new Map();
|
|
3980
4300
|
for (const service of services) {
|
|
3981
|
-
knownHosts.add(
|
|
4301
|
+
knownHosts.add(import_node_path22.default.basename(service.dir));
|
|
3982
4302
|
knownHosts.add(service.pkg.name);
|
|
3983
|
-
hostToNodeId.set(
|
|
4303
|
+
hostToNodeId.set(import_node_path22.default.basename(service.dir), service.node.id);
|
|
3984
4304
|
hostToNodeId.set(service.pkg.name, service.node.id);
|
|
3985
4305
|
}
|
|
3986
4306
|
let nodesAdded = 0;
|
|
@@ -3990,7 +4310,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
3990
4310
|
const seen = /* @__PURE__ */ new Set();
|
|
3991
4311
|
for (const file of files) {
|
|
3992
4312
|
if (isTestPath(file.path)) continue;
|
|
3993
|
-
const parser =
|
|
4313
|
+
const parser = import_node_path22.default.extname(file.path) === ".py" ? pyParser : jsParser;
|
|
3994
4314
|
let sites;
|
|
3995
4315
|
try {
|
|
3996
4316
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -3999,14 +4319,14 @@ async function addHttpCallEdges(graph, services) {
|
|
|
3999
4319
|
continue;
|
|
4000
4320
|
}
|
|
4001
4321
|
if (sites.length === 0) continue;
|
|
4002
|
-
const relFile = toPosix2(
|
|
4322
|
+
const relFile = toPosix2(import_node_path22.default.relative(service.dir, file.path));
|
|
4003
4323
|
for (const site of sites) {
|
|
4004
4324
|
const targetId = hostToNodeId.get(site.host);
|
|
4005
4325
|
if (!targetId || targetId === service.node.id) continue;
|
|
4006
4326
|
const dedupKey = `${relFile}|${targetId}`;
|
|
4007
4327
|
if (seen.has(dedupKey)) continue;
|
|
4008
4328
|
seen.add(dedupKey);
|
|
4009
|
-
const confidence = (0,
|
|
4329
|
+
const confidence = (0, import_types11.confidenceForExtracted)("hostname-shape-match");
|
|
4010
4330
|
const ev = {
|
|
4011
4331
|
file: relFile,
|
|
4012
4332
|
line: site.line,
|
|
@@ -4020,25 +4340,25 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4020
4340
|
);
|
|
4021
4341
|
nodesAdded += n;
|
|
4022
4342
|
edgesAdded += e;
|
|
4023
|
-
if (!(0,
|
|
4343
|
+
if (!(0, import_types11.passesExtractedFloor)(confidence)) {
|
|
4024
4344
|
noteExtractedDropped({
|
|
4025
4345
|
source: fileNodeId,
|
|
4026
4346
|
target: targetId,
|
|
4027
|
-
type:
|
|
4347
|
+
type: import_types11.EdgeType.CALLS,
|
|
4028
4348
|
confidence,
|
|
4029
4349
|
confidenceKind: "hostname-shape-match",
|
|
4030
4350
|
evidence: ev
|
|
4031
4351
|
});
|
|
4032
4352
|
continue;
|
|
4033
4353
|
}
|
|
4034
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, targetId,
|
|
4354
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, targetId, import_types11.EdgeType.CALLS);
|
|
4035
4355
|
if (!graph.hasEdge(edgeId)) {
|
|
4036
4356
|
const edge = {
|
|
4037
4357
|
id: edgeId,
|
|
4038
4358
|
source: fileNodeId,
|
|
4039
4359
|
target: targetId,
|
|
4040
|
-
type:
|
|
4041
|
-
provenance:
|
|
4360
|
+
type: import_types11.EdgeType.CALLS,
|
|
4361
|
+
provenance: import_types11.Provenance.EXTRACTED,
|
|
4042
4362
|
confidence,
|
|
4043
4363
|
evidence: ev
|
|
4044
4364
|
};
|
|
@@ -4053,8 +4373,8 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4053
4373
|
|
|
4054
4374
|
// src/extract/calls/kafka.ts
|
|
4055
4375
|
init_cjs_shims();
|
|
4056
|
-
var
|
|
4057
|
-
var
|
|
4376
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
4377
|
+
var import_types12 = require("@neat.is/types");
|
|
4058
4378
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4059
4379
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
4060
4380
|
function findAll(re, text) {
|
|
@@ -4075,7 +4395,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4075
4395
|
seen.add(key);
|
|
4076
4396
|
const line = lineOf(file.content, topic);
|
|
4077
4397
|
out.push({
|
|
4078
|
-
infraId: (0,
|
|
4398
|
+
infraId: (0, import_types12.infraId)("kafka-topic", topic),
|
|
4079
4399
|
name: topic,
|
|
4080
4400
|
kind: "kafka-topic",
|
|
4081
4401
|
edgeType,
|
|
@@ -4084,7 +4404,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4084
4404
|
// tier (ADR-066).
|
|
4085
4405
|
confidenceKind: "verified-call-site",
|
|
4086
4406
|
evidence: {
|
|
4087
|
-
file:
|
|
4407
|
+
file: import_node_path23.default.relative(serviceDir, file.path),
|
|
4088
4408
|
line,
|
|
4089
4409
|
snippet: snippet(file.content, line)
|
|
4090
4410
|
}
|
|
@@ -4097,8 +4417,8 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4097
4417
|
|
|
4098
4418
|
// src/extract/calls/redis.ts
|
|
4099
4419
|
init_cjs_shims();
|
|
4100
|
-
var
|
|
4101
|
-
var
|
|
4420
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
4421
|
+
var import_types13 = require("@neat.is/types");
|
|
4102
4422
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
4103
4423
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
4104
4424
|
const out = [];
|
|
@@ -4111,7 +4431,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4111
4431
|
seen.add(host);
|
|
4112
4432
|
const line = lineOf(file.content, host);
|
|
4113
4433
|
out.push({
|
|
4114
|
-
infraId: (0,
|
|
4434
|
+
infraId: (0, import_types13.infraId)("redis", host),
|
|
4115
4435
|
name: host,
|
|
4116
4436
|
kind: "redis",
|
|
4117
4437
|
edgeType: "CALLS",
|
|
@@ -4120,7 +4440,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4120
4440
|
// support tier (ADR-066).
|
|
4121
4441
|
confidenceKind: "url-with-structural-support",
|
|
4122
4442
|
evidence: {
|
|
4123
|
-
file:
|
|
4443
|
+
file: import_node_path24.default.relative(serviceDir, file.path),
|
|
4124
4444
|
line,
|
|
4125
4445
|
snippet: snippet(file.content, line)
|
|
4126
4446
|
}
|
|
@@ -4131,8 +4451,8 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4131
4451
|
|
|
4132
4452
|
// src/extract/calls/aws.ts
|
|
4133
4453
|
init_cjs_shims();
|
|
4134
|
-
var
|
|
4135
|
-
var
|
|
4454
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
4455
|
+
var import_types14 = require("@neat.is/types");
|
|
4136
4456
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4137
4457
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4138
4458
|
function hasMarker(text, markers) {
|
|
@@ -4156,7 +4476,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4156
4476
|
seen.add(key);
|
|
4157
4477
|
const line = lineOf(file.content, name);
|
|
4158
4478
|
out.push({
|
|
4159
|
-
infraId: (0,
|
|
4479
|
+
infraId: (0, import_types14.infraId)(kind, name),
|
|
4160
4480
|
name,
|
|
4161
4481
|
kind,
|
|
4162
4482
|
edgeType: "CALLS",
|
|
@@ -4165,7 +4485,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4165
4485
|
// (ADR-066).
|
|
4166
4486
|
confidenceKind: "verified-call-site",
|
|
4167
4487
|
evidence: {
|
|
4168
|
-
file:
|
|
4488
|
+
file: import_node_path25.default.relative(serviceDir, file.path),
|
|
4169
4489
|
line,
|
|
4170
4490
|
snippet: snippet(file.content, line)
|
|
4171
4491
|
}
|
|
@@ -4190,8 +4510,8 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4190
4510
|
|
|
4191
4511
|
// src/extract/calls/grpc.ts
|
|
4192
4512
|
init_cjs_shims();
|
|
4193
|
-
var
|
|
4194
|
-
var
|
|
4513
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
4514
|
+
var import_types15 = require("@neat.is/types");
|
|
4195
4515
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
4196
4516
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
4197
4517
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
@@ -4240,7 +4560,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4240
4560
|
const { kind } = classified;
|
|
4241
4561
|
const line = lineOf(file.content, m[0]);
|
|
4242
4562
|
out.push({
|
|
4243
|
-
infraId: (0,
|
|
4563
|
+
infraId: (0, import_types15.infraId)(kind, name),
|
|
4244
4564
|
name,
|
|
4245
4565
|
kind,
|
|
4246
4566
|
edgeType: "CALLS",
|
|
@@ -4249,7 +4569,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4249
4569
|
// tier (ADR-066).
|
|
4250
4570
|
confidenceKind: "verified-call-site",
|
|
4251
4571
|
evidence: {
|
|
4252
|
-
file:
|
|
4572
|
+
file: import_node_path26.default.relative(serviceDir, file.path),
|
|
4253
4573
|
line,
|
|
4254
4574
|
snippet: snippet(file.content, line)
|
|
4255
4575
|
}
|
|
@@ -4262,11 +4582,11 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4262
4582
|
function edgeTypeFromEndpoint(ep) {
|
|
4263
4583
|
switch (ep.edgeType) {
|
|
4264
4584
|
case "PUBLISHES_TO":
|
|
4265
|
-
return
|
|
4585
|
+
return import_types16.EdgeType.PUBLISHES_TO;
|
|
4266
4586
|
case "CONSUMES_FROM":
|
|
4267
|
-
return
|
|
4587
|
+
return import_types16.EdgeType.CONSUMES_FROM;
|
|
4268
4588
|
default:
|
|
4269
|
-
return
|
|
4589
|
+
return import_types16.EdgeType.CALLS;
|
|
4270
4590
|
}
|
|
4271
4591
|
}
|
|
4272
4592
|
function isAwsKind(kind) {
|
|
@@ -4293,7 +4613,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4293
4613
|
if (!graph.hasNode(ep.infraId)) {
|
|
4294
4614
|
const node = {
|
|
4295
4615
|
id: ep.infraId,
|
|
4296
|
-
type:
|
|
4616
|
+
type: import_types16.NodeType.InfraNode,
|
|
4297
4617
|
name: ep.name,
|
|
4298
4618
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
4299
4619
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -4305,7 +4625,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4305
4625
|
nodesAdded++;
|
|
4306
4626
|
}
|
|
4307
4627
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
4308
|
-
const confidence = (0,
|
|
4628
|
+
const confidence = (0, import_types16.confidenceForExtracted)(ep.confidenceKind);
|
|
4309
4629
|
const relFile = toPosix2(ep.evidence.file);
|
|
4310
4630
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
4311
4631
|
graph,
|
|
@@ -4315,7 +4635,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4315
4635
|
);
|
|
4316
4636
|
nodesAdded += n;
|
|
4317
4637
|
edgesAdded += e;
|
|
4318
|
-
if (!(0,
|
|
4638
|
+
if (!(0, import_types16.passesExtractedFloor)(confidence)) {
|
|
4319
4639
|
noteExtractedDropped({
|
|
4320
4640
|
source: fileNodeId,
|
|
4321
4641
|
target: ep.infraId,
|
|
@@ -4335,7 +4655,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4335
4655
|
source: fileNodeId,
|
|
4336
4656
|
target: ep.infraId,
|
|
4337
4657
|
type: edgeType,
|
|
4338
|
-
provenance:
|
|
4658
|
+
provenance: import_types16.Provenance.EXTRACTED,
|
|
4339
4659
|
confidence,
|
|
4340
4660
|
evidence: ep.evidence
|
|
4341
4661
|
};
|
|
@@ -4360,16 +4680,16 @@ init_cjs_shims();
|
|
|
4360
4680
|
|
|
4361
4681
|
// src/extract/infra/docker-compose.ts
|
|
4362
4682
|
init_cjs_shims();
|
|
4363
|
-
var
|
|
4364
|
-
var
|
|
4683
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
4684
|
+
var import_types18 = require("@neat.is/types");
|
|
4365
4685
|
|
|
4366
4686
|
// src/extract/infra/shared.ts
|
|
4367
4687
|
init_cjs_shims();
|
|
4368
|
-
var
|
|
4688
|
+
var import_types17 = require("@neat.is/types");
|
|
4369
4689
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
4370
4690
|
return {
|
|
4371
|
-
id: (0,
|
|
4372
|
-
type:
|
|
4691
|
+
id: (0, import_types17.infraId)(kind, name),
|
|
4692
|
+
type: import_types17.NodeType.InfraNode,
|
|
4373
4693
|
name,
|
|
4374
4694
|
provider,
|
|
4375
4695
|
kind,
|
|
@@ -4398,7 +4718,7 @@ function dependsOnList(value) {
|
|
|
4398
4718
|
}
|
|
4399
4719
|
function serviceNameToServiceNode(name, services) {
|
|
4400
4720
|
for (const s of services) {
|
|
4401
|
-
if (s.node.name === name ||
|
|
4721
|
+
if (s.node.name === name || import_node_path27.default.basename(s.dir) === name) return s.node.id;
|
|
4402
4722
|
}
|
|
4403
4723
|
return null;
|
|
4404
4724
|
}
|
|
@@ -4407,7 +4727,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4407
4727
|
let edgesAdded = 0;
|
|
4408
4728
|
let composePath = null;
|
|
4409
4729
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
4410
|
-
const abs =
|
|
4730
|
+
const abs = import_node_path27.default.join(scanPath, name);
|
|
4411
4731
|
if (await exists(abs)) {
|
|
4412
4732
|
composePath = abs;
|
|
4413
4733
|
break;
|
|
@@ -4420,13 +4740,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4420
4740
|
} catch (err) {
|
|
4421
4741
|
recordExtractionError(
|
|
4422
4742
|
"infra docker-compose",
|
|
4423
|
-
|
|
4743
|
+
import_node_path27.default.relative(scanPath, composePath),
|
|
4424
4744
|
err
|
|
4425
4745
|
);
|
|
4426
4746
|
return { nodesAdded, edgesAdded };
|
|
4427
4747
|
}
|
|
4428
4748
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
4429
|
-
const evidenceFile =
|
|
4749
|
+
const evidenceFile = import_node_path27.default.relative(scanPath, composePath).split(import_node_path27.default.sep).join("/");
|
|
4430
4750
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
4431
4751
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
4432
4752
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -4448,15 +4768,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4448
4768
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
4449
4769
|
const targetId = composeNameToNodeId.get(dep);
|
|
4450
4770
|
if (!targetId) continue;
|
|
4451
|
-
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId,
|
|
4771
|
+
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId, import_types18.EdgeType.DEPENDS_ON);
|
|
4452
4772
|
if (graph.hasEdge(edgeId)) continue;
|
|
4453
4773
|
const edge = {
|
|
4454
4774
|
id: edgeId,
|
|
4455
4775
|
source: sourceId,
|
|
4456
4776
|
target: targetId,
|
|
4457
|
-
type:
|
|
4458
|
-
provenance:
|
|
4459
|
-
confidence: (0,
|
|
4777
|
+
type: import_types18.EdgeType.DEPENDS_ON,
|
|
4778
|
+
provenance: import_types18.Provenance.EXTRACTED,
|
|
4779
|
+
confidence: (0, import_types18.confidenceForExtracted)("structural"),
|
|
4460
4780
|
evidence: { file: evidenceFile }
|
|
4461
4781
|
};
|
|
4462
4782
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4468,9 +4788,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4468
4788
|
|
|
4469
4789
|
// src/extract/infra/dockerfile.ts
|
|
4470
4790
|
init_cjs_shims();
|
|
4471
|
-
var
|
|
4472
|
-
var
|
|
4473
|
-
var
|
|
4791
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
4792
|
+
var import_node_fs15 = require("fs");
|
|
4793
|
+
var import_types19 = require("@neat.is/types");
|
|
4474
4794
|
function runtimeImage(content) {
|
|
4475
4795
|
const lines = content.split("\n");
|
|
4476
4796
|
let last = null;
|
|
@@ -4489,15 +4809,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4489
4809
|
let nodesAdded = 0;
|
|
4490
4810
|
let edgesAdded = 0;
|
|
4491
4811
|
for (const service of services) {
|
|
4492
|
-
const dockerfilePath =
|
|
4812
|
+
const dockerfilePath = import_node_path28.default.join(service.dir, "Dockerfile");
|
|
4493
4813
|
if (!await exists(dockerfilePath)) continue;
|
|
4494
4814
|
let content;
|
|
4495
4815
|
try {
|
|
4496
|
-
content = await
|
|
4816
|
+
content = await import_node_fs15.promises.readFile(dockerfilePath, "utf8");
|
|
4497
4817
|
} catch (err) {
|
|
4498
4818
|
recordExtractionError(
|
|
4499
4819
|
"infra dockerfile",
|
|
4500
|
-
|
|
4820
|
+
import_node_path28.default.relative(scanPath, dockerfilePath),
|
|
4501
4821
|
err
|
|
4502
4822
|
);
|
|
4503
4823
|
continue;
|
|
@@ -4509,7 +4829,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4509
4829
|
graph.addNode(node.id, node);
|
|
4510
4830
|
nodesAdded++;
|
|
4511
4831
|
}
|
|
4512
|
-
const relDockerfile = toPosix2(
|
|
4832
|
+
const relDockerfile = toPosix2(import_node_path28.default.relative(service.dir, dockerfilePath));
|
|
4513
4833
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4514
4834
|
graph,
|
|
4515
4835
|
service.pkg.name,
|
|
@@ -4518,17 +4838,17 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4518
4838
|
);
|
|
4519
4839
|
nodesAdded += fn;
|
|
4520
4840
|
edgesAdded += fe;
|
|
4521
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
4841
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types19.EdgeType.RUNS_ON);
|
|
4522
4842
|
if (!graph.hasEdge(edgeId)) {
|
|
4523
4843
|
const edge = {
|
|
4524
4844
|
id: edgeId,
|
|
4525
4845
|
source: fileNodeId,
|
|
4526
4846
|
target: node.id,
|
|
4527
|
-
type:
|
|
4528
|
-
provenance:
|
|
4529
|
-
confidence: (0,
|
|
4847
|
+
type: import_types19.EdgeType.RUNS_ON,
|
|
4848
|
+
provenance: import_types19.Provenance.EXTRACTED,
|
|
4849
|
+
confidence: (0, import_types19.confidenceForExtracted)("structural"),
|
|
4530
4850
|
evidence: {
|
|
4531
|
-
file: toPosix2(
|
|
4851
|
+
file: toPosix2(import_node_path28.default.relative(scanPath, dockerfilePath))
|
|
4532
4852
|
}
|
|
4533
4853
|
};
|
|
4534
4854
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4540,21 +4860,21 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4540
4860
|
|
|
4541
4861
|
// src/extract/infra/terraform.ts
|
|
4542
4862
|
init_cjs_shims();
|
|
4543
|
-
var
|
|
4544
|
-
var
|
|
4863
|
+
var import_node_fs16 = require("fs");
|
|
4864
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
4545
4865
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
4546
4866
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
4547
4867
|
if (depth > max) return [];
|
|
4548
4868
|
const out = [];
|
|
4549
|
-
const entries = await
|
|
4869
|
+
const entries = await import_node_fs16.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4550
4870
|
for (const entry2 of entries) {
|
|
4551
4871
|
if (entry2.isDirectory()) {
|
|
4552
4872
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
4553
|
-
const child =
|
|
4873
|
+
const child = import_node_path29.default.join(start, entry2.name);
|
|
4554
4874
|
if (await isPythonVenvDir(child)) continue;
|
|
4555
4875
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
4556
4876
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
4557
|
-
out.push(
|
|
4877
|
+
out.push(import_node_path29.default.join(start, entry2.name));
|
|
4558
4878
|
}
|
|
4559
4879
|
}
|
|
4560
4880
|
return out;
|
|
@@ -4563,7 +4883,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4563
4883
|
let nodesAdded = 0;
|
|
4564
4884
|
const files = await walkTfFiles(scanPath);
|
|
4565
4885
|
for (const file of files) {
|
|
4566
|
-
const content = await
|
|
4886
|
+
const content = await import_node_fs16.promises.readFile(file, "utf8");
|
|
4567
4887
|
RESOURCE_RE.lastIndex = 0;
|
|
4568
4888
|
let m;
|
|
4569
4889
|
while ((m = RESOURCE_RE.exec(content)) !== null) {
|
|
@@ -4581,8 +4901,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4581
4901
|
|
|
4582
4902
|
// src/extract/infra/k8s.ts
|
|
4583
4903
|
init_cjs_shims();
|
|
4584
|
-
var
|
|
4585
|
-
var
|
|
4904
|
+
var import_node_fs17 = require("fs");
|
|
4905
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
4586
4906
|
var import_yaml3 = require("yaml");
|
|
4587
4907
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
4588
4908
|
Service: "k8s-service",
|
|
@@ -4596,15 +4916,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
4596
4916
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
4597
4917
|
if (depth > max) return [];
|
|
4598
4918
|
const out = [];
|
|
4599
|
-
const entries = await
|
|
4919
|
+
const entries = await import_node_fs17.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4600
4920
|
for (const entry2 of entries) {
|
|
4601
4921
|
if (entry2.isDirectory()) {
|
|
4602
4922
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
4603
|
-
const child =
|
|
4923
|
+
const child = import_node_path30.default.join(start, entry2.name);
|
|
4604
4924
|
if (await isPythonVenvDir(child)) continue;
|
|
4605
4925
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
4606
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
4607
|
-
out.push(
|
|
4926
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path30.default.extname(entry2.name))) {
|
|
4927
|
+
out.push(import_node_path30.default.join(start, entry2.name));
|
|
4608
4928
|
}
|
|
4609
4929
|
}
|
|
4610
4930
|
return out;
|
|
@@ -4613,7 +4933,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
4613
4933
|
let nodesAdded = 0;
|
|
4614
4934
|
const files = await walkYamlFiles2(scanPath);
|
|
4615
4935
|
for (const file of files) {
|
|
4616
|
-
const content = await
|
|
4936
|
+
const content = await import_node_fs17.promises.readFile(file, "utf8");
|
|
4617
4937
|
let docs;
|
|
4618
4938
|
try {
|
|
4619
4939
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -4648,17 +4968,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
4648
4968
|
}
|
|
4649
4969
|
|
|
4650
4970
|
// src/extract/index.ts
|
|
4651
|
-
var
|
|
4971
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
4652
4972
|
|
|
4653
4973
|
// src/extract/retire.ts
|
|
4654
4974
|
init_cjs_shims();
|
|
4655
|
-
var
|
|
4656
|
-
var
|
|
4657
|
-
var
|
|
4975
|
+
var import_node_fs18 = require("fs");
|
|
4976
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
4977
|
+
var import_types20 = require("@neat.is/types");
|
|
4658
4978
|
function dropOrphanedFileNodes(graph) {
|
|
4659
4979
|
const orphans = [];
|
|
4660
4980
|
graph.forEachNode((id, attrs) => {
|
|
4661
|
-
if (attrs.type !==
|
|
4981
|
+
if (attrs.type !== import_types20.NodeType.FileNode) return;
|
|
4662
4982
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
4663
4983
|
orphans.push(id);
|
|
4664
4984
|
}
|
|
@@ -4671,7 +4991,7 @@ function retireEdgesByFile(graph, file) {
|
|
|
4671
4991
|
const toDrop = [];
|
|
4672
4992
|
graph.forEachEdge((id, attrs) => {
|
|
4673
4993
|
const edge = attrs;
|
|
4674
|
-
if (edge.provenance !==
|
|
4994
|
+
if (edge.provenance !== import_types20.Provenance.EXTRACTED) return;
|
|
4675
4995
|
if (!edge.evidence?.file) return;
|
|
4676
4996
|
if (edge.evidence.file === normalized) toDrop.push(id);
|
|
4677
4997
|
});
|
|
@@ -4684,14 +5004,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
4684
5004
|
const bases = [scanPath, ...serviceDirs];
|
|
4685
5005
|
graph.forEachEdge((id, attrs) => {
|
|
4686
5006
|
const edge = attrs;
|
|
4687
|
-
if (edge.provenance !==
|
|
5007
|
+
if (edge.provenance !== import_types20.Provenance.EXTRACTED) return;
|
|
4688
5008
|
const evidenceFile = edge.evidence?.file;
|
|
4689
5009
|
if (!evidenceFile) return;
|
|
4690
|
-
if (
|
|
4691
|
-
if (!(0,
|
|
5010
|
+
if (import_node_path31.default.isAbsolute(evidenceFile)) {
|
|
5011
|
+
if (!(0, import_node_fs18.existsSync)(evidenceFile)) toDrop.push(id);
|
|
4692
5012
|
return;
|
|
4693
5013
|
}
|
|
4694
|
-
const found = bases.some((base) => (0,
|
|
5014
|
+
const found = bases.some((base) => (0, import_node_fs18.existsSync)(import_node_path31.default.join(base, evidenceFile)));
|
|
4695
5015
|
if (!found) toDrop.push(id);
|
|
4696
5016
|
});
|
|
4697
5017
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -4706,6 +5026,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4706
5026
|
const services = await discoverServices(scanPath);
|
|
4707
5027
|
const phase1Nodes = addServiceNodes(graph, services);
|
|
4708
5028
|
await addServiceAliases(graph, scanPath, services);
|
|
5029
|
+
const fileEnum = await addFiles(graph, services);
|
|
5030
|
+
const importGraph = await addImports(graph, services);
|
|
4709
5031
|
const phase2 = await addDatabasesAndCompat(graph, services, scanPath);
|
|
4710
5032
|
const phase3 = await addConfigNodes(graph, services, scanPath);
|
|
4711
5033
|
const phase4 = await addCallEdges(graph, services);
|
|
@@ -4729,7 +5051,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4729
5051
|
}
|
|
4730
5052
|
const droppedEntries = drainDroppedExtracted();
|
|
4731
5053
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
4732
|
-
const rejectedPath =
|
|
5054
|
+
const rejectedPath = import_node_path32.default.join(import_node_path32.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
4733
5055
|
try {
|
|
4734
5056
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
4735
5057
|
} catch (err) {
|
|
@@ -4739,8 +5061,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4739
5061
|
}
|
|
4740
5062
|
}
|
|
4741
5063
|
const result = {
|
|
4742
|
-
nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
4743
|
-
edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
5064
|
+
nodesAdded: phase1Nodes + fileEnum.nodesAdded + importGraph.nodesAdded + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
5065
|
+
edgesAdded: fileEnum.edgesAdded + importGraph.edgesAdded + phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
4744
5066
|
frontiersPromoted,
|
|
4745
5067
|
extractionErrors: errorEntries.length,
|
|
4746
5068
|
errorEntries,
|
|
@@ -4763,7 +5085,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4763
5085
|
|
|
4764
5086
|
// src/divergences.ts
|
|
4765
5087
|
init_cjs_shims();
|
|
4766
|
-
var
|
|
5088
|
+
var import_types21 = require("@neat.is/types");
|
|
4767
5089
|
function bucketKey(source, target, type) {
|
|
4768
5090
|
return `${type}|${source}|${target}`;
|
|
4769
5091
|
}
|
|
@@ -4771,22 +5093,22 @@ function bucketEdges(graph) {
|
|
|
4771
5093
|
const buckets = /* @__PURE__ */ new Map();
|
|
4772
5094
|
graph.forEachEdge((id, attrs) => {
|
|
4773
5095
|
const e = attrs;
|
|
4774
|
-
const parsed = (0,
|
|
5096
|
+
const parsed = (0, import_types21.parseEdgeId)(id);
|
|
4775
5097
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
4776
5098
|
const key = bucketKey(e.source, e.target, e.type);
|
|
4777
5099
|
const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
4778
5100
|
switch (provenance) {
|
|
4779
|
-
case
|
|
5101
|
+
case import_types21.Provenance.EXTRACTED:
|
|
4780
5102
|
cur.extracted = e;
|
|
4781
5103
|
break;
|
|
4782
|
-
case
|
|
5104
|
+
case import_types21.Provenance.OBSERVED:
|
|
4783
5105
|
cur.observed = e;
|
|
4784
5106
|
break;
|
|
4785
|
-
case
|
|
5107
|
+
case import_types21.Provenance.INFERRED:
|
|
4786
5108
|
cur.inferred = e;
|
|
4787
5109
|
break;
|
|
4788
5110
|
default:
|
|
4789
|
-
if (e.provenance ===
|
|
5111
|
+
if (e.provenance === import_types21.Provenance.STALE) cur.stale = e;
|
|
4790
5112
|
}
|
|
4791
5113
|
buckets.set(key, cur);
|
|
4792
5114
|
});
|
|
@@ -4795,7 +5117,7 @@ function bucketEdges(graph) {
|
|
|
4795
5117
|
function nodeIsFrontier(graph, nodeId) {
|
|
4796
5118
|
if (!graph.hasNode(nodeId)) return false;
|
|
4797
5119
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
4798
|
-
return attrs.type ===
|
|
5120
|
+
return attrs.type === import_types21.NodeType.FrontierNode;
|
|
4799
5121
|
}
|
|
4800
5122
|
function clampConfidence(n) {
|
|
4801
5123
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -4816,7 +5138,7 @@ function gradedConfidence(edge) {
|
|
|
4816
5138
|
}
|
|
4817
5139
|
function detectMissingDivergences(graph, bucket) {
|
|
4818
5140
|
const out = [];
|
|
4819
|
-
if (bucket.type ===
|
|
5141
|
+
if (bucket.type === import_types21.EdgeType.CONTAINS) return out;
|
|
4820
5142
|
if (bucket.extracted && !bucket.observed) {
|
|
4821
5143
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
4822
5144
|
out.push({
|
|
@@ -4857,7 +5179,7 @@ function declaredHostFor(svc) {
|
|
|
4857
5179
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
4858
5180
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4859
5181
|
const e = graph.getEdgeAttributes(edgeId);
|
|
4860
|
-
if (e.type ===
|
|
5182
|
+
if (e.type === import_types21.EdgeType.CONFIGURED_BY && e.provenance === import_types21.Provenance.EXTRACTED) {
|
|
4861
5183
|
return true;
|
|
4862
5184
|
}
|
|
4863
5185
|
}
|
|
@@ -4870,10 +5192,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
4870
5192
|
const out = [];
|
|
4871
5193
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4872
5194
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
4873
|
-
if (edge.type !==
|
|
4874
|
-
if (edge.provenance !==
|
|
5195
|
+
if (edge.type !== import_types21.EdgeType.CONNECTS_TO) continue;
|
|
5196
|
+
if (edge.provenance !== import_types21.Provenance.OBSERVED) continue;
|
|
4875
5197
|
const target = graph.getNodeAttributes(edge.target);
|
|
4876
|
-
if (target.type !==
|
|
5198
|
+
if (target.type !== import_types21.NodeType.DatabaseNode) continue;
|
|
4877
5199
|
const observedHost = target.host?.trim();
|
|
4878
5200
|
if (!observedHost) continue;
|
|
4879
5201
|
if (observedHost === declaredHost) continue;
|
|
@@ -4895,10 +5217,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
4895
5217
|
const deps = svc.dependencies ?? {};
|
|
4896
5218
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4897
5219
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
4898
|
-
if (edge.type !==
|
|
4899
|
-
if (edge.provenance !==
|
|
5220
|
+
if (edge.type !== import_types21.EdgeType.CONNECTS_TO) continue;
|
|
5221
|
+
if (edge.provenance !== import_types21.Provenance.OBSERVED) continue;
|
|
4900
5222
|
const target = graph.getNodeAttributes(edge.target);
|
|
4901
|
-
if (target.type !==
|
|
5223
|
+
if (target.type !== import_types21.NodeType.DatabaseNode) continue;
|
|
4902
5224
|
for (const pair of compatPairs()) {
|
|
4903
5225
|
if (pair.engine !== target.engine) continue;
|
|
4904
5226
|
const declared = deps[pair.driver];
|
|
@@ -4959,7 +5281,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
4959
5281
|
}
|
|
4960
5282
|
graph.forEachNode((nodeId, attrs) => {
|
|
4961
5283
|
const n = attrs;
|
|
4962
|
-
if (n.type !==
|
|
5284
|
+
if (n.type !== import_types21.NodeType.ServiceNode) return;
|
|
4963
5285
|
const svc = n;
|
|
4964
5286
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
4965
5287
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -4992,7 +5314,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
4992
5314
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
4993
5315
|
return a.target.localeCompare(b.target);
|
|
4994
5316
|
});
|
|
4995
|
-
return
|
|
5317
|
+
return import_types21.DivergenceResultSchema.parse({
|
|
4996
5318
|
divergences: filtered,
|
|
4997
5319
|
totalAffected: filtered.length,
|
|
4998
5320
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -5001,9 +5323,9 @@ function computeDivergences(graph, opts = {}) {
|
|
|
5001
5323
|
|
|
5002
5324
|
// src/persist.ts
|
|
5003
5325
|
init_cjs_shims();
|
|
5004
|
-
var
|
|
5005
|
-
var
|
|
5006
|
-
var
|
|
5326
|
+
var import_node_fs19 = require("fs");
|
|
5327
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
5328
|
+
var import_types22 = require("@neat.is/types");
|
|
5007
5329
|
var SCHEMA_VERSION = 4;
|
|
5008
5330
|
function migrateV1ToV2(payload) {
|
|
5009
5331
|
const nodes = payload.graph.nodes;
|
|
@@ -5025,12 +5347,12 @@ function migrateV2ToV3(payload) {
|
|
|
5025
5347
|
for (const edge of edges) {
|
|
5026
5348
|
const attrs = edge.attributes;
|
|
5027
5349
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
5028
|
-
attrs.provenance =
|
|
5350
|
+
attrs.provenance = import_types22.Provenance.OBSERVED;
|
|
5029
5351
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
5030
5352
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
5031
5353
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
5032
5354
|
if (type && source && target) {
|
|
5033
|
-
const newId = (0,
|
|
5355
|
+
const newId = (0, import_types22.observedEdgeId)(source, target, type);
|
|
5034
5356
|
attrs.id = newId;
|
|
5035
5357
|
if (edge.key) edge.key = newId;
|
|
5036
5358
|
}
|
|
@@ -5039,7 +5361,7 @@ function migrateV2ToV3(payload) {
|
|
|
5039
5361
|
return { ...payload, schemaVersion: 3 };
|
|
5040
5362
|
}
|
|
5041
5363
|
async function ensureDir(filePath) {
|
|
5042
|
-
await
|
|
5364
|
+
await import_node_fs19.promises.mkdir(import_node_path33.default.dirname(filePath), { recursive: true });
|
|
5043
5365
|
}
|
|
5044
5366
|
async function saveGraphToDisk(graph, outPath) {
|
|
5045
5367
|
await ensureDir(outPath);
|
|
@@ -5049,13 +5371,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
5049
5371
|
graph: graph.export()
|
|
5050
5372
|
};
|
|
5051
5373
|
const tmp = `${outPath}.tmp`;
|
|
5052
|
-
await
|
|
5053
|
-
await
|
|
5374
|
+
await import_node_fs19.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
5375
|
+
await import_node_fs19.promises.rename(tmp, outPath);
|
|
5054
5376
|
}
|
|
5055
5377
|
async function loadGraphFromDisk(graph, outPath) {
|
|
5056
5378
|
let raw;
|
|
5057
5379
|
try {
|
|
5058
|
-
raw = await
|
|
5380
|
+
raw = await import_node_fs19.promises.readFile(outPath, "utf8");
|
|
5059
5381
|
} catch (err) {
|
|
5060
5382
|
if (err.code === "ENOENT") return;
|
|
5061
5383
|
throw err;
|
|
@@ -5114,8 +5436,8 @@ function startPersistLoop(graph, outPath, intervalMs = 6e4) {
|
|
|
5114
5436
|
|
|
5115
5437
|
// src/gitignore.ts
|
|
5116
5438
|
init_cjs_shims();
|
|
5117
|
-
var
|
|
5118
|
-
var
|
|
5439
|
+
var import_node_fs20 = require("fs");
|
|
5440
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
5119
5441
|
var NEAT_OUT_LINE = "neat-out/";
|
|
5120
5442
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
5121
5443
|
function isNeatOutLine(line) {
|
|
@@ -5123,15 +5445,15 @@ function isNeatOutLine(line) {
|
|
|
5123
5445
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
5124
5446
|
}
|
|
5125
5447
|
async function ensureNeatOutIgnored(projectDir) {
|
|
5126
|
-
const file =
|
|
5448
|
+
const file = import_node_path34.default.join(projectDir, ".gitignore");
|
|
5127
5449
|
let existing = null;
|
|
5128
5450
|
try {
|
|
5129
|
-
existing = await
|
|
5451
|
+
existing = await import_node_fs20.promises.readFile(file, "utf8");
|
|
5130
5452
|
} catch (err) {
|
|
5131
5453
|
if (err.code !== "ENOENT") throw err;
|
|
5132
5454
|
}
|
|
5133
5455
|
if (existing === null) {
|
|
5134
|
-
await
|
|
5456
|
+
await import_node_fs20.promises.writeFile(file, `${NEAT_HEADER}
|
|
5135
5457
|
${NEAT_OUT_LINE}
|
|
5136
5458
|
`, "utf8");
|
|
5137
5459
|
return { action: "created", file };
|
|
@@ -5144,13 +5466,13 @@ ${NEAT_OUT_LINE}
|
|
|
5144
5466
|
${NEAT_HEADER}
|
|
5145
5467
|
${NEAT_OUT_LINE}
|
|
5146
5468
|
`;
|
|
5147
|
-
await
|
|
5469
|
+
await import_node_fs20.promises.writeFile(file, existing + appended, "utf8");
|
|
5148
5470
|
return { action: "added", file };
|
|
5149
5471
|
}
|
|
5150
5472
|
|
|
5151
5473
|
// src/summary.ts
|
|
5152
5474
|
init_cjs_shims();
|
|
5153
|
-
var
|
|
5475
|
+
var import_types23 = require("@neat.is/types");
|
|
5154
5476
|
function renderOtelEnvBlock() {
|
|
5155
5477
|
return [
|
|
5156
5478
|
"for prod OTel routing, set these in your deploy platform's env:",
|
|
@@ -5160,19 +5482,19 @@ function renderOtelEnvBlock() {
|
|
|
5160
5482
|
}
|
|
5161
5483
|
function findIncompatServices(nodes) {
|
|
5162
5484
|
return nodes.filter(
|
|
5163
|
-
(n) => n.type ===
|
|
5485
|
+
(n) => n.type === import_types23.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
|
|
5164
5486
|
);
|
|
5165
5487
|
}
|
|
5166
5488
|
function servicesWithoutObserved(nodes, edges) {
|
|
5167
5489
|
const seen = /* @__PURE__ */ new Set();
|
|
5168
5490
|
for (const e of edges) {
|
|
5169
|
-
if (e.provenance ===
|
|
5491
|
+
if (e.provenance === import_types23.Provenance.OBSERVED) {
|
|
5170
5492
|
seen.add(e.source);
|
|
5171
5493
|
seen.add(e.target);
|
|
5172
5494
|
}
|
|
5173
5495
|
}
|
|
5174
5496
|
return nodes.filter(
|
|
5175
|
-
(n) => n.type ===
|
|
5497
|
+
(n) => n.type === import_types23.NodeType.ServiceNode && !seen.has(n.id)
|
|
5176
5498
|
);
|
|
5177
5499
|
}
|
|
5178
5500
|
function formatDivergence(d) {
|
|
@@ -5246,27 +5568,27 @@ function formatIncompat(inc) {
|
|
|
5246
5568
|
|
|
5247
5569
|
// src/watch.ts
|
|
5248
5570
|
init_cjs_shims();
|
|
5249
|
-
var
|
|
5250
|
-
var
|
|
5571
|
+
var import_node_fs26 = __toESM(require("fs"), 1);
|
|
5572
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
5251
5573
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
5252
5574
|
|
|
5253
5575
|
// src/api.ts
|
|
5254
5576
|
init_cjs_shims();
|
|
5255
5577
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
5256
5578
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
5257
|
-
var
|
|
5579
|
+
var import_types25 = require("@neat.is/types");
|
|
5258
5580
|
|
|
5259
5581
|
// src/extend/index.ts
|
|
5260
5582
|
init_cjs_shims();
|
|
5261
|
-
var
|
|
5262
|
-
var
|
|
5583
|
+
var import_node_fs22 = require("fs");
|
|
5584
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5263
5585
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
5264
5586
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
5265
5587
|
|
|
5266
5588
|
// src/installers/package-manager.ts
|
|
5267
5589
|
init_cjs_shims();
|
|
5268
|
-
var
|
|
5269
|
-
var
|
|
5590
|
+
var import_node_fs21 = require("fs");
|
|
5591
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
5270
5592
|
var import_node_child_process = require("child_process");
|
|
5271
5593
|
var LOCKFILE_PRIORITY = [
|
|
5272
5594
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -5281,29 +5603,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
5281
5603
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
5282
5604
|
async function exists2(p) {
|
|
5283
5605
|
try {
|
|
5284
|
-
await
|
|
5606
|
+
await import_node_fs21.promises.access(p);
|
|
5285
5607
|
return true;
|
|
5286
5608
|
} catch {
|
|
5287
5609
|
return false;
|
|
5288
5610
|
}
|
|
5289
5611
|
}
|
|
5290
5612
|
async function detectPackageManager(serviceDir) {
|
|
5291
|
-
let dir =
|
|
5613
|
+
let dir = import_node_path35.default.resolve(serviceDir);
|
|
5292
5614
|
const stops = /* @__PURE__ */ new Set();
|
|
5293
5615
|
for (let i = 0; i < 64; i++) {
|
|
5294
5616
|
if (stops.has(dir)) break;
|
|
5295
5617
|
stops.add(dir);
|
|
5296
5618
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
5297
|
-
const lockPath =
|
|
5619
|
+
const lockPath = import_node_path35.default.join(dir, candidate.lockfile);
|
|
5298
5620
|
if (await exists2(lockPath)) {
|
|
5299
5621
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
5300
5622
|
}
|
|
5301
5623
|
}
|
|
5302
|
-
const parent =
|
|
5624
|
+
const parent = import_node_path35.default.dirname(dir);
|
|
5303
5625
|
if (parent === dir) break;
|
|
5304
5626
|
dir = parent;
|
|
5305
5627
|
}
|
|
5306
|
-
return { pm: "npm", cwd:
|
|
5628
|
+
return { pm: "npm", cwd: import_node_path35.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
5307
5629
|
}
|
|
5308
5630
|
async function runPackageManagerInstall(cmd) {
|
|
5309
5631
|
return new Promise((resolve) => {
|
|
@@ -5343,32 +5665,32 @@ ${err.message}`
|
|
|
5343
5665
|
}
|
|
5344
5666
|
|
|
5345
5667
|
// src/extend/index.ts
|
|
5346
|
-
async function
|
|
5668
|
+
async function fileExists2(p) {
|
|
5347
5669
|
try {
|
|
5348
|
-
await
|
|
5670
|
+
await import_node_fs22.promises.access(p);
|
|
5349
5671
|
return true;
|
|
5350
5672
|
} catch {
|
|
5351
5673
|
return false;
|
|
5352
5674
|
}
|
|
5353
5675
|
}
|
|
5354
5676
|
async function readPackageJson(scanPath) {
|
|
5355
|
-
const pkgPath =
|
|
5356
|
-
const raw = await
|
|
5677
|
+
const pkgPath = import_node_path36.default.join(scanPath, "package.json");
|
|
5678
|
+
const raw = await import_node_fs22.promises.readFile(pkgPath, "utf8");
|
|
5357
5679
|
return JSON.parse(raw);
|
|
5358
5680
|
}
|
|
5359
5681
|
async function findHookFiles(scanPath) {
|
|
5360
|
-
const entries = await
|
|
5682
|
+
const entries = await import_node_fs22.promises.readdir(scanPath);
|
|
5361
5683
|
return entries.filter(
|
|
5362
5684
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
5363
5685
|
).sort();
|
|
5364
5686
|
}
|
|
5365
5687
|
function extendLogPath() {
|
|
5366
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
5688
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path36.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
5367
5689
|
}
|
|
5368
5690
|
async function appendExtendLog(entry2) {
|
|
5369
5691
|
const logPath = extendLogPath();
|
|
5370
|
-
await
|
|
5371
|
-
await
|
|
5692
|
+
await import_node_fs22.promises.mkdir(import_node_path36.default.dirname(logPath), { recursive: true });
|
|
5693
|
+
await import_node_fs22.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
5372
5694
|
}
|
|
5373
5695
|
function splicedContent(fileContent, snippet2) {
|
|
5374
5696
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -5426,7 +5748,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
5426
5748
|
}
|
|
5427
5749
|
async function describeProjectInstrumentation(ctx) {
|
|
5428
5750
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5429
|
-
const envNeat = await
|
|
5751
|
+
const envNeat = await fileExists2(import_node_path36.default.join(ctx.scanPath, ".env.neat"));
|
|
5430
5752
|
const registryInstrPackages = new Set(
|
|
5431
5753
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
5432
5754
|
);
|
|
@@ -5448,31 +5770,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
5448
5770
|
);
|
|
5449
5771
|
}
|
|
5450
5772
|
for (const file of hookFiles) {
|
|
5451
|
-
const content = await
|
|
5773
|
+
const content = await import_node_fs22.promises.readFile(import_node_path36.default.join(ctx.scanPath, file), "utf8");
|
|
5452
5774
|
if (content.includes(args.registration_snippet)) {
|
|
5453
5775
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
5454
5776
|
}
|
|
5455
5777
|
}
|
|
5456
5778
|
const primaryFile = hookFiles[0];
|
|
5457
|
-
const primaryPath =
|
|
5779
|
+
const primaryPath = import_node_path36.default.join(ctx.scanPath, primaryFile);
|
|
5458
5780
|
const filesTouched = [];
|
|
5459
5781
|
const depsAdded = [];
|
|
5460
|
-
const pkgPath =
|
|
5782
|
+
const pkgPath = import_node_path36.default.join(ctx.scanPath, "package.json");
|
|
5461
5783
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5462
5784
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
5463
5785
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
5464
|
-
await
|
|
5786
|
+
await import_node_fs22.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5465
5787
|
filesTouched.push("package.json");
|
|
5466
5788
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
5467
5789
|
}
|
|
5468
|
-
const hookContent = await
|
|
5790
|
+
const hookContent = await import_node_fs22.promises.readFile(primaryPath, "utf8");
|
|
5469
5791
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5470
5792
|
if (!patched) {
|
|
5471
5793
|
throw new Error(
|
|
5472
5794
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
5473
5795
|
);
|
|
5474
5796
|
}
|
|
5475
|
-
await
|
|
5797
|
+
await import_node_fs22.promises.writeFile(primaryPath, patched, "utf8");
|
|
5476
5798
|
filesTouched.push(primaryFile);
|
|
5477
5799
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
5478
5800
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -5503,7 +5825,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5503
5825
|
};
|
|
5504
5826
|
}
|
|
5505
5827
|
for (const file of hookFiles) {
|
|
5506
|
-
const content = await
|
|
5828
|
+
const content = await import_node_fs22.promises.readFile(import_node_path36.default.join(ctx.scanPath, file), "utf8");
|
|
5507
5829
|
if (content.includes(args.registration_snippet)) {
|
|
5508
5830
|
return {
|
|
5509
5831
|
library: args.library,
|
|
@@ -5525,7 +5847,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5525
5847
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
5526
5848
|
filesTouched.push("package.json");
|
|
5527
5849
|
}
|
|
5528
|
-
const hookContent = await
|
|
5850
|
+
const hookContent = await import_node_fs22.promises.readFile(import_node_path36.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
5529
5851
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5530
5852
|
if (patched) {
|
|
5531
5853
|
filesTouched.push(primaryFile);
|
|
@@ -5537,31 +5859,31 @@ async function dryRunExtension(ctx, args) {
|
|
|
5537
5859
|
}
|
|
5538
5860
|
async function rollbackExtension(ctx, args) {
|
|
5539
5861
|
const logPath = extendLogPath();
|
|
5540
|
-
if (!await
|
|
5862
|
+
if (!await fileExists2(logPath)) {
|
|
5541
5863
|
return { undone: false, message: "no apply found for library" };
|
|
5542
5864
|
}
|
|
5543
|
-
const raw = await
|
|
5865
|
+
const raw = await import_node_fs22.promises.readFile(logPath, "utf8");
|
|
5544
5866
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
5545
5867
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
5546
5868
|
if (!match) {
|
|
5547
5869
|
return { undone: false, message: "no apply found for library" };
|
|
5548
5870
|
}
|
|
5549
|
-
const pkgPath =
|
|
5550
|
-
if (await
|
|
5871
|
+
const pkgPath = import_node_path36.default.join(ctx.scanPath, "package.json");
|
|
5872
|
+
if (await fileExists2(pkgPath)) {
|
|
5551
5873
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5552
5874
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
5553
5875
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
5554
5876
|
pkg.dependencies = rest;
|
|
5555
|
-
await
|
|
5877
|
+
await import_node_fs22.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5556
5878
|
}
|
|
5557
5879
|
}
|
|
5558
5880
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5559
5881
|
for (const file of hookFiles) {
|
|
5560
|
-
const filePath =
|
|
5561
|
-
const content = await
|
|
5882
|
+
const filePath = import_node_path36.default.join(ctx.scanPath, file);
|
|
5883
|
+
const content = await import_node_fs22.promises.readFile(filePath, "utf8");
|
|
5562
5884
|
if (content.includes(match.registration_snippet)) {
|
|
5563
5885
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
5564
|
-
await
|
|
5886
|
+
await import_node_fs22.promises.writeFile(filePath, filtered, "utf8");
|
|
5565
5887
|
break;
|
|
5566
5888
|
}
|
|
5567
5889
|
}
|
|
@@ -5573,7 +5895,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
5573
5895
|
|
|
5574
5896
|
// src/diff.ts
|
|
5575
5897
|
init_cjs_shims();
|
|
5576
|
-
var
|
|
5898
|
+
var import_node_fs23 = require("fs");
|
|
5577
5899
|
async function loadSnapshotForDiff(target) {
|
|
5578
5900
|
if (/^https?:\/\//i.test(target)) {
|
|
5579
5901
|
const res = await fetch(target);
|
|
@@ -5582,7 +5904,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
5582
5904
|
}
|
|
5583
5905
|
return await res.json();
|
|
5584
5906
|
}
|
|
5585
|
-
const raw = await
|
|
5907
|
+
const raw = await import_node_fs23.promises.readFile(target, "utf8");
|
|
5586
5908
|
return JSON.parse(raw);
|
|
5587
5909
|
}
|
|
5588
5910
|
function indexEntries(entries) {
|
|
@@ -5650,23 +5972,23 @@ function canonicalJson(value) {
|
|
|
5650
5972
|
|
|
5651
5973
|
// src/projects.ts
|
|
5652
5974
|
init_cjs_shims();
|
|
5653
|
-
var
|
|
5975
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
5654
5976
|
function pathsForProject(project, baseDir) {
|
|
5655
5977
|
if (project === DEFAULT_PROJECT) {
|
|
5656
5978
|
return {
|
|
5657
|
-
snapshotPath:
|
|
5658
|
-
errorsPath:
|
|
5659
|
-
staleEventsPath:
|
|
5660
|
-
embeddingsCachePath:
|
|
5661
|
-
policyViolationsPath:
|
|
5979
|
+
snapshotPath: import_node_path37.default.join(baseDir, "graph.json"),
|
|
5980
|
+
errorsPath: import_node_path37.default.join(baseDir, "errors.ndjson"),
|
|
5981
|
+
staleEventsPath: import_node_path37.default.join(baseDir, "stale-events.ndjson"),
|
|
5982
|
+
embeddingsCachePath: import_node_path37.default.join(baseDir, "embeddings.json"),
|
|
5983
|
+
policyViolationsPath: import_node_path37.default.join(baseDir, "policy-violations.ndjson")
|
|
5662
5984
|
};
|
|
5663
5985
|
}
|
|
5664
5986
|
return {
|
|
5665
|
-
snapshotPath:
|
|
5666
|
-
errorsPath:
|
|
5667
|
-
staleEventsPath:
|
|
5668
|
-
embeddingsCachePath:
|
|
5669
|
-
policyViolationsPath:
|
|
5987
|
+
snapshotPath: import_node_path37.default.join(baseDir, `${project}.json`),
|
|
5988
|
+
errorsPath: import_node_path37.default.join(baseDir, `errors.${project}.ndjson`),
|
|
5989
|
+
staleEventsPath: import_node_path37.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
5990
|
+
embeddingsCachePath: import_node_path37.default.join(baseDir, `embeddings.${project}.json`),
|
|
5991
|
+
policyViolationsPath: import_node_path37.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5670
5992
|
};
|
|
5671
5993
|
}
|
|
5672
5994
|
var Projects = class {
|
|
@@ -5702,25 +6024,25 @@ var Projects = class {
|
|
|
5702
6024
|
|
|
5703
6025
|
// src/registry.ts
|
|
5704
6026
|
init_cjs_shims();
|
|
5705
|
-
var
|
|
6027
|
+
var import_node_fs24 = require("fs");
|
|
5706
6028
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
5707
|
-
var
|
|
5708
|
-
var
|
|
6029
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
6030
|
+
var import_types24 = require("@neat.is/types");
|
|
5709
6031
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
5710
6032
|
var LOCK_RETRY_MS = 50;
|
|
5711
6033
|
function neatHome() {
|
|
5712
6034
|
const override = process.env.NEAT_HOME;
|
|
5713
|
-
if (override && override.length > 0) return
|
|
5714
|
-
return
|
|
6035
|
+
if (override && override.length > 0) return import_node_path38.default.resolve(override);
|
|
6036
|
+
return import_node_path38.default.join(import_node_os3.default.homedir(), ".neat");
|
|
5715
6037
|
}
|
|
5716
6038
|
function registryPath() {
|
|
5717
|
-
return
|
|
6039
|
+
return import_node_path38.default.join(neatHome(), "projects.json");
|
|
5718
6040
|
}
|
|
5719
6041
|
function registryLockPath() {
|
|
5720
|
-
return
|
|
6042
|
+
return import_node_path38.default.join(neatHome(), "projects.json.lock");
|
|
5721
6043
|
}
|
|
5722
6044
|
function daemonPidPath() {
|
|
5723
|
-
return
|
|
6045
|
+
return import_node_path38.default.join(neatHome(), "neatd.pid");
|
|
5724
6046
|
}
|
|
5725
6047
|
function isPidAliveDefault(pid) {
|
|
5726
6048
|
try {
|
|
@@ -5732,7 +6054,7 @@ function isPidAliveDefault(pid) {
|
|
|
5732
6054
|
}
|
|
5733
6055
|
async function readPidFile(file) {
|
|
5734
6056
|
try {
|
|
5735
|
-
const raw = await
|
|
6057
|
+
const raw = await import_node_fs24.promises.readFile(file, "utf8");
|
|
5736
6058
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
5737
6059
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
5738
6060
|
} catch {
|
|
@@ -5780,32 +6102,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
5780
6102
|
}
|
|
5781
6103
|
}
|
|
5782
6104
|
async function normalizeProjectPath(input) {
|
|
5783
|
-
const resolved =
|
|
6105
|
+
const resolved = import_node_path38.default.resolve(input);
|
|
5784
6106
|
try {
|
|
5785
|
-
return await
|
|
6107
|
+
return await import_node_fs24.promises.realpath(resolved);
|
|
5786
6108
|
} catch {
|
|
5787
6109
|
return resolved;
|
|
5788
6110
|
}
|
|
5789
6111
|
}
|
|
5790
6112
|
async function writeAtomically(target, contents) {
|
|
5791
|
-
await
|
|
6113
|
+
await import_node_fs24.promises.mkdir(import_node_path38.default.dirname(target), { recursive: true });
|
|
5792
6114
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
5793
|
-
const fd = await
|
|
6115
|
+
const fd = await import_node_fs24.promises.open(tmp, "w");
|
|
5794
6116
|
try {
|
|
5795
6117
|
await fd.writeFile(contents, "utf8");
|
|
5796
6118
|
await fd.sync();
|
|
5797
6119
|
} finally {
|
|
5798
6120
|
await fd.close();
|
|
5799
6121
|
}
|
|
5800
|
-
await
|
|
6122
|
+
await import_node_fs24.promises.rename(tmp, target);
|
|
5801
6123
|
}
|
|
5802
6124
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
5803
6125
|
const deadline = Date.now() + timeoutMs;
|
|
5804
|
-
await
|
|
6126
|
+
await import_node_fs24.promises.mkdir(import_node_path38.default.dirname(lockPath), { recursive: true });
|
|
5805
6127
|
let probedHolder = false;
|
|
5806
6128
|
while (true) {
|
|
5807
6129
|
try {
|
|
5808
|
-
const fd = await
|
|
6130
|
+
const fd = await import_node_fs24.promises.open(lockPath, "wx");
|
|
5809
6131
|
try {
|
|
5810
6132
|
await fd.writeFile(`${process.pid}
|
|
5811
6133
|
`, "utf8");
|
|
@@ -5830,7 +6152,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
5830
6152
|
}
|
|
5831
6153
|
}
|
|
5832
6154
|
async function releaseLock(lockPath) {
|
|
5833
|
-
await
|
|
6155
|
+
await import_node_fs24.promises.unlink(lockPath).catch(() => {
|
|
5834
6156
|
});
|
|
5835
6157
|
}
|
|
5836
6158
|
async function withLock(fn) {
|
|
@@ -5846,7 +6168,7 @@ async function readRegistry() {
|
|
|
5846
6168
|
const file = registryPath();
|
|
5847
6169
|
let raw;
|
|
5848
6170
|
try {
|
|
5849
|
-
raw = await
|
|
6171
|
+
raw = await import_node_fs24.promises.readFile(file, "utf8");
|
|
5850
6172
|
} catch (err) {
|
|
5851
6173
|
if (err.code === "ENOENT") {
|
|
5852
6174
|
return { version: 1, projects: [] };
|
|
@@ -5854,10 +6176,10 @@ async function readRegistry() {
|
|
|
5854
6176
|
throw err;
|
|
5855
6177
|
}
|
|
5856
6178
|
const parsed = JSON.parse(raw);
|
|
5857
|
-
return
|
|
6179
|
+
return import_types24.RegistryFileSchema.parse(parsed);
|
|
5858
6180
|
}
|
|
5859
6181
|
async function writeRegistry(reg) {
|
|
5860
|
-
const validated =
|
|
6182
|
+
const validated = import_types24.RegistryFileSchema.parse(reg);
|
|
5861
6183
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
5862
6184
|
}
|
|
5863
6185
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -6120,11 +6442,11 @@ function registerRoutes(scope, ctx) {
|
|
|
6120
6442
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6121
6443
|
const parsed = [];
|
|
6122
6444
|
for (const c of candidates) {
|
|
6123
|
-
const r =
|
|
6445
|
+
const r = import_types25.DivergenceTypeSchema.safeParse(c);
|
|
6124
6446
|
if (!r.success) {
|
|
6125
6447
|
return reply.code(400).send({
|
|
6126
6448
|
error: `unknown divergence type "${c}"`,
|
|
6127
|
-
allowed:
|
|
6449
|
+
allowed: import_types25.DivergenceTypeSchema.options
|
|
6128
6450
|
});
|
|
6129
6451
|
}
|
|
6130
6452
|
parsed.push(r.data);
|
|
@@ -6337,7 +6659,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6337
6659
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
6338
6660
|
let violations = await log.readAll();
|
|
6339
6661
|
if (req.query.severity) {
|
|
6340
|
-
const sev =
|
|
6662
|
+
const sev = import_types25.PolicySeveritySchema.safeParse(req.query.severity);
|
|
6341
6663
|
if (!sev.success) {
|
|
6342
6664
|
return reply.code(400).send({
|
|
6343
6665
|
error: "invalid severity",
|
|
@@ -6354,7 +6676,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6354
6676
|
scope.post("/policies/check", async (req, reply) => {
|
|
6355
6677
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6356
6678
|
if (!proj) return;
|
|
6357
|
-
const parsed =
|
|
6679
|
+
const parsed = import_types25.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
6358
6680
|
if (!parsed.success) {
|
|
6359
6681
|
return reply.code(400).send({
|
|
6360
6682
|
error: "invalid /policies/check body",
|
|
@@ -6597,8 +6919,8 @@ init_otel_grpc();
|
|
|
6597
6919
|
|
|
6598
6920
|
// src/search.ts
|
|
6599
6921
|
init_cjs_shims();
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
6922
|
+
var import_node_fs25 = require("fs");
|
|
6923
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
6602
6924
|
var import_node_crypto3 = require("crypto");
|
|
6603
6925
|
var DEFAULT_LIMIT = 10;
|
|
6604
6926
|
var NOMIC_DIM = 768;
|
|
@@ -6728,7 +7050,7 @@ async function pickEmbedder() {
|
|
|
6728
7050
|
}
|
|
6729
7051
|
async function readCache(cachePath) {
|
|
6730
7052
|
try {
|
|
6731
|
-
const raw = await
|
|
7053
|
+
const raw = await import_node_fs25.promises.readFile(cachePath, "utf8");
|
|
6732
7054
|
const parsed = JSON.parse(raw);
|
|
6733
7055
|
if (parsed.version !== 1) return null;
|
|
6734
7056
|
return parsed;
|
|
@@ -6737,8 +7059,8 @@ async function readCache(cachePath) {
|
|
|
6737
7059
|
}
|
|
6738
7060
|
}
|
|
6739
7061
|
async function writeCache(cachePath, cache) {
|
|
6740
|
-
await
|
|
6741
|
-
await
|
|
7062
|
+
await import_node_fs25.promises.mkdir(import_node_path41.default.dirname(cachePath), { recursive: true });
|
|
7063
|
+
await import_node_fs25.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
6742
7064
|
}
|
|
6743
7065
|
var VectorIndex = class {
|
|
6744
7066
|
constructor(embedder, cachePath) {
|
|
@@ -6886,6 +7208,7 @@ async function buildSearchIndex(graph, options = {}) {
|
|
|
6886
7208
|
var ALL_PHASES = [
|
|
6887
7209
|
"services",
|
|
6888
7210
|
"aliases",
|
|
7211
|
+
"imports",
|
|
6889
7212
|
"databases",
|
|
6890
7213
|
"configs",
|
|
6891
7214
|
"calls",
|
|
@@ -6893,8 +7216,8 @@ var ALL_PHASES = [
|
|
|
6893
7216
|
];
|
|
6894
7217
|
function classifyChange(relPath) {
|
|
6895
7218
|
const phases = /* @__PURE__ */ new Set();
|
|
6896
|
-
const base =
|
|
6897
|
-
const segments = relPath.split(
|
|
7219
|
+
const base = import_node_path42.default.basename(relPath).toLowerCase();
|
|
7220
|
+
const segments = relPath.split(import_node_path42.default.sep).map((s) => s.toLowerCase());
|
|
6898
7221
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
6899
7222
|
phases.add("services");
|
|
6900
7223
|
phases.add("aliases");
|
|
@@ -6909,6 +7232,7 @@ function classifyChange(relPath) {
|
|
|
6909
7232
|
phases.add("aliases");
|
|
6910
7233
|
}
|
|
6911
7234
|
if (/\.(?:js|jsx|mjs|cjs|ts|tsx|py)$/.test(base)) {
|
|
7235
|
+
phases.add("imports");
|
|
6912
7236
|
phases.add("calls");
|
|
6913
7237
|
}
|
|
6914
7238
|
if (/\.ya?ml$/.test(base) && !/^docker-compose.*\.ya?ml$/.test(base)) {
|
|
@@ -6930,6 +7254,11 @@ async function runExtractPhases(graph, scanPath, phases, project = DEFAULT_PROJE
|
|
|
6930
7254
|
if (phases.has("aliases")) {
|
|
6931
7255
|
await addServiceAliases(graph, scanPath, services);
|
|
6932
7256
|
}
|
|
7257
|
+
if (phases.has("imports")) {
|
|
7258
|
+
const r = await addImports(graph, services);
|
|
7259
|
+
nodesAdded += r.nodesAdded;
|
|
7260
|
+
edgesAdded += r.edgesAdded;
|
|
7261
|
+
}
|
|
6933
7262
|
if (phases.has("databases")) {
|
|
6934
7263
|
const r = await addDatabasesAndCompat(graph, services, scanPath);
|
|
6935
7264
|
nodesAdded += r.nodesAdded;
|
|
@@ -7002,16 +7331,16 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
7002
7331
|
if (count >= limit) return;
|
|
7003
7332
|
let entries;
|
|
7004
7333
|
try {
|
|
7005
|
-
entries =
|
|
7334
|
+
entries = import_node_fs26.default.readdirSync(dir, { withFileTypes: true });
|
|
7006
7335
|
} catch {
|
|
7007
7336
|
return;
|
|
7008
7337
|
}
|
|
7009
7338
|
for (const e of entries) {
|
|
7010
7339
|
if (count >= limit) return;
|
|
7011
7340
|
if (!e.isDirectory()) continue;
|
|
7012
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
7341
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path42.default.join(dir, e.name) + import_node_path42.default.sep))) continue;
|
|
7013
7342
|
count++;
|
|
7014
|
-
if (depth < 2) visit(
|
|
7343
|
+
if (depth < 2) visit(import_node_path42.default.join(dir, e.name), depth + 1);
|
|
7015
7344
|
}
|
|
7016
7345
|
};
|
|
7017
7346
|
visit(scanPath, 0);
|
|
@@ -7029,8 +7358,8 @@ async function startWatch(graph, opts) {
|
|
|
7029
7358
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
7030
7359
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
7031
7360
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
7032
|
-
const policyFilePath =
|
|
7033
|
-
const policyViolationsPath =
|
|
7361
|
+
const policyFilePath = import_node_path42.default.join(opts.scanPath, "policy.json");
|
|
7362
|
+
const policyViolationsPath = import_node_path42.default.join(import_node_path42.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
7034
7363
|
let policies = [];
|
|
7035
7364
|
try {
|
|
7036
7365
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -7081,7 +7410,7 @@ async function startWatch(graph, opts) {
|
|
|
7081
7410
|
assertBindAuthority(host, auth.authToken);
|
|
7082
7411
|
const port = opts.port ?? 8080;
|
|
7083
7412
|
const otelPort = opts.otelPort ?? 4318;
|
|
7084
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
7413
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path42.default.join(import_node_path42.default.dirname(opts.outPath), "embeddings.json");
|
|
7085
7414
|
let searchIndex;
|
|
7086
7415
|
try {
|
|
7087
7416
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -7099,7 +7428,7 @@ async function startWatch(graph, opts) {
|
|
|
7099
7428
|
// Paths are derived from the explicit options the watch caller passes
|
|
7100
7429
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
7101
7430
|
// fields so the registry shape is complete.
|
|
7102
|
-
...pathsForProject(projectName,
|
|
7431
|
+
...pathsForProject(projectName, import_node_path42.default.dirname(opts.outPath)),
|
|
7103
7432
|
snapshotPath: opts.outPath,
|
|
7104
7433
|
errorsPath: opts.errorsPath,
|
|
7105
7434
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -7186,9 +7515,9 @@ async function startWatch(graph, opts) {
|
|
|
7186
7515
|
};
|
|
7187
7516
|
const onPath = (absPath) => {
|
|
7188
7517
|
if (shouldIgnore(absPath)) return;
|
|
7189
|
-
const rel =
|
|
7518
|
+
const rel = import_node_path42.default.relative(opts.scanPath, absPath);
|
|
7190
7519
|
if (!rel || rel.startsWith("..")) return;
|
|
7191
|
-
pendingPaths.add(rel.split(
|
|
7520
|
+
pendingPaths.add(rel.split(import_node_path42.default.sep).join("/"));
|
|
7192
7521
|
const phases = classifyChange(rel);
|
|
7193
7522
|
if (phases.size === 0) {
|
|
7194
7523
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -7242,8 +7571,8 @@ async function startWatch(graph, opts) {
|
|
|
7242
7571
|
|
|
7243
7572
|
// src/deploy/detect.ts
|
|
7244
7573
|
init_cjs_shims();
|
|
7245
|
-
var
|
|
7246
|
-
var
|
|
7574
|
+
var import_node_fs27 = require("fs");
|
|
7575
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
7247
7576
|
var import_node_child_process2 = require("child_process");
|
|
7248
7577
|
var import_node_crypto4 = require("crypto");
|
|
7249
7578
|
function generateToken() {
|
|
@@ -7343,21 +7672,21 @@ async function runDeploy(opts = {}) {
|
|
|
7343
7672
|
const token = generateToken();
|
|
7344
7673
|
switch (substrate) {
|
|
7345
7674
|
case "docker-compose": {
|
|
7346
|
-
const artifactPath =
|
|
7675
|
+
const artifactPath = import_node_path43.default.join(cwd, "docker-compose.neat.yml");
|
|
7347
7676
|
const contents = emitDockerCompose(cwd);
|
|
7348
|
-
await
|
|
7677
|
+
await import_node_fs27.promises.writeFile(artifactPath, contents, "utf8");
|
|
7349
7678
|
return {
|
|
7350
7679
|
substrate,
|
|
7351
7680
|
artifactPath,
|
|
7352
7681
|
token,
|
|
7353
7682
|
contents,
|
|
7354
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
7683
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path43.default.basename(artifactPath)} up -d`
|
|
7355
7684
|
};
|
|
7356
7685
|
}
|
|
7357
7686
|
case "systemd": {
|
|
7358
|
-
const artifactPath =
|
|
7687
|
+
const artifactPath = import_node_path43.default.join(cwd, "neat.service");
|
|
7359
7688
|
const contents = emitSystemdUnit(cwd);
|
|
7360
|
-
await
|
|
7689
|
+
await import_node_fs27.promises.writeFile(artifactPath, contents, "utf8");
|
|
7361
7690
|
return {
|
|
7362
7691
|
substrate,
|
|
7363
7692
|
artifactPath,
|
|
@@ -7390,8 +7719,8 @@ init_cjs_shims();
|
|
|
7390
7719
|
|
|
7391
7720
|
// src/installers/javascript.ts
|
|
7392
7721
|
init_cjs_shims();
|
|
7393
|
-
var
|
|
7394
|
-
var
|
|
7722
|
+
var import_node_fs28 = require("fs");
|
|
7723
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
7395
7724
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
7396
7725
|
|
|
7397
7726
|
// src/installers/templates.ts
|
|
@@ -7929,15 +8258,15 @@ var OTEL_ENV = {
|
|
|
7929
8258
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
7930
8259
|
};
|
|
7931
8260
|
function serviceNodeName(pkg, serviceDir) {
|
|
7932
|
-
return pkg.name ??
|
|
8261
|
+
return pkg.name ?? import_node_path44.default.basename(serviceDir);
|
|
7933
8262
|
}
|
|
7934
8263
|
function projectToken(pkg, serviceDir, project) {
|
|
7935
8264
|
if (project && project.length > 0) return project;
|
|
7936
|
-
return pkg.name ??
|
|
8265
|
+
return pkg.name ?? import_node_path44.default.basename(serviceDir);
|
|
7937
8266
|
}
|
|
7938
8267
|
async function readJsonFile(p) {
|
|
7939
8268
|
try {
|
|
7940
|
-
const raw = await
|
|
8269
|
+
const raw = await import_node_fs28.promises.readFile(p, "utf8");
|
|
7941
8270
|
return JSON.parse(raw);
|
|
7942
8271
|
} catch {
|
|
7943
8272
|
return null;
|
|
@@ -7946,16 +8275,16 @@ async function readJsonFile(p) {
|
|
|
7946
8275
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
7947
8276
|
const deps = allDeps(pkg);
|
|
7948
8277
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
7949
|
-
const appJson = await readJsonFile(
|
|
8278
|
+
const appJson = await readJsonFile(import_node_path44.default.join(pkgRoot, "app.json"));
|
|
7950
8279
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
7951
8280
|
return "react-native";
|
|
7952
8281
|
}
|
|
7953
|
-
if (await exists3(
|
|
8282
|
+
if (await exists3(import_node_path44.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path44.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path44.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
7954
8283
|
return "browser-bundle";
|
|
7955
8284
|
}
|
|
7956
|
-
if (await exists3(
|
|
7957
|
-
if (await exists3(
|
|
7958
|
-
if (await exists3(
|
|
8285
|
+
if (await exists3(import_node_path44.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
8286
|
+
if (await exists3(import_node_path44.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
8287
|
+
if (await exists3(import_node_path44.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path44.default.join(pkgRoot, "deno.lock"))) {
|
|
7959
8288
|
return "deno";
|
|
7960
8289
|
}
|
|
7961
8290
|
const engines = pkg.engines ?? {};
|
|
@@ -7964,7 +8293,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
7964
8293
|
}
|
|
7965
8294
|
async function readPackageJson2(serviceDir) {
|
|
7966
8295
|
try {
|
|
7967
|
-
const raw = await
|
|
8296
|
+
const raw = await import_node_fs28.promises.readFile(import_node_path44.default.join(serviceDir, "package.json"), "utf8");
|
|
7968
8297
|
return JSON.parse(raw);
|
|
7969
8298
|
} catch {
|
|
7970
8299
|
return null;
|
|
@@ -7972,7 +8301,7 @@ async function readPackageJson2(serviceDir) {
|
|
|
7972
8301
|
}
|
|
7973
8302
|
async function exists3(p) {
|
|
7974
8303
|
try {
|
|
7975
|
-
await
|
|
8304
|
+
await import_node_fs28.promises.stat(p);
|
|
7976
8305
|
return true;
|
|
7977
8306
|
} catch {
|
|
7978
8307
|
return false;
|
|
@@ -7980,7 +8309,7 @@ async function exists3(p) {
|
|
|
7980
8309
|
}
|
|
7981
8310
|
async function readFileMaybe(p) {
|
|
7982
8311
|
try {
|
|
7983
|
-
return await
|
|
8312
|
+
return await import_node_fs28.promises.readFile(p, "utf8");
|
|
7984
8313
|
} catch {
|
|
7985
8314
|
return null;
|
|
7986
8315
|
}
|
|
@@ -8008,7 +8337,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
8008
8337
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
8009
8338
|
async function findNextConfig(serviceDir) {
|
|
8010
8339
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
8011
|
-
const candidate =
|
|
8340
|
+
const candidate = import_node_path44.default.join(serviceDir, name);
|
|
8012
8341
|
if (await exists3(candidate)) return candidate;
|
|
8013
8342
|
}
|
|
8014
8343
|
return null;
|
|
@@ -8035,7 +8364,7 @@ function hasRemixDependency(pkg) {
|
|
|
8035
8364
|
}
|
|
8036
8365
|
async function findRemixEntry(serviceDir) {
|
|
8037
8366
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
8038
|
-
const candidate =
|
|
8367
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8039
8368
|
if (await exists3(candidate)) return candidate;
|
|
8040
8369
|
}
|
|
8041
8370
|
return null;
|
|
@@ -8047,14 +8376,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
8047
8376
|
}
|
|
8048
8377
|
async function findSvelteKitHooks(serviceDir) {
|
|
8049
8378
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
8050
|
-
const candidate =
|
|
8379
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8051
8380
|
if (await exists3(candidate)) return candidate;
|
|
8052
8381
|
}
|
|
8053
8382
|
return null;
|
|
8054
8383
|
}
|
|
8055
8384
|
async function findSvelteKitConfig(serviceDir) {
|
|
8056
8385
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
8057
|
-
const candidate =
|
|
8386
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8058
8387
|
if (await exists3(candidate)) return candidate;
|
|
8059
8388
|
}
|
|
8060
8389
|
return null;
|
|
@@ -8065,7 +8394,7 @@ function hasNuxtDependency(pkg) {
|
|
|
8065
8394
|
}
|
|
8066
8395
|
async function findNuxtConfig(serviceDir) {
|
|
8067
8396
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
8068
|
-
const candidate =
|
|
8397
|
+
const candidate = import_node_path44.default.join(serviceDir, name);
|
|
8069
8398
|
if (await exists3(candidate)) return candidate;
|
|
8070
8399
|
}
|
|
8071
8400
|
return null;
|
|
@@ -8076,7 +8405,7 @@ function hasAstroDependency(pkg) {
|
|
|
8076
8405
|
}
|
|
8077
8406
|
async function findAstroConfig(serviceDir) {
|
|
8078
8407
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
8079
|
-
const candidate =
|
|
8408
|
+
const candidate = import_node_path44.default.join(serviceDir, name);
|
|
8080
8409
|
if (await exists3(candidate)) return candidate;
|
|
8081
8410
|
}
|
|
8082
8411
|
return null;
|
|
@@ -8090,7 +8419,7 @@ function parseNextMajor(range) {
|
|
|
8090
8419
|
return Number.isFinite(n) ? n : null;
|
|
8091
8420
|
}
|
|
8092
8421
|
async function isTypeScriptProject(serviceDir) {
|
|
8093
|
-
return exists3(
|
|
8422
|
+
return exists3(import_node_path44.default.join(serviceDir, "tsconfig.json"));
|
|
8094
8423
|
}
|
|
8095
8424
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
8096
8425
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -8136,7 +8465,7 @@ function entryFromScript(script) {
|
|
|
8136
8465
|
}
|
|
8137
8466
|
async function resolveEntry(serviceDir, pkg) {
|
|
8138
8467
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
8139
|
-
const candidate =
|
|
8468
|
+
const candidate = import_node_path44.default.resolve(serviceDir, pkg.main);
|
|
8140
8469
|
if (await exists3(candidate)) return candidate;
|
|
8141
8470
|
}
|
|
8142
8471
|
if (pkg.bin) {
|
|
@@ -8150,36 +8479,36 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
8150
8479
|
if (typeof first === "string") binEntry = first;
|
|
8151
8480
|
}
|
|
8152
8481
|
if (binEntry) {
|
|
8153
|
-
const candidate =
|
|
8482
|
+
const candidate = import_node_path44.default.resolve(serviceDir, binEntry);
|
|
8154
8483
|
if (await exists3(candidate)) return candidate;
|
|
8155
8484
|
}
|
|
8156
8485
|
}
|
|
8157
8486
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
8158
8487
|
if (startEntry) {
|
|
8159
|
-
const candidate =
|
|
8488
|
+
const candidate = import_node_path44.default.resolve(serviceDir, startEntry);
|
|
8160
8489
|
if (await exists3(candidate)) return candidate;
|
|
8161
8490
|
}
|
|
8162
8491
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
8163
8492
|
if (devEntry) {
|
|
8164
|
-
const candidate =
|
|
8493
|
+
const candidate = import_node_path44.default.resolve(serviceDir, devEntry);
|
|
8165
8494
|
if (await exists3(candidate)) return candidate;
|
|
8166
8495
|
}
|
|
8167
8496
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
8168
|
-
const candidate =
|
|
8497
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8169
8498
|
if (await exists3(candidate)) return candidate;
|
|
8170
8499
|
}
|
|
8171
8500
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
8172
|
-
const candidate =
|
|
8501
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8173
8502
|
if (await exists3(candidate)) return candidate;
|
|
8174
8503
|
}
|
|
8175
8504
|
for (const name of INDEX_CANDIDATES) {
|
|
8176
|
-
const candidate =
|
|
8505
|
+
const candidate = import_node_path44.default.join(serviceDir, name);
|
|
8177
8506
|
if (await exists3(candidate)) return candidate;
|
|
8178
8507
|
}
|
|
8179
8508
|
return null;
|
|
8180
8509
|
}
|
|
8181
8510
|
function dispatchEntry(entryFile, pkg) {
|
|
8182
|
-
const ext =
|
|
8511
|
+
const ext = import_node_path44.default.extname(entryFile).toLowerCase();
|
|
8183
8512
|
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
8184
8513
|
if (ext === ".mjs") return "esm";
|
|
8185
8514
|
if (ext === ".cjs") return "cjs";
|
|
@@ -8196,9 +8525,9 @@ function otelInitContents(flavor) {
|
|
|
8196
8525
|
return OTEL_INIT_CJS;
|
|
8197
8526
|
}
|
|
8198
8527
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
8199
|
-
let rel =
|
|
8528
|
+
let rel = import_node_path44.default.relative(import_node_path44.default.dirname(entryFile), otelInitFile);
|
|
8200
8529
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
8201
|
-
rel = rel.split(
|
|
8530
|
+
rel = rel.split(import_node_path44.default.sep).join("/");
|
|
8202
8531
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
8203
8532
|
if (flavor === "esm") return `import '${rel}'`;
|
|
8204
8533
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -8211,23 +8540,23 @@ function lineIsOtelInjection(line) {
|
|
|
8211
8540
|
}
|
|
8212
8541
|
async function detectsSrcLayout(serviceDir) {
|
|
8213
8542
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
8214
|
-
exists3(
|
|
8215
|
-
exists3(
|
|
8216
|
-
exists3(
|
|
8217
|
-
exists3(
|
|
8543
|
+
exists3(import_node_path44.default.join(serviceDir, "src", "app")),
|
|
8544
|
+
exists3(import_node_path44.default.join(serviceDir, "src", "pages")),
|
|
8545
|
+
exists3(import_node_path44.default.join(serviceDir, "app")),
|
|
8546
|
+
exists3(import_node_path44.default.join(serviceDir, "pages"))
|
|
8218
8547
|
]);
|
|
8219
8548
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
8220
8549
|
}
|
|
8221
8550
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
8222
8551
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8223
8552
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
8224
|
-
const baseDir = srcLayout ?
|
|
8225
|
-
const instrumentationFile =
|
|
8226
|
-
const instrumentationNodeFile =
|
|
8553
|
+
const baseDir = srcLayout ? import_node_path44.default.join(serviceDir, "src") : serviceDir;
|
|
8554
|
+
const instrumentationFile = import_node_path44.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
8555
|
+
const instrumentationNodeFile = import_node_path44.default.join(
|
|
8227
8556
|
baseDir,
|
|
8228
8557
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
8229
8558
|
);
|
|
8230
|
-
const envNeatFile =
|
|
8559
|
+
const envNeatFile = import_node_path44.default.join(baseDir, ".env.neat");
|
|
8231
8560
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
8232
8561
|
const dependencyEdits = [];
|
|
8233
8562
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -8284,7 +8613,7 @@ async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project)
|
|
|
8284
8613
|
const nextMajor = parseNextMajor(nextRange);
|
|
8285
8614
|
if (nextMajor !== null && nextMajor < 15) {
|
|
8286
8615
|
try {
|
|
8287
|
-
const raw = await
|
|
8616
|
+
const raw = await import_node_fs28.promises.readFile(nextConfigPath, "utf8");
|
|
8288
8617
|
if (!raw.includes("instrumentationHook")) {
|
|
8289
8618
|
nextConfigEdit = {
|
|
8290
8619
|
file: nextConfigPath,
|
|
@@ -8332,7 +8661,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
8332
8661
|
return edits;
|
|
8333
8662
|
}
|
|
8334
8663
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
8335
|
-
const envNeatFile =
|
|
8664
|
+
const envNeatFile = import_node_path44.default.join(serviceDir, ".env.neat");
|
|
8336
8665
|
if (!await exists3(envNeatFile)) {
|
|
8337
8666
|
generatedFiles.push({
|
|
8338
8667
|
file: envNeatFile,
|
|
@@ -8367,7 +8696,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
8367
8696
|
}
|
|
8368
8697
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
8369
8698
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8370
|
-
const otelServerFile =
|
|
8699
|
+
const otelServerFile = import_node_path44.default.join(
|
|
8371
8700
|
serviceDir,
|
|
8372
8701
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
8373
8702
|
);
|
|
@@ -8388,7 +8717,7 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
8388
8717
|
await queueEnvNeat(serviceDir, pkg, project, generatedFiles);
|
|
8389
8718
|
const entrypointEdits = [];
|
|
8390
8719
|
try {
|
|
8391
|
-
const raw = await
|
|
8720
|
+
const raw = await import_node_fs28.promises.readFile(entryFile, "utf8");
|
|
8392
8721
|
if (!fileImportsOtelHook(raw, ["./otel.server"])) {
|
|
8393
8722
|
const lines = raw.split(/\r?\n/);
|
|
8394
8723
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8424,11 +8753,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
8424
8753
|
}
|
|
8425
8754
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
8426
8755
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8427
|
-
const otelInitFile =
|
|
8756
|
+
const otelInitFile = import_node_path44.default.join(
|
|
8428
8757
|
serviceDir,
|
|
8429
8758
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
8430
8759
|
);
|
|
8431
|
-
const resolvedHooksFile = hooksFile ??
|
|
8760
|
+
const resolvedHooksFile = hooksFile ?? import_node_path44.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
8432
8761
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8433
8762
|
const generatedFiles = [];
|
|
8434
8763
|
const entrypointEdits = [];
|
|
@@ -8453,7 +8782,7 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
8453
8782
|
});
|
|
8454
8783
|
} else {
|
|
8455
8784
|
try {
|
|
8456
|
-
const raw = await
|
|
8785
|
+
const raw = await import_node_fs28.promises.readFile(hooksFile, "utf8");
|
|
8457
8786
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8458
8787
|
const lines = raw.split(/\r?\n/);
|
|
8459
8788
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8490,11 +8819,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
8490
8819
|
}
|
|
8491
8820
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
8492
8821
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8493
|
-
const otelPluginFile =
|
|
8822
|
+
const otelPluginFile = import_node_path44.default.join(
|
|
8494
8823
|
serviceDir,
|
|
8495
8824
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
8496
8825
|
);
|
|
8497
|
-
const otelInitFile =
|
|
8826
|
+
const otelInitFile = import_node_path44.default.join(
|
|
8498
8827
|
serviceDir,
|
|
8499
8828
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
8500
8829
|
);
|
|
@@ -8545,19 +8874,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
8545
8874
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
8546
8875
|
async function findAstroMiddleware(serviceDir) {
|
|
8547
8876
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
8548
|
-
const candidate =
|
|
8877
|
+
const candidate = import_node_path44.default.join(serviceDir, rel);
|
|
8549
8878
|
if (await exists3(candidate)) return candidate;
|
|
8550
8879
|
}
|
|
8551
8880
|
return null;
|
|
8552
8881
|
}
|
|
8553
8882
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
8554
8883
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8555
|
-
const otelInitFile =
|
|
8884
|
+
const otelInitFile = import_node_path44.default.join(
|
|
8556
8885
|
serviceDir,
|
|
8557
8886
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
8558
8887
|
);
|
|
8559
8888
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
8560
|
-
const middlewareFile = existingMiddleware ??
|
|
8889
|
+
const middlewareFile = existingMiddleware ?? import_node_path44.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
8561
8890
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8562
8891
|
const generatedFiles = [];
|
|
8563
8892
|
const entrypointEdits = [];
|
|
@@ -8582,7 +8911,7 @@ async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
|
8582
8911
|
});
|
|
8583
8912
|
} else {
|
|
8584
8913
|
try {
|
|
8585
|
-
const raw = await
|
|
8914
|
+
const raw = await import_node_fs28.promises.readFile(existingMiddleware, "utf8");
|
|
8586
8915
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8587
8916
|
const lines = raw.split(/\r?\n/);
|
|
8588
8917
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8653,7 +8982,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
8653
8982
|
}
|
|
8654
8983
|
async function plan(serviceDir, opts) {
|
|
8655
8984
|
const pkg = await readPackageJson2(serviceDir);
|
|
8656
|
-
const manifestPath =
|
|
8985
|
+
const manifestPath = import_node_path44.default.join(serviceDir, "package.json");
|
|
8657
8986
|
const project = opts?.project;
|
|
8658
8987
|
const empty = {
|
|
8659
8988
|
language: "javascript",
|
|
@@ -8688,8 +9017,8 @@ async function plan(serviceDir, opts) {
|
|
|
8688
9017
|
return { ...empty, libOnly: true };
|
|
8689
9018
|
}
|
|
8690
9019
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
8691
|
-
const otelInitFile =
|
|
8692
|
-
const envNeatFile =
|
|
9020
|
+
const otelInitFile = import_node_path44.default.join(import_node_path44.default.dirname(entryFile), otelInitFilename(flavor));
|
|
9021
|
+
const envNeatFile = import_node_path44.default.join(serviceDir, ".env.neat");
|
|
8693
9022
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
8694
9023
|
const dependencyEdits = [];
|
|
8695
9024
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -8713,7 +9042,7 @@ async function plan(serviceDir, opts) {
|
|
|
8713
9042
|
}
|
|
8714
9043
|
const entrypointEdits = [];
|
|
8715
9044
|
try {
|
|
8716
|
-
const raw = await
|
|
9045
|
+
const raw = await import_node_fs28.promises.readFile(entryFile, "utf8");
|
|
8717
9046
|
const lines = raw.split(/\r?\n/);
|
|
8718
9047
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
8719
9048
|
if (!lineIsOtelInjection(firstReal)) {
|
|
@@ -8758,13 +9087,13 @@ async function plan(serviceDir, opts) {
|
|
|
8758
9087
|
};
|
|
8759
9088
|
}
|
|
8760
9089
|
function isAllowedWritePath(serviceDir, target) {
|
|
8761
|
-
const rel =
|
|
9090
|
+
const rel = import_node_path44.default.relative(serviceDir, target);
|
|
8762
9091
|
if (rel.startsWith("..")) return false;
|
|
8763
|
-
const base =
|
|
9092
|
+
const base = import_node_path44.default.basename(target);
|
|
8764
9093
|
if (base === "package.json") return true;
|
|
8765
9094
|
if (base === ".env.neat") return true;
|
|
8766
9095
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
8767
|
-
const relPosix = rel.split(
|
|
9096
|
+
const relPosix = rel.split(import_node_path44.default.sep).join("/");
|
|
8768
9097
|
if (/^instrumentation(?:\.node)?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
8769
9098
|
if (relPosix === base) return true;
|
|
8770
9099
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -8781,10 +9110,10 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
8781
9110
|
return false;
|
|
8782
9111
|
}
|
|
8783
9112
|
async function writeAtomic(file, contents) {
|
|
8784
|
-
await
|
|
9113
|
+
await import_node_fs28.promises.mkdir(import_node_path44.default.dirname(file), { recursive: true });
|
|
8785
9114
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
8786
|
-
await
|
|
8787
|
-
await
|
|
9115
|
+
await import_node_fs28.promises.writeFile(tmp, contents, "utf8");
|
|
9116
|
+
await import_node_fs28.promises.rename(tmp, file);
|
|
8788
9117
|
}
|
|
8789
9118
|
async function apply(installPlan) {
|
|
8790
9119
|
const { serviceDir } = installPlan;
|
|
@@ -8860,7 +9189,7 @@ async function apply(installPlan) {
|
|
|
8860
9189
|
for (const target of allTargets) {
|
|
8861
9190
|
if (await exists3(target)) {
|
|
8862
9191
|
try {
|
|
8863
|
-
originals.set(target, await
|
|
9192
|
+
originals.set(target, await import_node_fs28.promises.readFile(target, "utf8"));
|
|
8864
9193
|
} catch {
|
|
8865
9194
|
}
|
|
8866
9195
|
}
|
|
@@ -8943,14 +9272,14 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
8943
9272
|
const removed = [];
|
|
8944
9273
|
for (const [file, raw] of originals.entries()) {
|
|
8945
9274
|
try {
|
|
8946
|
-
await
|
|
9275
|
+
await import_node_fs28.promises.writeFile(file, raw, "utf8");
|
|
8947
9276
|
restored.push(file);
|
|
8948
9277
|
} catch {
|
|
8949
9278
|
}
|
|
8950
9279
|
}
|
|
8951
9280
|
for (const file of createdFiles) {
|
|
8952
9281
|
try {
|
|
8953
|
-
await
|
|
9282
|
+
await import_node_fs28.promises.unlink(file);
|
|
8954
9283
|
removed.push(file);
|
|
8955
9284
|
} catch {
|
|
8956
9285
|
}
|
|
@@ -8965,8 +9294,8 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
8965
9294
|
...removed.map((f) => `removed: ${f}`),
|
|
8966
9295
|
""
|
|
8967
9296
|
];
|
|
8968
|
-
const rollbackPath =
|
|
8969
|
-
await
|
|
9297
|
+
const rollbackPath = import_node_path44.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
9298
|
+
await import_node_fs28.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
8970
9299
|
}
|
|
8971
9300
|
function injectInstrumentationHook(raw) {
|
|
8972
9301
|
if (raw.includes("instrumentationHook")) return raw;
|
|
@@ -8995,8 +9324,8 @@ var javascriptInstaller = {
|
|
|
8995
9324
|
|
|
8996
9325
|
// src/installers/python.ts
|
|
8997
9326
|
init_cjs_shims();
|
|
8998
|
-
var
|
|
8999
|
-
var
|
|
9327
|
+
var import_node_fs29 = require("fs");
|
|
9328
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
9000
9329
|
var SDK_PACKAGES2 = [
|
|
9001
9330
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
9002
9331
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -9008,7 +9337,7 @@ var OTEL_ENV2 = {
|
|
|
9008
9337
|
};
|
|
9009
9338
|
async function exists4(p) {
|
|
9010
9339
|
try {
|
|
9011
|
-
await
|
|
9340
|
+
await import_node_fs29.promises.stat(p);
|
|
9012
9341
|
return true;
|
|
9013
9342
|
} catch {
|
|
9014
9343
|
return false;
|
|
@@ -9017,7 +9346,7 @@ async function exists4(p) {
|
|
|
9017
9346
|
async function detect2(serviceDir) {
|
|
9018
9347
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
9019
9348
|
for (const m of markers) {
|
|
9020
|
-
if (await exists4(
|
|
9349
|
+
if (await exists4(import_node_path45.default.join(serviceDir, m))) return true;
|
|
9021
9350
|
}
|
|
9022
9351
|
return false;
|
|
9023
9352
|
}
|
|
@@ -9027,9 +9356,9 @@ function reqPackageName(line) {
|
|
|
9027
9356
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
9028
9357
|
}
|
|
9029
9358
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
9030
|
-
const file =
|
|
9359
|
+
const file = import_node_path45.default.join(serviceDir, "requirements.txt");
|
|
9031
9360
|
if (!await exists4(file)) return null;
|
|
9032
|
-
const raw = await
|
|
9361
|
+
const raw = await import_node_fs29.promises.readFile(file, "utf8");
|
|
9033
9362
|
const presentNames = new Set(
|
|
9034
9363
|
raw.split(/\r?\n/).map(reqPackageName).filter((n) => n.length > 0)
|
|
9035
9364
|
);
|
|
@@ -9037,9 +9366,9 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
9037
9366
|
return { manifest: file, missing: [...missing] };
|
|
9038
9367
|
}
|
|
9039
9368
|
async function planProcfileEdits(serviceDir) {
|
|
9040
|
-
const procfile =
|
|
9369
|
+
const procfile = import_node_path45.default.join(serviceDir, "Procfile");
|
|
9041
9370
|
if (!await exists4(procfile)) return [];
|
|
9042
|
-
const raw = await
|
|
9371
|
+
const raw = await import_node_fs29.promises.readFile(procfile, "utf8");
|
|
9043
9372
|
const edits = [];
|
|
9044
9373
|
for (const line of raw.split(/\r?\n/)) {
|
|
9045
9374
|
if (line.length === 0) continue;
|
|
@@ -9091,8 +9420,8 @@ async function applyRequirementsTxt(manifest, edits, original) {
|
|
|
9091
9420
|
const next = `${original}${trailing}${newlines.join("\n")}
|
|
9092
9421
|
`;
|
|
9093
9422
|
const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`;
|
|
9094
|
-
await
|
|
9095
|
-
await
|
|
9423
|
+
await import_node_fs29.promises.writeFile(tmp, next, "utf8");
|
|
9424
|
+
await import_node_fs29.promises.rename(tmp, manifest);
|
|
9096
9425
|
}
|
|
9097
9426
|
async function applyProcfile(procfile, edits, original) {
|
|
9098
9427
|
let next = original;
|
|
@@ -9101,8 +9430,8 @@ async function applyProcfile(procfile, edits, original) {
|
|
|
9101
9430
|
next = next.replace(e.before, e.after);
|
|
9102
9431
|
}
|
|
9103
9432
|
const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`;
|
|
9104
|
-
await
|
|
9105
|
-
await
|
|
9433
|
+
await import_node_fs29.promises.writeFile(tmp, next, "utf8");
|
|
9434
|
+
await import_node_fs29.promises.rename(tmp, procfile);
|
|
9106
9435
|
}
|
|
9107
9436
|
async function apply2(installPlan) {
|
|
9108
9437
|
const { serviceDir } = installPlan;
|
|
@@ -9115,7 +9444,7 @@ async function apply2(installPlan) {
|
|
|
9115
9444
|
const originals = /* @__PURE__ */ new Map();
|
|
9116
9445
|
for (const file of touched) {
|
|
9117
9446
|
try {
|
|
9118
|
-
originals.set(file, await
|
|
9447
|
+
originals.set(file, await import_node_fs29.promises.readFile(file, "utf8"));
|
|
9119
9448
|
} catch {
|
|
9120
9449
|
}
|
|
9121
9450
|
}
|
|
@@ -9126,7 +9455,7 @@ async function apply2(installPlan) {
|
|
|
9126
9455
|
if (raw === void 0) {
|
|
9127
9456
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
9128
9457
|
}
|
|
9129
|
-
const base =
|
|
9458
|
+
const base = import_node_path45.default.basename(file);
|
|
9130
9459
|
if (base === "requirements.txt") {
|
|
9131
9460
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
9132
9461
|
if (edits.length > 0) {
|
|
@@ -9151,7 +9480,7 @@ async function rollback2(installPlan, originals) {
|
|
|
9151
9480
|
const restored = [];
|
|
9152
9481
|
for (const [file, raw] of originals.entries()) {
|
|
9153
9482
|
try {
|
|
9154
|
-
await
|
|
9483
|
+
await import_node_fs29.promises.writeFile(file, raw, "utf8");
|
|
9155
9484
|
restored.push(file);
|
|
9156
9485
|
} catch {
|
|
9157
9486
|
}
|
|
@@ -9165,8 +9494,8 @@ async function rollback2(installPlan, originals) {
|
|
|
9165
9494
|
...restored.map((f) => `restored: ${f}`),
|
|
9166
9495
|
""
|
|
9167
9496
|
];
|
|
9168
|
-
const rollbackPath =
|
|
9169
|
-
await
|
|
9497
|
+
const rollbackPath = import_node_path45.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
9498
|
+
await import_node_fs29.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
9170
9499
|
}
|
|
9171
9500
|
var pythonInstaller = {
|
|
9172
9501
|
name: "python",
|
|
@@ -9289,10 +9618,10 @@ function renderPatch(sections) {
|
|
|
9289
9618
|
|
|
9290
9619
|
// src/orchestrator.ts
|
|
9291
9620
|
init_cjs_shims();
|
|
9292
|
-
var
|
|
9621
|
+
var import_node_fs30 = require("fs");
|
|
9293
9622
|
var import_node_http = __toESM(require("http"), 1);
|
|
9294
9623
|
var import_node_net = __toESM(require("net"), 1);
|
|
9295
|
-
var
|
|
9624
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
9296
9625
|
var import_node_child_process3 = require("child_process");
|
|
9297
9626
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
9298
9627
|
async function extractAndPersist(opts) {
|
|
@@ -9301,7 +9630,7 @@ async function extractAndPersist(opts) {
|
|
|
9301
9630
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
9302
9631
|
resetGraph(graphKey);
|
|
9303
9632
|
const graph = getGraph(graphKey);
|
|
9304
|
-
const projectPaths = pathsForProject(graphKey,
|
|
9633
|
+
const projectPaths = pathsForProject(graphKey, import_node_path46.default.join(opts.scanPath, "neat-out"));
|
|
9305
9634
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
9306
9635
|
errorsPath: projectPaths.errorsPath
|
|
9307
9636
|
});
|
|
@@ -9355,7 +9684,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9355
9684
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
9356
9685
|
} else if (outcome.outcome === "react-native") {
|
|
9357
9686
|
reactNative++;
|
|
9358
|
-
const svcName =
|
|
9687
|
+
const svcName = import_node_path46.default.basename(svc.dir);
|
|
9359
9688
|
console.log(
|
|
9360
9689
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
9361
9690
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9366,7 +9695,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9366
9695
|
);
|
|
9367
9696
|
} else if (outcome.outcome === "bun") {
|
|
9368
9697
|
bun++;
|
|
9369
|
-
const svcName =
|
|
9698
|
+
const svcName = import_node_path46.default.basename(svc.dir);
|
|
9370
9699
|
console.log(
|
|
9371
9700
|
`neat: ${svc.dir} detected as Bun
|
|
9372
9701
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9377,7 +9706,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9377
9706
|
);
|
|
9378
9707
|
} else if (outcome.outcome === "deno") {
|
|
9379
9708
|
deno++;
|
|
9380
|
-
const svcName =
|
|
9709
|
+
const svcName = import_node_path46.default.basename(svc.dir);
|
|
9381
9710
|
console.log(
|
|
9382
9711
|
`neat: ${svc.dir} detected as Deno
|
|
9383
9712
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9388,7 +9717,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9388
9717
|
);
|
|
9389
9718
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
9390
9719
|
cloudflareWorkers++;
|
|
9391
|
-
const svcName =
|
|
9720
|
+
const svcName = import_node_path46.default.basename(svc.dir);
|
|
9392
9721
|
console.log(
|
|
9393
9722
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
9394
9723
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9399,7 +9728,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9399
9728
|
);
|
|
9400
9729
|
} else if (outcome.outcome === "electron") {
|
|
9401
9730
|
electron++;
|
|
9402
|
-
const svcName =
|
|
9731
|
+
const svcName = import_node_path46.default.basename(svc.dir);
|
|
9403
9732
|
console.log(
|
|
9404
9733
|
`neat: ${svc.dir} detected as Electron
|
|
9405
9734
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9573,10 +9902,10 @@ function formatPortCollisionMessage(port) {
|
|
|
9573
9902
|
];
|
|
9574
9903
|
}
|
|
9575
9904
|
function spawnDaemonDetached() {
|
|
9576
|
-
const here =
|
|
9905
|
+
const here = import_node_path46.default.dirname(new URL(importMetaUrl).pathname);
|
|
9577
9906
|
const candidates = [
|
|
9578
|
-
|
|
9579
|
-
|
|
9907
|
+
import_node_path46.default.join(here, "neatd.cjs"),
|
|
9908
|
+
import_node_path46.default.join(here, "neatd.js")
|
|
9580
9909
|
];
|
|
9581
9910
|
let entry2 = null;
|
|
9582
9911
|
const fsSync = require("fs");
|
|
@@ -9634,7 +9963,7 @@ async function runOrchestrator(opts) {
|
|
|
9634
9963
|
browser: "skipped"
|
|
9635
9964
|
}
|
|
9636
9965
|
};
|
|
9637
|
-
const stat = await
|
|
9966
|
+
const stat = await import_node_fs30.promises.stat(opts.scanPath).catch(() => null);
|
|
9638
9967
|
if (!stat || !stat.isDirectory()) {
|
|
9639
9968
|
console.error(`neat: ${opts.scanPath} is not a directory`);
|
|
9640
9969
|
result.exitCode = 2;
|
|
@@ -9777,11 +10106,11 @@ function printSummary(result, graph, dashboardUrl) {
|
|
|
9777
10106
|
|
|
9778
10107
|
// src/cli-verbs.ts
|
|
9779
10108
|
init_cjs_shims();
|
|
9780
|
-
var
|
|
10109
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9781
10110
|
|
|
9782
10111
|
// src/cli-client.ts
|
|
9783
10112
|
init_cjs_shims();
|
|
9784
|
-
var
|
|
10113
|
+
var import_types26 = require("@neat.is/types");
|
|
9785
10114
|
var HttpError = class extends Error {
|
|
9786
10115
|
constructor(status2, message, responseBody = "") {
|
|
9787
10116
|
super(message);
|
|
@@ -9806,10 +10135,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9806
10135
|
const root = baseUrl.replace(/\/$/, "");
|
|
9807
10136
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
9808
10137
|
return {
|
|
9809
|
-
async get(
|
|
10138
|
+
async get(path49) {
|
|
9810
10139
|
let res;
|
|
9811
10140
|
try {
|
|
9812
|
-
res = await fetch(`${root}${
|
|
10141
|
+
res = await fetch(`${root}${path49}`, {
|
|
9813
10142
|
headers: { ...authHeader }
|
|
9814
10143
|
});
|
|
9815
10144
|
} catch (err) {
|
|
@@ -9821,16 +10150,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9821
10150
|
const body = await res.text().catch(() => "");
|
|
9822
10151
|
throw new HttpError(
|
|
9823
10152
|
res.status,
|
|
9824
|
-
`${res.status} ${res.statusText} on GET ${
|
|
10153
|
+
`${res.status} ${res.statusText} on GET ${path49}: ${body}`,
|
|
9825
10154
|
body
|
|
9826
10155
|
);
|
|
9827
10156
|
}
|
|
9828
10157
|
return await res.json();
|
|
9829
10158
|
},
|
|
9830
|
-
async post(
|
|
10159
|
+
async post(path49, body) {
|
|
9831
10160
|
let res;
|
|
9832
10161
|
try {
|
|
9833
|
-
res = await fetch(`${root}${
|
|
10162
|
+
res = await fetch(`${root}${path49}`, {
|
|
9834
10163
|
method: "POST",
|
|
9835
10164
|
headers: { "content-type": "application/json", ...authHeader },
|
|
9836
10165
|
body: JSON.stringify(body)
|
|
@@ -9844,7 +10173,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9844
10173
|
const text = await res.text().catch(() => "");
|
|
9845
10174
|
throw new HttpError(
|
|
9846
10175
|
res.status,
|
|
9847
|
-
`${res.status} ${res.statusText} on POST ${
|
|
10176
|
+
`${res.status} ${res.statusText} on POST ${path49}: ${text}`,
|
|
9848
10177
|
text
|
|
9849
10178
|
);
|
|
9850
10179
|
}
|
|
@@ -9858,12 +10187,12 @@ function projectPath(project, suffix) {
|
|
|
9858
10187
|
}
|
|
9859
10188
|
async function runRootCause(client, input) {
|
|
9860
10189
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
9861
|
-
const
|
|
10190
|
+
const path49 = projectPath(
|
|
9862
10191
|
input.project,
|
|
9863
10192
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
9864
10193
|
);
|
|
9865
10194
|
try {
|
|
9866
|
-
const result = await client.get(
|
|
10195
|
+
const result = await client.get(path49);
|
|
9867
10196
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
9868
10197
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
9869
10198
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -9889,12 +10218,12 @@ async function runRootCause(client, input) {
|
|
|
9889
10218
|
}
|
|
9890
10219
|
async function runBlastRadius(client, input) {
|
|
9891
10220
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
9892
|
-
const
|
|
10221
|
+
const path49 = projectPath(
|
|
9893
10222
|
input.project,
|
|
9894
10223
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
9895
10224
|
);
|
|
9896
10225
|
try {
|
|
9897
|
-
const result = await client.get(
|
|
10226
|
+
const result = await client.get(path49);
|
|
9898
10227
|
if (result.totalAffected === 0) {
|
|
9899
10228
|
return {
|
|
9900
10229
|
summary: `${result.origin} has no downstream dependencies. Nothing else would break if it failed.`
|
|
@@ -9923,17 +10252,17 @@ async function runBlastRadius(client, input) {
|
|
|
9923
10252
|
}
|
|
9924
10253
|
}
|
|
9925
10254
|
function formatBlastEntry(n) {
|
|
9926
|
-
const tag = n.edgeProvenance ===
|
|
10255
|
+
const tag = n.edgeProvenance === import_types26.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
9927
10256
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
9928
10257
|
}
|
|
9929
10258
|
async function runDependencies(client, input) {
|
|
9930
10259
|
const depth = input.depth ?? 3;
|
|
9931
|
-
const
|
|
10260
|
+
const path49 = projectPath(
|
|
9932
10261
|
input.project,
|
|
9933
10262
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
9934
10263
|
);
|
|
9935
10264
|
try {
|
|
9936
|
-
const result = await client.get(
|
|
10265
|
+
const result = await client.get(path49);
|
|
9937
10266
|
if (result.total === 0) {
|
|
9938
10267
|
return {
|
|
9939
10268
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -9969,9 +10298,9 @@ async function runObservedDependencies(client, input) {
|
|
|
9969
10298
|
const edges = await client.get(
|
|
9970
10299
|
projectPath(input.project, `/graph/edges/${encodeURIComponent(input.nodeId)}`)
|
|
9971
10300
|
);
|
|
9972
|
-
const observed = edges.outbound.filter((e) => e.provenance ===
|
|
10301
|
+
const observed = edges.outbound.filter((e) => e.provenance === import_types26.Provenance.OBSERVED);
|
|
9973
10302
|
if (observed.length === 0) {
|
|
9974
|
-
const hasExtracted = edges.outbound.some((e) => e.provenance ===
|
|
10303
|
+
const hasExtracted = edges.outbound.some((e) => e.provenance === import_types26.Provenance.EXTRACTED);
|
|
9975
10304
|
const note = hasExtracted ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
9976
10305
|
return { summary: `No OBSERVED dependencies for ${input.nodeId}.${note}` };
|
|
9977
10306
|
}
|
|
@@ -9979,7 +10308,7 @@ async function runObservedDependencies(client, input) {
|
|
|
9979
10308
|
return {
|
|
9980
10309
|
summary: `${input.nodeId} has ${observed.length} runtime dependenc${observed.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
9981
10310
|
block: blockLines.join("\n"),
|
|
9982
|
-
provenance:
|
|
10311
|
+
provenance: import_types26.Provenance.OBSERVED
|
|
9983
10312
|
};
|
|
9984
10313
|
} catch (err) {
|
|
9985
10314
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -10014,9 +10343,9 @@ function formatDuration(ms) {
|
|
|
10014
10343
|
return `${Math.round(h / 24)}d`;
|
|
10015
10344
|
}
|
|
10016
10345
|
async function runIncidents(client, input) {
|
|
10017
|
-
const
|
|
10346
|
+
const path49 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
10018
10347
|
try {
|
|
10019
|
-
const body = await client.get(
|
|
10348
|
+
const body = await client.get(path49);
|
|
10020
10349
|
const events = body.events;
|
|
10021
10350
|
if (events.length === 0) {
|
|
10022
10351
|
return {
|
|
@@ -10033,7 +10362,7 @@ async function runIncidents(client, input) {
|
|
|
10033
10362
|
return {
|
|
10034
10363
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
10035
10364
|
block: blockLines.join("\n"),
|
|
10036
|
-
provenance:
|
|
10365
|
+
provenance: import_types26.Provenance.OBSERVED
|
|
10037
10366
|
};
|
|
10038
10367
|
} catch (err) {
|
|
10039
10368
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -10142,7 +10471,7 @@ async function runStaleEdges(client, input) {
|
|
|
10142
10471
|
return {
|
|
10143
10472
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
10144
10473
|
block: blockLines.join("\n"),
|
|
10145
|
-
provenance:
|
|
10474
|
+
provenance: import_types26.Provenance.STALE
|
|
10146
10475
|
};
|
|
10147
10476
|
}
|
|
10148
10477
|
async function runPolicies(client, input) {
|
|
@@ -10306,7 +10635,7 @@ async function resolveProjectEntry(opts) {
|
|
|
10306
10635
|
const cwd = opts.cwd ?? process.cwd();
|
|
10307
10636
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
10308
10637
|
for (const entry2 of entries) {
|
|
10309
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
10638
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path47.default.sep}`)) {
|
|
10310
10639
|
return entry2;
|
|
10311
10640
|
}
|
|
10312
10641
|
}
|
|
@@ -10456,7 +10785,7 @@ async function runSync(opts) {
|
|
|
10456
10785
|
}
|
|
10457
10786
|
|
|
10458
10787
|
// src/cli.ts
|
|
10459
|
-
var
|
|
10788
|
+
var import_types27 = require("@neat.is/types");
|
|
10460
10789
|
function usage() {
|
|
10461
10790
|
console.log("usage: neat <command> [args] [--project <name>]");
|
|
10462
10791
|
console.log("");
|
|
@@ -10666,14 +10995,14 @@ function assignFlag(out, field, value) {
|
|
|
10666
10995
|
out[field] = value;
|
|
10667
10996
|
}
|
|
10668
10997
|
function readPackageVersion() {
|
|
10669
|
-
const here = typeof __dirname !== "undefined" ? __dirname :
|
|
10998
|
+
const here = typeof __dirname !== "undefined" ? __dirname : import_node_path48.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
10670
10999
|
const candidates = [
|
|
10671
|
-
|
|
10672
|
-
|
|
11000
|
+
import_node_path48.default.resolve(here, "../package.json"),
|
|
11001
|
+
import_node_path48.default.resolve(here, "../../package.json")
|
|
10673
11002
|
];
|
|
10674
11003
|
for (const candidate of candidates) {
|
|
10675
11004
|
try {
|
|
10676
|
-
const raw = (0,
|
|
11005
|
+
const raw = (0, import_node_fs31.readFileSync)(candidate, "utf8");
|
|
10677
11006
|
const parsed = JSON.parse(raw);
|
|
10678
11007
|
if (parsed.name === "@neat.is/core" && typeof parsed.version === "string") {
|
|
10679
11008
|
return parsed.version;
|
|
@@ -10737,7 +11066,7 @@ async function buildPatchSections(services, project) {
|
|
|
10737
11066
|
}
|
|
10738
11067
|
async function runInit(opts) {
|
|
10739
11068
|
const written = [];
|
|
10740
|
-
const stat = await
|
|
11069
|
+
const stat = await import_node_fs31.promises.stat(opts.scanPath).catch(() => null);
|
|
10741
11070
|
if (!stat || !stat.isDirectory()) {
|
|
10742
11071
|
console.error(`neat init: ${opts.scanPath} is not a directory`);
|
|
10743
11072
|
return { exitCode: 2, writtenFiles: written };
|
|
@@ -10746,13 +11075,13 @@ async function runInit(opts) {
|
|
|
10746
11075
|
printDiscoveryReport(opts, services);
|
|
10747
11076
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
10748
11077
|
const patch = renderPatch(sections);
|
|
10749
|
-
const patchPath =
|
|
11078
|
+
const patchPath = import_node_path48.default.join(opts.scanPath, "neat.patch");
|
|
10750
11079
|
if (opts.dryRun) {
|
|
10751
|
-
await
|
|
11080
|
+
await import_node_fs31.promises.writeFile(patchPath, patch, "utf8");
|
|
10752
11081
|
written.push(patchPath);
|
|
10753
11082
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
10754
|
-
const gitignorePath =
|
|
10755
|
-
const gitignoreExists = await
|
|
11083
|
+
const gitignorePath = import_node_path48.default.join(opts.scanPath, ".gitignore");
|
|
11084
|
+
const gitignoreExists = await import_node_fs31.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
10756
11085
|
const verb = gitignoreExists ? "append" : "create";
|
|
10757
11086
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
10758
11087
|
console.log("rerun without --dry-run to register and snapshot.");
|
|
@@ -10763,9 +11092,9 @@ async function runInit(opts) {
|
|
|
10763
11092
|
const graph = getGraph(graphKey);
|
|
10764
11093
|
const projectPaths = pathsForProject(
|
|
10765
11094
|
graphKey,
|
|
10766
|
-
|
|
11095
|
+
import_node_path48.default.join(opts.scanPath, "neat-out")
|
|
10767
11096
|
);
|
|
10768
|
-
const errorsPath =
|
|
11097
|
+
const errorsPath = import_node_path48.default.join(import_node_path48.default.dirname(opts.outPath), import_node_path48.default.basename(projectPaths.errorsPath));
|
|
10769
11098
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
10770
11099
|
await saveGraphToDisk(graph, opts.outPath);
|
|
10771
11100
|
written.push(opts.outPath);
|
|
@@ -10844,7 +11173,7 @@ async function runInit(opts) {
|
|
|
10844
11173
|
console.log("Run `npm install` (or your language equivalent) to refresh lockfiles.");
|
|
10845
11174
|
}
|
|
10846
11175
|
} else {
|
|
10847
|
-
await
|
|
11176
|
+
await import_node_fs31.promises.writeFile(patchPath, patch, "utf8");
|
|
10848
11177
|
written.push(patchPath);
|
|
10849
11178
|
}
|
|
10850
11179
|
}
|
|
@@ -10884,9 +11213,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
10884
11213
|
};
|
|
10885
11214
|
function claudeConfigPath() {
|
|
10886
11215
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
10887
|
-
if (override && override.length > 0) return
|
|
11216
|
+
if (override && override.length > 0) return import_node_path48.default.resolve(override);
|
|
10888
11217
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10889
|
-
return
|
|
11218
|
+
return import_node_path48.default.join(home, ".claude.json");
|
|
10890
11219
|
}
|
|
10891
11220
|
async function runSkill(opts) {
|
|
10892
11221
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -10898,7 +11227,7 @@ async function runSkill(opts) {
|
|
|
10898
11227
|
const target = claudeConfigPath();
|
|
10899
11228
|
let existing = {};
|
|
10900
11229
|
try {
|
|
10901
|
-
existing = JSON.parse(await
|
|
11230
|
+
existing = JSON.parse(await import_node_fs31.promises.readFile(target, "utf8"));
|
|
10902
11231
|
} catch (err) {
|
|
10903
11232
|
if (err.code !== "ENOENT") {
|
|
10904
11233
|
console.error(`neat skill: failed to read ${target} \u2014 ${err.message}`);
|
|
@@ -10910,8 +11239,8 @@ async function runSkill(opts) {
|
|
|
10910
11239
|
...existing,
|
|
10911
11240
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
10912
11241
|
};
|
|
10913
|
-
await
|
|
10914
|
-
await
|
|
11242
|
+
await import_node_fs31.promises.mkdir(import_node_path48.default.dirname(target), { recursive: true });
|
|
11243
|
+
await import_node_fs31.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
10915
11244
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
10916
11245
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
10917
11246
|
return { exitCode: 0 };
|
|
@@ -10949,12 +11278,12 @@ async function main() {
|
|
|
10949
11278
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
10950
11279
|
process.exit(2);
|
|
10951
11280
|
}
|
|
10952
|
-
const scanPath =
|
|
11281
|
+
const scanPath = import_node_path48.default.resolve(target);
|
|
10953
11282
|
const projectExplicit = parsed.project !== null;
|
|
10954
|
-
const projectName = projectExplicit ? project :
|
|
11283
|
+
const projectName = projectExplicit ? project : import_node_path48.default.basename(scanPath);
|
|
10955
11284
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
10956
|
-
const fallback = pathsForProject(projectKey,
|
|
10957
|
-
const outPath =
|
|
11285
|
+
const fallback = pathsForProject(projectKey, import_node_path48.default.join(scanPath, "neat-out")).snapshotPath;
|
|
11286
|
+
const outPath = import_node_path48.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
10958
11287
|
const result = await runInit({
|
|
10959
11288
|
scanPath,
|
|
10960
11289
|
outPath,
|
|
@@ -10975,21 +11304,21 @@ async function main() {
|
|
|
10975
11304
|
usage();
|
|
10976
11305
|
process.exit(2);
|
|
10977
11306
|
}
|
|
10978
|
-
const scanPath =
|
|
10979
|
-
const stat = await
|
|
11307
|
+
const scanPath = import_node_path48.default.resolve(target);
|
|
11308
|
+
const stat = await import_node_fs31.promises.stat(scanPath).catch(() => null);
|
|
10980
11309
|
if (!stat || !stat.isDirectory()) {
|
|
10981
11310
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
10982
11311
|
process.exit(2);
|
|
10983
11312
|
}
|
|
10984
|
-
const projectPaths = pathsForProject(project,
|
|
10985
|
-
const outPath =
|
|
10986
|
-
const errorsPath =
|
|
10987
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
11313
|
+
const projectPaths = pathsForProject(project, import_node_path48.default.join(scanPath, "neat-out"));
|
|
11314
|
+
const outPath = import_node_path48.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
11315
|
+
const errorsPath = import_node_path48.default.resolve(
|
|
11316
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path48.default.join(import_node_path48.default.dirname(outPath), import_node_path48.default.basename(projectPaths.errorsPath))
|
|
10988
11317
|
);
|
|
10989
|
-
const staleEventsPath =
|
|
10990
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
11318
|
+
const staleEventsPath = import_node_path48.default.resolve(
|
|
11319
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path48.default.join(import_node_path48.default.dirname(outPath), import_node_path48.default.basename(projectPaths.staleEventsPath))
|
|
10991
11320
|
);
|
|
10992
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
11321
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path48.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
10993
11322
|
const handle = await startWatch(getGraph(project), {
|
|
10994
11323
|
scanPath,
|
|
10995
11324
|
outPath,
|
|
@@ -11135,11 +11464,11 @@ async function main() {
|
|
|
11135
11464
|
process.exit(1);
|
|
11136
11465
|
}
|
|
11137
11466
|
async function tryOrchestrator(cmd, parsed) {
|
|
11138
|
-
const scanPath =
|
|
11139
|
-
const stat = await
|
|
11467
|
+
const scanPath = import_node_path48.default.resolve(cmd);
|
|
11468
|
+
const stat = await import_node_fs31.promises.stat(scanPath).catch(() => null);
|
|
11140
11469
|
if (!stat || !stat.isDirectory()) return null;
|
|
11141
11470
|
const projectExplicit = parsed.project !== null;
|
|
11142
|
-
const projectName = projectExplicit ? parsed.project :
|
|
11471
|
+
const projectName = projectExplicit ? parsed.project : import_node_path48.default.basename(scanPath);
|
|
11143
11472
|
const result = await runOrchestrator({
|
|
11144
11473
|
scanPath,
|
|
11145
11474
|
project: projectName,
|
|
@@ -11289,10 +11618,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
11289
11618
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
11290
11619
|
const out = [];
|
|
11291
11620
|
for (const p of parts) {
|
|
11292
|
-
const r =
|
|
11621
|
+
const r = import_types27.DivergenceTypeSchema.safeParse(p);
|
|
11293
11622
|
if (!r.success) {
|
|
11294
11623
|
console.error(
|
|
11295
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
11624
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types27.DivergenceTypeSchema.options.join(", ")}`
|
|
11296
11625
|
);
|
|
11297
11626
|
return 2;
|
|
11298
11627
|
}
|