@neat.is/core 0.4.11 → 0.4.12
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-W4RNPPB5.js → chunk-7JY6F7BY.js} +2 -2
- package/dist/{chunk-OJHI33LD.js → chunk-WDG4QEFO.js} +616 -173
- package/dist/chunk-WDG4QEFO.js.map +1 -0
- package/dist/cli.cjs +994 -534
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +189 -169
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +669 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +667 -224
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +802 -359
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-OJHI33LD.js.map +0 -1
- /package/dist/{chunk-W4RNPPB5.js.map → chunk-7JY6F7BY.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 path47 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
62
62
|
for (const suffix of suffixes) {
|
|
63
|
-
if (
|
|
63
|
+
if (path47 === suffix || path47.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_path37.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
190
|
+
return import_node_path37.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_path37, 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_path37 = __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_path38.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
375
|
+
const protoRoot = import_node_path38.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_path38.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_path38, 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_path38 = __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_path46 = __toESM(require("path"), 1);
|
|
604
|
+
var import_node_fs30 = 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, path47, edges) {
|
|
1135
|
+
if (path47.length > best.path.length) {
|
|
1136
|
+
best = { path: [...path47], edges: [...edges] };
|
|
1137
1137
|
}
|
|
1138
|
-
if (
|
|
1138
|
+
if (path47.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
|
+
path47.push(srcId);
|
|
1144
1144
|
edges.push(edge);
|
|
1145
|
-
step(srcId,
|
|
1146
|
-
|
|
1145
|
+
step(srcId, path47, edges);
|
|
1146
|
+
path47.pop();
|
|
1147
1147
|
edges.pop();
|
|
1148
1148
|
visited.delete(srcId);
|
|
1149
1149
|
}
|
|
@@ -1975,7 +1975,7 @@ function ensureFrontierNode(graph, host, ts) {
|
|
|
1975
1975
|
graph.addNode(id, node);
|
|
1976
1976
|
return id;
|
|
1977
1977
|
}
|
|
1978
|
-
function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
|
|
1978
|
+
function upsertObservedEdge(graph, type, source, target, ts, isError = false, evidence) {
|
|
1979
1979
|
if (!graph.hasNode(source) || !graph.hasNode(target)) return null;
|
|
1980
1980
|
const id = makeObservedEdgeId(type, source, target);
|
|
1981
1981
|
if (graph.hasEdge(id)) {
|
|
@@ -2012,7 +2012,10 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
|
|
|
2012
2012
|
confidence: (0, import_types3.confidenceForObservedSignal)(signal),
|
|
2013
2013
|
lastObserved: ts,
|
|
2014
2014
|
callCount: 1,
|
|
2015
|
-
signal
|
|
2015
|
+
signal,
|
|
2016
|
+
// Call-site evidence from span code.* semconv (file-awareness.md §4 + §6).
|
|
2017
|
+
// Only set when code.filepath was present on the span — never fabricated.
|
|
2018
|
+
...evidence ? { evidence } : {}
|
|
2016
2019
|
};
|
|
2017
2020
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
2018
2021
|
return { edge, created: true };
|
|
@@ -2106,6 +2109,7 @@ async function handleSpan(ctx, span) {
|
|
|
2106
2109
|
const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
|
|
2107
2110
|
const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
|
|
2108
2111
|
const observedSource = () => callSite ? ensureObservedFileNode(ctx.graph, span.service, sourceId, callSite) : sourceId;
|
|
2112
|
+
const callSiteEvidence = callSite ? { file: callSite.relPath, ...callSite.line !== void 0 ? { line: callSite.line } : {} } : void 0;
|
|
2109
2113
|
let affectedNode = sourceId;
|
|
2110
2114
|
const mintsFromCallerSide = spanMintsObservedEdge(span.kind);
|
|
2111
2115
|
if (span.dbSystem) {
|
|
@@ -2119,7 +2123,8 @@ async function handleSpan(ctx, span) {
|
|
|
2119
2123
|
observedSource(),
|
|
2120
2124
|
targetId,
|
|
2121
2125
|
ts,
|
|
2122
|
-
isError
|
|
2126
|
+
isError,
|
|
2127
|
+
callSiteEvidence
|
|
2123
2128
|
);
|
|
2124
2129
|
if (result) affectedNode = targetId;
|
|
2125
2130
|
}
|
|
@@ -2135,7 +2140,8 @@ async function handleSpan(ctx, span) {
|
|
|
2135
2140
|
observedSource(),
|
|
2136
2141
|
targetId,
|
|
2137
2142
|
ts,
|
|
2138
|
-
isError
|
|
2143
|
+
isError,
|
|
2144
|
+
callSiteEvidence
|
|
2139
2145
|
);
|
|
2140
2146
|
affectedNode = targetId;
|
|
2141
2147
|
resolvedViaAddress = true;
|
|
@@ -2147,7 +2153,8 @@ async function handleSpan(ctx, span) {
|
|
|
2147
2153
|
observedSource(),
|
|
2148
2154
|
frontierNodeId,
|
|
2149
2155
|
ts,
|
|
2150
|
-
isError
|
|
2156
|
+
isError,
|
|
2157
|
+
callSiteEvidence
|
|
2151
2158
|
);
|
|
2152
2159
|
affectedNode = frontierNodeId;
|
|
2153
2160
|
resolvedViaAddress = true;
|
|
@@ -3110,14 +3117,111 @@ async function addServiceAliases(graph, scanPath, services) {
|
|
|
3110
3117
|
|
|
3111
3118
|
// src/extract/databases/index.ts
|
|
3112
3119
|
init_cjs_shims();
|
|
3113
|
-
var
|
|
3120
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
3121
|
+
var import_types8 = require("@neat.is/types");
|
|
3122
|
+
|
|
3123
|
+
// src/extract/calls/shared.ts
|
|
3124
|
+
init_cjs_shims();
|
|
3125
|
+
var import_node_fs10 = require("fs");
|
|
3126
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
3114
3127
|
var import_types7 = require("@neat.is/types");
|
|
3128
|
+
async function walkSourceFiles(dir) {
|
|
3129
|
+
const out = [];
|
|
3130
|
+
async function walk(current) {
|
|
3131
|
+
const entries = await import_node_fs10.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
3132
|
+
for (const entry2 of entries) {
|
|
3133
|
+
const full = import_node_path10.default.join(current, entry2.name);
|
|
3134
|
+
if (entry2.isDirectory()) {
|
|
3135
|
+
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3136
|
+
if (await isPythonVenvDir(full)) continue;
|
|
3137
|
+
await walk(full);
|
|
3138
|
+
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path10.default.extname(entry2.name))) {
|
|
3139
|
+
out.push(full);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
await walk(dir);
|
|
3144
|
+
return out;
|
|
3145
|
+
}
|
|
3146
|
+
async function loadSourceFiles(dir) {
|
|
3147
|
+
const paths = await walkSourceFiles(dir);
|
|
3148
|
+
const out = [];
|
|
3149
|
+
for (const p of paths) {
|
|
3150
|
+
try {
|
|
3151
|
+
const content = await import_node_fs10.promises.readFile(p, "utf8");
|
|
3152
|
+
out.push({ path: p, content });
|
|
3153
|
+
} catch {
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
return out;
|
|
3157
|
+
}
|
|
3158
|
+
function lineOf(text, needle) {
|
|
3159
|
+
const idx = text.indexOf(needle);
|
|
3160
|
+
if (idx < 0) return 1;
|
|
3161
|
+
return text.slice(0, idx).split("\n").length;
|
|
3162
|
+
}
|
|
3163
|
+
function snippet(text, line) {
|
|
3164
|
+
const lines = text.split("\n");
|
|
3165
|
+
return (lines[line - 1] ?? "").trim();
|
|
3166
|
+
}
|
|
3167
|
+
function toPosix2(p) {
|
|
3168
|
+
return p.split("\\").join("/");
|
|
3169
|
+
}
|
|
3170
|
+
function languageForPath(relPath) {
|
|
3171
|
+
switch (import_node_path10.default.extname(relPath).toLowerCase()) {
|
|
3172
|
+
case ".py":
|
|
3173
|
+
return "python";
|
|
3174
|
+
case ".ts":
|
|
3175
|
+
case ".tsx":
|
|
3176
|
+
return "typescript";
|
|
3177
|
+
case ".js":
|
|
3178
|
+
case ".jsx":
|
|
3179
|
+
case ".mjs":
|
|
3180
|
+
case ".cjs":
|
|
3181
|
+
return "javascript";
|
|
3182
|
+
default:
|
|
3183
|
+
return void 0;
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
3187
|
+
let nodesAdded = 0;
|
|
3188
|
+
let edgesAdded = 0;
|
|
3189
|
+
const fileNodeId = (0, import_types7.fileId)(serviceName, relPath);
|
|
3190
|
+
if (!graph.hasNode(fileNodeId)) {
|
|
3191
|
+
const language = languageForPath(relPath);
|
|
3192
|
+
const node = {
|
|
3193
|
+
id: fileNodeId,
|
|
3194
|
+
type: import_types7.NodeType.FileNode,
|
|
3195
|
+
service: serviceName,
|
|
3196
|
+
path: relPath,
|
|
3197
|
+
...language ? { language } : {},
|
|
3198
|
+
discoveredVia: "static"
|
|
3199
|
+
};
|
|
3200
|
+
graph.addNode(fileNodeId, node);
|
|
3201
|
+
nodesAdded++;
|
|
3202
|
+
}
|
|
3203
|
+
const containsId = (0, import_types7.extractedEdgeId)(serviceNodeId, fileNodeId, import_types7.EdgeType.CONTAINS);
|
|
3204
|
+
if (!graph.hasEdge(containsId)) {
|
|
3205
|
+
const edge = {
|
|
3206
|
+
id: containsId,
|
|
3207
|
+
source: serviceNodeId,
|
|
3208
|
+
target: fileNodeId,
|
|
3209
|
+
type: import_types7.EdgeType.CONTAINS,
|
|
3210
|
+
provenance: import_types7.Provenance.EXTRACTED,
|
|
3211
|
+
confidence: (0, import_types7.confidenceForExtracted)("structural"),
|
|
3212
|
+
evidence: { file: relPath }
|
|
3213
|
+
};
|
|
3214
|
+
graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge);
|
|
3215
|
+
edgesAdded++;
|
|
3216
|
+
}
|
|
3217
|
+
return { fileNodeId, nodesAdded, edgesAdded };
|
|
3218
|
+
}
|
|
3115
3219
|
|
|
3116
3220
|
// src/extract/databases/db-config-yaml.ts
|
|
3117
3221
|
init_cjs_shims();
|
|
3118
|
-
var
|
|
3222
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
3119
3223
|
async function parse(serviceDir) {
|
|
3120
|
-
const yamlPath =
|
|
3224
|
+
const yamlPath = import_node_path11.default.join(serviceDir, "db-config.yaml");
|
|
3121
3225
|
if (!await exists(yamlPath)) return [];
|
|
3122
3226
|
const raw = await readYaml(yamlPath);
|
|
3123
3227
|
return [
|
|
@@ -3135,13 +3239,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
|
|
|
3135
3239
|
|
|
3136
3240
|
// src/extract/databases/dotenv.ts
|
|
3137
3241
|
init_cjs_shims();
|
|
3138
|
-
var
|
|
3139
|
-
var
|
|
3242
|
+
var import_node_fs12 = require("fs");
|
|
3243
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
3140
3244
|
|
|
3141
3245
|
// src/extract/databases/shared.ts
|
|
3142
3246
|
init_cjs_shims();
|
|
3143
|
-
var
|
|
3144
|
-
var
|
|
3247
|
+
var import_node_fs11 = require("fs");
|
|
3248
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
3145
3249
|
function schemeToEngine(scheme) {
|
|
3146
3250
|
const s = scheme.toLowerCase().split("+")[0];
|
|
3147
3251
|
switch (s) {
|
|
@@ -3180,14 +3284,14 @@ function parseConnectionString(url) {
|
|
|
3180
3284
|
}
|
|
3181
3285
|
async function readIfExists(filePath) {
|
|
3182
3286
|
try {
|
|
3183
|
-
return await
|
|
3287
|
+
return await import_node_fs11.promises.readFile(filePath, "utf8");
|
|
3184
3288
|
} catch {
|
|
3185
3289
|
return null;
|
|
3186
3290
|
}
|
|
3187
3291
|
}
|
|
3188
3292
|
async function findFirst(serviceDir, candidates) {
|
|
3189
3293
|
for (const rel of candidates) {
|
|
3190
|
-
const abs =
|
|
3294
|
+
const abs = import_node_path12.default.join(serviceDir, rel);
|
|
3191
3295
|
const content = await readIfExists(abs);
|
|
3192
3296
|
if (content !== null) return abs;
|
|
3193
3297
|
}
|
|
@@ -3238,15 +3342,15 @@ function parseDotenvLine(line) {
|
|
|
3238
3342
|
return { key, value };
|
|
3239
3343
|
}
|
|
3240
3344
|
async function parse2(serviceDir) {
|
|
3241
|
-
const entries = await
|
|
3345
|
+
const entries = await import_node_fs12.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
3242
3346
|
const configs = [];
|
|
3243
3347
|
const seen = /* @__PURE__ */ new Set();
|
|
3244
3348
|
for (const entry2 of entries) {
|
|
3245
3349
|
if (!entry2.isFile()) continue;
|
|
3246
3350
|
const match = isConfigFile(entry2.name);
|
|
3247
3351
|
if (!match.match || match.fileType !== "env") continue;
|
|
3248
|
-
const filePath =
|
|
3249
|
-
const content = await
|
|
3352
|
+
const filePath = import_node_path13.default.join(serviceDir, entry2.name);
|
|
3353
|
+
const content = await import_node_fs12.promises.readFile(filePath, "utf8");
|
|
3250
3354
|
for (const line of content.split("\n")) {
|
|
3251
3355
|
const parsed = parseDotenvLine(line);
|
|
3252
3356
|
if (!parsed) continue;
|
|
@@ -3265,9 +3369,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
|
|
|
3265
3369
|
|
|
3266
3370
|
// src/extract/databases/prisma.ts
|
|
3267
3371
|
init_cjs_shims();
|
|
3268
|
-
var
|
|
3372
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3269
3373
|
async function parse3(serviceDir) {
|
|
3270
|
-
const schemaPath =
|
|
3374
|
+
const schemaPath = import_node_path14.default.join(serviceDir, "prisma", "schema.prisma");
|
|
3271
3375
|
const content = await readIfExists(schemaPath);
|
|
3272
3376
|
if (!content) return [];
|
|
3273
3377
|
const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
|
|
@@ -3399,10 +3503,10 @@ var knexParser = { name: "knex", parse: parse5 };
|
|
|
3399
3503
|
|
|
3400
3504
|
// src/extract/databases/ormconfig.ts
|
|
3401
3505
|
init_cjs_shims();
|
|
3402
|
-
var
|
|
3506
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3403
3507
|
async function parse6(serviceDir) {
|
|
3404
3508
|
for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
|
|
3405
|
-
const abs =
|
|
3509
|
+
const abs = import_node_path15.default.join(serviceDir, candidate);
|
|
3406
3510
|
if (!await exists(abs)) continue;
|
|
3407
3511
|
const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
|
|
3408
3512
|
const entries = Array.isArray(raw) ? raw : [raw];
|
|
@@ -3462,9 +3566,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
|
|
|
3462
3566
|
|
|
3463
3567
|
// src/extract/databases/sequelize.ts
|
|
3464
3568
|
init_cjs_shims();
|
|
3465
|
-
var
|
|
3569
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3466
3570
|
async function parse8(serviceDir) {
|
|
3467
|
-
const configPath =
|
|
3571
|
+
const configPath = import_node_path16.default.join(serviceDir, "config", "config.json");
|
|
3468
3572
|
if (!await exists(configPath)) return [];
|
|
3469
3573
|
const raw = await readJson(configPath);
|
|
3470
3574
|
const out = [];
|
|
@@ -3491,7 +3595,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
|
3491
3595
|
|
|
3492
3596
|
// src/extract/databases/docker-compose.ts
|
|
3493
3597
|
init_cjs_shims();
|
|
3494
|
-
var
|
|
3598
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
3495
3599
|
function portFromService(svc) {
|
|
3496
3600
|
for (const raw of svc.ports ?? []) {
|
|
3497
3601
|
const str = String(raw);
|
|
@@ -3518,7 +3622,7 @@ function databaseFromEnv(svc) {
|
|
|
3518
3622
|
}
|
|
3519
3623
|
async function parse9(serviceDir) {
|
|
3520
3624
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
3521
|
-
const abs =
|
|
3625
|
+
const abs = import_node_path17.default.join(serviceDir, name);
|
|
3522
3626
|
if (!await exists(abs)) continue;
|
|
3523
3627
|
const raw = await readYaml(abs);
|
|
3524
3628
|
if (!raw?.services) return [];
|
|
@@ -3559,8 +3663,8 @@ function compatibleDriversFor(engine) {
|
|
|
3559
3663
|
}
|
|
3560
3664
|
function toDatabaseNode(config) {
|
|
3561
3665
|
return {
|
|
3562
|
-
id: (0,
|
|
3563
|
-
type:
|
|
3666
|
+
id: (0, import_types8.databaseId)(config.host),
|
|
3667
|
+
type: import_types8.NodeType.DatabaseNode,
|
|
3564
3668
|
name: config.database || config.host,
|
|
3565
3669
|
engine: config.engine,
|
|
3566
3670
|
engineVersion: config.engineVersion,
|
|
@@ -3690,19 +3794,24 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3690
3794
|
discoveredVia: mergedDiscoveredVia
|
|
3691
3795
|
});
|
|
3692
3796
|
}
|
|
3797
|
+
const relConfigFile = toPosix2(import_node_path18.default.relative(service.dir, config.sourceFile));
|
|
3798
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3799
|
+
graph,
|
|
3800
|
+
service.pkg.name,
|
|
3801
|
+
service.node.id,
|
|
3802
|
+
relConfigFile
|
|
3803
|
+
);
|
|
3804
|
+
nodesAdded += fn;
|
|
3805
|
+
edgesAdded += fe;
|
|
3806
|
+
const evidenceFile = toPosix2(import_node_path18.default.relative(scanPath, config.sourceFile));
|
|
3693
3807
|
const edge = {
|
|
3694
|
-
id: (0, import_types4.extractedEdgeId)(
|
|
3695
|
-
source:
|
|
3808
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id, import_types8.EdgeType.CONNECTS_TO),
|
|
3809
|
+
source: fileNodeId,
|
|
3696
3810
|
target: dbNode.id,
|
|
3697
|
-
type:
|
|
3698
|
-
provenance:
|
|
3699
|
-
confidence: (0,
|
|
3700
|
-
|
|
3701
|
-
// Ghost-edge cleanup keys retirement on this; the conditional
|
|
3702
|
-
// sourceFile spread that used to live here was a v0.1.x leftover.
|
|
3703
|
-
evidence: {
|
|
3704
|
-
file: import_node_path17.default.relative(scanPath, config.sourceFile).split(import_node_path17.default.sep).join("/")
|
|
3705
|
-
}
|
|
3811
|
+
type: import_types8.EdgeType.CONNECTS_TO,
|
|
3812
|
+
provenance: import_types8.Provenance.EXTRACTED,
|
|
3813
|
+
confidence: (0, import_types8.confidenceForExtracted)("structural"),
|
|
3814
|
+
evidence: { file: evidenceFile }
|
|
3706
3815
|
};
|
|
3707
3816
|
if (!graph.hasEdge(edge.id)) {
|
|
3708
3817
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -3728,15 +3837,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3728
3837
|
|
|
3729
3838
|
// src/extract/configs.ts
|
|
3730
3839
|
init_cjs_shims();
|
|
3731
|
-
var
|
|
3732
|
-
var
|
|
3733
|
-
var
|
|
3840
|
+
var import_node_fs13 = require("fs");
|
|
3841
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
3842
|
+
var import_types9 = require("@neat.is/types");
|
|
3734
3843
|
async function walkConfigFiles(dir) {
|
|
3735
3844
|
const out = [];
|
|
3736
3845
|
async function walk(current) {
|
|
3737
|
-
const entries = await
|
|
3846
|
+
const entries = await import_node_fs13.promises.readdir(current, { withFileTypes: true });
|
|
3738
3847
|
for (const entry2 of entries) {
|
|
3739
|
-
const full =
|
|
3848
|
+
const full = import_node_path19.default.join(current, entry2.name);
|
|
3740
3849
|
if (entry2.isDirectory()) {
|
|
3741
3850
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3742
3851
|
if (await isPythonVenvDir(full)) continue;
|
|
@@ -3755,26 +3864,35 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3755
3864
|
for (const service of services) {
|
|
3756
3865
|
const configFiles = await walkConfigFiles(service.dir);
|
|
3757
3866
|
for (const file of configFiles) {
|
|
3758
|
-
const relPath =
|
|
3867
|
+
const relPath = import_node_path19.default.relative(scanPath, file);
|
|
3759
3868
|
const node = {
|
|
3760
|
-
id: (0,
|
|
3761
|
-
type:
|
|
3762
|
-
name:
|
|
3869
|
+
id: (0, import_types9.configId)(relPath),
|
|
3870
|
+
type: import_types9.NodeType.ConfigNode,
|
|
3871
|
+
name: import_node_path19.default.basename(file),
|
|
3763
3872
|
path: relPath,
|
|
3764
|
-
fileType: isConfigFile(
|
|
3873
|
+
fileType: isConfigFile(import_node_path19.default.basename(file)).fileType
|
|
3765
3874
|
};
|
|
3766
3875
|
if (!graph.hasNode(node.id)) {
|
|
3767
3876
|
graph.addNode(node.id, node);
|
|
3768
3877
|
nodesAdded++;
|
|
3769
3878
|
}
|
|
3879
|
+
const relToService = toPosix2(import_node_path19.default.relative(service.dir, file));
|
|
3880
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3881
|
+
graph,
|
|
3882
|
+
service.pkg.name,
|
|
3883
|
+
service.node.id,
|
|
3884
|
+
relToService
|
|
3885
|
+
);
|
|
3886
|
+
nodesAdded += fn;
|
|
3887
|
+
edgesAdded += fe;
|
|
3770
3888
|
const edge = {
|
|
3771
|
-
id: (0, import_types4.extractedEdgeId)(
|
|
3772
|
-
source:
|
|
3889
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types9.EdgeType.CONFIGURED_BY),
|
|
3890
|
+
source: fileNodeId,
|
|
3773
3891
|
target: node.id,
|
|
3774
|
-
type:
|
|
3775
|
-
provenance:
|
|
3776
|
-
confidence: (0,
|
|
3777
|
-
evidence: { file: relPath.split(
|
|
3892
|
+
type: import_types9.EdgeType.CONFIGURED_BY,
|
|
3893
|
+
provenance: import_types9.Provenance.EXTRACTED,
|
|
3894
|
+
confidence: (0, import_types9.confidenceForExtracted)("structural"),
|
|
3895
|
+
evidence: { file: relPath.split(import_node_path19.default.sep).join("/") }
|
|
3778
3896
|
};
|
|
3779
3897
|
if (!graph.hasEdge(edge.id)) {
|
|
3780
3898
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -3796,105 +3914,6 @@ var import_tree_sitter = __toESM(require("tree-sitter"), 1);
|
|
|
3796
3914
|
var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
|
|
3797
3915
|
var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
|
|
3798
3916
|
var import_types10 = require("@neat.is/types");
|
|
3799
|
-
|
|
3800
|
-
// src/extract/calls/shared.ts
|
|
3801
|
-
init_cjs_shims();
|
|
3802
|
-
var import_node_fs13 = require("fs");
|
|
3803
|
-
var import_node_path19 = __toESM(require("path"), 1);
|
|
3804
|
-
var import_types9 = require("@neat.is/types");
|
|
3805
|
-
async function walkSourceFiles(dir) {
|
|
3806
|
-
const out = [];
|
|
3807
|
-
async function walk(current) {
|
|
3808
|
-
const entries = await import_node_fs13.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
3809
|
-
for (const entry2 of entries) {
|
|
3810
|
-
const full = import_node_path19.default.join(current, entry2.name);
|
|
3811
|
-
if (entry2.isDirectory()) {
|
|
3812
|
-
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3813
|
-
if (await isPythonVenvDir(full)) continue;
|
|
3814
|
-
await walk(full);
|
|
3815
|
-
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path19.default.extname(entry2.name))) {
|
|
3816
|
-
out.push(full);
|
|
3817
|
-
}
|
|
3818
|
-
}
|
|
3819
|
-
}
|
|
3820
|
-
await walk(dir);
|
|
3821
|
-
return out;
|
|
3822
|
-
}
|
|
3823
|
-
async function loadSourceFiles(dir) {
|
|
3824
|
-
const paths = await walkSourceFiles(dir);
|
|
3825
|
-
const out = [];
|
|
3826
|
-
for (const p of paths) {
|
|
3827
|
-
try {
|
|
3828
|
-
const content = await import_node_fs13.promises.readFile(p, "utf8");
|
|
3829
|
-
out.push({ path: p, content });
|
|
3830
|
-
} catch {
|
|
3831
|
-
}
|
|
3832
|
-
}
|
|
3833
|
-
return out;
|
|
3834
|
-
}
|
|
3835
|
-
function lineOf(text, needle) {
|
|
3836
|
-
const idx = text.indexOf(needle);
|
|
3837
|
-
if (idx < 0) return 1;
|
|
3838
|
-
return text.slice(0, idx).split("\n").length;
|
|
3839
|
-
}
|
|
3840
|
-
function snippet(text, line) {
|
|
3841
|
-
const lines = text.split("\n");
|
|
3842
|
-
return (lines[line - 1] ?? "").trim();
|
|
3843
|
-
}
|
|
3844
|
-
function toPosix2(p) {
|
|
3845
|
-
return p.split("\\").join("/");
|
|
3846
|
-
}
|
|
3847
|
-
function languageForPath(relPath) {
|
|
3848
|
-
switch (import_node_path19.default.extname(relPath).toLowerCase()) {
|
|
3849
|
-
case ".py":
|
|
3850
|
-
return "python";
|
|
3851
|
-
case ".ts":
|
|
3852
|
-
case ".tsx":
|
|
3853
|
-
return "typescript";
|
|
3854
|
-
case ".js":
|
|
3855
|
-
case ".jsx":
|
|
3856
|
-
case ".mjs":
|
|
3857
|
-
case ".cjs":
|
|
3858
|
-
return "javascript";
|
|
3859
|
-
default:
|
|
3860
|
-
return void 0;
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
3864
|
-
let nodesAdded = 0;
|
|
3865
|
-
let edgesAdded = 0;
|
|
3866
|
-
const fileNodeId = (0, import_types9.fileId)(serviceName, relPath);
|
|
3867
|
-
if (!graph.hasNode(fileNodeId)) {
|
|
3868
|
-
const language = languageForPath(relPath);
|
|
3869
|
-
const node = {
|
|
3870
|
-
id: fileNodeId,
|
|
3871
|
-
type: import_types9.NodeType.FileNode,
|
|
3872
|
-
service: serviceName,
|
|
3873
|
-
path: relPath,
|
|
3874
|
-
...language ? { language } : {},
|
|
3875
|
-
discoveredVia: "static"
|
|
3876
|
-
};
|
|
3877
|
-
graph.addNode(fileNodeId, node);
|
|
3878
|
-
nodesAdded++;
|
|
3879
|
-
}
|
|
3880
|
-
const containsId = (0, import_types9.extractedEdgeId)(serviceNodeId, fileNodeId, import_types9.EdgeType.CONTAINS);
|
|
3881
|
-
if (!graph.hasEdge(containsId)) {
|
|
3882
|
-
const edge = {
|
|
3883
|
-
id: containsId,
|
|
3884
|
-
source: serviceNodeId,
|
|
3885
|
-
target: fileNodeId,
|
|
3886
|
-
type: import_types9.EdgeType.CONTAINS,
|
|
3887
|
-
provenance: import_types9.Provenance.EXTRACTED,
|
|
3888
|
-
confidence: (0, import_types9.confidenceForExtracted)("structural"),
|
|
3889
|
-
evidence: { file: relPath }
|
|
3890
|
-
};
|
|
3891
|
-
graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge);
|
|
3892
|
-
edgesAdded++;
|
|
3893
|
-
}
|
|
3894
|
-
return { fileNodeId, nodesAdded, edgesAdded };
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
|
-
// src/extract/calls/http.ts
|
|
3898
3917
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
3899
3918
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
3900
3919
|
function isInsideJsxExternalLink(node) {
|
|
@@ -4178,6 +4197,7 @@ var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-
|
|
|
4178
4197
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
4179
4198
|
function isLikelyAddress(value) {
|
|
4180
4199
|
if (!value) return false;
|
|
4200
|
+
if (/\s/.test(value) || value.startsWith("{")) return false;
|
|
4181
4201
|
return /:\d{2,5}$/.test(value) || value.includes(".");
|
|
4182
4202
|
}
|
|
4183
4203
|
function normaliseForMatch(s) {
|
|
@@ -4489,17 +4509,26 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4489
4509
|
graph.addNode(node.id, node);
|
|
4490
4510
|
nodesAdded++;
|
|
4491
4511
|
}
|
|
4492
|
-
const
|
|
4512
|
+
const relDockerfile = toPosix2(import_node_path26.default.relative(service.dir, dockerfilePath));
|
|
4513
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4514
|
+
graph,
|
|
4515
|
+
service.pkg.name,
|
|
4516
|
+
service.node.id,
|
|
4517
|
+
relDockerfile
|
|
4518
|
+
);
|
|
4519
|
+
nodesAdded += fn;
|
|
4520
|
+
edgesAdded += fe;
|
|
4521
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types18.EdgeType.RUNS_ON);
|
|
4493
4522
|
if (!graph.hasEdge(edgeId)) {
|
|
4494
4523
|
const edge = {
|
|
4495
4524
|
id: edgeId,
|
|
4496
|
-
source:
|
|
4525
|
+
source: fileNodeId,
|
|
4497
4526
|
target: node.id,
|
|
4498
4527
|
type: import_types18.EdgeType.RUNS_ON,
|
|
4499
4528
|
provenance: import_types18.Provenance.EXTRACTED,
|
|
4500
4529
|
confidence: (0, import_types18.confidenceForExtracted)("structural"),
|
|
4501
4530
|
evidence: {
|
|
4502
|
-
file: import_node_path26.default.relative(scanPath, dockerfilePath)
|
|
4531
|
+
file: toPosix2(import_node_path26.default.relative(scanPath, dockerfilePath))
|
|
4503
4532
|
}
|
|
4504
4533
|
};
|
|
4505
4534
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -5198,38 +5227,353 @@ function renderValueForwardSummary(input) {
|
|
|
5198
5227
|
for (const [t, c] of [...byEdge.entries()].sort()) lines.push(` ${t}: ${c}`);
|
|
5199
5228
|
lines.push("");
|
|
5200
5229
|
}
|
|
5201
|
-
return lines.join("\n");
|
|
5230
|
+
return lines.join("\n");
|
|
5231
|
+
}
|
|
5232
|
+
function formatIncompat(inc) {
|
|
5233
|
+
if (inc.kind === "node-engine") {
|
|
5234
|
+
const range = inc.declaredNodeEngine ? ` (engines.node="${inc.declaredNodeEngine}")` : "";
|
|
5235
|
+
return `${inc.package}@${inc.packageVersion ?? "?"} requires Node ${inc.requiredNodeVersion}${range} \u2014 ${inc.reason}`;
|
|
5236
|
+
}
|
|
5237
|
+
if (inc.kind === "package-conflict") {
|
|
5238
|
+
const found = inc.foundVersion ? `@${inc.foundVersion}` : " (missing)";
|
|
5239
|
+
return `${inc.package}@${inc.packageVersion ?? "?"} requires ${inc.requires.name}>=${inc.requires.minVersion}; found ${inc.requires.name}${found} \u2014 ${inc.reason}`;
|
|
5240
|
+
}
|
|
5241
|
+
if (inc.kind === "deprecated-api") {
|
|
5242
|
+
return `${inc.package}@${inc.packageVersion ?? "?"} is deprecated \u2014 ${inc.reason}`;
|
|
5243
|
+
}
|
|
5244
|
+
return `${inc.driver}@${inc.driverVersion} vs ${inc.engine} ${inc.engineVersion} \u2014 ${inc.reason}`;
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
// src/watch.ts
|
|
5248
|
+
init_cjs_shims();
|
|
5249
|
+
var import_node_fs25 = __toESM(require("fs"), 1);
|
|
5250
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
5251
|
+
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
5252
|
+
|
|
5253
|
+
// src/api.ts
|
|
5254
|
+
init_cjs_shims();
|
|
5255
|
+
var import_fastify = __toESM(require("fastify"), 1);
|
|
5256
|
+
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
5257
|
+
var import_types24 = require("@neat.is/types");
|
|
5258
|
+
|
|
5259
|
+
// src/extend/index.ts
|
|
5260
|
+
init_cjs_shims();
|
|
5261
|
+
var import_node_fs21 = require("fs");
|
|
5262
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
5263
|
+
var import_node_os2 = __toESM(require("os"), 1);
|
|
5264
|
+
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
5265
|
+
|
|
5266
|
+
// src/installers/package-manager.ts
|
|
5267
|
+
init_cjs_shims();
|
|
5268
|
+
var import_node_fs20 = require("fs");
|
|
5269
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
5270
|
+
var import_node_child_process = require("child_process");
|
|
5271
|
+
var LOCKFILE_PRIORITY = [
|
|
5272
|
+
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
5273
|
+
{ lockfile: "pnpm-lock.yaml", pm: "pnpm", args: ["install", "--no-summary"] },
|
|
5274
|
+
{ lockfile: "yarn.lock", pm: "yarn", args: ["install", "--silent"] },
|
|
5275
|
+
{
|
|
5276
|
+
lockfile: "package-lock.json",
|
|
5277
|
+
pm: "npm",
|
|
5278
|
+
args: ["install", "--no-audit", "--no-fund", "--prefer-offline"]
|
|
5279
|
+
}
|
|
5280
|
+
];
|
|
5281
|
+
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
5282
|
+
async function exists2(p) {
|
|
5283
|
+
try {
|
|
5284
|
+
await import_node_fs20.promises.access(p);
|
|
5285
|
+
return true;
|
|
5286
|
+
} catch {
|
|
5287
|
+
return false;
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
async function detectPackageManager(serviceDir) {
|
|
5291
|
+
let dir = import_node_path33.default.resolve(serviceDir);
|
|
5292
|
+
const stops = /* @__PURE__ */ new Set();
|
|
5293
|
+
for (let i = 0; i < 64; i++) {
|
|
5294
|
+
if (stops.has(dir)) break;
|
|
5295
|
+
stops.add(dir);
|
|
5296
|
+
for (const candidate of LOCKFILE_PRIORITY) {
|
|
5297
|
+
const lockPath = import_node_path33.default.join(dir, candidate.lockfile);
|
|
5298
|
+
if (await exists2(lockPath)) {
|
|
5299
|
+
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
const parent = import_node_path33.default.dirname(dir);
|
|
5303
|
+
if (parent === dir) break;
|
|
5304
|
+
dir = parent;
|
|
5305
|
+
}
|
|
5306
|
+
return { pm: "npm", cwd: import_node_path33.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
5307
|
+
}
|
|
5308
|
+
async function runPackageManagerInstall(cmd) {
|
|
5309
|
+
return new Promise((resolve) => {
|
|
5310
|
+
const child = (0, import_node_child_process.spawn)(cmd.pm, cmd.args, {
|
|
5311
|
+
cwd: cmd.cwd,
|
|
5312
|
+
// Inherit PATH + HOME so the user's installed managers resolve.
|
|
5313
|
+
env: process.env,
|
|
5314
|
+
// `false` keeps the parent in control of cleanup if the orchestrator
|
|
5315
|
+
// exits before install finishes. Cross-platform-safe.
|
|
5316
|
+
shell: false,
|
|
5317
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
5318
|
+
});
|
|
5319
|
+
let stderr = "";
|
|
5320
|
+
child.stderr?.on("data", (chunk) => {
|
|
5321
|
+
stderr += chunk.toString("utf8");
|
|
5322
|
+
});
|
|
5323
|
+
child.on("error", (err) => {
|
|
5324
|
+
resolve({
|
|
5325
|
+
pm: cmd.pm,
|
|
5326
|
+
cwd: cmd.cwd,
|
|
5327
|
+
args: cmd.args,
|
|
5328
|
+
exitCode: 127,
|
|
5329
|
+
stderr: stderr + `
|
|
5330
|
+
${err.message}`
|
|
5331
|
+
});
|
|
5332
|
+
});
|
|
5333
|
+
child.on("close", (code) => {
|
|
5334
|
+
resolve({
|
|
5335
|
+
pm: cmd.pm,
|
|
5336
|
+
cwd: cmd.cwd,
|
|
5337
|
+
args: cmd.args,
|
|
5338
|
+
exitCode: code ?? 1,
|
|
5339
|
+
stderr: stderr.trim()
|
|
5340
|
+
});
|
|
5341
|
+
});
|
|
5342
|
+
});
|
|
5343
|
+
}
|
|
5344
|
+
|
|
5345
|
+
// src/extend/index.ts
|
|
5346
|
+
async function fileExists(p) {
|
|
5347
|
+
try {
|
|
5348
|
+
await import_node_fs21.promises.access(p);
|
|
5349
|
+
return true;
|
|
5350
|
+
} catch {
|
|
5351
|
+
return false;
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
async function readPackageJson(scanPath) {
|
|
5355
|
+
const pkgPath = import_node_path34.default.join(scanPath, "package.json");
|
|
5356
|
+
const raw = await import_node_fs21.promises.readFile(pkgPath, "utf8");
|
|
5357
|
+
return JSON.parse(raw);
|
|
5358
|
+
}
|
|
5359
|
+
async function findHookFiles(scanPath) {
|
|
5360
|
+
const entries = await import_node_fs21.promises.readdir(scanPath);
|
|
5361
|
+
return entries.filter(
|
|
5362
|
+
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
5363
|
+
).sort();
|
|
5364
|
+
}
|
|
5365
|
+
function extendLogPath() {
|
|
5366
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path34.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
5367
|
+
}
|
|
5368
|
+
async function appendExtendLog(entry2) {
|
|
5369
|
+
const logPath = extendLogPath();
|
|
5370
|
+
await import_node_fs21.promises.mkdir(import_node_path34.default.dirname(logPath), { recursive: true });
|
|
5371
|
+
await import_node_fs21.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
5372
|
+
}
|
|
5373
|
+
function splicedContent(fileContent, snippet2) {
|
|
5374
|
+
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
5375
|
+
return fileContent.replace("__INSTRUMENTATION_BLOCK__", `${snippet2}
|
|
5376
|
+
__INSTRUMENTATION_BLOCK__`);
|
|
5377
|
+
}
|
|
5378
|
+
const lines = fileContent.split("\n");
|
|
5379
|
+
let lastPushIdx = -1;
|
|
5380
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5381
|
+
if (lines[i].includes("instrumentations.push(")) lastPushIdx = i;
|
|
5382
|
+
}
|
|
5383
|
+
if (lastPushIdx >= 0) {
|
|
5384
|
+
lines.splice(lastPushIdx + 1, 0, snippet2);
|
|
5385
|
+
return lines.join("\n");
|
|
5386
|
+
}
|
|
5387
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5388
|
+
if (lines[i].includes("new NodeSDK(")) {
|
|
5389
|
+
lines.splice(i, 0, snippet2);
|
|
5390
|
+
return lines.join("\n");
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
return null;
|
|
5394
|
+
}
|
|
5395
|
+
async function listUninstrumented(ctx) {
|
|
5396
|
+
const pkg = await readPackageJson(ctx.scanPath);
|
|
5397
|
+
const allDeps2 = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
5398
|
+
const results = [];
|
|
5399
|
+
for (const [library, installedVersion] of Object.entries(allDeps2)) {
|
|
5400
|
+
const entry2 = (0, import_instrumentation_registry.resolve)(library, installedVersion);
|
|
5401
|
+
if (!entry2) continue;
|
|
5402
|
+
if (entry2.coverage === "bundled" || entry2.coverage === "http-only") continue;
|
|
5403
|
+
results.push({
|
|
5404
|
+
library,
|
|
5405
|
+
coverage: entry2.coverage,
|
|
5406
|
+
installedVersion,
|
|
5407
|
+
instrumentation_package: entry2.instrumentation_package,
|
|
5408
|
+
package_version: entry2.package_version,
|
|
5409
|
+
registration: entry2.registration,
|
|
5410
|
+
notes: entry2.notes
|
|
5411
|
+
});
|
|
5412
|
+
}
|
|
5413
|
+
return results;
|
|
5414
|
+
}
|
|
5415
|
+
function lookupInstrumentation(library, installedVersion) {
|
|
5416
|
+
const entry2 = (0, import_instrumentation_registry.resolve)(library, installedVersion);
|
|
5417
|
+
if (!entry2) return null;
|
|
5418
|
+
return {
|
|
5419
|
+
library: entry2.library,
|
|
5420
|
+
coverage: entry2.coverage,
|
|
5421
|
+
instrumentation_package: entry2.instrumentation_package,
|
|
5422
|
+
package_version: entry2.package_version,
|
|
5423
|
+
registration: entry2.registration,
|
|
5424
|
+
notes: entry2.notes
|
|
5425
|
+
};
|
|
5426
|
+
}
|
|
5427
|
+
async function describeProjectInstrumentation(ctx) {
|
|
5428
|
+
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5429
|
+
const envNeat = await fileExists(import_node_path34.default.join(ctx.scanPath, ".env.neat"));
|
|
5430
|
+
const registryInstrPackages = new Set(
|
|
5431
|
+
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
5432
|
+
);
|
|
5433
|
+
const pkg = await readPackageJson(ctx.scanPath);
|
|
5434
|
+
const allDeps2 = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
5435
|
+
const installedDeps = {};
|
|
5436
|
+
for (const [key, version] of Object.entries(allDeps2)) {
|
|
5437
|
+
if (key.startsWith("@opentelemetry/") || registryInstrPackages.has(key)) {
|
|
5438
|
+
installedDeps[key] = version;
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
return { hookFiles, envNeat, installedDeps };
|
|
5442
|
+
}
|
|
5443
|
+
async function applyExtension(ctx, args, options) {
|
|
5444
|
+
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5445
|
+
if (hookFiles.length === 0) {
|
|
5446
|
+
throw new Error(
|
|
5447
|
+
`No instrumentation hook files found in ${ctx.scanPath}. Run \`neat init\` first.`
|
|
5448
|
+
);
|
|
5449
|
+
}
|
|
5450
|
+
for (const file of hookFiles) {
|
|
5451
|
+
const content = await import_node_fs21.promises.readFile(import_node_path34.default.join(ctx.scanPath, file), "utf8");
|
|
5452
|
+
if (content.includes(args.registration_snippet)) {
|
|
5453
|
+
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
const primaryFile = hookFiles[0];
|
|
5457
|
+
const primaryPath = import_node_path34.default.join(ctx.scanPath, primaryFile);
|
|
5458
|
+
const filesTouched = [];
|
|
5459
|
+
const depsAdded = [];
|
|
5460
|
+
const pkgPath = import_node_path34.default.join(ctx.scanPath, "package.json");
|
|
5461
|
+
const pkg = await readPackageJson(ctx.scanPath);
|
|
5462
|
+
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
5463
|
+
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
5464
|
+
await import_node_fs21.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5465
|
+
filesTouched.push("package.json");
|
|
5466
|
+
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
5467
|
+
}
|
|
5468
|
+
const hookContent = await import_node_fs21.promises.readFile(primaryPath, "utf8");
|
|
5469
|
+
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5470
|
+
if (!patched) {
|
|
5471
|
+
throw new Error(
|
|
5472
|
+
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
5473
|
+
);
|
|
5474
|
+
}
|
|
5475
|
+
await import_node_fs21.promises.writeFile(primaryPath, patched, "utf8");
|
|
5476
|
+
filesTouched.push(primaryFile);
|
|
5477
|
+
const cmd = await detectPackageManager(ctx.scanPath);
|
|
5478
|
+
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
5479
|
+
const install = await installer(cmd);
|
|
5480
|
+
const installOutput = install.exitCode === 0 ? `${cmd.pm} install succeeded` : install.stderr || `${cmd.pm} install failed (exit ${install.exitCode})`;
|
|
5481
|
+
await appendExtendLog({
|
|
5482
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5483
|
+
project: ctx.project,
|
|
5484
|
+
library: args.library,
|
|
5485
|
+
instrumentation_package: args.instrumentation_package,
|
|
5486
|
+
version: args.version,
|
|
5487
|
+
registration_snippet: args.registration_snippet,
|
|
5488
|
+
filesTouched,
|
|
5489
|
+
depsAdded,
|
|
5490
|
+
installOutput
|
|
5491
|
+
});
|
|
5492
|
+
return { library: args.library, filesTouched, depsAdded, installOutput, alreadyApplied: false };
|
|
5202
5493
|
}
|
|
5203
|
-
function
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
return
|
|
5494
|
+
async function dryRunExtension(ctx, args) {
|
|
5495
|
+
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5496
|
+
if (hookFiles.length === 0) {
|
|
5497
|
+
return {
|
|
5498
|
+
library: args.library,
|
|
5499
|
+
filesTouched: [],
|
|
5500
|
+
depsToAdd: [],
|
|
5501
|
+
packageJsonPatch: {},
|
|
5502
|
+
templatePatch: "No hook files found. Run 'neat init' first."
|
|
5503
|
+
};
|
|
5207
5504
|
}
|
|
5208
|
-
|
|
5209
|
-
const
|
|
5210
|
-
|
|
5505
|
+
for (const file of hookFiles) {
|
|
5506
|
+
const content = await import_node_fs21.promises.readFile(import_node_path34.default.join(ctx.scanPath, file), "utf8");
|
|
5507
|
+
if (content.includes(args.registration_snippet)) {
|
|
5508
|
+
return {
|
|
5509
|
+
library: args.library,
|
|
5510
|
+
filesTouched: [],
|
|
5511
|
+
depsToAdd: [],
|
|
5512
|
+
packageJsonPatch: {},
|
|
5513
|
+
templatePatch: "Already applied \u2014 no changes would be made."
|
|
5514
|
+
};
|
|
5515
|
+
}
|
|
5211
5516
|
}
|
|
5212
|
-
|
|
5213
|
-
|
|
5517
|
+
const primaryFile = hookFiles[0];
|
|
5518
|
+
const filesTouched = [];
|
|
5519
|
+
const depsToAdd = [];
|
|
5520
|
+
let packageJsonPatch = {};
|
|
5521
|
+
let templatePatch = "";
|
|
5522
|
+
const pkg = await readPackageJson(ctx.scanPath);
|
|
5523
|
+
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
5524
|
+
packageJsonPatch = { dependencies: { [args.instrumentation_package]: args.version } };
|
|
5525
|
+
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
5526
|
+
filesTouched.push("package.json");
|
|
5527
|
+
}
|
|
5528
|
+
const hookContent = await import_node_fs21.promises.readFile(import_node_path34.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
5529
|
+
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5530
|
+
if (patched) {
|
|
5531
|
+
filesTouched.push(primaryFile);
|
|
5532
|
+
templatePatch = `+ ${args.registration_snippet}`;
|
|
5533
|
+
} else {
|
|
5534
|
+
templatePatch = "Could not find insertion point in hook file.";
|
|
5535
|
+
}
|
|
5536
|
+
return { library: args.library, filesTouched, depsToAdd, packageJsonPatch, templatePatch };
|
|
5537
|
+
}
|
|
5538
|
+
async function rollbackExtension(ctx, args) {
|
|
5539
|
+
const logPath = extendLogPath();
|
|
5540
|
+
if (!await fileExists(logPath)) {
|
|
5541
|
+
return { undone: false, message: "no apply found for library" };
|
|
5542
|
+
}
|
|
5543
|
+
const raw = await import_node_fs21.promises.readFile(logPath, "utf8");
|
|
5544
|
+
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
5545
|
+
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
5546
|
+
if (!match) {
|
|
5547
|
+
return { undone: false, message: "no apply found for library" };
|
|
5548
|
+
}
|
|
5549
|
+
const pkgPath = import_node_path34.default.join(ctx.scanPath, "package.json");
|
|
5550
|
+
if (await fileExists(pkgPath)) {
|
|
5551
|
+
const pkg = await readPackageJson(ctx.scanPath);
|
|
5552
|
+
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
5553
|
+
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
5554
|
+
pkg.dependencies = rest;
|
|
5555
|
+
await import_node_fs21.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5559
|
+
for (const file of hookFiles) {
|
|
5560
|
+
const filePath = import_node_path34.default.join(ctx.scanPath, file);
|
|
5561
|
+
const content = await import_node_fs21.promises.readFile(filePath, "utf8");
|
|
5562
|
+
if (content.includes(match.registration_snippet)) {
|
|
5563
|
+
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
5564
|
+
await import_node_fs21.promises.writeFile(filePath, filtered, "utf8");
|
|
5565
|
+
break;
|
|
5566
|
+
}
|
|
5214
5567
|
}
|
|
5215
|
-
return
|
|
5568
|
+
return {
|
|
5569
|
+
undone: true,
|
|
5570
|
+
message: `rolled back ${match.library} (${match.instrumentation_package})`
|
|
5571
|
+
};
|
|
5216
5572
|
}
|
|
5217
5573
|
|
|
5218
|
-
// src/watch.ts
|
|
5219
|
-
init_cjs_shims();
|
|
5220
|
-
var import_node_fs23 = __toESM(require("fs"), 1);
|
|
5221
|
-
var import_node_path38 = __toESM(require("path"), 1);
|
|
5222
|
-
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
5223
|
-
|
|
5224
|
-
// src/api.ts
|
|
5225
|
-
init_cjs_shims();
|
|
5226
|
-
var import_fastify = __toESM(require("fastify"), 1);
|
|
5227
|
-
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
5228
|
-
var import_types24 = require("@neat.is/types");
|
|
5229
|
-
|
|
5230
5574
|
// src/diff.ts
|
|
5231
5575
|
init_cjs_shims();
|
|
5232
|
-
var
|
|
5576
|
+
var import_node_fs22 = require("fs");
|
|
5233
5577
|
async function loadSnapshotForDiff(target) {
|
|
5234
5578
|
if (/^https?:\/\//i.test(target)) {
|
|
5235
5579
|
const res = await fetch(target);
|
|
@@ -5238,7 +5582,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
5238
5582
|
}
|
|
5239
5583
|
return await res.json();
|
|
5240
5584
|
}
|
|
5241
|
-
const raw = await
|
|
5585
|
+
const raw = await import_node_fs22.promises.readFile(target, "utf8");
|
|
5242
5586
|
return JSON.parse(raw);
|
|
5243
5587
|
}
|
|
5244
5588
|
function indexEntries(entries) {
|
|
@@ -5306,23 +5650,23 @@ function canonicalJson(value) {
|
|
|
5306
5650
|
|
|
5307
5651
|
// src/projects.ts
|
|
5308
5652
|
init_cjs_shims();
|
|
5309
|
-
var
|
|
5653
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
5310
5654
|
function pathsForProject(project, baseDir) {
|
|
5311
5655
|
if (project === DEFAULT_PROJECT) {
|
|
5312
5656
|
return {
|
|
5313
|
-
snapshotPath:
|
|
5314
|
-
errorsPath:
|
|
5315
|
-
staleEventsPath:
|
|
5316
|
-
embeddingsCachePath:
|
|
5317
|
-
policyViolationsPath:
|
|
5657
|
+
snapshotPath: import_node_path35.default.join(baseDir, "graph.json"),
|
|
5658
|
+
errorsPath: import_node_path35.default.join(baseDir, "errors.ndjson"),
|
|
5659
|
+
staleEventsPath: import_node_path35.default.join(baseDir, "stale-events.ndjson"),
|
|
5660
|
+
embeddingsCachePath: import_node_path35.default.join(baseDir, "embeddings.json"),
|
|
5661
|
+
policyViolationsPath: import_node_path35.default.join(baseDir, "policy-violations.ndjson")
|
|
5318
5662
|
};
|
|
5319
5663
|
}
|
|
5320
5664
|
return {
|
|
5321
|
-
snapshotPath:
|
|
5322
|
-
errorsPath:
|
|
5323
|
-
staleEventsPath:
|
|
5324
|
-
embeddingsCachePath:
|
|
5325
|
-
policyViolationsPath:
|
|
5665
|
+
snapshotPath: import_node_path35.default.join(baseDir, `${project}.json`),
|
|
5666
|
+
errorsPath: import_node_path35.default.join(baseDir, `errors.${project}.ndjson`),
|
|
5667
|
+
staleEventsPath: import_node_path35.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
5668
|
+
embeddingsCachePath: import_node_path35.default.join(baseDir, `embeddings.${project}.json`),
|
|
5669
|
+
policyViolationsPath: import_node_path35.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5326
5670
|
};
|
|
5327
5671
|
}
|
|
5328
5672
|
var Projects = class {
|
|
@@ -5358,25 +5702,25 @@ var Projects = class {
|
|
|
5358
5702
|
|
|
5359
5703
|
// src/registry.ts
|
|
5360
5704
|
init_cjs_shims();
|
|
5361
|
-
var
|
|
5362
|
-
var
|
|
5363
|
-
var
|
|
5705
|
+
var import_node_fs23 = require("fs");
|
|
5706
|
+
var import_node_os3 = __toESM(require("os"), 1);
|
|
5707
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5364
5708
|
var import_types23 = require("@neat.is/types");
|
|
5365
5709
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
5366
5710
|
var LOCK_RETRY_MS = 50;
|
|
5367
5711
|
function neatHome() {
|
|
5368
5712
|
const override = process.env.NEAT_HOME;
|
|
5369
|
-
if (override && override.length > 0) return
|
|
5370
|
-
return
|
|
5713
|
+
if (override && override.length > 0) return import_node_path36.default.resolve(override);
|
|
5714
|
+
return import_node_path36.default.join(import_node_os3.default.homedir(), ".neat");
|
|
5371
5715
|
}
|
|
5372
5716
|
function registryPath() {
|
|
5373
|
-
return
|
|
5717
|
+
return import_node_path36.default.join(neatHome(), "projects.json");
|
|
5374
5718
|
}
|
|
5375
5719
|
function registryLockPath() {
|
|
5376
|
-
return
|
|
5720
|
+
return import_node_path36.default.join(neatHome(), "projects.json.lock");
|
|
5377
5721
|
}
|
|
5378
5722
|
function daemonPidPath() {
|
|
5379
|
-
return
|
|
5723
|
+
return import_node_path36.default.join(neatHome(), "neatd.pid");
|
|
5380
5724
|
}
|
|
5381
5725
|
function isPidAliveDefault(pid) {
|
|
5382
5726
|
try {
|
|
@@ -5388,7 +5732,7 @@ function isPidAliveDefault(pid) {
|
|
|
5388
5732
|
}
|
|
5389
5733
|
async function readPidFile(file) {
|
|
5390
5734
|
try {
|
|
5391
|
-
const raw = await
|
|
5735
|
+
const raw = await import_node_fs23.promises.readFile(file, "utf8");
|
|
5392
5736
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
5393
5737
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
5394
5738
|
} catch {
|
|
@@ -5436,32 +5780,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
5436
5780
|
}
|
|
5437
5781
|
}
|
|
5438
5782
|
async function normalizeProjectPath(input) {
|
|
5439
|
-
const resolved =
|
|
5783
|
+
const resolved = import_node_path36.default.resolve(input);
|
|
5440
5784
|
try {
|
|
5441
|
-
return await
|
|
5785
|
+
return await import_node_fs23.promises.realpath(resolved);
|
|
5442
5786
|
} catch {
|
|
5443
5787
|
return resolved;
|
|
5444
5788
|
}
|
|
5445
5789
|
}
|
|
5446
5790
|
async function writeAtomically(target, contents) {
|
|
5447
|
-
await
|
|
5791
|
+
await import_node_fs23.promises.mkdir(import_node_path36.default.dirname(target), { recursive: true });
|
|
5448
5792
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
5449
|
-
const fd = await
|
|
5793
|
+
const fd = await import_node_fs23.promises.open(tmp, "w");
|
|
5450
5794
|
try {
|
|
5451
5795
|
await fd.writeFile(contents, "utf8");
|
|
5452
5796
|
await fd.sync();
|
|
5453
5797
|
} finally {
|
|
5454
5798
|
await fd.close();
|
|
5455
5799
|
}
|
|
5456
|
-
await
|
|
5800
|
+
await import_node_fs23.promises.rename(tmp, target);
|
|
5457
5801
|
}
|
|
5458
5802
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
5459
5803
|
const deadline = Date.now() + timeoutMs;
|
|
5460
|
-
await
|
|
5804
|
+
await import_node_fs23.promises.mkdir(import_node_path36.default.dirname(lockPath), { recursive: true });
|
|
5461
5805
|
let probedHolder = false;
|
|
5462
5806
|
while (true) {
|
|
5463
5807
|
try {
|
|
5464
|
-
const fd = await
|
|
5808
|
+
const fd = await import_node_fs23.promises.open(lockPath, "wx");
|
|
5465
5809
|
try {
|
|
5466
5810
|
await fd.writeFile(`${process.pid}
|
|
5467
5811
|
`, "utf8");
|
|
@@ -5486,7 +5830,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
5486
5830
|
}
|
|
5487
5831
|
}
|
|
5488
5832
|
async function releaseLock(lockPath) {
|
|
5489
|
-
await
|
|
5833
|
+
await import_node_fs23.promises.unlink(lockPath).catch(() => {
|
|
5490
5834
|
});
|
|
5491
5835
|
}
|
|
5492
5836
|
async function withLock(fn) {
|
|
@@ -5502,7 +5846,7 @@ async function readRegistry() {
|
|
|
5502
5846
|
const file = registryPath();
|
|
5503
5847
|
let raw;
|
|
5504
5848
|
try {
|
|
5505
|
-
raw = await
|
|
5849
|
+
raw = await import_node_fs23.promises.readFile(file, "utf8");
|
|
5506
5850
|
} catch (err) {
|
|
5507
5851
|
if (err.code === "ENOENT") {
|
|
5508
5852
|
return { version: 1, projects: [] };
|
|
@@ -6043,6 +6387,105 @@ function registerRoutes(scope, ctx) {
|
|
|
6043
6387
|
violations
|
|
6044
6388
|
};
|
|
6045
6389
|
});
|
|
6390
|
+
scope.get("/extend/list-uninstrumented", async (req, reply) => {
|
|
6391
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6392
|
+
if (!proj) return;
|
|
6393
|
+
if (!proj.scanPath) {
|
|
6394
|
+
return reply.code(409).send({ error: "scan path not configured for this project", project: proj.name });
|
|
6395
|
+
}
|
|
6396
|
+
try {
|
|
6397
|
+
const results = await listUninstrumented({ project: proj.name, scanPath: proj.scanPath });
|
|
6398
|
+
return { libraries: results };
|
|
6399
|
+
} catch (err) {
|
|
6400
|
+
return reply.code(500).send({ error: err.message });
|
|
6401
|
+
}
|
|
6402
|
+
});
|
|
6403
|
+
scope.get("/extend/lookup", async (req, reply) => {
|
|
6404
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6405
|
+
if (!proj) return;
|
|
6406
|
+
const { library, version } = req.query;
|
|
6407
|
+
if (!library) {
|
|
6408
|
+
return reply.code(400).send({ error: "query parameter `library` is required" });
|
|
6409
|
+
}
|
|
6410
|
+
const result = lookupInstrumentation(library, version);
|
|
6411
|
+
if (!result) {
|
|
6412
|
+
return reply.code(404).send({ error: "library not found in registry", library });
|
|
6413
|
+
}
|
|
6414
|
+
return result;
|
|
6415
|
+
});
|
|
6416
|
+
scope.get("/extend/describe", async (req, reply) => {
|
|
6417
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6418
|
+
if (!proj) return;
|
|
6419
|
+
if (!proj.scanPath) {
|
|
6420
|
+
return reply.code(409).send({ error: "scan path not configured for this project", project: proj.name });
|
|
6421
|
+
}
|
|
6422
|
+
try {
|
|
6423
|
+
const state = await describeProjectInstrumentation({ project: proj.name, scanPath: proj.scanPath });
|
|
6424
|
+
return state;
|
|
6425
|
+
} catch (err) {
|
|
6426
|
+
return reply.code(500).send({ error: err.message });
|
|
6427
|
+
}
|
|
6428
|
+
});
|
|
6429
|
+
scope.post("/extend/apply", async (req, reply) => {
|
|
6430
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6431
|
+
if (!proj) return;
|
|
6432
|
+
if (!proj.scanPath) {
|
|
6433
|
+
return reply.code(409).send({ error: "scan path not configured for this project", project: proj.name });
|
|
6434
|
+
}
|
|
6435
|
+
const { library, instrumentation_package, version, registration_snippet } = req.body ?? {};
|
|
6436
|
+
if (!library || !instrumentation_package || !version || !registration_snippet) {
|
|
6437
|
+
return reply.code(400).send({ error: "body must include library, instrumentation_package, version, registration_snippet" });
|
|
6438
|
+
}
|
|
6439
|
+
try {
|
|
6440
|
+
const result = await applyExtension(
|
|
6441
|
+
{ project: proj.name, scanPath: proj.scanPath },
|
|
6442
|
+
{ library, instrumentation_package, version, registration_snippet }
|
|
6443
|
+
);
|
|
6444
|
+
return result;
|
|
6445
|
+
} catch (err) {
|
|
6446
|
+
return reply.code(500).send({ error: err.message });
|
|
6447
|
+
}
|
|
6448
|
+
});
|
|
6449
|
+
scope.post("/extend/dry-run", async (req, reply) => {
|
|
6450
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6451
|
+
if (!proj) return;
|
|
6452
|
+
if (!proj.scanPath) {
|
|
6453
|
+
return reply.code(409).send({ error: "scan path not configured for this project", project: proj.name });
|
|
6454
|
+
}
|
|
6455
|
+
const { library, instrumentation_package, version, registration_snippet } = req.body ?? {};
|
|
6456
|
+
if (!library || !instrumentation_package || !version || !registration_snippet) {
|
|
6457
|
+
return reply.code(400).send({ error: "body must include library, instrumentation_package, version, registration_snippet" });
|
|
6458
|
+
}
|
|
6459
|
+
try {
|
|
6460
|
+
const result = await dryRunExtension(
|
|
6461
|
+
{ project: proj.name, scanPath: proj.scanPath },
|
|
6462
|
+
{ library, instrumentation_package, version, registration_snippet }
|
|
6463
|
+
);
|
|
6464
|
+
return result;
|
|
6465
|
+
} catch (err) {
|
|
6466
|
+
return reply.code(500).send({ error: err.message });
|
|
6467
|
+
}
|
|
6468
|
+
});
|
|
6469
|
+
scope.post("/extend/rollback", async (req, reply) => {
|
|
6470
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6471
|
+
if (!proj) return;
|
|
6472
|
+
if (!proj.scanPath) {
|
|
6473
|
+
return reply.code(409).send({ error: "scan path not configured for this project", project: proj.name });
|
|
6474
|
+
}
|
|
6475
|
+
const { library } = req.body ?? {};
|
|
6476
|
+
if (!library) {
|
|
6477
|
+
return reply.code(400).send({ error: "body must include library" });
|
|
6478
|
+
}
|
|
6479
|
+
try {
|
|
6480
|
+
const result = await rollbackExtension(
|
|
6481
|
+
{ project: proj.name, scanPath: proj.scanPath },
|
|
6482
|
+
{ library }
|
|
6483
|
+
);
|
|
6484
|
+
return result;
|
|
6485
|
+
} catch (err) {
|
|
6486
|
+
return reply.code(500).send({ error: err.message });
|
|
6487
|
+
}
|
|
6488
|
+
});
|
|
6046
6489
|
}
|
|
6047
6490
|
async function buildApi(opts) {
|
|
6048
6491
|
const app = (0, import_fastify.default)({ logger: false });
|
|
@@ -6154,8 +6597,8 @@ init_otel_grpc();
|
|
|
6154
6597
|
|
|
6155
6598
|
// src/search.ts
|
|
6156
6599
|
init_cjs_shims();
|
|
6157
|
-
var
|
|
6158
|
-
var
|
|
6600
|
+
var import_node_fs24 = require("fs");
|
|
6601
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
6159
6602
|
var import_node_crypto3 = require("crypto");
|
|
6160
6603
|
var DEFAULT_LIMIT = 10;
|
|
6161
6604
|
var NOMIC_DIM = 768;
|
|
@@ -6285,7 +6728,7 @@ async function pickEmbedder() {
|
|
|
6285
6728
|
}
|
|
6286
6729
|
async function readCache(cachePath) {
|
|
6287
6730
|
try {
|
|
6288
|
-
const raw = await
|
|
6731
|
+
const raw = await import_node_fs24.promises.readFile(cachePath, "utf8");
|
|
6289
6732
|
const parsed = JSON.parse(raw);
|
|
6290
6733
|
if (parsed.version !== 1) return null;
|
|
6291
6734
|
return parsed;
|
|
@@ -6294,8 +6737,8 @@ async function readCache(cachePath) {
|
|
|
6294
6737
|
}
|
|
6295
6738
|
}
|
|
6296
6739
|
async function writeCache(cachePath, cache) {
|
|
6297
|
-
await
|
|
6298
|
-
await
|
|
6740
|
+
await import_node_fs24.promises.mkdir(import_node_path39.default.dirname(cachePath), { recursive: true });
|
|
6741
|
+
await import_node_fs24.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
6299
6742
|
}
|
|
6300
6743
|
var VectorIndex = class {
|
|
6301
6744
|
constructor(embedder, cachePath) {
|
|
@@ -6450,8 +6893,8 @@ var ALL_PHASES = [
|
|
|
6450
6893
|
];
|
|
6451
6894
|
function classifyChange(relPath) {
|
|
6452
6895
|
const phases = /* @__PURE__ */ new Set();
|
|
6453
|
-
const base =
|
|
6454
|
-
const segments = relPath.split(
|
|
6896
|
+
const base = import_node_path40.default.basename(relPath).toLowerCase();
|
|
6897
|
+
const segments = relPath.split(import_node_path40.default.sep).map((s) => s.toLowerCase());
|
|
6455
6898
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
6456
6899
|
phases.add("services");
|
|
6457
6900
|
phases.add("aliases");
|
|
@@ -6559,16 +7002,16 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
6559
7002
|
if (count >= limit) return;
|
|
6560
7003
|
let entries;
|
|
6561
7004
|
try {
|
|
6562
|
-
entries =
|
|
7005
|
+
entries = import_node_fs25.default.readdirSync(dir, { withFileTypes: true });
|
|
6563
7006
|
} catch {
|
|
6564
7007
|
return;
|
|
6565
7008
|
}
|
|
6566
7009
|
for (const e of entries) {
|
|
6567
7010
|
if (count >= limit) return;
|
|
6568
7011
|
if (!e.isDirectory()) continue;
|
|
6569
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
7012
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path40.default.join(dir, e.name) + import_node_path40.default.sep))) continue;
|
|
6570
7013
|
count++;
|
|
6571
|
-
if (depth < 2) visit(
|
|
7014
|
+
if (depth < 2) visit(import_node_path40.default.join(dir, e.name), depth + 1);
|
|
6572
7015
|
}
|
|
6573
7016
|
};
|
|
6574
7017
|
visit(scanPath, 0);
|
|
@@ -6586,8 +7029,8 @@ async function startWatch(graph, opts) {
|
|
|
6586
7029
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
6587
7030
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
6588
7031
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
6589
|
-
const policyFilePath =
|
|
6590
|
-
const policyViolationsPath =
|
|
7032
|
+
const policyFilePath = import_node_path40.default.join(opts.scanPath, "policy.json");
|
|
7033
|
+
const policyViolationsPath = import_node_path40.default.join(import_node_path40.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
6591
7034
|
let policies = [];
|
|
6592
7035
|
try {
|
|
6593
7036
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -6638,7 +7081,7 @@ async function startWatch(graph, opts) {
|
|
|
6638
7081
|
assertBindAuthority(host, auth.authToken);
|
|
6639
7082
|
const port = opts.port ?? 8080;
|
|
6640
7083
|
const otelPort = opts.otelPort ?? 4318;
|
|
6641
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
7084
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path40.default.join(import_node_path40.default.dirname(opts.outPath), "embeddings.json");
|
|
6642
7085
|
let searchIndex;
|
|
6643
7086
|
try {
|
|
6644
7087
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -6656,7 +7099,7 @@ async function startWatch(graph, opts) {
|
|
|
6656
7099
|
// Paths are derived from the explicit options the watch caller passes
|
|
6657
7100
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
6658
7101
|
// fields so the registry shape is complete.
|
|
6659
|
-
...pathsForProject(projectName,
|
|
7102
|
+
...pathsForProject(projectName, import_node_path40.default.dirname(opts.outPath)),
|
|
6660
7103
|
snapshotPath: opts.outPath,
|
|
6661
7104
|
errorsPath: opts.errorsPath,
|
|
6662
7105
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -6743,9 +7186,9 @@ async function startWatch(graph, opts) {
|
|
|
6743
7186
|
};
|
|
6744
7187
|
const onPath = (absPath) => {
|
|
6745
7188
|
if (shouldIgnore(absPath)) return;
|
|
6746
|
-
const rel =
|
|
7189
|
+
const rel = import_node_path40.default.relative(opts.scanPath, absPath);
|
|
6747
7190
|
if (!rel || rel.startsWith("..")) return;
|
|
6748
|
-
pendingPaths.add(rel.split(
|
|
7191
|
+
pendingPaths.add(rel.split(import_node_path40.default.sep).join("/"));
|
|
6749
7192
|
const phases = classifyChange(rel);
|
|
6750
7193
|
if (phases.size === 0) {
|
|
6751
7194
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -6799,16 +7242,16 @@ async function startWatch(graph, opts) {
|
|
|
6799
7242
|
|
|
6800
7243
|
// src/deploy/detect.ts
|
|
6801
7244
|
init_cjs_shims();
|
|
6802
|
-
var
|
|
6803
|
-
var
|
|
6804
|
-
var
|
|
7245
|
+
var import_node_fs26 = require("fs");
|
|
7246
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7247
|
+
var import_node_child_process2 = require("child_process");
|
|
6805
7248
|
var import_node_crypto4 = require("crypto");
|
|
6806
7249
|
function generateToken() {
|
|
6807
7250
|
return (0, import_node_crypto4.randomBytes)(32).toString("base64url");
|
|
6808
7251
|
}
|
|
6809
7252
|
async function probeBinary(binary, arg) {
|
|
6810
7253
|
return new Promise((resolve) => {
|
|
6811
|
-
const child = (0,
|
|
7254
|
+
const child = (0, import_node_child_process2.spawn)(binary, [arg], { stdio: "ignore" });
|
|
6812
7255
|
const timer = setTimeout(() => {
|
|
6813
7256
|
child.kill("SIGKILL");
|
|
6814
7257
|
resolve(false);
|
|
@@ -6900,21 +7343,21 @@ async function runDeploy(opts = {}) {
|
|
|
6900
7343
|
const token = generateToken();
|
|
6901
7344
|
switch (substrate) {
|
|
6902
7345
|
case "docker-compose": {
|
|
6903
|
-
const artifactPath =
|
|
7346
|
+
const artifactPath = import_node_path41.default.join(cwd, "docker-compose.neat.yml");
|
|
6904
7347
|
const contents = emitDockerCompose(cwd);
|
|
6905
|
-
await
|
|
7348
|
+
await import_node_fs26.promises.writeFile(artifactPath, contents, "utf8");
|
|
6906
7349
|
return {
|
|
6907
7350
|
substrate,
|
|
6908
7351
|
artifactPath,
|
|
6909
7352
|
token,
|
|
6910
7353
|
contents,
|
|
6911
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
7354
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path41.default.basename(artifactPath)} up -d`
|
|
6912
7355
|
};
|
|
6913
7356
|
}
|
|
6914
7357
|
case "systemd": {
|
|
6915
|
-
const artifactPath =
|
|
7358
|
+
const artifactPath = import_node_path41.default.join(cwd, "neat.service");
|
|
6916
7359
|
const contents = emitSystemdUnit(cwd);
|
|
6917
|
-
await
|
|
7360
|
+
await import_node_fs26.promises.writeFile(artifactPath, contents, "utf8");
|
|
6918
7361
|
return {
|
|
6919
7362
|
substrate,
|
|
6920
7363
|
artifactPath,
|
|
@@ -6947,8 +7390,9 @@ init_cjs_shims();
|
|
|
6947
7390
|
|
|
6948
7391
|
// src/installers/javascript.ts
|
|
6949
7392
|
init_cjs_shims();
|
|
6950
|
-
var
|
|
6951
|
-
var
|
|
7393
|
+
var import_node_fs27 = require("fs");
|
|
7394
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
7395
|
+
var import_semver2 = __toESM(require("semver"), 1);
|
|
6952
7396
|
|
|
6953
7397
|
// src/installers/templates.ts
|
|
6954
7398
|
init_cjs_shims();
|
|
@@ -7485,15 +7929,15 @@ var OTEL_ENV = {
|
|
|
7485
7929
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
7486
7930
|
};
|
|
7487
7931
|
function serviceNodeName(pkg, serviceDir) {
|
|
7488
|
-
return pkg.name ??
|
|
7932
|
+
return pkg.name ?? import_node_path42.default.basename(serviceDir);
|
|
7489
7933
|
}
|
|
7490
7934
|
function projectToken(pkg, serviceDir, project) {
|
|
7491
7935
|
if (project && project.length > 0) return project;
|
|
7492
|
-
return pkg.name ??
|
|
7936
|
+
return pkg.name ?? import_node_path42.default.basename(serviceDir);
|
|
7493
7937
|
}
|
|
7494
7938
|
async function readJsonFile(p) {
|
|
7495
7939
|
try {
|
|
7496
|
-
const raw = await
|
|
7940
|
+
const raw = await import_node_fs27.promises.readFile(p, "utf8");
|
|
7497
7941
|
return JSON.parse(raw);
|
|
7498
7942
|
} catch {
|
|
7499
7943
|
return null;
|
|
@@ -7502,26 +7946,33 @@ async function readJsonFile(p) {
|
|
|
7502
7946
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
7503
7947
|
const deps = allDeps(pkg);
|
|
7504
7948
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
7505
|
-
const appJson = await readJsonFile(
|
|
7949
|
+
const appJson = await readJsonFile(import_node_path42.default.join(pkgRoot, "app.json"));
|
|
7506
7950
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
7507
7951
|
return "react-native";
|
|
7508
7952
|
}
|
|
7509
|
-
if (await
|
|
7953
|
+
if (await exists3(import_node_path42.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path42.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path42.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
7510
7954
|
return "browser-bundle";
|
|
7511
7955
|
}
|
|
7956
|
+
if (await exists3(import_node_path42.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
7957
|
+
if (await exists3(import_node_path42.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
7958
|
+
if (await exists3(import_node_path42.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path42.default.join(pkgRoot, "deno.lock"))) {
|
|
7959
|
+
return "deno";
|
|
7960
|
+
}
|
|
7961
|
+
const engines = pkg.engines ?? {};
|
|
7962
|
+
if ("electron" in engines) return "electron";
|
|
7512
7963
|
return "node";
|
|
7513
7964
|
}
|
|
7514
|
-
async function
|
|
7965
|
+
async function readPackageJson2(serviceDir) {
|
|
7515
7966
|
try {
|
|
7516
|
-
const raw = await
|
|
7967
|
+
const raw = await import_node_fs27.promises.readFile(import_node_path42.default.join(serviceDir, "package.json"), "utf8");
|
|
7517
7968
|
return JSON.parse(raw);
|
|
7518
7969
|
} catch {
|
|
7519
7970
|
return null;
|
|
7520
7971
|
}
|
|
7521
7972
|
}
|
|
7522
|
-
async function
|
|
7973
|
+
async function exists3(p) {
|
|
7523
7974
|
try {
|
|
7524
|
-
await
|
|
7975
|
+
await import_node_fs27.promises.stat(p);
|
|
7525
7976
|
return true;
|
|
7526
7977
|
} catch {
|
|
7527
7978
|
return false;
|
|
@@ -7529,7 +7980,7 @@ async function exists2(p) {
|
|
|
7529
7980
|
}
|
|
7530
7981
|
async function readFileMaybe(p) {
|
|
7531
7982
|
try {
|
|
7532
|
-
return await
|
|
7983
|
+
return await import_node_fs27.promises.readFile(p, "utf8");
|
|
7533
7984
|
} catch {
|
|
7534
7985
|
return null;
|
|
7535
7986
|
}
|
|
@@ -7545,14 +7996,20 @@ async function planOtelInitGeneration(file, contents) {
|
|
|
7545
7996
|
return null;
|
|
7546
7997
|
}
|
|
7547
7998
|
async function detect(serviceDir) {
|
|
7548
|
-
const pkg = await
|
|
7999
|
+
const pkg = await readPackageJson2(serviceDir);
|
|
7549
8000
|
return pkg !== null && typeof pkg.name === "string";
|
|
7550
8001
|
}
|
|
8002
|
+
function needsVersionUpgrade(installed, expected) {
|
|
8003
|
+
return !import_semver2.default.satisfies(
|
|
8004
|
+
import_semver2.default.minVersion(installed)?.version ?? installed,
|
|
8005
|
+
expected
|
|
8006
|
+
) && !import_semver2.default.intersects(installed, expected);
|
|
8007
|
+
}
|
|
7551
8008
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
7552
8009
|
async function findNextConfig(serviceDir) {
|
|
7553
8010
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
7554
|
-
const candidate =
|
|
7555
|
-
if (await
|
|
8011
|
+
const candidate = import_node_path42.default.join(serviceDir, name);
|
|
8012
|
+
if (await exists3(candidate)) return candidate;
|
|
7556
8013
|
}
|
|
7557
8014
|
return null;
|
|
7558
8015
|
}
|
|
@@ -7578,8 +8035,8 @@ function hasRemixDependency(pkg) {
|
|
|
7578
8035
|
}
|
|
7579
8036
|
async function findRemixEntry(serviceDir) {
|
|
7580
8037
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
7581
|
-
const candidate =
|
|
7582
|
-
if (await
|
|
8038
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8039
|
+
if (await exists3(candidate)) return candidate;
|
|
7583
8040
|
}
|
|
7584
8041
|
return null;
|
|
7585
8042
|
}
|
|
@@ -7590,15 +8047,15 @@ function hasSvelteKitDependency(pkg) {
|
|
|
7590
8047
|
}
|
|
7591
8048
|
async function findSvelteKitHooks(serviceDir) {
|
|
7592
8049
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
7593
|
-
const candidate =
|
|
7594
|
-
if (await
|
|
8050
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8051
|
+
if (await exists3(candidate)) return candidate;
|
|
7595
8052
|
}
|
|
7596
8053
|
return null;
|
|
7597
8054
|
}
|
|
7598
8055
|
async function findSvelteKitConfig(serviceDir) {
|
|
7599
8056
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
7600
|
-
const candidate =
|
|
7601
|
-
if (await
|
|
8057
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8058
|
+
if (await exists3(candidate)) return candidate;
|
|
7602
8059
|
}
|
|
7603
8060
|
return null;
|
|
7604
8061
|
}
|
|
@@ -7608,8 +8065,8 @@ function hasNuxtDependency(pkg) {
|
|
|
7608
8065
|
}
|
|
7609
8066
|
async function findNuxtConfig(serviceDir) {
|
|
7610
8067
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
7611
|
-
const candidate =
|
|
7612
|
-
if (await
|
|
8068
|
+
const candidate = import_node_path42.default.join(serviceDir, name);
|
|
8069
|
+
if (await exists3(candidate)) return candidate;
|
|
7613
8070
|
}
|
|
7614
8071
|
return null;
|
|
7615
8072
|
}
|
|
@@ -7619,8 +8076,8 @@ function hasAstroDependency(pkg) {
|
|
|
7619
8076
|
}
|
|
7620
8077
|
async function findAstroConfig(serviceDir) {
|
|
7621
8078
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
7622
|
-
const candidate =
|
|
7623
|
-
if (await
|
|
8079
|
+
const candidate = import_node_path42.default.join(serviceDir, name);
|
|
8080
|
+
if (await exists3(candidate)) return candidate;
|
|
7624
8081
|
}
|
|
7625
8082
|
return null;
|
|
7626
8083
|
}
|
|
@@ -7633,7 +8090,7 @@ function parseNextMajor(range) {
|
|
|
7633
8090
|
return Number.isFinite(n) ? n : null;
|
|
7634
8091
|
}
|
|
7635
8092
|
async function isTypeScriptProject(serviceDir) {
|
|
7636
|
-
return
|
|
8093
|
+
return exists3(import_node_path42.default.join(serviceDir, "tsconfig.json"));
|
|
7637
8094
|
}
|
|
7638
8095
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
7639
8096
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -7679,8 +8136,8 @@ function entryFromScript(script) {
|
|
|
7679
8136
|
}
|
|
7680
8137
|
async function resolveEntry(serviceDir, pkg) {
|
|
7681
8138
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
7682
|
-
const candidate =
|
|
7683
|
-
if (await
|
|
8139
|
+
const candidate = import_node_path42.default.resolve(serviceDir, pkg.main);
|
|
8140
|
+
if (await exists3(candidate)) return candidate;
|
|
7684
8141
|
}
|
|
7685
8142
|
if (pkg.bin) {
|
|
7686
8143
|
let binEntry;
|
|
@@ -7693,36 +8150,36 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
7693
8150
|
if (typeof first === "string") binEntry = first;
|
|
7694
8151
|
}
|
|
7695
8152
|
if (binEntry) {
|
|
7696
|
-
const candidate =
|
|
7697
|
-
if (await
|
|
8153
|
+
const candidate = import_node_path42.default.resolve(serviceDir, binEntry);
|
|
8154
|
+
if (await exists3(candidate)) return candidate;
|
|
7698
8155
|
}
|
|
7699
8156
|
}
|
|
7700
8157
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
7701
8158
|
if (startEntry) {
|
|
7702
|
-
const candidate =
|
|
7703
|
-
if (await
|
|
8159
|
+
const candidate = import_node_path42.default.resolve(serviceDir, startEntry);
|
|
8160
|
+
if (await exists3(candidate)) return candidate;
|
|
7704
8161
|
}
|
|
7705
8162
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
7706
8163
|
if (devEntry) {
|
|
7707
|
-
const candidate =
|
|
7708
|
-
if (await
|
|
8164
|
+
const candidate = import_node_path42.default.resolve(serviceDir, devEntry);
|
|
8165
|
+
if (await exists3(candidate)) return candidate;
|
|
7709
8166
|
}
|
|
7710
8167
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
7711
|
-
const candidate =
|
|
7712
|
-
if (await
|
|
8168
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8169
|
+
if (await exists3(candidate)) return candidate;
|
|
7713
8170
|
}
|
|
7714
8171
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
7715
|
-
const candidate =
|
|
7716
|
-
if (await
|
|
8172
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8173
|
+
if (await exists3(candidate)) return candidate;
|
|
7717
8174
|
}
|
|
7718
8175
|
for (const name of INDEX_CANDIDATES) {
|
|
7719
|
-
const candidate =
|
|
7720
|
-
if (await
|
|
8176
|
+
const candidate = import_node_path42.default.join(serviceDir, name);
|
|
8177
|
+
if (await exists3(candidate)) return candidate;
|
|
7721
8178
|
}
|
|
7722
8179
|
return null;
|
|
7723
8180
|
}
|
|
7724
8181
|
function dispatchEntry(entryFile, pkg) {
|
|
7725
|
-
const ext =
|
|
8182
|
+
const ext = import_node_path42.default.extname(entryFile).toLowerCase();
|
|
7726
8183
|
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
7727
8184
|
if (ext === ".mjs") return "esm";
|
|
7728
8185
|
if (ext === ".cjs") return "cjs";
|
|
@@ -7739,9 +8196,9 @@ function otelInitContents(flavor) {
|
|
|
7739
8196
|
return OTEL_INIT_CJS;
|
|
7740
8197
|
}
|
|
7741
8198
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
7742
|
-
let rel =
|
|
8199
|
+
let rel = import_node_path42.default.relative(import_node_path42.default.dirname(entryFile), otelInitFile);
|
|
7743
8200
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
7744
|
-
rel = rel.split(
|
|
8201
|
+
rel = rel.split(import_node_path42.default.sep).join("/");
|
|
7745
8202
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
7746
8203
|
if (flavor === "esm") return `import '${rel}'`;
|
|
7747
8204
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -7754,56 +8211,56 @@ function lineIsOtelInjection(line) {
|
|
|
7754
8211
|
}
|
|
7755
8212
|
async function detectsSrcLayout(serviceDir) {
|
|
7756
8213
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
8214
|
+
exists3(import_node_path42.default.join(serviceDir, "src", "app")),
|
|
8215
|
+
exists3(import_node_path42.default.join(serviceDir, "src", "pages")),
|
|
8216
|
+
exists3(import_node_path42.default.join(serviceDir, "app")),
|
|
8217
|
+
exists3(import_node_path42.default.join(serviceDir, "pages"))
|
|
7761
8218
|
]);
|
|
7762
8219
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
7763
8220
|
}
|
|
7764
8221
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
7765
8222
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
7766
8223
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
7767
|
-
const baseDir = srcLayout ?
|
|
7768
|
-
const instrumentationFile =
|
|
7769
|
-
const instrumentationNodeFile =
|
|
8224
|
+
const baseDir = srcLayout ? import_node_path42.default.join(serviceDir, "src") : serviceDir;
|
|
8225
|
+
const instrumentationFile = import_node_path42.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
8226
|
+
const instrumentationNodeFile = import_node_path42.default.join(
|
|
7770
8227
|
baseDir,
|
|
7771
8228
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
7772
8229
|
);
|
|
7773
|
-
const envNeatFile =
|
|
8230
|
+
const envNeatFile = import_node_path42.default.join(baseDir, ".env.neat");
|
|
7774
8231
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
7775
8232
|
const dependencyEdits = [];
|
|
7776
8233
|
for (const sdk of SDK_PACKAGES) {
|
|
7777
|
-
if (sdk.name in existingDeps)
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
});
|
|
8234
|
+
if (sdk.name in existingDeps) {
|
|
8235
|
+
if (needsVersionUpgrade(existingDeps[sdk.name], sdk.version)) {
|
|
8236
|
+
dependencyEdits.push({ file: manifestPath, kind: "upgrade", name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name] });
|
|
8237
|
+
}
|
|
8238
|
+
continue;
|
|
8239
|
+
}
|
|
8240
|
+
dependencyEdits.push({ file: manifestPath, kind: "add", name: sdk.name, version: sdk.version });
|
|
7784
8241
|
}
|
|
7785
8242
|
const nonBundled = detectNonBundledInstrumentations(pkg);
|
|
7786
8243
|
for (const inst of nonBundled) {
|
|
7787
|
-
if (inst.pkg in existingDeps)
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
});
|
|
8244
|
+
if (inst.pkg in existingDeps) {
|
|
8245
|
+
if (needsVersionUpgrade(existingDeps[inst.pkg], inst.version)) {
|
|
8246
|
+
dependencyEdits.push({ file: manifestPath, kind: "upgrade", name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg] });
|
|
8247
|
+
}
|
|
8248
|
+
continue;
|
|
8249
|
+
}
|
|
8250
|
+
dependencyEdits.push({ file: manifestPath, kind: "add", name: inst.pkg, version: inst.version });
|
|
7794
8251
|
}
|
|
7795
8252
|
const svcName = serviceNodeName(pkg, serviceDir);
|
|
7796
8253
|
const projectName = projectToken(pkg, serviceDir, project);
|
|
7797
8254
|
const registrations = nonBundled.map((i) => i.registration);
|
|
7798
8255
|
const generatedFiles = [];
|
|
7799
|
-
if (!await
|
|
8256
|
+
if (!await exists3(instrumentationFile)) {
|
|
7800
8257
|
generatedFiles.push({
|
|
7801
8258
|
file: instrumentationFile,
|
|
7802
8259
|
contents: useTs ? NEXT_INSTRUMENTATION_TS : NEXT_INSTRUMENTATION_JS,
|
|
7803
8260
|
skipIfExists: true
|
|
7804
8261
|
});
|
|
7805
8262
|
}
|
|
7806
|
-
if (!await
|
|
8263
|
+
if (!await exists3(instrumentationNodeFile)) {
|
|
7807
8264
|
generatedFiles.push({
|
|
7808
8265
|
file: instrumentationNodeFile,
|
|
7809
8266
|
contents: renderNextInstrumentationNode(
|
|
@@ -7815,7 +8272,7 @@ async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project)
|
|
|
7815
8272
|
skipIfExists: true
|
|
7816
8273
|
});
|
|
7817
8274
|
}
|
|
7818
|
-
if (!await
|
|
8275
|
+
if (!await exists3(envNeatFile)) {
|
|
7819
8276
|
generatedFiles.push({
|
|
7820
8277
|
file: envNeatFile,
|
|
7821
8278
|
contents: renderEnvNeat(svcName, projectName),
|
|
@@ -7827,7 +8284,7 @@ async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project)
|
|
|
7827
8284
|
const nextMajor = parseNextMajor(nextRange);
|
|
7828
8285
|
if (nextMajor !== null && nextMajor < 15) {
|
|
7829
8286
|
try {
|
|
7830
|
-
const raw = await
|
|
8287
|
+
const raw = await import_node_fs27.promises.readFile(nextConfigPath, "utf8");
|
|
7831
8288
|
if (!raw.includes("instrumentationHook")) {
|
|
7832
8289
|
nextConfigEdit = {
|
|
7833
8290
|
file: nextConfigPath,
|
|
@@ -7875,8 +8332,8 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
7875
8332
|
return edits;
|
|
7876
8333
|
}
|
|
7877
8334
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
7878
|
-
const envNeatFile =
|
|
7879
|
-
if (!await
|
|
8335
|
+
const envNeatFile = import_node_path42.default.join(serviceDir, ".env.neat");
|
|
8336
|
+
if (!await exists3(envNeatFile)) {
|
|
7880
8337
|
generatedFiles.push({
|
|
7881
8338
|
file: envNeatFile,
|
|
7882
8339
|
contents: renderEnvNeat(
|
|
@@ -7910,13 +8367,13 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
7910
8367
|
}
|
|
7911
8368
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
7912
8369
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
7913
|
-
const otelServerFile =
|
|
8370
|
+
const otelServerFile = import_node_path42.default.join(
|
|
7914
8371
|
serviceDir,
|
|
7915
8372
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
7916
8373
|
);
|
|
7917
8374
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
7918
8375
|
const generatedFiles = [];
|
|
7919
|
-
if (!await
|
|
8376
|
+
if (!await exists3(otelServerFile)) {
|
|
7920
8377
|
generatedFiles.push({
|
|
7921
8378
|
file: otelServerFile,
|
|
7922
8379
|
contents: renderFrameworkOtelInitForPkg(
|
|
@@ -7931,7 +8388,7 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
7931
8388
|
await queueEnvNeat(serviceDir, pkg, project, generatedFiles);
|
|
7932
8389
|
const entrypointEdits = [];
|
|
7933
8390
|
try {
|
|
7934
|
-
const raw = await
|
|
8391
|
+
const raw = await import_node_fs27.promises.readFile(entryFile, "utf8");
|
|
7935
8392
|
if (!fileImportsOtelHook(raw, ["./otel.server"])) {
|
|
7936
8393
|
const lines = raw.split(/\r?\n/);
|
|
7937
8394
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -7967,15 +8424,15 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
7967
8424
|
}
|
|
7968
8425
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
7969
8426
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
7970
|
-
const otelInitFile =
|
|
8427
|
+
const otelInitFile = import_node_path42.default.join(
|
|
7971
8428
|
serviceDir,
|
|
7972
8429
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
7973
8430
|
);
|
|
7974
|
-
const resolvedHooksFile = hooksFile ??
|
|
8431
|
+
const resolvedHooksFile = hooksFile ?? import_node_path42.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
7975
8432
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
7976
8433
|
const generatedFiles = [];
|
|
7977
8434
|
const entrypointEdits = [];
|
|
7978
|
-
if (!await
|
|
8435
|
+
if (!await exists3(otelInitFile)) {
|
|
7979
8436
|
generatedFiles.push({
|
|
7980
8437
|
file: otelInitFile,
|
|
7981
8438
|
contents: renderFrameworkOtelInitForPkg(
|
|
@@ -7996,7 +8453,7 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
7996
8453
|
});
|
|
7997
8454
|
} else {
|
|
7998
8455
|
try {
|
|
7999
|
-
const raw = await
|
|
8456
|
+
const raw = await import_node_fs27.promises.readFile(hooksFile, "utf8");
|
|
8000
8457
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8001
8458
|
const lines = raw.split(/\r?\n/);
|
|
8002
8459
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8033,17 +8490,17 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
8033
8490
|
}
|
|
8034
8491
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
8035
8492
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8036
|
-
const otelPluginFile =
|
|
8493
|
+
const otelPluginFile = import_node_path42.default.join(
|
|
8037
8494
|
serviceDir,
|
|
8038
8495
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
8039
8496
|
);
|
|
8040
|
-
const otelInitFile =
|
|
8497
|
+
const otelInitFile = import_node_path42.default.join(
|
|
8041
8498
|
serviceDir,
|
|
8042
8499
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
8043
8500
|
);
|
|
8044
8501
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8045
8502
|
const generatedFiles = [];
|
|
8046
|
-
if (!await
|
|
8503
|
+
if (!await exists3(otelInitFile)) {
|
|
8047
8504
|
generatedFiles.push({
|
|
8048
8505
|
file: otelInitFile,
|
|
8049
8506
|
contents: renderFrameworkOtelInitForPkg(
|
|
@@ -8055,7 +8512,7 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
8055
8512
|
skipIfExists: true
|
|
8056
8513
|
});
|
|
8057
8514
|
}
|
|
8058
|
-
if (!await
|
|
8515
|
+
if (!await exists3(otelPluginFile)) {
|
|
8059
8516
|
generatedFiles.push({
|
|
8060
8517
|
file: otelPluginFile,
|
|
8061
8518
|
contents: useTs ? NUXT_OTEL_PLUGIN_TS : NUXT_OTEL_PLUGIN_JS,
|
|
@@ -8088,23 +8545,23 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
8088
8545
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
8089
8546
|
async function findAstroMiddleware(serviceDir) {
|
|
8090
8547
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
8091
|
-
const candidate =
|
|
8092
|
-
if (await
|
|
8548
|
+
const candidate = import_node_path42.default.join(serviceDir, rel);
|
|
8549
|
+
if (await exists3(candidate)) return candidate;
|
|
8093
8550
|
}
|
|
8094
8551
|
return null;
|
|
8095
8552
|
}
|
|
8096
8553
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
8097
8554
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8098
|
-
const otelInitFile =
|
|
8555
|
+
const otelInitFile = import_node_path42.default.join(
|
|
8099
8556
|
serviceDir,
|
|
8100
8557
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
8101
8558
|
);
|
|
8102
8559
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
8103
|
-
const middlewareFile = existingMiddleware ??
|
|
8560
|
+
const middlewareFile = existingMiddleware ?? import_node_path42.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
8104
8561
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8105
8562
|
const generatedFiles = [];
|
|
8106
8563
|
const entrypointEdits = [];
|
|
8107
|
-
if (!await
|
|
8564
|
+
if (!await exists3(otelInitFile)) {
|
|
8108
8565
|
generatedFiles.push({
|
|
8109
8566
|
file: otelInitFile,
|
|
8110
8567
|
contents: renderFrameworkOtelInitForPkg(
|
|
@@ -8125,7 +8582,7 @@ async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
|
8125
8582
|
});
|
|
8126
8583
|
} else {
|
|
8127
8584
|
try {
|
|
8128
|
-
const raw = await
|
|
8585
|
+
const raw = await import_node_fs27.promises.readFile(existingMiddleware, "utf8");
|
|
8129
8586
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8130
8587
|
const lines = raw.split(/\r?\n/);
|
|
8131
8588
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8195,8 +8652,8 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
8195
8652
|
return null;
|
|
8196
8653
|
}
|
|
8197
8654
|
async function plan(serviceDir, opts) {
|
|
8198
|
-
const pkg = await
|
|
8199
|
-
const manifestPath =
|
|
8655
|
+
const pkg = await readPackageJson2(serviceDir);
|
|
8656
|
+
const manifestPath = import_node_path42.default.join(serviceDir, "package.json");
|
|
8200
8657
|
const project = opts?.project;
|
|
8201
8658
|
const empty = {
|
|
8202
8659
|
language: "javascript",
|
|
@@ -8231,32 +8688,32 @@ async function plan(serviceDir, opts) {
|
|
|
8231
8688
|
return { ...empty, libOnly: true };
|
|
8232
8689
|
}
|
|
8233
8690
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
8234
|
-
const otelInitFile =
|
|
8235
|
-
const envNeatFile =
|
|
8691
|
+
const otelInitFile = import_node_path42.default.join(import_node_path42.default.dirname(entryFile), otelInitFilename(flavor));
|
|
8692
|
+
const envNeatFile = import_node_path42.default.join(serviceDir, ".env.neat");
|
|
8236
8693
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
8237
8694
|
const dependencyEdits = [];
|
|
8238
8695
|
for (const sdk of SDK_PACKAGES) {
|
|
8239
|
-
if (sdk.name in existingDeps)
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
});
|
|
8696
|
+
if (sdk.name in existingDeps) {
|
|
8697
|
+
if (needsVersionUpgrade(existingDeps[sdk.name], sdk.version)) {
|
|
8698
|
+
dependencyEdits.push({ file: manifestPath, kind: "upgrade", name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name] });
|
|
8699
|
+
}
|
|
8700
|
+
continue;
|
|
8701
|
+
}
|
|
8702
|
+
dependencyEdits.push({ file: manifestPath, kind: "add", name: sdk.name, version: sdk.version });
|
|
8246
8703
|
}
|
|
8247
8704
|
const nonBundled = detectNonBundledInstrumentations(pkg);
|
|
8248
8705
|
for (const inst of nonBundled) {
|
|
8249
|
-
if (inst.pkg in existingDeps)
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
});
|
|
8706
|
+
if (inst.pkg in existingDeps) {
|
|
8707
|
+
if (needsVersionUpgrade(existingDeps[inst.pkg], inst.version)) {
|
|
8708
|
+
dependencyEdits.push({ file: manifestPath, kind: "upgrade", name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg] });
|
|
8709
|
+
}
|
|
8710
|
+
continue;
|
|
8711
|
+
}
|
|
8712
|
+
dependencyEdits.push({ file: manifestPath, kind: "add", name: inst.pkg, version: inst.version });
|
|
8256
8713
|
}
|
|
8257
8714
|
const entrypointEdits = [];
|
|
8258
8715
|
try {
|
|
8259
|
-
const raw = await
|
|
8716
|
+
const raw = await import_node_fs27.promises.readFile(entryFile, "utf8");
|
|
8260
8717
|
const lines = raw.split(/\r?\n/);
|
|
8261
8718
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
8262
8719
|
if (!lineIsOtelInjection(firstReal)) {
|
|
@@ -8279,7 +8736,7 @@ async function plan(serviceDir, opts) {
|
|
|
8279
8736
|
renderNodeOtelInit(otelInitContents(flavor), svcName, projectName, registrations)
|
|
8280
8737
|
);
|
|
8281
8738
|
if (otelInitGen) generatedFiles.push(otelInitGen);
|
|
8282
|
-
if (!await
|
|
8739
|
+
if (!await exists3(envNeatFile)) {
|
|
8283
8740
|
generatedFiles.push({
|
|
8284
8741
|
file: envNeatFile,
|
|
8285
8742
|
contents: renderEnvNeat(svcName, projectName),
|
|
@@ -8301,13 +8758,13 @@ async function plan(serviceDir, opts) {
|
|
|
8301
8758
|
};
|
|
8302
8759
|
}
|
|
8303
8760
|
function isAllowedWritePath(serviceDir, target) {
|
|
8304
|
-
const rel =
|
|
8761
|
+
const rel = import_node_path42.default.relative(serviceDir, target);
|
|
8305
8762
|
if (rel.startsWith("..")) return false;
|
|
8306
|
-
const base =
|
|
8763
|
+
const base = import_node_path42.default.basename(target);
|
|
8307
8764
|
if (base === "package.json") return true;
|
|
8308
8765
|
if (base === ".env.neat") return true;
|
|
8309
8766
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
8310
|
-
const relPosix = rel.split(
|
|
8767
|
+
const relPosix = rel.split(import_node_path42.default.sep).join("/");
|
|
8311
8768
|
if (/^instrumentation(?:\.node)?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
8312
8769
|
if (relPosix === base) return true;
|
|
8313
8770
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -8324,10 +8781,10 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
8324
8781
|
return false;
|
|
8325
8782
|
}
|
|
8326
8783
|
async function writeAtomic(file, contents) {
|
|
8327
|
-
await
|
|
8784
|
+
await import_node_fs27.promises.mkdir(import_node_path42.default.dirname(file), { recursive: true });
|
|
8328
8785
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
8329
|
-
await
|
|
8330
|
-
await
|
|
8786
|
+
await import_node_fs27.promises.writeFile(tmp, contents, "utf8");
|
|
8787
|
+
await import_node_fs27.promises.rename(tmp, file);
|
|
8331
8788
|
}
|
|
8332
8789
|
async function apply(installPlan) {
|
|
8333
8790
|
const { serviceDir } = installPlan;
|
|
@@ -8355,6 +8812,28 @@ async function apply(installPlan) {
|
|
|
8355
8812
|
writtenFiles: []
|
|
8356
8813
|
};
|
|
8357
8814
|
}
|
|
8815
|
+
if (installPlan.runtimeKind === "bun") {
|
|
8816
|
+
return { serviceDir, outcome: "bun", reason: "Bun runtime; use BYO-OTel", writtenFiles: [] };
|
|
8817
|
+
}
|
|
8818
|
+
if (installPlan.runtimeKind === "deno") {
|
|
8819
|
+
return { serviceDir, outcome: "deno", reason: "Deno runtime; use BYO-OTel", writtenFiles: [] };
|
|
8820
|
+
}
|
|
8821
|
+
if (installPlan.runtimeKind === "cloudflare-workers") {
|
|
8822
|
+
return {
|
|
8823
|
+
serviceDir,
|
|
8824
|
+
outcome: "cloudflare-workers",
|
|
8825
|
+
reason: "Cloudflare Workers runtime; use BYO-OTel",
|
|
8826
|
+
writtenFiles: []
|
|
8827
|
+
};
|
|
8828
|
+
}
|
|
8829
|
+
if (installPlan.runtimeKind === "electron") {
|
|
8830
|
+
return {
|
|
8831
|
+
serviceDir,
|
|
8832
|
+
outcome: "electron",
|
|
8833
|
+
reason: "Electron; use BYO-OTel",
|
|
8834
|
+
writtenFiles: []
|
|
8835
|
+
};
|
|
8836
|
+
}
|
|
8358
8837
|
if (installPlan.dependencyEdits.length === 0 && installPlan.entrypointEdits.length === 0 && (installPlan.generatedFiles?.length ?? 0) === 0 && installPlan.nextConfigEdit === void 0) {
|
|
8359
8838
|
return {
|
|
8360
8839
|
serviceDir,
|
|
@@ -8379,9 +8858,9 @@ async function apply(installPlan) {
|
|
|
8379
8858
|
const originals = /* @__PURE__ */ new Map();
|
|
8380
8859
|
const createdFiles = [];
|
|
8381
8860
|
for (const target of allTargets) {
|
|
8382
|
-
if (await
|
|
8861
|
+
if (await exists3(target)) {
|
|
8383
8862
|
try {
|
|
8384
|
-
originals.set(target, await
|
|
8863
|
+
originals.set(target, await import_node_fs27.promises.readFile(target, "utf8"));
|
|
8385
8864
|
} catch {
|
|
8386
8865
|
}
|
|
8387
8866
|
}
|
|
@@ -8405,6 +8884,8 @@ async function apply(installPlan) {
|
|
|
8405
8884
|
if (!(dep.name in (pkg.dependencies ?? {}))) {
|
|
8406
8885
|
pkg.dependencies[dep.name] = dep.version;
|
|
8407
8886
|
}
|
|
8887
|
+
} else if (dep.kind === "upgrade") {
|
|
8888
|
+
pkg.dependencies[dep.name] = dep.version;
|
|
8408
8889
|
} else {
|
|
8409
8890
|
delete pkg.dependencies[dep.name];
|
|
8410
8891
|
}
|
|
@@ -8414,7 +8895,7 @@ async function apply(installPlan) {
|
|
|
8414
8895
|
writtenFiles.push(file);
|
|
8415
8896
|
}
|
|
8416
8897
|
for (const gen of installPlan.generatedFiles ?? []) {
|
|
8417
|
-
if (gen.skipIfExists && await
|
|
8898
|
+
if (gen.skipIfExists && await exists3(gen.file)) {
|
|
8418
8899
|
continue;
|
|
8419
8900
|
}
|
|
8420
8901
|
await writeAtomic(gen.file, gen.contents);
|
|
@@ -8462,14 +8943,14 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
8462
8943
|
const removed = [];
|
|
8463
8944
|
for (const [file, raw] of originals.entries()) {
|
|
8464
8945
|
try {
|
|
8465
|
-
await
|
|
8946
|
+
await import_node_fs27.promises.writeFile(file, raw, "utf8");
|
|
8466
8947
|
restored.push(file);
|
|
8467
8948
|
} catch {
|
|
8468
8949
|
}
|
|
8469
8950
|
}
|
|
8470
8951
|
for (const file of createdFiles) {
|
|
8471
8952
|
try {
|
|
8472
|
-
await
|
|
8953
|
+
await import_node_fs27.promises.unlink(file);
|
|
8473
8954
|
removed.push(file);
|
|
8474
8955
|
} catch {
|
|
8475
8956
|
}
|
|
@@ -8484,8 +8965,8 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
8484
8965
|
...removed.map((f) => `removed: ${f}`),
|
|
8485
8966
|
""
|
|
8486
8967
|
];
|
|
8487
|
-
const rollbackPath =
|
|
8488
|
-
await
|
|
8968
|
+
const rollbackPath = import_node_path42.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
8969
|
+
await import_node_fs27.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
8489
8970
|
}
|
|
8490
8971
|
function injectInstrumentationHook(raw) {
|
|
8491
8972
|
if (raw.includes("instrumentationHook")) return raw;
|
|
@@ -8514,8 +8995,8 @@ var javascriptInstaller = {
|
|
|
8514
8995
|
|
|
8515
8996
|
// src/installers/python.ts
|
|
8516
8997
|
init_cjs_shims();
|
|
8517
|
-
var
|
|
8518
|
-
var
|
|
8998
|
+
var import_node_fs28 = require("fs");
|
|
8999
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8519
9000
|
var SDK_PACKAGES2 = [
|
|
8520
9001
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
8521
9002
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -8525,9 +9006,9 @@ var OTEL_ENV2 = {
|
|
|
8525
9006
|
key: "OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
8526
9007
|
value: "http://localhost:4318"
|
|
8527
9008
|
};
|
|
8528
|
-
async function
|
|
9009
|
+
async function exists4(p) {
|
|
8529
9010
|
try {
|
|
8530
|
-
await
|
|
9011
|
+
await import_node_fs28.promises.stat(p);
|
|
8531
9012
|
return true;
|
|
8532
9013
|
} catch {
|
|
8533
9014
|
return false;
|
|
@@ -8536,7 +9017,7 @@ async function exists3(p) {
|
|
|
8536
9017
|
async function detect2(serviceDir) {
|
|
8537
9018
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
8538
9019
|
for (const m of markers) {
|
|
8539
|
-
if (await
|
|
9020
|
+
if (await exists4(import_node_path43.default.join(serviceDir, m))) return true;
|
|
8540
9021
|
}
|
|
8541
9022
|
return false;
|
|
8542
9023
|
}
|
|
@@ -8546,9 +9027,9 @@ function reqPackageName(line) {
|
|
|
8546
9027
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
8547
9028
|
}
|
|
8548
9029
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
8549
|
-
const file =
|
|
8550
|
-
if (!await
|
|
8551
|
-
const raw = await
|
|
9030
|
+
const file = import_node_path43.default.join(serviceDir, "requirements.txt");
|
|
9031
|
+
if (!await exists4(file)) return null;
|
|
9032
|
+
const raw = await import_node_fs28.promises.readFile(file, "utf8");
|
|
8552
9033
|
const presentNames = new Set(
|
|
8553
9034
|
raw.split(/\r?\n/).map(reqPackageName).filter((n) => n.length > 0)
|
|
8554
9035
|
);
|
|
@@ -8556,9 +9037,9 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
8556
9037
|
return { manifest: file, missing: [...missing] };
|
|
8557
9038
|
}
|
|
8558
9039
|
async function planProcfileEdits(serviceDir) {
|
|
8559
|
-
const procfile =
|
|
8560
|
-
if (!await
|
|
8561
|
-
const raw = await
|
|
9040
|
+
const procfile = import_node_path43.default.join(serviceDir, "Procfile");
|
|
9041
|
+
if (!await exists4(procfile)) return [];
|
|
9042
|
+
const raw = await import_node_fs28.promises.readFile(procfile, "utf8");
|
|
8562
9043
|
const edits = [];
|
|
8563
9044
|
for (const line of raw.split(/\r?\n/)) {
|
|
8564
9045
|
if (line.length === 0) continue;
|
|
@@ -8610,8 +9091,8 @@ async function applyRequirementsTxt(manifest, edits, original) {
|
|
|
8610
9091
|
const next = `${original}${trailing}${newlines.join("\n")}
|
|
8611
9092
|
`;
|
|
8612
9093
|
const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`;
|
|
8613
|
-
await
|
|
8614
|
-
await
|
|
9094
|
+
await import_node_fs28.promises.writeFile(tmp, next, "utf8");
|
|
9095
|
+
await import_node_fs28.promises.rename(tmp, manifest);
|
|
8615
9096
|
}
|
|
8616
9097
|
async function applyProcfile(procfile, edits, original) {
|
|
8617
9098
|
let next = original;
|
|
@@ -8620,8 +9101,8 @@ async function applyProcfile(procfile, edits, original) {
|
|
|
8620
9101
|
next = next.replace(e.before, e.after);
|
|
8621
9102
|
}
|
|
8622
9103
|
const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`;
|
|
8623
|
-
await
|
|
8624
|
-
await
|
|
9104
|
+
await import_node_fs28.promises.writeFile(tmp, next, "utf8");
|
|
9105
|
+
await import_node_fs28.promises.rename(tmp, procfile);
|
|
8625
9106
|
}
|
|
8626
9107
|
async function apply2(installPlan) {
|
|
8627
9108
|
const { serviceDir } = installPlan;
|
|
@@ -8634,7 +9115,7 @@ async function apply2(installPlan) {
|
|
|
8634
9115
|
const originals = /* @__PURE__ */ new Map();
|
|
8635
9116
|
for (const file of touched) {
|
|
8636
9117
|
try {
|
|
8637
|
-
originals.set(file, await
|
|
9118
|
+
originals.set(file, await import_node_fs28.promises.readFile(file, "utf8"));
|
|
8638
9119
|
} catch {
|
|
8639
9120
|
}
|
|
8640
9121
|
}
|
|
@@ -8645,7 +9126,7 @@ async function apply2(installPlan) {
|
|
|
8645
9126
|
if (raw === void 0) {
|
|
8646
9127
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
8647
9128
|
}
|
|
8648
|
-
const base =
|
|
9129
|
+
const base = import_node_path43.default.basename(file);
|
|
8649
9130
|
if (base === "requirements.txt") {
|
|
8650
9131
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
8651
9132
|
if (edits.length > 0) {
|
|
@@ -8670,7 +9151,7 @@ async function rollback2(installPlan, originals) {
|
|
|
8670
9151
|
const restored = [];
|
|
8671
9152
|
for (const [file, raw] of originals.entries()) {
|
|
8672
9153
|
try {
|
|
8673
|
-
await
|
|
9154
|
+
await import_node_fs28.promises.writeFile(file, raw, "utf8");
|
|
8674
9155
|
restored.push(file);
|
|
8675
9156
|
} catch {
|
|
8676
9157
|
}
|
|
@@ -8684,8 +9165,8 @@ async function rollback2(installPlan, originals) {
|
|
|
8684
9165
|
...restored.map((f) => `restored: ${f}`),
|
|
8685
9166
|
""
|
|
8686
9167
|
];
|
|
8687
|
-
const rollbackPath =
|
|
8688
|
-
await
|
|
9168
|
+
const rollbackPath = import_node_path43.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
9169
|
+
await import_node_fs28.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
8689
9170
|
}
|
|
8690
9171
|
var pythonInstaller = {
|
|
8691
9172
|
name: "python",
|
|
@@ -8808,100 +9289,19 @@ function renderPatch(sections) {
|
|
|
8808
9289
|
|
|
8809
9290
|
// src/orchestrator.ts
|
|
8810
9291
|
init_cjs_shims();
|
|
8811
|
-
var
|
|
9292
|
+
var import_node_fs29 = require("fs");
|
|
8812
9293
|
var import_node_http = __toESM(require("http"), 1);
|
|
8813
9294
|
var import_node_net = __toESM(require("net"), 1);
|
|
8814
|
-
var
|
|
9295
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8815
9296
|
var import_node_child_process3 = require("child_process");
|
|
8816
9297
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
8817
|
-
|
|
8818
|
-
// src/installers/package-manager.ts
|
|
8819
|
-
init_cjs_shims();
|
|
8820
|
-
var import_node_fs27 = require("fs");
|
|
8821
|
-
var import_node_path42 = __toESM(require("path"), 1);
|
|
8822
|
-
var import_node_child_process2 = require("child_process");
|
|
8823
|
-
var LOCKFILE_PRIORITY = [
|
|
8824
|
-
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
8825
|
-
{ lockfile: "pnpm-lock.yaml", pm: "pnpm", args: ["install", "--no-summary"] },
|
|
8826
|
-
{ lockfile: "yarn.lock", pm: "yarn", args: ["install", "--silent"] },
|
|
8827
|
-
{
|
|
8828
|
-
lockfile: "package-lock.json",
|
|
8829
|
-
pm: "npm",
|
|
8830
|
-
args: ["install", "--no-audit", "--no-fund", "--prefer-offline"]
|
|
8831
|
-
}
|
|
8832
|
-
];
|
|
8833
|
-
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
8834
|
-
async function exists4(p) {
|
|
8835
|
-
try {
|
|
8836
|
-
await import_node_fs27.promises.access(p);
|
|
8837
|
-
return true;
|
|
8838
|
-
} catch {
|
|
8839
|
-
return false;
|
|
8840
|
-
}
|
|
8841
|
-
}
|
|
8842
|
-
async function detectPackageManager(serviceDir) {
|
|
8843
|
-
let dir = import_node_path42.default.resolve(serviceDir);
|
|
8844
|
-
const stops = /* @__PURE__ */ new Set();
|
|
8845
|
-
for (let i = 0; i < 64; i++) {
|
|
8846
|
-
if (stops.has(dir)) break;
|
|
8847
|
-
stops.add(dir);
|
|
8848
|
-
for (const candidate of LOCKFILE_PRIORITY) {
|
|
8849
|
-
const lockPath = import_node_path42.default.join(dir, candidate.lockfile);
|
|
8850
|
-
if (await exists4(lockPath)) {
|
|
8851
|
-
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
8852
|
-
}
|
|
8853
|
-
}
|
|
8854
|
-
const parent = import_node_path42.default.dirname(dir);
|
|
8855
|
-
if (parent === dir) break;
|
|
8856
|
-
dir = parent;
|
|
8857
|
-
}
|
|
8858
|
-
return { pm: "npm", cwd: import_node_path42.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
8859
|
-
}
|
|
8860
|
-
async function runPackageManagerInstall(cmd) {
|
|
8861
|
-
return new Promise((resolve) => {
|
|
8862
|
-
const child = (0, import_node_child_process2.spawn)(cmd.pm, cmd.args, {
|
|
8863
|
-
cwd: cmd.cwd,
|
|
8864
|
-
// Inherit PATH + HOME so the user's installed managers resolve.
|
|
8865
|
-
env: process.env,
|
|
8866
|
-
// `false` keeps the parent in control of cleanup if the orchestrator
|
|
8867
|
-
// exits before install finishes. Cross-platform-safe.
|
|
8868
|
-
shell: false,
|
|
8869
|
-
stdio: ["ignore", "ignore", "pipe"]
|
|
8870
|
-
});
|
|
8871
|
-
let stderr = "";
|
|
8872
|
-
child.stderr?.on("data", (chunk) => {
|
|
8873
|
-
stderr += chunk.toString("utf8");
|
|
8874
|
-
});
|
|
8875
|
-
child.on("error", (err) => {
|
|
8876
|
-
resolve({
|
|
8877
|
-
pm: cmd.pm,
|
|
8878
|
-
cwd: cmd.cwd,
|
|
8879
|
-
args: cmd.args,
|
|
8880
|
-
exitCode: 127,
|
|
8881
|
-
stderr: stderr + `
|
|
8882
|
-
${err.message}`
|
|
8883
|
-
});
|
|
8884
|
-
});
|
|
8885
|
-
child.on("close", (code) => {
|
|
8886
|
-
resolve({
|
|
8887
|
-
pm: cmd.pm,
|
|
8888
|
-
cwd: cmd.cwd,
|
|
8889
|
-
args: cmd.args,
|
|
8890
|
-
exitCode: code ?? 1,
|
|
8891
|
-
stderr: stderr.trim()
|
|
8892
|
-
});
|
|
8893
|
-
});
|
|
8894
|
-
});
|
|
8895
|
-
}
|
|
8896
|
-
|
|
8897
|
-
// src/orchestrator.ts
|
|
8898
9298
|
async function extractAndPersist(opts) {
|
|
8899
9299
|
const services = await discoverServices(opts.scanPath);
|
|
8900
9300
|
const languages = [...new Set(services.map((s) => s.node.language))].sort();
|
|
8901
9301
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
8902
9302
|
resetGraph(graphKey);
|
|
8903
9303
|
const graph = getGraph(graphKey);
|
|
8904
|
-
const projectPaths = pathsForProject(graphKey,
|
|
9304
|
+
const projectPaths = pathsForProject(graphKey, import_node_path44.default.join(opts.scanPath, "neat-out"));
|
|
8905
9305
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
8906
9306
|
errorsPath: projectPaths.errorsPath
|
|
8907
9307
|
});
|
|
@@ -8927,6 +9327,10 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
8927
9327
|
let libOnly = 0;
|
|
8928
9328
|
let browserBundle = 0;
|
|
8929
9329
|
let reactNative = 0;
|
|
9330
|
+
let bun = 0;
|
|
9331
|
+
let deno = 0;
|
|
9332
|
+
let cloudflareWorkers = 0;
|
|
9333
|
+
let electron = 0;
|
|
8930
9334
|
const installPlans = /* @__PURE__ */ new Map();
|
|
8931
9335
|
for (const svc of services) {
|
|
8932
9336
|
const installer = await pickInstaller(svc.dir);
|
|
@@ -8951,7 +9355,59 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
8951
9355
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
8952
9356
|
} else if (outcome.outcome === "react-native") {
|
|
8953
9357
|
reactNative++;
|
|
8954
|
-
|
|
9358
|
+
const svcName = import_node_path44.default.basename(svc.dir);
|
|
9359
|
+
console.log(
|
|
9360
|
+
`neat: ${svc.dir} detected as React Native / Expo
|
|
9361
|
+
The installer doesn't cover this runtime deterministically.
|
|
9362
|
+
Configure your OTel binding to send spans to:
|
|
9363
|
+
http://localhost:4318/projects/${project}/v1/traces
|
|
9364
|
+
Set OTEL_SERVICE_NAME=${svcName}
|
|
9365
|
+
See docs/installer-scope.md \u2192 "Manual setup for out-of-scope runtimes"`
|
|
9366
|
+
);
|
|
9367
|
+
} else if (outcome.outcome === "bun") {
|
|
9368
|
+
bun++;
|
|
9369
|
+
const svcName = import_node_path44.default.basename(svc.dir);
|
|
9370
|
+
console.log(
|
|
9371
|
+
`neat: ${svc.dir} detected as Bun
|
|
9372
|
+
The installer doesn't cover this runtime deterministically.
|
|
9373
|
+
Configure your OTel binding to send spans to:
|
|
9374
|
+
http://localhost:4318/projects/${project}/v1/traces
|
|
9375
|
+
Set OTEL_SERVICE_NAME=${svcName}
|
|
9376
|
+
See docs/installer-scope.md \u2192 "Manual setup for out-of-scope runtimes"`
|
|
9377
|
+
);
|
|
9378
|
+
} else if (outcome.outcome === "deno") {
|
|
9379
|
+
deno++;
|
|
9380
|
+
const svcName = import_node_path44.default.basename(svc.dir);
|
|
9381
|
+
console.log(
|
|
9382
|
+
`neat: ${svc.dir} detected as Deno
|
|
9383
|
+
The installer doesn't cover this runtime deterministically.
|
|
9384
|
+
Configure your OTel binding to send spans to:
|
|
9385
|
+
http://localhost:4318/projects/${project}/v1/traces
|
|
9386
|
+
Set OTEL_SERVICE_NAME=${svcName}
|
|
9387
|
+
See docs/installer-scope.md \u2192 "Manual setup for out-of-scope runtimes"`
|
|
9388
|
+
);
|
|
9389
|
+
} else if (outcome.outcome === "cloudflare-workers") {
|
|
9390
|
+
cloudflareWorkers++;
|
|
9391
|
+
const svcName = import_node_path44.default.basename(svc.dir);
|
|
9392
|
+
console.log(
|
|
9393
|
+
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
9394
|
+
The installer doesn't cover this runtime deterministically.
|
|
9395
|
+
Configure your OTel binding to send spans to:
|
|
9396
|
+
http://localhost:4318/projects/${project}/v1/traces
|
|
9397
|
+
Set OTEL_SERVICE_NAME=${svcName}
|
|
9398
|
+
See docs/installer-scope.md \u2192 "Manual setup for out-of-scope runtimes"`
|
|
9399
|
+
);
|
|
9400
|
+
} else if (outcome.outcome === "electron") {
|
|
9401
|
+
electron++;
|
|
9402
|
+
const svcName = import_node_path44.default.basename(svc.dir);
|
|
9403
|
+
console.log(
|
|
9404
|
+
`neat: ${svc.dir} detected as Electron
|
|
9405
|
+
The installer doesn't cover this runtime deterministically.
|
|
9406
|
+
Configure your OTel binding to send spans to:
|
|
9407
|
+
http://localhost:4318/projects/${project}/v1/traces
|
|
9408
|
+
Set OTEL_SERVICE_NAME=${svcName}
|
|
9409
|
+
See docs/installer-scope.md \u2192 "Manual setup for out-of-scope runtimes"`
|
|
9410
|
+
);
|
|
8955
9411
|
}
|
|
8956
9412
|
}
|
|
8957
9413
|
const packageManagerInstalls = [];
|
|
@@ -8976,6 +9432,10 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
8976
9432
|
libOnly,
|
|
8977
9433
|
browserBundle,
|
|
8978
9434
|
reactNative,
|
|
9435
|
+
bun,
|
|
9436
|
+
deno,
|
|
9437
|
+
cloudflareWorkers,
|
|
9438
|
+
electron,
|
|
8979
9439
|
packageManagerInstalls
|
|
8980
9440
|
};
|
|
8981
9441
|
}
|
|
@@ -9113,10 +9573,10 @@ function formatPortCollisionMessage(port) {
|
|
|
9113
9573
|
];
|
|
9114
9574
|
}
|
|
9115
9575
|
function spawnDaemonDetached() {
|
|
9116
|
-
const here =
|
|
9576
|
+
const here = import_node_path44.default.dirname(new URL(importMetaUrl).pathname);
|
|
9117
9577
|
const candidates = [
|
|
9118
|
-
|
|
9119
|
-
|
|
9578
|
+
import_node_path44.default.join(here, "neatd.cjs"),
|
|
9579
|
+
import_node_path44.default.join(here, "neatd.js")
|
|
9120
9580
|
];
|
|
9121
9581
|
let entry2 = null;
|
|
9122
9582
|
const fsSync = require("fs");
|
|
@@ -9174,7 +9634,7 @@ async function runOrchestrator(opts) {
|
|
|
9174
9634
|
browser: "skipped"
|
|
9175
9635
|
}
|
|
9176
9636
|
};
|
|
9177
|
-
const stat = await
|
|
9637
|
+
const stat = await import_node_fs29.promises.stat(opts.scanPath).catch(() => null);
|
|
9178
9638
|
if (!stat || !stat.isDirectory()) {
|
|
9179
9639
|
console.error(`neat: ${opts.scanPath} is not a directory`);
|
|
9180
9640
|
result.exitCode = 2;
|
|
@@ -9317,7 +9777,7 @@ function printSummary(result, graph, dashboardUrl) {
|
|
|
9317
9777
|
|
|
9318
9778
|
// src/cli-verbs.ts
|
|
9319
9779
|
init_cjs_shims();
|
|
9320
|
-
var
|
|
9780
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
9321
9781
|
|
|
9322
9782
|
// src/cli-client.ts
|
|
9323
9783
|
init_cjs_shims();
|
|
@@ -9346,10 +9806,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9346
9806
|
const root = baseUrl.replace(/\/$/, "");
|
|
9347
9807
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
9348
9808
|
return {
|
|
9349
|
-
async get(
|
|
9809
|
+
async get(path47) {
|
|
9350
9810
|
let res;
|
|
9351
9811
|
try {
|
|
9352
|
-
res = await fetch(`${root}${
|
|
9812
|
+
res = await fetch(`${root}${path47}`, {
|
|
9353
9813
|
headers: { ...authHeader }
|
|
9354
9814
|
});
|
|
9355
9815
|
} catch (err) {
|
|
@@ -9361,16 +9821,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9361
9821
|
const body = await res.text().catch(() => "");
|
|
9362
9822
|
throw new HttpError(
|
|
9363
9823
|
res.status,
|
|
9364
|
-
`${res.status} ${res.statusText} on GET ${
|
|
9824
|
+
`${res.status} ${res.statusText} on GET ${path47}: ${body}`,
|
|
9365
9825
|
body
|
|
9366
9826
|
);
|
|
9367
9827
|
}
|
|
9368
9828
|
return await res.json();
|
|
9369
9829
|
},
|
|
9370
|
-
async post(
|
|
9830
|
+
async post(path47, body) {
|
|
9371
9831
|
let res;
|
|
9372
9832
|
try {
|
|
9373
|
-
res = await fetch(`${root}${
|
|
9833
|
+
res = await fetch(`${root}${path47}`, {
|
|
9374
9834
|
method: "POST",
|
|
9375
9835
|
headers: { "content-type": "application/json", ...authHeader },
|
|
9376
9836
|
body: JSON.stringify(body)
|
|
@@ -9384,7 +9844,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
9384
9844
|
const text = await res.text().catch(() => "");
|
|
9385
9845
|
throw new HttpError(
|
|
9386
9846
|
res.status,
|
|
9387
|
-
`${res.status} ${res.statusText} on POST ${
|
|
9847
|
+
`${res.status} ${res.statusText} on POST ${path47}: ${text}`,
|
|
9388
9848
|
text
|
|
9389
9849
|
);
|
|
9390
9850
|
}
|
|
@@ -9398,12 +9858,12 @@ function projectPath(project, suffix) {
|
|
|
9398
9858
|
}
|
|
9399
9859
|
async function runRootCause(client, input) {
|
|
9400
9860
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
9401
|
-
const
|
|
9861
|
+
const path47 = projectPath(
|
|
9402
9862
|
input.project,
|
|
9403
9863
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
9404
9864
|
);
|
|
9405
9865
|
try {
|
|
9406
|
-
const result = await client.get(
|
|
9866
|
+
const result = await client.get(path47);
|
|
9407
9867
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
9408
9868
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
9409
9869
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -9429,12 +9889,12 @@ async function runRootCause(client, input) {
|
|
|
9429
9889
|
}
|
|
9430
9890
|
async function runBlastRadius(client, input) {
|
|
9431
9891
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
9432
|
-
const
|
|
9892
|
+
const path47 = projectPath(
|
|
9433
9893
|
input.project,
|
|
9434
9894
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
9435
9895
|
);
|
|
9436
9896
|
try {
|
|
9437
|
-
const result = await client.get(
|
|
9897
|
+
const result = await client.get(path47);
|
|
9438
9898
|
if (result.totalAffected === 0) {
|
|
9439
9899
|
return {
|
|
9440
9900
|
summary: `${result.origin} has no downstream dependencies. Nothing else would break if it failed.`
|
|
@@ -9468,12 +9928,12 @@ function formatBlastEntry(n) {
|
|
|
9468
9928
|
}
|
|
9469
9929
|
async function runDependencies(client, input) {
|
|
9470
9930
|
const depth = input.depth ?? 3;
|
|
9471
|
-
const
|
|
9931
|
+
const path47 = projectPath(
|
|
9472
9932
|
input.project,
|
|
9473
9933
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
9474
9934
|
);
|
|
9475
9935
|
try {
|
|
9476
|
-
const result = await client.get(
|
|
9936
|
+
const result = await client.get(path47);
|
|
9477
9937
|
if (result.total === 0) {
|
|
9478
9938
|
return {
|
|
9479
9939
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -9554,9 +10014,9 @@ function formatDuration(ms) {
|
|
|
9554
10014
|
return `${Math.round(h / 24)}d`;
|
|
9555
10015
|
}
|
|
9556
10016
|
async function runIncidents(client, input) {
|
|
9557
|
-
const
|
|
10017
|
+
const path47 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
9558
10018
|
try {
|
|
9559
|
-
const body = await client.get(
|
|
10019
|
+
const body = await client.get(path47);
|
|
9560
10020
|
const events = body.events;
|
|
9561
10021
|
if (events.length === 0) {
|
|
9562
10022
|
return {
|
|
@@ -9846,7 +10306,7 @@ async function resolveProjectEntry(opts) {
|
|
|
9846
10306
|
const cwd = opts.cwd ?? process.cwd();
|
|
9847
10307
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
9848
10308
|
for (const entry2 of entries) {
|
|
9849
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
10309
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path45.default.sep}`)) {
|
|
9850
10310
|
return entry2;
|
|
9851
10311
|
}
|
|
9852
10312
|
}
|
|
@@ -10206,14 +10666,14 @@ function assignFlag(out, field, value) {
|
|
|
10206
10666
|
out[field] = value;
|
|
10207
10667
|
}
|
|
10208
10668
|
function readPackageVersion() {
|
|
10209
|
-
const here = typeof __dirname !== "undefined" ? __dirname :
|
|
10669
|
+
const here = typeof __dirname !== "undefined" ? __dirname : import_node_path46.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
10210
10670
|
const candidates = [
|
|
10211
|
-
|
|
10212
|
-
|
|
10671
|
+
import_node_path46.default.resolve(here, "../package.json"),
|
|
10672
|
+
import_node_path46.default.resolve(here, "../../package.json")
|
|
10213
10673
|
];
|
|
10214
10674
|
for (const candidate of candidates) {
|
|
10215
10675
|
try {
|
|
10216
|
-
const raw = (0,
|
|
10676
|
+
const raw = (0, import_node_fs30.readFileSync)(candidate, "utf8");
|
|
10217
10677
|
const parsed = JSON.parse(raw);
|
|
10218
10678
|
if (parsed.name === "@neat.is/core" && typeof parsed.version === "string") {
|
|
10219
10679
|
return parsed.version;
|
|
@@ -10277,7 +10737,7 @@ async function buildPatchSections(services, project) {
|
|
|
10277
10737
|
}
|
|
10278
10738
|
async function runInit(opts) {
|
|
10279
10739
|
const written = [];
|
|
10280
|
-
const stat = await
|
|
10740
|
+
const stat = await import_node_fs30.promises.stat(opts.scanPath).catch(() => null);
|
|
10281
10741
|
if (!stat || !stat.isDirectory()) {
|
|
10282
10742
|
console.error(`neat init: ${opts.scanPath} is not a directory`);
|
|
10283
10743
|
return { exitCode: 2, writtenFiles: written };
|
|
@@ -10286,13 +10746,13 @@ async function runInit(opts) {
|
|
|
10286
10746
|
printDiscoveryReport(opts, services);
|
|
10287
10747
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
10288
10748
|
const patch = renderPatch(sections);
|
|
10289
|
-
const patchPath =
|
|
10749
|
+
const patchPath = import_node_path46.default.join(opts.scanPath, "neat.patch");
|
|
10290
10750
|
if (opts.dryRun) {
|
|
10291
|
-
await
|
|
10751
|
+
await import_node_fs30.promises.writeFile(patchPath, patch, "utf8");
|
|
10292
10752
|
written.push(patchPath);
|
|
10293
10753
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
10294
|
-
const gitignorePath =
|
|
10295
|
-
const gitignoreExists = await
|
|
10754
|
+
const gitignorePath = import_node_path46.default.join(opts.scanPath, ".gitignore");
|
|
10755
|
+
const gitignoreExists = await import_node_fs30.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
10296
10756
|
const verb = gitignoreExists ? "append" : "create";
|
|
10297
10757
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
10298
10758
|
console.log("rerun without --dry-run to register and snapshot.");
|
|
@@ -10303,9 +10763,9 @@ async function runInit(opts) {
|
|
|
10303
10763
|
const graph = getGraph(graphKey);
|
|
10304
10764
|
const projectPaths = pathsForProject(
|
|
10305
10765
|
graphKey,
|
|
10306
|
-
|
|
10766
|
+
import_node_path46.default.join(opts.scanPath, "neat-out")
|
|
10307
10767
|
);
|
|
10308
|
-
const errorsPath =
|
|
10768
|
+
const errorsPath = import_node_path46.default.join(import_node_path46.default.dirname(opts.outPath), import_node_path46.default.basename(projectPaths.errorsPath));
|
|
10309
10769
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
10310
10770
|
await saveGraphToDisk(graph, opts.outPath);
|
|
10311
10771
|
written.push(opts.outPath);
|
|
@@ -10384,7 +10844,7 @@ async function runInit(opts) {
|
|
|
10384
10844
|
console.log("Run `npm install` (or your language equivalent) to refresh lockfiles.");
|
|
10385
10845
|
}
|
|
10386
10846
|
} else {
|
|
10387
|
-
await
|
|
10847
|
+
await import_node_fs30.promises.writeFile(patchPath, patch, "utf8");
|
|
10388
10848
|
written.push(patchPath);
|
|
10389
10849
|
}
|
|
10390
10850
|
}
|
|
@@ -10424,9 +10884,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
10424
10884
|
};
|
|
10425
10885
|
function claudeConfigPath() {
|
|
10426
10886
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
10427
|
-
if (override && override.length > 0) return
|
|
10887
|
+
if (override && override.length > 0) return import_node_path46.default.resolve(override);
|
|
10428
10888
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10429
|
-
return
|
|
10889
|
+
return import_node_path46.default.join(home, ".claude.json");
|
|
10430
10890
|
}
|
|
10431
10891
|
async function runSkill(opts) {
|
|
10432
10892
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -10438,7 +10898,7 @@ async function runSkill(opts) {
|
|
|
10438
10898
|
const target = claudeConfigPath();
|
|
10439
10899
|
let existing = {};
|
|
10440
10900
|
try {
|
|
10441
|
-
existing = JSON.parse(await
|
|
10901
|
+
existing = JSON.parse(await import_node_fs30.promises.readFile(target, "utf8"));
|
|
10442
10902
|
} catch (err) {
|
|
10443
10903
|
if (err.code !== "ENOENT") {
|
|
10444
10904
|
console.error(`neat skill: failed to read ${target} \u2014 ${err.message}`);
|
|
@@ -10450,8 +10910,8 @@ async function runSkill(opts) {
|
|
|
10450
10910
|
...existing,
|
|
10451
10911
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
10452
10912
|
};
|
|
10453
|
-
await
|
|
10454
|
-
await
|
|
10913
|
+
await import_node_fs30.promises.mkdir(import_node_path46.default.dirname(target), { recursive: true });
|
|
10914
|
+
await import_node_fs30.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
10455
10915
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
10456
10916
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
10457
10917
|
return { exitCode: 0 };
|
|
@@ -10489,12 +10949,12 @@ async function main() {
|
|
|
10489
10949
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
10490
10950
|
process.exit(2);
|
|
10491
10951
|
}
|
|
10492
|
-
const scanPath =
|
|
10952
|
+
const scanPath = import_node_path46.default.resolve(target);
|
|
10493
10953
|
const projectExplicit = parsed.project !== null;
|
|
10494
|
-
const projectName = projectExplicit ? project :
|
|
10954
|
+
const projectName = projectExplicit ? project : import_node_path46.default.basename(scanPath);
|
|
10495
10955
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
10496
|
-
const fallback = pathsForProject(projectKey,
|
|
10497
|
-
const outPath =
|
|
10956
|
+
const fallback = pathsForProject(projectKey, import_node_path46.default.join(scanPath, "neat-out")).snapshotPath;
|
|
10957
|
+
const outPath = import_node_path46.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
10498
10958
|
const result = await runInit({
|
|
10499
10959
|
scanPath,
|
|
10500
10960
|
outPath,
|
|
@@ -10515,21 +10975,21 @@ async function main() {
|
|
|
10515
10975
|
usage();
|
|
10516
10976
|
process.exit(2);
|
|
10517
10977
|
}
|
|
10518
|
-
const scanPath =
|
|
10519
|
-
const stat = await
|
|
10978
|
+
const scanPath = import_node_path46.default.resolve(target);
|
|
10979
|
+
const stat = await import_node_fs30.promises.stat(scanPath).catch(() => null);
|
|
10520
10980
|
if (!stat || !stat.isDirectory()) {
|
|
10521
10981
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
10522
10982
|
process.exit(2);
|
|
10523
10983
|
}
|
|
10524
|
-
const projectPaths = pathsForProject(project,
|
|
10525
|
-
const outPath =
|
|
10526
|
-
const errorsPath =
|
|
10527
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
10984
|
+
const projectPaths = pathsForProject(project, import_node_path46.default.join(scanPath, "neat-out"));
|
|
10985
|
+
const outPath = import_node_path46.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
10986
|
+
const errorsPath = import_node_path46.default.resolve(
|
|
10987
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path46.default.join(import_node_path46.default.dirname(outPath), import_node_path46.default.basename(projectPaths.errorsPath))
|
|
10528
10988
|
);
|
|
10529
|
-
const staleEventsPath =
|
|
10530
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
10989
|
+
const staleEventsPath = import_node_path46.default.resolve(
|
|
10990
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path46.default.join(import_node_path46.default.dirname(outPath), import_node_path46.default.basename(projectPaths.staleEventsPath))
|
|
10531
10991
|
);
|
|
10532
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
10992
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path46.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
10533
10993
|
const handle = await startWatch(getGraph(project), {
|
|
10534
10994
|
scanPath,
|
|
10535
10995
|
outPath,
|
|
@@ -10675,11 +11135,11 @@ async function main() {
|
|
|
10675
11135
|
process.exit(1);
|
|
10676
11136
|
}
|
|
10677
11137
|
async function tryOrchestrator(cmd, parsed) {
|
|
10678
|
-
const scanPath =
|
|
10679
|
-
const stat = await
|
|
11138
|
+
const scanPath = import_node_path46.default.resolve(cmd);
|
|
11139
|
+
const stat = await import_node_fs30.promises.stat(scanPath).catch(() => null);
|
|
10680
11140
|
if (!stat || !stat.isDirectory()) return null;
|
|
10681
11141
|
const projectExplicit = parsed.project !== null;
|
|
10682
|
-
const projectName = projectExplicit ? parsed.project :
|
|
11142
|
+
const projectName = projectExplicit ? parsed.project : import_node_path46.default.basename(scanPath);
|
|
10683
11143
|
const result = await runOrchestrator({
|
|
10684
11144
|
scanPath,
|
|
10685
11145
|
project: projectName,
|