@neat.is/core 0.4.15 → 0.4.16
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/cli.cjs +558 -507
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +8 -3
- package/dist/cli.d.ts +8 -3
- package/dist/cli.js +215 -169
- package/dist/cli.js.map +1 -1
- package/package.json +3 -4
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 path50 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
62
62
|
for (const suffix of suffixes) {
|
|
63
|
-
if (
|
|
63
|
+
if (path50 === suffix || path50.endsWith(suffix)) {
|
|
64
64
|
done();
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -188,8 +188,8 @@ function reshapeGrpcRequest(req) {
|
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
function resolveProtoRoot() {
|
|
191
|
-
const here =
|
|
192
|
-
return
|
|
191
|
+
const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
192
|
+
return import_node_path40.default.resolve(here, "..", "proto");
|
|
193
193
|
}
|
|
194
194
|
function loadTraceService() {
|
|
195
195
|
const protoRoot = resolveProtoRoot();
|
|
@@ -257,13 +257,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
257
257
|
})
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
|
-
var
|
|
260
|
+
var import_node_url2, import_node_path40, import_node_crypto2, grpc, protoLoader;
|
|
261
261
|
var init_otel_grpc = __esm({
|
|
262
262
|
"src/otel-grpc.ts"() {
|
|
263
263
|
"use strict";
|
|
264
264
|
init_cjs_shims();
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
import_node_url2 = require("url");
|
|
266
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
267
267
|
import_node_crypto2 = require("crypto");
|
|
268
268
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
269
269
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -373,10 +373,10 @@ function parseOtlpRequest(body) {
|
|
|
373
373
|
return out;
|
|
374
374
|
}
|
|
375
375
|
function loadProtoRoot() {
|
|
376
|
-
const here =
|
|
377
|
-
const protoRoot =
|
|
376
|
+
const here = import_node_path41.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
377
|
+
const protoRoot = import_node_path41.default.resolve(here, "..", "proto");
|
|
378
378
|
const root = new import_protobufjs.default.Root();
|
|
379
|
-
root.resolvePath = (_origin, target) =>
|
|
379
|
+
root.resolvePath = (_origin, target) => import_node_path41.default.resolve(protoRoot, target);
|
|
380
380
|
root.loadSync(
|
|
381
381
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
382
382
|
{ keepCase: true }
|
|
@@ -572,13 +572,13 @@ async function buildOtelReceiver(opts) {
|
|
|
572
572
|
};
|
|
573
573
|
return decorated;
|
|
574
574
|
}
|
|
575
|
-
var
|
|
575
|
+
var import_node_path41, import_node_url3, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
576
576
|
var init_otel = __esm({
|
|
577
577
|
"src/otel.ts"() {
|
|
578
578
|
"use strict";
|
|
579
579
|
init_cjs_shims();
|
|
580
|
-
|
|
581
|
-
|
|
580
|
+
import_node_path41 = __toESM(require("path"), 1);
|
|
581
|
+
import_node_url3 = require("url");
|
|
582
582
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
583
583
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
584
584
|
init_auth();
|
|
@@ -596,18 +596,57 @@ var cli_exports = {};
|
|
|
596
596
|
__export(cli_exports, {
|
|
597
597
|
CLAUDE_SKILL_CONFIG: () => CLAUDE_SKILL_CONFIG,
|
|
598
598
|
QUERY_VERBS: () => QUERY_VERBS,
|
|
599
|
+
commandPrefix: () => commandPrefix,
|
|
600
|
+
isNpxInvocation: () => isNpxInvocation,
|
|
601
|
+
main: () => main,
|
|
599
602
|
parseArgs: () => parseArgs,
|
|
600
603
|
printBanner: () => printBanner,
|
|
601
604
|
readPackageVersion: () => readPackageVersion,
|
|
602
605
|
runInit: () => runInit,
|
|
603
606
|
runQueryVerb: () => runQueryVerb,
|
|
604
|
-
runSkill: () => runSkill
|
|
607
|
+
runSkill: () => runSkill,
|
|
608
|
+
usage: () => usage
|
|
605
609
|
});
|
|
606
610
|
module.exports = __toCommonJS(cli_exports);
|
|
607
611
|
init_cjs_shims();
|
|
608
|
-
var
|
|
609
|
-
var
|
|
610
|
-
|
|
612
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
613
|
+
var import_node_fs32 = require("fs");
|
|
614
|
+
|
|
615
|
+
// src/banner.ts
|
|
616
|
+
init_cjs_shims();
|
|
617
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
618
|
+
var import_node_fs = require("fs");
|
|
619
|
+
var import_node_url = require("url");
|
|
620
|
+
function readPackageVersion() {
|
|
621
|
+
const here = typeof __dirname !== "undefined" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
622
|
+
const candidates = [
|
|
623
|
+
import_node_path.default.resolve(here, "../package.json"),
|
|
624
|
+
import_node_path.default.resolve(here, "../../package.json")
|
|
625
|
+
];
|
|
626
|
+
for (const candidate of candidates) {
|
|
627
|
+
try {
|
|
628
|
+
const raw = (0, import_node_fs.readFileSync)(candidate, "utf8");
|
|
629
|
+
const parsed = JSON.parse(raw);
|
|
630
|
+
if (parsed.name === "@neat.is/core" && typeof parsed.version === "string") {
|
|
631
|
+
return parsed.version;
|
|
632
|
+
}
|
|
633
|
+
} catch {
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return "unknown";
|
|
637
|
+
}
|
|
638
|
+
function printBanner() {
|
|
639
|
+
console.log("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
640
|
+
console.log("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D");
|
|
641
|
+
console.log("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
642
|
+
console.log("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
643
|
+
console.log("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
644
|
+
console.log("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D ");
|
|
645
|
+
console.log("");
|
|
646
|
+
console.log(" Network Expressive Architecting Tool");
|
|
647
|
+
console.log(` neat.is \xB7 v${readPackageVersion()} \xB7 Apache 2.0`);
|
|
648
|
+
console.log("");
|
|
649
|
+
}
|
|
611
650
|
|
|
612
651
|
// src/graph.ts
|
|
613
652
|
init_cjs_shims();
|
|
@@ -642,21 +681,21 @@ init_cjs_shims();
|
|
|
642
681
|
|
|
643
682
|
// src/ingest.ts
|
|
644
683
|
init_cjs_shims();
|
|
645
|
-
var
|
|
646
|
-
var
|
|
684
|
+
var import_node_fs4 = require("fs");
|
|
685
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
647
686
|
var sourceMapJs = __toESM(require("source-map-js"), 1);
|
|
648
687
|
|
|
649
688
|
// src/policy.ts
|
|
650
689
|
init_cjs_shims();
|
|
651
|
-
var
|
|
652
|
-
var
|
|
690
|
+
var import_node_fs3 = require("fs");
|
|
691
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
653
692
|
var import_types2 = require("@neat.is/types");
|
|
654
693
|
|
|
655
694
|
// src/compat.ts
|
|
656
695
|
init_cjs_shims();
|
|
657
|
-
var
|
|
696
|
+
var import_node_fs2 = require("fs");
|
|
658
697
|
var import_node_os = __toESM(require("os"), 1);
|
|
659
|
-
var
|
|
698
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
660
699
|
var import_semver = __toESM(require("semver"), 1);
|
|
661
700
|
|
|
662
701
|
// compat.json
|
|
@@ -785,8 +824,8 @@ var compat_default = {
|
|
|
785
824
|
var bundledMatrix = compat_default;
|
|
786
825
|
var mergedMatrix = null;
|
|
787
826
|
var remoteLoadAttempted = false;
|
|
788
|
-
var REMOTE_CACHE_DIR =
|
|
789
|
-
var REMOTE_CACHE_PATH =
|
|
827
|
+
var REMOTE_CACHE_DIR = import_node_path2.default.join(import_node_os.default.homedir(), ".neat");
|
|
828
|
+
var REMOTE_CACHE_PATH = import_node_path2.default.join(REMOTE_CACHE_DIR, "compat-cache.json");
|
|
790
829
|
var REMOTE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
791
830
|
function engineMeetsThreshold(engineVersion, threshold) {
|
|
792
831
|
const e = parseInt(engineVersion, 10);
|
|
@@ -897,7 +936,7 @@ function mergeMatrices(a, b) {
|
|
|
897
936
|
}
|
|
898
937
|
async function readRemoteCache(url) {
|
|
899
938
|
try {
|
|
900
|
-
const raw = await
|
|
939
|
+
const raw = await import_node_fs2.promises.readFile(REMOTE_CACHE_PATH, "utf8");
|
|
901
940
|
const parsed = JSON.parse(raw);
|
|
902
941
|
if (parsed.url !== url) return null;
|
|
903
942
|
const age = Date.now() - new Date(parsed.fetchedAt).getTime();
|
|
@@ -914,8 +953,8 @@ async function writeRemoteCache(url, matrix) {
|
|
|
914
953
|
matrix
|
|
915
954
|
};
|
|
916
955
|
try {
|
|
917
|
-
await
|
|
918
|
-
await
|
|
956
|
+
await import_node_fs2.promises.mkdir(REMOTE_CACHE_DIR, { recursive: true });
|
|
957
|
+
await import_node_fs2.promises.writeFile(REMOTE_CACHE_PATH, JSON.stringify(file), "utf8");
|
|
919
958
|
} catch (err) {
|
|
920
959
|
console.warn(`[neat] failed to cache compat matrix: ${err.message}`);
|
|
921
960
|
}
|
|
@@ -1136,19 +1175,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1136
1175
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1137
1176
|
let best = { path: [start], edges: [] };
|
|
1138
1177
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1139
|
-
function step(node,
|
|
1140
|
-
if (
|
|
1141
|
-
best = { path: [...
|
|
1178
|
+
function step(node, path50, edges) {
|
|
1179
|
+
if (path50.length > best.path.length) {
|
|
1180
|
+
best = { path: [...path50], edges: [...edges] };
|
|
1142
1181
|
}
|
|
1143
|
-
if (
|
|
1182
|
+
if (path50.length - 1 >= maxDepth) return;
|
|
1144
1183
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1145
1184
|
for (const [srcId, edge] of incoming) {
|
|
1146
1185
|
if (visited.has(srcId)) continue;
|
|
1147
1186
|
visited.add(srcId);
|
|
1148
|
-
|
|
1187
|
+
path50.push(srcId);
|
|
1149
1188
|
edges.push(edge);
|
|
1150
|
-
step(srcId,
|
|
1151
|
-
|
|
1189
|
+
step(srcId, path50, edges);
|
|
1190
|
+
path50.pop();
|
|
1152
1191
|
edges.pop();
|
|
1153
1192
|
visited.delete(srcId);
|
|
1154
1193
|
}
|
|
@@ -1607,7 +1646,7 @@ function evaluateAllPolicies(graph, policies, ctx) {
|
|
|
1607
1646
|
async function loadPolicyFile(policyPath) {
|
|
1608
1647
|
let raw;
|
|
1609
1648
|
try {
|
|
1610
|
-
raw = await
|
|
1649
|
+
raw = await import_node_fs3.promises.readFile(policyPath, "utf8");
|
|
1611
1650
|
} catch (err) {
|
|
1612
1651
|
if (err.code === "ENOENT") return [];
|
|
1613
1652
|
throw err;
|
|
@@ -1628,8 +1667,8 @@ var PolicyViolationsLog = class {
|
|
|
1628
1667
|
if (!this.seen) await this.hydrate();
|
|
1629
1668
|
if (this.seen.has(v.id)) return false;
|
|
1630
1669
|
this.seen.add(v.id);
|
|
1631
|
-
await
|
|
1632
|
-
await
|
|
1670
|
+
await import_node_fs3.promises.mkdir(import_node_path3.default.dirname(this.path), { recursive: true });
|
|
1671
|
+
await import_node_fs3.promises.appendFile(this.path, JSON.stringify(v) + "\n", "utf8");
|
|
1633
1672
|
emitNeatEvent({
|
|
1634
1673
|
type: "policy-violation",
|
|
1635
1674
|
project: this.project,
|
|
@@ -1639,7 +1678,7 @@ var PolicyViolationsLog = class {
|
|
|
1639
1678
|
}
|
|
1640
1679
|
async readAll() {
|
|
1641
1680
|
try {
|
|
1642
|
-
const raw = await
|
|
1681
|
+
const raw = await import_node_fs3.promises.readFile(this.path, "utf8");
|
|
1643
1682
|
return raw.split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
1644
1683
|
} catch (err) {
|
|
1645
1684
|
if (err.code === "ENOENT") return [];
|
|
@@ -1752,7 +1791,7 @@ function languageForExt(relPath) {
|
|
|
1752
1791
|
function relPathForRuntimeFile(filepath, serviceNode, scanPath) {
|
|
1753
1792
|
let p = toPosix(filepath).replace(/^file:\/\//, "");
|
|
1754
1793
|
if (scanPath && scanPath.length > 0) {
|
|
1755
|
-
const absRoot = toPosix(
|
|
1794
|
+
const absRoot = toPosix(import_node_path4.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
|
|
1756
1795
|
const anchor = absRoot.endsWith("/") ? absRoot : `${absRoot}/`;
|
|
1757
1796
|
if (p.startsWith(anchor)) return p.slice(anchor.length);
|
|
1758
1797
|
}
|
|
@@ -1780,10 +1819,10 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
1780
1819
|
entry2 = null;
|
|
1781
1820
|
const mapPath = `${absFilepath}.map`;
|
|
1782
1821
|
try {
|
|
1783
|
-
if ((0,
|
|
1784
|
-
const raw = JSON.parse((0,
|
|
1822
|
+
if ((0, import_node_fs4.existsSync)(mapPath)) {
|
|
1823
|
+
const raw = JSON.parse((0, import_node_fs4.readFileSync)(mapPath, "utf8"));
|
|
1785
1824
|
const consumer = new sourceMapJs.SourceMapConsumer(raw);
|
|
1786
|
-
entry2 = { consumer, dir:
|
|
1825
|
+
entry2 = { consumer, dir: import_node_path4.default.dirname(mapPath) };
|
|
1787
1826
|
}
|
|
1788
1827
|
} catch {
|
|
1789
1828
|
entry2 = null;
|
|
@@ -1798,7 +1837,7 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
1798
1837
|
});
|
|
1799
1838
|
if (!pos || !pos.source) return null;
|
|
1800
1839
|
const root = entry2.consumer.sourceRoot ?? "";
|
|
1801
|
-
const resolved =
|
|
1840
|
+
const resolved = import_node_path4.default.resolve(entry2.dir, root, pos.source);
|
|
1802
1841
|
return { filepath: resolved, ...pos.line ? { line: pos.line } : {} };
|
|
1803
1842
|
} catch {
|
|
1804
1843
|
return null;
|
|
@@ -2065,8 +2104,8 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
2065
2104
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
2066
2105
|
}
|
|
2067
2106
|
async function appendErrorEvent(ctx, ev) {
|
|
2068
|
-
await
|
|
2069
|
-
await
|
|
2107
|
+
await import_node_fs4.promises.mkdir(import_node_path4.default.dirname(ctx.errorsPath), { recursive: true });
|
|
2108
|
+
await import_node_fs4.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
2070
2109
|
}
|
|
2071
2110
|
function sanitizeAttributes(attrs) {
|
|
2072
2111
|
const out = {};
|
|
@@ -2097,8 +2136,8 @@ function makeErrorSpanWriter(errorsPath) {
|
|
|
2097
2136
|
return async (span) => {
|
|
2098
2137
|
const ev = buildErrorEventForReceiver(span);
|
|
2099
2138
|
if (!ev) return;
|
|
2100
|
-
await
|
|
2101
|
-
await
|
|
2139
|
+
await import_node_fs4.promises.mkdir(import_node_path4.default.dirname(errorsPath), { recursive: true });
|
|
2140
|
+
await import_node_fs4.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
2102
2141
|
};
|
|
2103
2142
|
}
|
|
2104
2143
|
async function handleSpan(ctx, span) {
|
|
@@ -2317,13 +2356,13 @@ async function markStaleEdges(graph, options = {}) {
|
|
|
2317
2356
|
return { count: events.length, events };
|
|
2318
2357
|
}
|
|
2319
2358
|
async function appendStaleEvents(staleEventsPath, events) {
|
|
2320
|
-
await
|
|
2359
|
+
await import_node_fs4.promises.mkdir(import_node_path4.default.dirname(staleEventsPath), { recursive: true });
|
|
2321
2360
|
const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2322
|
-
await
|
|
2361
|
+
await import_node_fs4.promises.appendFile(staleEventsPath, lines, "utf8");
|
|
2323
2362
|
}
|
|
2324
2363
|
async function readStaleEvents(staleEventsPath) {
|
|
2325
2364
|
try {
|
|
2326
|
-
const raw = await
|
|
2365
|
+
const raw = await import_node_fs4.promises.readFile(staleEventsPath, "utf8");
|
|
2327
2366
|
return raw.split("\n").filter((line) => line.length > 0).map((line) => JSON.parse(line));
|
|
2328
2367
|
} catch (err) {
|
|
2329
2368
|
if (err.code === "ENOENT") return [];
|
|
@@ -2357,7 +2396,7 @@ function startStalenessLoop(graph, options = {}) {
|
|
|
2357
2396
|
}
|
|
2358
2397
|
async function readErrorEvents(errorsPath) {
|
|
2359
2398
|
try {
|
|
2360
|
-
const raw = await
|
|
2399
|
+
const raw = await import_node_fs4.promises.readFile(errorsPath, "utf8");
|
|
2361
2400
|
return raw.split("\n").filter((line) => line.length > 0).map((line) => JSON.parse(line));
|
|
2362
2401
|
} catch (err) {
|
|
2363
2402
|
if (err.code === "ENOENT") return [];
|
|
@@ -2389,16 +2428,16 @@ function mergeSnapshot(graph, snapshot) {
|
|
|
2389
2428
|
|
|
2390
2429
|
// src/extract/services.ts
|
|
2391
2430
|
init_cjs_shims();
|
|
2392
|
-
var
|
|
2393
|
-
var
|
|
2431
|
+
var import_node_fs9 = require("fs");
|
|
2432
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
2394
2433
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
2395
2434
|
var import_minimatch2 = require("minimatch");
|
|
2396
2435
|
var import_types5 = require("@neat.is/types");
|
|
2397
2436
|
|
|
2398
2437
|
// src/extract/shared.ts
|
|
2399
2438
|
init_cjs_shims();
|
|
2400
|
-
var
|
|
2401
|
-
var
|
|
2439
|
+
var import_node_fs5 = require("fs");
|
|
2440
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
2402
2441
|
var import_yaml = require("yaml");
|
|
2403
2442
|
var import_types4 = require("@neat.is/types");
|
|
2404
2443
|
var SERVICE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs", ".ts", ".tsx", ".py"]);
|
|
@@ -2430,7 +2469,7 @@ async function isPythonVenvDir(dir) {
|
|
|
2430
2469
|
const cached = PYVENV_MARKER_CACHE.get(dir);
|
|
2431
2470
|
if (cached !== void 0) return cached;
|
|
2432
2471
|
try {
|
|
2433
|
-
const stat = await
|
|
2472
|
+
const stat = await import_node_fs5.promises.stat(import_node_path5.default.join(dir, "pyvenv.cfg"));
|
|
2434
2473
|
const ok = stat.isFile();
|
|
2435
2474
|
PYVENV_MARKER_CACHE.set(dir, ok);
|
|
2436
2475
|
return ok;
|
|
@@ -2440,7 +2479,7 @@ async function isPythonVenvDir(dir) {
|
|
|
2440
2479
|
}
|
|
2441
2480
|
}
|
|
2442
2481
|
function isConfigFile(name) {
|
|
2443
|
-
const ext =
|
|
2482
|
+
const ext = import_node_path5.default.extname(name);
|
|
2444
2483
|
if (CONFIG_FILE_EXTENSIONS.has(ext)) return { match: true, fileType: ext.slice(1) };
|
|
2445
2484
|
if (name === ".env" || name.startsWith(".env.")) {
|
|
2446
2485
|
if (isEnvTemplateFile(name)) return { match: false, fileType: "" };
|
|
@@ -2548,16 +2587,16 @@ function cleanVersion(raw) {
|
|
|
2548
2587
|
return raw.replace(/^[\^~><=v\s]+/, "").trim() || void 0;
|
|
2549
2588
|
}
|
|
2550
2589
|
async function readJson(filePath) {
|
|
2551
|
-
const raw = await
|
|
2590
|
+
const raw = await import_node_fs5.promises.readFile(filePath, "utf8");
|
|
2552
2591
|
return JSON.parse(raw);
|
|
2553
2592
|
}
|
|
2554
2593
|
async function readYaml(filePath) {
|
|
2555
|
-
const raw = await
|
|
2594
|
+
const raw = await import_node_fs5.promises.readFile(filePath, "utf8");
|
|
2556
2595
|
return (0, import_yaml.parse)(raw);
|
|
2557
2596
|
}
|
|
2558
2597
|
async function exists(p) {
|
|
2559
2598
|
try {
|
|
2560
|
-
await
|
|
2599
|
+
await import_node_fs5.promises.access(p);
|
|
2561
2600
|
return true;
|
|
2562
2601
|
} catch {
|
|
2563
2602
|
return false;
|
|
@@ -2566,8 +2605,8 @@ async function exists(p) {
|
|
|
2566
2605
|
|
|
2567
2606
|
// src/extract/python.ts
|
|
2568
2607
|
init_cjs_shims();
|
|
2569
|
-
var
|
|
2570
|
-
var
|
|
2608
|
+
var import_node_fs6 = require("fs");
|
|
2609
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
2571
2610
|
var import_smol_toml = require("smol-toml");
|
|
2572
2611
|
var REQUIREMENT_LINE = /^\s*([A-Za-z0-9_.-]+)(?:\[[^\]]*\])?\s*(?:(==)\s*([A-Za-z0-9_.+-]+))?/;
|
|
2573
2612
|
function parseRequirementsTxt(content) {
|
|
@@ -2600,25 +2639,25 @@ function depsFromPyProject(pyproject) {
|
|
|
2600
2639
|
return out;
|
|
2601
2640
|
}
|
|
2602
2641
|
async function discoverPythonService(serviceDir) {
|
|
2603
|
-
const pyprojectPath =
|
|
2604
|
-
const requirementsPath =
|
|
2605
|
-
const setupPath =
|
|
2642
|
+
const pyprojectPath = import_node_path6.default.join(serviceDir, "pyproject.toml");
|
|
2643
|
+
const requirementsPath = import_node_path6.default.join(serviceDir, "requirements.txt");
|
|
2644
|
+
const setupPath = import_node_path6.default.join(serviceDir, "setup.py");
|
|
2606
2645
|
const hasPyproject = await exists(pyprojectPath);
|
|
2607
2646
|
const hasRequirements = await exists(requirementsPath);
|
|
2608
2647
|
const hasSetup = await exists(setupPath);
|
|
2609
2648
|
if (!hasPyproject && !hasRequirements && !hasSetup) return null;
|
|
2610
|
-
let name =
|
|
2649
|
+
let name = import_node_path6.default.basename(serviceDir);
|
|
2611
2650
|
let version;
|
|
2612
2651
|
const dependencies = {};
|
|
2613
2652
|
if (hasPyproject) {
|
|
2614
|
-
const raw = await
|
|
2653
|
+
const raw = await import_node_fs6.promises.readFile(pyprojectPath, "utf8");
|
|
2615
2654
|
const pyproject = (0, import_smol_toml.parse)(raw);
|
|
2616
2655
|
name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name;
|
|
2617
2656
|
version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? void 0;
|
|
2618
2657
|
Object.assign(dependencies, depsFromPyProject(pyproject));
|
|
2619
2658
|
}
|
|
2620
2659
|
if (hasRequirements) {
|
|
2621
|
-
const raw = await
|
|
2660
|
+
const raw = await import_node_fs6.promises.readFile(requirementsPath, "utf8");
|
|
2622
2661
|
Object.assign(dependencies, parseRequirementsTxt(raw));
|
|
2623
2662
|
}
|
|
2624
2663
|
return { name, version, dependencies };
|
|
@@ -2633,17 +2672,17 @@ function pythonToPackage(service) {
|
|
|
2633
2672
|
|
|
2634
2673
|
// src/extract/owners.ts
|
|
2635
2674
|
init_cjs_shims();
|
|
2636
|
-
var
|
|
2637
|
-
var
|
|
2675
|
+
var import_node_fs7 = require("fs");
|
|
2676
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
2638
2677
|
var import_minimatch = require("minimatch");
|
|
2639
2678
|
async function loadCodeowners(scanPath) {
|
|
2640
2679
|
const candidates = [
|
|
2641
|
-
|
|
2642
|
-
|
|
2680
|
+
import_node_path7.default.join(scanPath, "CODEOWNERS"),
|
|
2681
|
+
import_node_path7.default.join(scanPath, ".github", "CODEOWNERS")
|
|
2643
2682
|
];
|
|
2644
2683
|
for (const file of candidates) {
|
|
2645
2684
|
if (await exists(file)) {
|
|
2646
|
-
const raw = await
|
|
2685
|
+
const raw = await import_node_fs7.promises.readFile(file, "utf8");
|
|
2647
2686
|
return parseCodeowners(raw);
|
|
2648
2687
|
}
|
|
2649
2688
|
}
|
|
@@ -2661,7 +2700,7 @@ function parseCodeowners(raw) {
|
|
|
2661
2700
|
return { rules };
|
|
2662
2701
|
}
|
|
2663
2702
|
function matchOwner(file, repoPath) {
|
|
2664
|
-
const normalized = repoPath.split(
|
|
2703
|
+
const normalized = repoPath.split(import_node_path7.default.sep).join("/");
|
|
2665
2704
|
for (const rule of file.rules) {
|
|
2666
2705
|
if (matchesPattern(rule.pattern, normalized)) return rule.owners;
|
|
2667
2706
|
}
|
|
@@ -2677,7 +2716,7 @@ function matchesPattern(rawPattern, repoPath) {
|
|
|
2677
2716
|
return false;
|
|
2678
2717
|
}
|
|
2679
2718
|
async function readPackageJsonAuthor(serviceDir) {
|
|
2680
|
-
const pkgPath =
|
|
2719
|
+
const pkgPath = import_node_path7.default.join(serviceDir, "package.json");
|
|
2681
2720
|
if (!await exists(pkgPath)) return null;
|
|
2682
2721
|
try {
|
|
2683
2722
|
const pkg = await readJson(pkgPath);
|
|
@@ -2700,8 +2739,8 @@ async function computeServiceOwner(codeowners, repoPath, serviceDir) {
|
|
|
2700
2739
|
|
|
2701
2740
|
// src/extract/errors.ts
|
|
2702
2741
|
init_cjs_shims();
|
|
2703
|
-
var
|
|
2704
|
-
var
|
|
2742
|
+
var import_node_fs8 = require("fs");
|
|
2743
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
2705
2744
|
var sink = [];
|
|
2706
2745
|
function recordExtractionError(producer, file, err) {
|
|
2707
2746
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
@@ -2720,9 +2759,9 @@ function drainExtractionErrors() {
|
|
|
2720
2759
|
}
|
|
2721
2760
|
async function writeExtractionErrors(errors, errorsPath) {
|
|
2722
2761
|
if (errors.length === 0) return;
|
|
2723
|
-
await
|
|
2762
|
+
await import_node_fs8.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
|
|
2724
2763
|
const lines = errors.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
2725
|
-
await
|
|
2764
|
+
await import_node_fs8.promises.appendFile(errorsPath, lines, "utf8");
|
|
2726
2765
|
}
|
|
2727
2766
|
function isStrictExtractionEnabled() {
|
|
2728
2767
|
const raw = process.env.NEAT_STRICT_EXTRACTION;
|
|
@@ -2745,9 +2784,9 @@ function isRejectedLogEnabled() {
|
|
|
2745
2784
|
}
|
|
2746
2785
|
async function writeRejectedExtracted(drops, rejectedPath) {
|
|
2747
2786
|
if (drops.length === 0) return;
|
|
2748
|
-
await
|
|
2787
|
+
await import_node_fs8.promises.mkdir(import_node_path8.default.dirname(rejectedPath), { recursive: true });
|
|
2749
2788
|
const lines = drops.map((d) => JSON.stringify({ ...d, ts: (/* @__PURE__ */ new Date()).toISOString() })).join("\n") + "\n";
|
|
2750
|
-
await
|
|
2789
|
+
await import_node_fs8.promises.appendFile(rejectedPath, lines, "utf8");
|
|
2751
2790
|
}
|
|
2752
2791
|
function formatPrecisionFloorBanner(count) {
|
|
2753
2792
|
if (count === 1) return `[neat] 1 extracted edge dropped below precision floor`;
|
|
@@ -2770,21 +2809,21 @@ function workspaceGlobs(pkg) {
|
|
|
2770
2809
|
return null;
|
|
2771
2810
|
}
|
|
2772
2811
|
async function loadGitignore(scanPath) {
|
|
2773
|
-
const gitignorePath =
|
|
2812
|
+
const gitignorePath = import_node_path9.default.join(scanPath, ".gitignore");
|
|
2774
2813
|
if (!await exists(gitignorePath)) return null;
|
|
2775
|
-
const raw = await
|
|
2814
|
+
const raw = await import_node_fs9.promises.readFile(gitignorePath, "utf8");
|
|
2776
2815
|
return (0, import_ignore.default)().add(raw);
|
|
2777
2816
|
}
|
|
2778
2817
|
async function walkDirs(start, scanPath, options, visit) {
|
|
2779
2818
|
async function recurse(current, depth) {
|
|
2780
2819
|
if (depth > options.maxDepth) return;
|
|
2781
|
-
const entries = await
|
|
2820
|
+
const entries = await import_node_fs9.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2782
2821
|
for (const entry2 of entries) {
|
|
2783
2822
|
if (!entry2.isDirectory()) continue;
|
|
2784
2823
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
2785
|
-
const child =
|
|
2824
|
+
const child = import_node_path9.default.join(current, entry2.name);
|
|
2786
2825
|
if (options.ig) {
|
|
2787
|
-
const rel =
|
|
2826
|
+
const rel = import_node_path9.default.relative(scanPath, child).split(import_node_path9.default.sep).join("/");
|
|
2788
2827
|
if (rel && options.ig.ignores(rel + "/")) continue;
|
|
2789
2828
|
}
|
|
2790
2829
|
if (await isPythonVenvDir(child)) continue;
|
|
@@ -2800,8 +2839,8 @@ async function expandWorkspaceGlobs(scanPath, globs) {
|
|
|
2800
2839
|
for (const raw of globs) {
|
|
2801
2840
|
const pattern = raw.replace(/^\.\//, "");
|
|
2802
2841
|
if (!pattern.includes("*")) {
|
|
2803
|
-
const candidate =
|
|
2804
|
-
if (await exists(
|
|
2842
|
+
const candidate = import_node_path9.default.join(scanPath, pattern);
|
|
2843
|
+
if (await exists(import_node_path9.default.join(candidate, "package.json"))) found.add(candidate);
|
|
2805
2844
|
continue;
|
|
2806
2845
|
}
|
|
2807
2846
|
const segments = pattern.split("/");
|
|
@@ -2810,13 +2849,13 @@ async function expandWorkspaceGlobs(scanPath, globs) {
|
|
|
2810
2849
|
if (seg.includes("*")) break;
|
|
2811
2850
|
staticSegments.push(seg);
|
|
2812
2851
|
}
|
|
2813
|
-
const start =
|
|
2852
|
+
const start = import_node_path9.default.join(scanPath, ...staticSegments);
|
|
2814
2853
|
if (!await exists(start)) continue;
|
|
2815
2854
|
const hasDoubleStar = pattern.includes("**");
|
|
2816
2855
|
const walkDepth = hasDoubleStar ? scanDepth : Math.max(0, segments.length - staticSegments.length - 1);
|
|
2817
2856
|
await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {
|
|
2818
|
-
const rel =
|
|
2819
|
-
if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists(
|
|
2857
|
+
const rel = import_node_path9.default.relative(scanPath, dir).split(import_node_path9.default.sep).join("/");
|
|
2858
|
+
if ((0, import_minimatch2.minimatch)(rel, pattern) && await exists(import_node_path9.default.join(dir, "package.json"))) {
|
|
2820
2859
|
found.add(dir);
|
|
2821
2860
|
}
|
|
2822
2861
|
});
|
|
@@ -2836,13 +2875,13 @@ function detectJsFramework(pkg) {
|
|
|
2836
2875
|
return void 0;
|
|
2837
2876
|
}
|
|
2838
2877
|
async function discoverNodeService(scanPath, dir) {
|
|
2839
|
-
const pkgPath =
|
|
2878
|
+
const pkgPath = import_node_path9.default.join(dir, "package.json");
|
|
2840
2879
|
if (!await exists(pkgPath)) return null;
|
|
2841
2880
|
let pkg;
|
|
2842
2881
|
try {
|
|
2843
2882
|
pkg = await readJson(pkgPath);
|
|
2844
2883
|
} catch (err) {
|
|
2845
|
-
recordExtractionError("services",
|
|
2884
|
+
recordExtractionError("services", import_node_path9.default.relative(scanPath, pkgPath), err);
|
|
2846
2885
|
return null;
|
|
2847
2886
|
}
|
|
2848
2887
|
if (!pkg.name) return null;
|
|
@@ -2854,7 +2893,7 @@ async function discoverNodeService(scanPath, dir) {
|
|
|
2854
2893
|
language: "javascript",
|
|
2855
2894
|
version: pkg.version,
|
|
2856
2895
|
dependencies: pkg.dependencies ?? {},
|
|
2857
|
-
repoPath:
|
|
2896
|
+
repoPath: import_node_path9.default.relative(scanPath, dir),
|
|
2858
2897
|
...pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {},
|
|
2859
2898
|
...framework ? { framework } : {}
|
|
2860
2899
|
};
|
|
@@ -2871,12 +2910,12 @@ async function discoverPyService(scanPath, dir) {
|
|
|
2871
2910
|
language: "python",
|
|
2872
2911
|
version: py.version,
|
|
2873
2912
|
dependencies: py.dependencies,
|
|
2874
|
-
repoPath:
|
|
2913
|
+
repoPath: import_node_path9.default.relative(scanPath, dir)
|
|
2875
2914
|
};
|
|
2876
2915
|
return { pkg, dir, node };
|
|
2877
2916
|
}
|
|
2878
2917
|
async function discoverServices(scanPath) {
|
|
2879
|
-
const rootPkgPath =
|
|
2918
|
+
const rootPkgPath = import_node_path9.default.join(scanPath, "package.json");
|
|
2880
2919
|
let rootPkg = null;
|
|
2881
2920
|
if (await exists(rootPkgPath)) {
|
|
2882
2921
|
try {
|
|
@@ -2884,7 +2923,7 @@ async function discoverServices(scanPath) {
|
|
|
2884
2923
|
} catch (err) {
|
|
2885
2924
|
recordExtractionError(
|
|
2886
2925
|
"services workspaces",
|
|
2887
|
-
|
|
2926
|
+
import_node_path9.default.relative(scanPath, rootPkgPath),
|
|
2888
2927
|
err
|
|
2889
2928
|
);
|
|
2890
2929
|
}
|
|
@@ -2901,9 +2940,9 @@ async function discoverServices(scanPath) {
|
|
|
2901
2940
|
scanPath,
|
|
2902
2941
|
{ maxDepth: parseScanDepth(), ig },
|
|
2903
2942
|
async (dir) => {
|
|
2904
|
-
if (await exists(
|
|
2943
|
+
if (await exists(import_node_path9.default.join(dir, "package.json"))) {
|
|
2905
2944
|
candidateDirs.push(dir);
|
|
2906
|
-
} else if (await exists(
|
|
2945
|
+
} else if (await exists(import_node_path9.default.join(dir, "pyproject.toml")) || await exists(import_node_path9.default.join(dir, "requirements.txt")) || await exists(import_node_path9.default.join(dir, "setup.py"))) {
|
|
2907
2946
|
candidateDirs.push(dir);
|
|
2908
2947
|
}
|
|
2909
2948
|
}
|
|
@@ -2917,8 +2956,8 @@ async function discoverServices(scanPath) {
|
|
|
2917
2956
|
if (!service) continue;
|
|
2918
2957
|
const existingDir = seen.get(service.node.name);
|
|
2919
2958
|
if (existingDir !== void 0) {
|
|
2920
|
-
const a =
|
|
2921
|
-
const b =
|
|
2959
|
+
const a = import_node_path9.default.relative(scanPath, existingDir) || ".";
|
|
2960
|
+
const b = import_node_path9.default.relative(scanPath, dir) || ".";
|
|
2922
2961
|
console.warn(
|
|
2923
2962
|
`[neat] duplicate package name "${service.node.name}" \u2014 keeping ${a}, ignoring ${b}`
|
|
2924
2963
|
);
|
|
@@ -2955,8 +2994,8 @@ function addServiceNodes(graph, services) {
|
|
|
2955
2994
|
|
|
2956
2995
|
// src/extract/aliases.ts
|
|
2957
2996
|
init_cjs_shims();
|
|
2958
|
-
var
|
|
2959
|
-
var
|
|
2997
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
2998
|
+
var import_node_fs10 = require("fs");
|
|
2960
2999
|
var import_yaml2 = require("yaml");
|
|
2961
3000
|
var import_types6 = require("@neat.is/types");
|
|
2962
3001
|
var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
@@ -2983,14 +3022,14 @@ function indexServicesByName(services) {
|
|
|
2983
3022
|
const map = /* @__PURE__ */ new Map();
|
|
2984
3023
|
for (const s of services) {
|
|
2985
3024
|
map.set(s.node.name, s.node.id);
|
|
2986
|
-
map.set(
|
|
3025
|
+
map.set(import_node_path10.default.basename(s.dir), s.node.id);
|
|
2987
3026
|
}
|
|
2988
3027
|
return map;
|
|
2989
3028
|
}
|
|
2990
3029
|
async function collectComposeAliases(graph, scanPath, serviceIndex) {
|
|
2991
3030
|
let composePath = null;
|
|
2992
3031
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
2993
|
-
const abs =
|
|
3032
|
+
const abs = import_node_path10.default.join(scanPath, name);
|
|
2994
3033
|
if (await exists(abs)) {
|
|
2995
3034
|
composePath = abs;
|
|
2996
3035
|
break;
|
|
@@ -3003,7 +3042,7 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
|
|
|
3003
3042
|
} catch (err) {
|
|
3004
3043
|
recordExtractionError(
|
|
3005
3044
|
"aliases compose",
|
|
3006
|
-
|
|
3045
|
+
import_node_path10.default.relative(scanPath, composePath),
|
|
3007
3046
|
err
|
|
3008
3047
|
);
|
|
3009
3048
|
return;
|
|
@@ -3046,11 +3085,11 @@ function parseDockerfileLabels(content) {
|
|
|
3046
3085
|
}
|
|
3047
3086
|
async function collectDockerfileAliases(graph, services) {
|
|
3048
3087
|
for (const service of services) {
|
|
3049
|
-
const dockerfilePath =
|
|
3088
|
+
const dockerfilePath = import_node_path10.default.join(service.dir, "Dockerfile");
|
|
3050
3089
|
if (!await exists(dockerfilePath)) continue;
|
|
3051
3090
|
let content;
|
|
3052
3091
|
try {
|
|
3053
|
-
content = await
|
|
3092
|
+
content = await import_node_fs10.promises.readFile(dockerfilePath, "utf8");
|
|
3054
3093
|
} catch (err) {
|
|
3055
3094
|
recordExtractionError("aliases dockerfile", dockerfilePath, err);
|
|
3056
3095
|
continue;
|
|
@@ -3062,15 +3101,15 @@ async function collectDockerfileAliases(graph, services) {
|
|
|
3062
3101
|
async function walkYamlFiles(start, depth = 0, max = 5) {
|
|
3063
3102
|
if (depth > max) return [];
|
|
3064
3103
|
const out = [];
|
|
3065
|
-
const entries = await
|
|
3104
|
+
const entries = await import_node_fs10.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
3066
3105
|
for (const entry2 of entries) {
|
|
3067
3106
|
if (entry2.isDirectory()) {
|
|
3068
3107
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3069
|
-
const child =
|
|
3108
|
+
const child = import_node_path10.default.join(start, entry2.name);
|
|
3070
3109
|
if (await isPythonVenvDir(child)) continue;
|
|
3071
3110
|
out.push(...await walkYamlFiles(child, depth + 1, max));
|
|
3072
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
3073
|
-
out.push(
|
|
3111
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path10.default.extname(entry2.name))) {
|
|
3112
|
+
out.push(import_node_path10.default.join(start, entry2.name));
|
|
3074
3113
|
}
|
|
3075
3114
|
}
|
|
3076
3115
|
return out;
|
|
@@ -3097,7 +3136,7 @@ function k8sServiceTarget(doc, byName) {
|
|
|
3097
3136
|
async function collectK8sAliases(graph, scanPath, serviceIndex) {
|
|
3098
3137
|
const files = await walkYamlFiles(scanPath);
|
|
3099
3138
|
for (const file of files) {
|
|
3100
|
-
const content = await
|
|
3139
|
+
const content = await import_node_fs10.promises.readFile(file, "utf8");
|
|
3101
3140
|
let docs;
|
|
3102
3141
|
try {
|
|
3103
3142
|
docs = (0, import_yaml2.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -3125,20 +3164,20 @@ init_cjs_shims();
|
|
|
3125
3164
|
|
|
3126
3165
|
// src/extract/calls/shared.ts
|
|
3127
3166
|
init_cjs_shims();
|
|
3128
|
-
var
|
|
3129
|
-
var
|
|
3167
|
+
var import_node_fs11 = require("fs");
|
|
3168
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
3130
3169
|
var import_types7 = require("@neat.is/types");
|
|
3131
3170
|
async function walkSourceFiles(dir) {
|
|
3132
3171
|
const out = [];
|
|
3133
3172
|
async function walk(current) {
|
|
3134
|
-
const entries = await
|
|
3173
|
+
const entries = await import_node_fs11.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
3135
3174
|
for (const entry2 of entries) {
|
|
3136
|
-
const full =
|
|
3175
|
+
const full = import_node_path11.default.join(current, entry2.name);
|
|
3137
3176
|
if (entry2.isDirectory()) {
|
|
3138
3177
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
3139
3178
|
if (await isPythonVenvDir(full)) continue;
|
|
3140
3179
|
await walk(full);
|
|
3141
|
-
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(
|
|
3180
|
+
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path11.default.extname(entry2.name))) {
|
|
3142
3181
|
out.push(full);
|
|
3143
3182
|
}
|
|
3144
3183
|
}
|
|
@@ -3151,7 +3190,7 @@ async function loadSourceFiles(dir) {
|
|
|
3151
3190
|
const out = [];
|
|
3152
3191
|
for (const p of paths) {
|
|
3153
3192
|
try {
|
|
3154
|
-
const content = await
|
|
3193
|
+
const content = await import_node_fs11.promises.readFile(p, "utf8");
|
|
3155
3194
|
out.push({ path: p, content });
|
|
3156
3195
|
} catch {
|
|
3157
3196
|
}
|
|
@@ -3171,7 +3210,7 @@ function toPosix2(p) {
|
|
|
3171
3210
|
return p.split("\\").join("/");
|
|
3172
3211
|
}
|
|
3173
3212
|
function languageForPath(relPath) {
|
|
3174
|
-
switch (
|
|
3213
|
+
switch (import_node_path11.default.extname(relPath).toLowerCase()) {
|
|
3175
3214
|
case ".py":
|
|
3176
3215
|
return "python";
|
|
3177
3216
|
case ".ts":
|
|
@@ -3221,14 +3260,14 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
|
3221
3260
|
}
|
|
3222
3261
|
|
|
3223
3262
|
// src/extract/files.ts
|
|
3224
|
-
var
|
|
3263
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
3225
3264
|
async function addFiles(graph, services) {
|
|
3226
3265
|
let nodesAdded = 0;
|
|
3227
3266
|
let edgesAdded = 0;
|
|
3228
3267
|
for (const service of services) {
|
|
3229
3268
|
const filePaths = await walkSourceFiles(service.dir);
|
|
3230
3269
|
for (const filePath of filePaths) {
|
|
3231
|
-
const relPath = toPosix2(
|
|
3270
|
+
const relPath = toPosix2(import_node_path12.default.relative(service.dir, filePath));
|
|
3232
3271
|
const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
3233
3272
|
graph,
|
|
3234
3273
|
service.pkg.name,
|
|
@@ -3244,8 +3283,8 @@ async function addFiles(graph, services) {
|
|
|
3244
3283
|
|
|
3245
3284
|
// src/extract/imports.ts
|
|
3246
3285
|
init_cjs_shims();
|
|
3247
|
-
var
|
|
3248
|
-
var
|
|
3286
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
3287
|
+
var import_node_fs12 = require("fs");
|
|
3249
3288
|
var import_tree_sitter = __toESM(require("tree-sitter"), 1);
|
|
3250
3289
|
var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
|
|
3251
3290
|
var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
|
|
@@ -3349,15 +3388,15 @@ function collectPyImports(node, out) {
|
|
|
3349
3388
|
}
|
|
3350
3389
|
async function fileExists(p) {
|
|
3351
3390
|
try {
|
|
3352
|
-
await
|
|
3391
|
+
await import_node_fs12.promises.access(p);
|
|
3353
3392
|
return true;
|
|
3354
3393
|
} catch {
|
|
3355
3394
|
return false;
|
|
3356
3395
|
}
|
|
3357
3396
|
}
|
|
3358
3397
|
function isWithinServiceDir(candidate, serviceDir) {
|
|
3359
|
-
const rel =
|
|
3360
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
3398
|
+
const rel = import_node_path13.default.relative(serviceDir, candidate);
|
|
3399
|
+
return rel !== "" && !rel.startsWith("..") && !import_node_path13.default.isAbsolute(rel);
|
|
3361
3400
|
}
|
|
3362
3401
|
var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
3363
3402
|
var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -3365,22 +3404,22 @@ async function firstExistingCandidate(base, serviceDir) {
|
|
|
3365
3404
|
for (const ext of JS_EXTENSIONS) {
|
|
3366
3405
|
const candidate = base + ext;
|
|
3367
3406
|
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3368
|
-
return toPosix2(
|
|
3407
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, candidate));
|
|
3369
3408
|
}
|
|
3370
3409
|
}
|
|
3371
3410
|
for (const indexFile of JS_INDEX_FILES) {
|
|
3372
|
-
const candidate =
|
|
3411
|
+
const candidate = import_node_path13.default.join(base, indexFile);
|
|
3373
3412
|
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3374
|
-
return toPosix2(
|
|
3413
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, candidate));
|
|
3375
3414
|
}
|
|
3376
3415
|
}
|
|
3377
3416
|
return null;
|
|
3378
3417
|
}
|
|
3379
3418
|
async function loadTsPathConfig(serviceDir) {
|
|
3380
|
-
const tsconfigPath =
|
|
3419
|
+
const tsconfigPath = import_node_path13.default.join(serviceDir, "tsconfig.json");
|
|
3381
3420
|
let raw;
|
|
3382
3421
|
try {
|
|
3383
|
-
raw = await
|
|
3422
|
+
raw = await import_node_fs12.promises.readFile(tsconfigPath, "utf8");
|
|
3384
3423
|
} catch {
|
|
3385
3424
|
return null;
|
|
3386
3425
|
}
|
|
@@ -3389,7 +3428,7 @@ async function loadTsPathConfig(serviceDir) {
|
|
|
3389
3428
|
const paths = parsed.compilerOptions?.paths;
|
|
3390
3429
|
if (!paths || Object.keys(paths).length === 0) return null;
|
|
3391
3430
|
const baseUrl = parsed.compilerOptions?.baseUrl;
|
|
3392
|
-
return { paths, baseDir: baseUrl ?
|
|
3431
|
+
return { paths, baseDir: baseUrl ? import_node_path13.default.resolve(serviceDir, baseUrl) : serviceDir };
|
|
3393
3432
|
} catch (err) {
|
|
3394
3433
|
recordExtractionError("import alias resolution", tsconfigPath, err);
|
|
3395
3434
|
return null;
|
|
@@ -3407,11 +3446,11 @@ async function resolveTsAlias(specifier, config, serviceDir) {
|
|
|
3407
3446
|
if (suffix === null) continue;
|
|
3408
3447
|
for (const target of targets) {
|
|
3409
3448
|
const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
|
|
3410
|
-
const resolvedBase =
|
|
3449
|
+
const resolvedBase = import_node_path13.default.resolve(config.baseDir, targetBase, suffix);
|
|
3411
3450
|
const hit = await firstExistingCandidate(resolvedBase, serviceDir);
|
|
3412
3451
|
if (hit) return hit;
|
|
3413
3452
|
if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists(resolvedBase)) {
|
|
3414
|
-
return toPosix2(
|
|
3453
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, resolvedBase));
|
|
3415
3454
|
}
|
|
3416
3455
|
}
|
|
3417
3456
|
}
|
|
@@ -3420,18 +3459,18 @@ async function resolveTsAlias(specifier, config, serviceDir) {
|
|
|
3420
3459
|
async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
|
|
3421
3460
|
if (!specifier) return null;
|
|
3422
3461
|
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
3423
|
-
const base =
|
|
3424
|
-
const ext =
|
|
3462
|
+
const base = import_node_path13.default.resolve(importerDir, specifier);
|
|
3463
|
+
const ext = import_node_path13.default.extname(specifier);
|
|
3425
3464
|
if (ext) {
|
|
3426
3465
|
if (ext === ".js" || ext === ".jsx") {
|
|
3427
3466
|
const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
|
|
3428
3467
|
const tsSibling = base.slice(0, -ext.length) + tsExt;
|
|
3429
3468
|
if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists(tsSibling)) {
|
|
3430
|
-
return toPosix2(
|
|
3469
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, tsSibling));
|
|
3431
3470
|
}
|
|
3432
3471
|
}
|
|
3433
3472
|
if (isWithinServiceDir(base, serviceDir) && await fileExists(base)) {
|
|
3434
|
-
return toPosix2(
|
|
3473
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, base));
|
|
3435
3474
|
}
|
|
3436
3475
|
return null;
|
|
3437
3476
|
}
|
|
@@ -3445,15 +3484,15 @@ async function resolvePyImport(imp, importerPath, serviceDir) {
|
|
|
3445
3484
|
const relPath = imp.modulePath.split(".").join("/");
|
|
3446
3485
|
let baseDir;
|
|
3447
3486
|
if (imp.level > 0) {
|
|
3448
|
-
baseDir =
|
|
3449
|
-
for (let i = 1; i < imp.level; i++) baseDir =
|
|
3487
|
+
baseDir = import_node_path13.default.dirname(importerPath);
|
|
3488
|
+
for (let i = 1; i < imp.level; i++) baseDir = import_node_path13.default.dirname(baseDir);
|
|
3450
3489
|
} else {
|
|
3451
3490
|
baseDir = serviceDir;
|
|
3452
3491
|
}
|
|
3453
|
-
const candidates = [
|
|
3492
|
+
const candidates = [import_node_path13.default.join(baseDir, `${relPath}.py`), import_node_path13.default.join(baseDir, relPath, "__init__.py")];
|
|
3454
3493
|
for (const candidate of candidates) {
|
|
3455
3494
|
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3456
|
-
return toPosix2(
|
|
3495
|
+
return toPosix2(import_node_path13.default.relative(serviceDir, candidate));
|
|
3457
3496
|
}
|
|
3458
3497
|
}
|
|
3459
3498
|
return null;
|
|
@@ -3484,9 +3523,9 @@ async function addImports(graph, services) {
|
|
|
3484
3523
|
const files = await loadSourceFiles(service.dir);
|
|
3485
3524
|
for (const file of files) {
|
|
3486
3525
|
if (isTestPath(file.path)) continue;
|
|
3487
|
-
const relFile = toPosix2(
|
|
3526
|
+
const relFile = toPosix2(import_node_path13.default.relative(service.dir, file.path));
|
|
3488
3527
|
const importerFileId = (0, import_types8.fileId)(service.pkg.name, relFile);
|
|
3489
|
-
const isPython =
|
|
3528
|
+
const isPython = import_node_path13.default.extname(file.path) === ".py";
|
|
3490
3529
|
if (isPython) {
|
|
3491
3530
|
let pyImports = [];
|
|
3492
3531
|
try {
|
|
@@ -3520,7 +3559,7 @@ async function addImports(graph, services) {
|
|
|
3520
3559
|
continue;
|
|
3521
3560
|
}
|
|
3522
3561
|
for (const imp of jsImports) {
|
|
3523
|
-
const resolved = await resolveJsImport(imp.specifier,
|
|
3562
|
+
const resolved = await resolveJsImport(imp.specifier, import_node_path13.default.dirname(file.path), service.dir, tsPaths);
|
|
3524
3563
|
if (!resolved) continue;
|
|
3525
3564
|
edgesAdded += emitImportEdge(
|
|
3526
3565
|
graph,
|
|
@@ -3539,14 +3578,14 @@ async function addImports(graph, services) {
|
|
|
3539
3578
|
|
|
3540
3579
|
// src/extract/databases/index.ts
|
|
3541
3580
|
init_cjs_shims();
|
|
3542
|
-
var
|
|
3581
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
3543
3582
|
var import_types9 = require("@neat.is/types");
|
|
3544
3583
|
|
|
3545
3584
|
// src/extract/databases/db-config-yaml.ts
|
|
3546
3585
|
init_cjs_shims();
|
|
3547
|
-
var
|
|
3586
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3548
3587
|
async function parse(serviceDir) {
|
|
3549
|
-
const yamlPath =
|
|
3588
|
+
const yamlPath = import_node_path14.default.join(serviceDir, "db-config.yaml");
|
|
3550
3589
|
if (!await exists(yamlPath)) return [];
|
|
3551
3590
|
const raw = await readYaml(yamlPath);
|
|
3552
3591
|
return [
|
|
@@ -3564,13 +3603,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
|
|
|
3564
3603
|
|
|
3565
3604
|
// src/extract/databases/dotenv.ts
|
|
3566
3605
|
init_cjs_shims();
|
|
3567
|
-
var
|
|
3568
|
-
var
|
|
3606
|
+
var import_node_fs14 = require("fs");
|
|
3607
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3569
3608
|
|
|
3570
3609
|
// src/extract/databases/shared.ts
|
|
3571
3610
|
init_cjs_shims();
|
|
3572
|
-
var
|
|
3573
|
-
var
|
|
3611
|
+
var import_node_fs13 = require("fs");
|
|
3612
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3574
3613
|
function schemeToEngine(scheme) {
|
|
3575
3614
|
const s = scheme.toLowerCase().split("+")[0];
|
|
3576
3615
|
switch (s) {
|
|
@@ -3609,14 +3648,14 @@ function parseConnectionString(url) {
|
|
|
3609
3648
|
}
|
|
3610
3649
|
async function readIfExists(filePath) {
|
|
3611
3650
|
try {
|
|
3612
|
-
return await
|
|
3651
|
+
return await import_node_fs13.promises.readFile(filePath, "utf8");
|
|
3613
3652
|
} catch {
|
|
3614
3653
|
return null;
|
|
3615
3654
|
}
|
|
3616
3655
|
}
|
|
3617
3656
|
async function findFirst(serviceDir, candidates) {
|
|
3618
3657
|
for (const rel of candidates) {
|
|
3619
|
-
const abs =
|
|
3658
|
+
const abs = import_node_path15.default.join(serviceDir, rel);
|
|
3620
3659
|
const content = await readIfExists(abs);
|
|
3621
3660
|
if (content !== null) return abs;
|
|
3622
3661
|
}
|
|
@@ -3667,15 +3706,15 @@ function parseDotenvLine(line) {
|
|
|
3667
3706
|
return { key, value };
|
|
3668
3707
|
}
|
|
3669
3708
|
async function parse2(serviceDir) {
|
|
3670
|
-
const entries = await
|
|
3709
|
+
const entries = await import_node_fs14.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
3671
3710
|
const configs = [];
|
|
3672
3711
|
const seen = /* @__PURE__ */ new Set();
|
|
3673
3712
|
for (const entry2 of entries) {
|
|
3674
3713
|
if (!entry2.isFile()) continue;
|
|
3675
3714
|
const match = isConfigFile(entry2.name);
|
|
3676
3715
|
if (!match.match || match.fileType !== "env") continue;
|
|
3677
|
-
const filePath =
|
|
3678
|
-
const content = await
|
|
3716
|
+
const filePath = import_node_path16.default.join(serviceDir, entry2.name);
|
|
3717
|
+
const content = await import_node_fs14.promises.readFile(filePath, "utf8");
|
|
3679
3718
|
for (const line of content.split("\n")) {
|
|
3680
3719
|
const parsed = parseDotenvLine(line);
|
|
3681
3720
|
if (!parsed) continue;
|
|
@@ -3694,9 +3733,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
|
|
|
3694
3733
|
|
|
3695
3734
|
// src/extract/databases/prisma.ts
|
|
3696
3735
|
init_cjs_shims();
|
|
3697
|
-
var
|
|
3736
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
3698
3737
|
async function parse3(serviceDir) {
|
|
3699
|
-
const schemaPath =
|
|
3738
|
+
const schemaPath = import_node_path17.default.join(serviceDir, "prisma", "schema.prisma");
|
|
3700
3739
|
const content = await readIfExists(schemaPath);
|
|
3701
3740
|
if (!content) return [];
|
|
3702
3741
|
const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
|
|
@@ -3828,10 +3867,10 @@ var knexParser = { name: "knex", parse: parse5 };
|
|
|
3828
3867
|
|
|
3829
3868
|
// src/extract/databases/ormconfig.ts
|
|
3830
3869
|
init_cjs_shims();
|
|
3831
|
-
var
|
|
3870
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
3832
3871
|
async function parse6(serviceDir) {
|
|
3833
3872
|
for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
|
|
3834
|
-
const abs =
|
|
3873
|
+
const abs = import_node_path18.default.join(serviceDir, candidate);
|
|
3835
3874
|
if (!await exists(abs)) continue;
|
|
3836
3875
|
const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
|
|
3837
3876
|
const entries = Array.isArray(raw) ? raw : [raw];
|
|
@@ -3891,9 +3930,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
|
|
|
3891
3930
|
|
|
3892
3931
|
// src/extract/databases/sequelize.ts
|
|
3893
3932
|
init_cjs_shims();
|
|
3894
|
-
var
|
|
3933
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
3895
3934
|
async function parse8(serviceDir) {
|
|
3896
|
-
const configPath =
|
|
3935
|
+
const configPath = import_node_path19.default.join(serviceDir, "config", "config.json");
|
|
3897
3936
|
if (!await exists(configPath)) return [];
|
|
3898
3937
|
const raw = await readJson(configPath);
|
|
3899
3938
|
const out = [];
|
|
@@ -3920,7 +3959,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
|
3920
3959
|
|
|
3921
3960
|
// src/extract/databases/docker-compose.ts
|
|
3922
3961
|
init_cjs_shims();
|
|
3923
|
-
var
|
|
3962
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
3924
3963
|
function portFromService(svc) {
|
|
3925
3964
|
for (const raw of svc.ports ?? []) {
|
|
3926
3965
|
const str = String(raw);
|
|
@@ -3947,7 +3986,7 @@ function databaseFromEnv(svc) {
|
|
|
3947
3986
|
}
|
|
3948
3987
|
async function parse9(serviceDir) {
|
|
3949
3988
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
3950
|
-
const abs =
|
|
3989
|
+
const abs = import_node_path20.default.join(serviceDir, name);
|
|
3951
3990
|
if (!await exists(abs)) continue;
|
|
3952
3991
|
const raw = await readYaml(abs);
|
|
3953
3992
|
if (!raw?.services) return [];
|
|
@@ -4119,7 +4158,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4119
4158
|
discoveredVia: mergedDiscoveredVia
|
|
4120
4159
|
});
|
|
4121
4160
|
}
|
|
4122
|
-
const relConfigFile = toPosix2(
|
|
4161
|
+
const relConfigFile = toPosix2(import_node_path21.default.relative(service.dir, config.sourceFile));
|
|
4123
4162
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4124
4163
|
graph,
|
|
4125
4164
|
service.pkg.name,
|
|
@@ -4128,7 +4167,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4128
4167
|
);
|
|
4129
4168
|
nodesAdded += fn;
|
|
4130
4169
|
edgesAdded += fe;
|
|
4131
|
-
const evidenceFile = toPosix2(
|
|
4170
|
+
const evidenceFile = toPosix2(import_node_path21.default.relative(scanPath, config.sourceFile));
|
|
4132
4171
|
const edge = {
|
|
4133
4172
|
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id, import_types9.EdgeType.CONNECTS_TO),
|
|
4134
4173
|
source: fileNodeId,
|
|
@@ -4162,15 +4201,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4162
4201
|
|
|
4163
4202
|
// src/extract/configs.ts
|
|
4164
4203
|
init_cjs_shims();
|
|
4165
|
-
var
|
|
4166
|
-
var
|
|
4204
|
+
var import_node_fs15 = require("fs");
|
|
4205
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
4167
4206
|
var import_types10 = require("@neat.is/types");
|
|
4168
4207
|
async function walkConfigFiles(dir) {
|
|
4169
4208
|
const out = [];
|
|
4170
4209
|
async function walk(current) {
|
|
4171
|
-
const entries = await
|
|
4210
|
+
const entries = await import_node_fs15.promises.readdir(current, { withFileTypes: true });
|
|
4172
4211
|
for (const entry2 of entries) {
|
|
4173
|
-
const full =
|
|
4212
|
+
const full = import_node_path22.default.join(current, entry2.name);
|
|
4174
4213
|
if (entry2.isDirectory()) {
|
|
4175
4214
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
4176
4215
|
if (await isPythonVenvDir(full)) continue;
|
|
@@ -4189,19 +4228,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4189
4228
|
for (const service of services) {
|
|
4190
4229
|
const configFiles = await walkConfigFiles(service.dir);
|
|
4191
4230
|
for (const file of configFiles) {
|
|
4192
|
-
const relPath =
|
|
4231
|
+
const relPath = import_node_path22.default.relative(scanPath, file);
|
|
4193
4232
|
const node = {
|
|
4194
4233
|
id: (0, import_types10.configId)(relPath),
|
|
4195
4234
|
type: import_types10.NodeType.ConfigNode,
|
|
4196
|
-
name:
|
|
4235
|
+
name: import_node_path22.default.basename(file),
|
|
4197
4236
|
path: relPath,
|
|
4198
|
-
fileType: isConfigFile(
|
|
4237
|
+
fileType: isConfigFile(import_node_path22.default.basename(file)).fileType
|
|
4199
4238
|
};
|
|
4200
4239
|
if (!graph.hasNode(node.id)) {
|
|
4201
4240
|
graph.addNode(node.id, node);
|
|
4202
4241
|
nodesAdded++;
|
|
4203
4242
|
}
|
|
4204
|
-
const relToService = toPosix2(
|
|
4243
|
+
const relToService = toPosix2(import_node_path22.default.relative(service.dir, file));
|
|
4205
4244
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4206
4245
|
graph,
|
|
4207
4246
|
service.pkg.name,
|
|
@@ -4217,7 +4256,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4217
4256
|
type: import_types10.EdgeType.CONFIGURED_BY,
|
|
4218
4257
|
provenance: import_types10.Provenance.EXTRACTED,
|
|
4219
4258
|
confidence: (0, import_types10.confidenceForExtracted)("structural"),
|
|
4220
|
-
evidence: { file: relPath.split(
|
|
4259
|
+
evidence: { file: relPath.split(import_node_path22.default.sep).join("/") }
|
|
4221
4260
|
};
|
|
4222
4261
|
if (!graph.hasEdge(edge.id)) {
|
|
4223
4262
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -4234,7 +4273,7 @@ var import_types16 = require("@neat.is/types");
|
|
|
4234
4273
|
|
|
4235
4274
|
// src/extract/calls/http.ts
|
|
4236
4275
|
init_cjs_shims();
|
|
4237
|
-
var
|
|
4276
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
4238
4277
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
4239
4278
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
4240
4279
|
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
@@ -4303,9 +4342,9 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4303
4342
|
const knownHosts = /* @__PURE__ */ new Set();
|
|
4304
4343
|
const hostToNodeId = /* @__PURE__ */ new Map();
|
|
4305
4344
|
for (const service of services) {
|
|
4306
|
-
knownHosts.add(
|
|
4345
|
+
knownHosts.add(import_node_path23.default.basename(service.dir));
|
|
4307
4346
|
knownHosts.add(service.pkg.name);
|
|
4308
|
-
hostToNodeId.set(
|
|
4347
|
+
hostToNodeId.set(import_node_path23.default.basename(service.dir), service.node.id);
|
|
4309
4348
|
hostToNodeId.set(service.pkg.name, service.node.id);
|
|
4310
4349
|
}
|
|
4311
4350
|
let nodesAdded = 0;
|
|
@@ -4315,7 +4354,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4315
4354
|
const seen = /* @__PURE__ */ new Set();
|
|
4316
4355
|
for (const file of files) {
|
|
4317
4356
|
if (isTestPath(file.path)) continue;
|
|
4318
|
-
const parser =
|
|
4357
|
+
const parser = import_node_path23.default.extname(file.path) === ".py" ? pyParser : jsParser;
|
|
4319
4358
|
let sites;
|
|
4320
4359
|
try {
|
|
4321
4360
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -4324,7 +4363,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4324
4363
|
continue;
|
|
4325
4364
|
}
|
|
4326
4365
|
if (sites.length === 0) continue;
|
|
4327
|
-
const relFile = toPosix2(
|
|
4366
|
+
const relFile = toPosix2(import_node_path23.default.relative(service.dir, file.path));
|
|
4328
4367
|
for (const site of sites) {
|
|
4329
4368
|
const targetId = hostToNodeId.get(site.host);
|
|
4330
4369
|
if (!targetId || targetId === service.node.id) continue;
|
|
@@ -4378,7 +4417,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4378
4417
|
|
|
4379
4418
|
// src/extract/calls/kafka.ts
|
|
4380
4419
|
init_cjs_shims();
|
|
4381
|
-
var
|
|
4420
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
4382
4421
|
var import_types12 = require("@neat.is/types");
|
|
4383
4422
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4384
4423
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
@@ -4409,7 +4448,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4409
4448
|
// tier (ADR-066).
|
|
4410
4449
|
confidenceKind: "verified-call-site",
|
|
4411
4450
|
evidence: {
|
|
4412
|
-
file:
|
|
4451
|
+
file: import_node_path24.default.relative(serviceDir, file.path),
|
|
4413
4452
|
line,
|
|
4414
4453
|
snippet: snippet(file.content, line)
|
|
4415
4454
|
}
|
|
@@ -4422,7 +4461,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4422
4461
|
|
|
4423
4462
|
// src/extract/calls/redis.ts
|
|
4424
4463
|
init_cjs_shims();
|
|
4425
|
-
var
|
|
4464
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
4426
4465
|
var import_types13 = require("@neat.is/types");
|
|
4427
4466
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
4428
4467
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
@@ -4445,7 +4484,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4445
4484
|
// support tier (ADR-066).
|
|
4446
4485
|
confidenceKind: "url-with-structural-support",
|
|
4447
4486
|
evidence: {
|
|
4448
|
-
file:
|
|
4487
|
+
file: import_node_path25.default.relative(serviceDir, file.path),
|
|
4449
4488
|
line,
|
|
4450
4489
|
snippet: snippet(file.content, line)
|
|
4451
4490
|
}
|
|
@@ -4456,7 +4495,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4456
4495
|
|
|
4457
4496
|
// src/extract/calls/aws.ts
|
|
4458
4497
|
init_cjs_shims();
|
|
4459
|
-
var
|
|
4498
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
4460
4499
|
var import_types14 = require("@neat.is/types");
|
|
4461
4500
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4462
4501
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
@@ -4490,7 +4529,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4490
4529
|
// (ADR-066).
|
|
4491
4530
|
confidenceKind: "verified-call-site",
|
|
4492
4531
|
evidence: {
|
|
4493
|
-
file:
|
|
4532
|
+
file: import_node_path26.default.relative(serviceDir, file.path),
|
|
4494
4533
|
line,
|
|
4495
4534
|
snippet: snippet(file.content, line)
|
|
4496
4535
|
}
|
|
@@ -4515,7 +4554,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4515
4554
|
|
|
4516
4555
|
// src/extract/calls/grpc.ts
|
|
4517
4556
|
init_cjs_shims();
|
|
4518
|
-
var
|
|
4557
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
4519
4558
|
var import_types15 = require("@neat.is/types");
|
|
4520
4559
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
4521
4560
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
@@ -4574,7 +4613,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4574
4613
|
// tier (ADR-066).
|
|
4575
4614
|
confidenceKind: "verified-call-site",
|
|
4576
4615
|
evidence: {
|
|
4577
|
-
file:
|
|
4616
|
+
file: import_node_path27.default.relative(serviceDir, file.path),
|
|
4578
4617
|
line,
|
|
4579
4618
|
snippet: snippet(file.content, line)
|
|
4580
4619
|
}
|
|
@@ -4685,7 +4724,7 @@ init_cjs_shims();
|
|
|
4685
4724
|
|
|
4686
4725
|
// src/extract/infra/docker-compose.ts
|
|
4687
4726
|
init_cjs_shims();
|
|
4688
|
-
var
|
|
4727
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
4689
4728
|
var import_types18 = require("@neat.is/types");
|
|
4690
4729
|
|
|
4691
4730
|
// src/extract/infra/shared.ts
|
|
@@ -4723,7 +4762,7 @@ function dependsOnList(value) {
|
|
|
4723
4762
|
}
|
|
4724
4763
|
function serviceNameToServiceNode(name, services) {
|
|
4725
4764
|
for (const s of services) {
|
|
4726
|
-
if (s.node.name === name ||
|
|
4765
|
+
if (s.node.name === name || import_node_path28.default.basename(s.dir) === name) return s.node.id;
|
|
4727
4766
|
}
|
|
4728
4767
|
return null;
|
|
4729
4768
|
}
|
|
@@ -4732,7 +4771,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4732
4771
|
let edgesAdded = 0;
|
|
4733
4772
|
let composePath = null;
|
|
4734
4773
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
4735
|
-
const abs =
|
|
4774
|
+
const abs = import_node_path28.default.join(scanPath, name);
|
|
4736
4775
|
if (await exists(abs)) {
|
|
4737
4776
|
composePath = abs;
|
|
4738
4777
|
break;
|
|
@@ -4745,13 +4784,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4745
4784
|
} catch (err) {
|
|
4746
4785
|
recordExtractionError(
|
|
4747
4786
|
"infra docker-compose",
|
|
4748
|
-
|
|
4787
|
+
import_node_path28.default.relative(scanPath, composePath),
|
|
4749
4788
|
err
|
|
4750
4789
|
);
|
|
4751
4790
|
return { nodesAdded, edgesAdded };
|
|
4752
4791
|
}
|
|
4753
4792
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
4754
|
-
const evidenceFile =
|
|
4793
|
+
const evidenceFile = import_node_path28.default.relative(scanPath, composePath).split(import_node_path28.default.sep).join("/");
|
|
4755
4794
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
4756
4795
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
4757
4796
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -4793,8 +4832,8 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4793
4832
|
|
|
4794
4833
|
// src/extract/infra/dockerfile.ts
|
|
4795
4834
|
init_cjs_shims();
|
|
4796
|
-
var
|
|
4797
|
-
var
|
|
4835
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
4836
|
+
var import_node_fs16 = require("fs");
|
|
4798
4837
|
var import_types19 = require("@neat.is/types");
|
|
4799
4838
|
function runtimeImage(content) {
|
|
4800
4839
|
const lines = content.split("\n");
|
|
@@ -4814,15 +4853,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4814
4853
|
let nodesAdded = 0;
|
|
4815
4854
|
let edgesAdded = 0;
|
|
4816
4855
|
for (const service of services) {
|
|
4817
|
-
const dockerfilePath =
|
|
4856
|
+
const dockerfilePath = import_node_path29.default.join(service.dir, "Dockerfile");
|
|
4818
4857
|
if (!await exists(dockerfilePath)) continue;
|
|
4819
4858
|
let content;
|
|
4820
4859
|
try {
|
|
4821
|
-
content = await
|
|
4860
|
+
content = await import_node_fs16.promises.readFile(dockerfilePath, "utf8");
|
|
4822
4861
|
} catch (err) {
|
|
4823
4862
|
recordExtractionError(
|
|
4824
4863
|
"infra dockerfile",
|
|
4825
|
-
|
|
4864
|
+
import_node_path29.default.relative(scanPath, dockerfilePath),
|
|
4826
4865
|
err
|
|
4827
4866
|
);
|
|
4828
4867
|
continue;
|
|
@@ -4834,7 +4873,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4834
4873
|
graph.addNode(node.id, node);
|
|
4835
4874
|
nodesAdded++;
|
|
4836
4875
|
}
|
|
4837
|
-
const relDockerfile = toPosix2(
|
|
4876
|
+
const relDockerfile = toPosix2(import_node_path29.default.relative(service.dir, dockerfilePath));
|
|
4838
4877
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4839
4878
|
graph,
|
|
4840
4879
|
service.pkg.name,
|
|
@@ -4853,7 +4892,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4853
4892
|
provenance: import_types19.Provenance.EXTRACTED,
|
|
4854
4893
|
confidence: (0, import_types19.confidenceForExtracted)("structural"),
|
|
4855
4894
|
evidence: {
|
|
4856
|
-
file: toPosix2(
|
|
4895
|
+
file: toPosix2(import_node_path29.default.relative(scanPath, dockerfilePath))
|
|
4857
4896
|
}
|
|
4858
4897
|
};
|
|
4859
4898
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4865,21 +4904,21 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4865
4904
|
|
|
4866
4905
|
// src/extract/infra/terraform.ts
|
|
4867
4906
|
init_cjs_shims();
|
|
4868
|
-
var
|
|
4869
|
-
var
|
|
4907
|
+
var import_node_fs17 = require("fs");
|
|
4908
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
4870
4909
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
4871
4910
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
4872
4911
|
if (depth > max) return [];
|
|
4873
4912
|
const out = [];
|
|
4874
|
-
const entries = await
|
|
4913
|
+
const entries = await import_node_fs17.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4875
4914
|
for (const entry2 of entries) {
|
|
4876
4915
|
if (entry2.isDirectory()) {
|
|
4877
4916
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
4878
|
-
const child =
|
|
4917
|
+
const child = import_node_path30.default.join(start, entry2.name);
|
|
4879
4918
|
if (await isPythonVenvDir(child)) continue;
|
|
4880
4919
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
4881
4920
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
4882
|
-
out.push(
|
|
4921
|
+
out.push(import_node_path30.default.join(start, entry2.name));
|
|
4883
4922
|
}
|
|
4884
4923
|
}
|
|
4885
4924
|
return out;
|
|
@@ -4888,7 +4927,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4888
4927
|
let nodesAdded = 0;
|
|
4889
4928
|
const files = await walkTfFiles(scanPath);
|
|
4890
4929
|
for (const file of files) {
|
|
4891
|
-
const content = await
|
|
4930
|
+
const content = await import_node_fs17.promises.readFile(file, "utf8");
|
|
4892
4931
|
RESOURCE_RE.lastIndex = 0;
|
|
4893
4932
|
let m;
|
|
4894
4933
|
while ((m = RESOURCE_RE.exec(content)) !== null) {
|
|
@@ -4906,8 +4945,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4906
4945
|
|
|
4907
4946
|
// src/extract/infra/k8s.ts
|
|
4908
4947
|
init_cjs_shims();
|
|
4909
|
-
var
|
|
4910
|
-
var
|
|
4948
|
+
var import_node_fs18 = require("fs");
|
|
4949
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
4911
4950
|
var import_yaml3 = require("yaml");
|
|
4912
4951
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
4913
4952
|
Service: "k8s-service",
|
|
@@ -4921,15 +4960,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
4921
4960
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
4922
4961
|
if (depth > max) return [];
|
|
4923
4962
|
const out = [];
|
|
4924
|
-
const entries = await
|
|
4963
|
+
const entries = await import_node_fs18.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4925
4964
|
for (const entry2 of entries) {
|
|
4926
4965
|
if (entry2.isDirectory()) {
|
|
4927
4966
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
4928
|
-
const child =
|
|
4967
|
+
const child = import_node_path31.default.join(start, entry2.name);
|
|
4929
4968
|
if (await isPythonVenvDir(child)) continue;
|
|
4930
4969
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
4931
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
4932
|
-
out.push(
|
|
4970
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path31.default.extname(entry2.name))) {
|
|
4971
|
+
out.push(import_node_path31.default.join(start, entry2.name));
|
|
4933
4972
|
}
|
|
4934
4973
|
}
|
|
4935
4974
|
return out;
|
|
@@ -4938,7 +4977,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
4938
4977
|
let nodesAdded = 0;
|
|
4939
4978
|
const files = await walkYamlFiles2(scanPath);
|
|
4940
4979
|
for (const file of files) {
|
|
4941
|
-
const content = await
|
|
4980
|
+
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
4942
4981
|
let docs;
|
|
4943
4982
|
try {
|
|
4944
4983
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -4973,12 +5012,12 @@ async function addInfra(graph, scanPath, services) {
|
|
|
4973
5012
|
}
|
|
4974
5013
|
|
|
4975
5014
|
// src/extract/index.ts
|
|
4976
|
-
var
|
|
5015
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
4977
5016
|
|
|
4978
5017
|
// src/extract/retire.ts
|
|
4979
5018
|
init_cjs_shims();
|
|
4980
|
-
var
|
|
4981
|
-
var
|
|
5019
|
+
var import_node_fs19 = require("fs");
|
|
5020
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
4982
5021
|
var import_types20 = require("@neat.is/types");
|
|
4983
5022
|
function dropOrphanedFileNodes(graph) {
|
|
4984
5023
|
const orphans = [];
|
|
@@ -5012,11 +5051,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
5012
5051
|
if (edge.provenance !== import_types20.Provenance.EXTRACTED) return;
|
|
5013
5052
|
const evidenceFile = edge.evidence?.file;
|
|
5014
5053
|
if (!evidenceFile) return;
|
|
5015
|
-
if (
|
|
5016
|
-
if (!(0,
|
|
5054
|
+
if (import_node_path32.default.isAbsolute(evidenceFile)) {
|
|
5055
|
+
if (!(0, import_node_fs19.existsSync)(evidenceFile)) toDrop.push(id);
|
|
5017
5056
|
return;
|
|
5018
5057
|
}
|
|
5019
|
-
const found = bases.some((base) => (0,
|
|
5058
|
+
const found = bases.some((base) => (0, import_node_fs19.existsSync)(import_node_path32.default.join(base, evidenceFile)));
|
|
5020
5059
|
if (!found) toDrop.push(id);
|
|
5021
5060
|
});
|
|
5022
5061
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -5056,7 +5095,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5056
5095
|
}
|
|
5057
5096
|
const droppedEntries = drainDroppedExtracted();
|
|
5058
5097
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
5059
|
-
const rejectedPath =
|
|
5098
|
+
const rejectedPath = import_node_path33.default.join(import_node_path33.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
5060
5099
|
try {
|
|
5061
5100
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
5062
5101
|
} catch (err) {
|
|
@@ -5328,8 +5367,8 @@ function computeDivergences(graph, opts = {}) {
|
|
|
5328
5367
|
|
|
5329
5368
|
// src/persist.ts
|
|
5330
5369
|
init_cjs_shims();
|
|
5331
|
-
var
|
|
5332
|
-
var
|
|
5370
|
+
var import_node_fs20 = require("fs");
|
|
5371
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
5333
5372
|
var import_types22 = require("@neat.is/types");
|
|
5334
5373
|
var SCHEMA_VERSION = 4;
|
|
5335
5374
|
function migrateV1ToV2(payload) {
|
|
@@ -5366,7 +5405,7 @@ function migrateV2ToV3(payload) {
|
|
|
5366
5405
|
return { ...payload, schemaVersion: 3 };
|
|
5367
5406
|
}
|
|
5368
5407
|
async function ensureDir(filePath) {
|
|
5369
|
-
await
|
|
5408
|
+
await import_node_fs20.promises.mkdir(import_node_path34.default.dirname(filePath), { recursive: true });
|
|
5370
5409
|
}
|
|
5371
5410
|
async function saveGraphToDisk(graph, outPath) {
|
|
5372
5411
|
await ensureDir(outPath);
|
|
@@ -5376,13 +5415,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
5376
5415
|
graph: graph.export()
|
|
5377
5416
|
};
|
|
5378
5417
|
const tmp = `${outPath}.tmp`;
|
|
5379
|
-
await
|
|
5380
|
-
await
|
|
5418
|
+
await import_node_fs20.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
5419
|
+
await import_node_fs20.promises.rename(tmp, outPath);
|
|
5381
5420
|
}
|
|
5382
5421
|
async function loadGraphFromDisk(graph, outPath) {
|
|
5383
5422
|
let raw;
|
|
5384
5423
|
try {
|
|
5385
|
-
raw = await
|
|
5424
|
+
raw = await import_node_fs20.promises.readFile(outPath, "utf8");
|
|
5386
5425
|
} catch (err) {
|
|
5387
5426
|
if (err.code === "ENOENT") return;
|
|
5388
5427
|
throw err;
|
|
@@ -5441,8 +5480,8 @@ function startPersistLoop(graph, outPath, intervalMs = 6e4) {
|
|
|
5441
5480
|
|
|
5442
5481
|
// src/gitignore.ts
|
|
5443
5482
|
init_cjs_shims();
|
|
5444
|
-
var
|
|
5445
|
-
var
|
|
5483
|
+
var import_node_fs21 = require("fs");
|
|
5484
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
5446
5485
|
var NEAT_OUT_LINE = "neat-out/";
|
|
5447
5486
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
5448
5487
|
function isNeatOutLine(line) {
|
|
@@ -5450,15 +5489,15 @@ function isNeatOutLine(line) {
|
|
|
5450
5489
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
5451
5490
|
}
|
|
5452
5491
|
async function ensureNeatOutIgnored(projectDir) {
|
|
5453
|
-
const file =
|
|
5492
|
+
const file = import_node_path35.default.join(projectDir, ".gitignore");
|
|
5454
5493
|
let existing = null;
|
|
5455
5494
|
try {
|
|
5456
|
-
existing = await
|
|
5495
|
+
existing = await import_node_fs21.promises.readFile(file, "utf8");
|
|
5457
5496
|
} catch (err) {
|
|
5458
5497
|
if (err.code !== "ENOENT") throw err;
|
|
5459
5498
|
}
|
|
5460
5499
|
if (existing === null) {
|
|
5461
|
-
await
|
|
5500
|
+
await import_node_fs21.promises.writeFile(file, `${NEAT_HEADER}
|
|
5462
5501
|
${NEAT_OUT_LINE}
|
|
5463
5502
|
`, "utf8");
|
|
5464
5503
|
return { action: "created", file };
|
|
@@ -5471,7 +5510,7 @@ ${NEAT_OUT_LINE}
|
|
|
5471
5510
|
${NEAT_HEADER}
|
|
5472
5511
|
${NEAT_OUT_LINE}
|
|
5473
5512
|
`;
|
|
5474
|
-
await
|
|
5513
|
+
await import_node_fs21.promises.writeFile(file, existing + appended, "utf8");
|
|
5475
5514
|
return { action: "added", file };
|
|
5476
5515
|
}
|
|
5477
5516
|
|
|
@@ -5573,8 +5612,8 @@ function formatIncompat(inc) {
|
|
|
5573
5612
|
|
|
5574
5613
|
// src/watch.ts
|
|
5575
5614
|
init_cjs_shims();
|
|
5576
|
-
var
|
|
5577
|
-
var
|
|
5615
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
5616
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
5578
5617
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
5579
5618
|
|
|
5580
5619
|
// src/api.ts
|
|
@@ -5585,15 +5624,15 @@ var import_types25 = require("@neat.is/types");
|
|
|
5585
5624
|
|
|
5586
5625
|
// src/extend/index.ts
|
|
5587
5626
|
init_cjs_shims();
|
|
5588
|
-
var
|
|
5589
|
-
var
|
|
5627
|
+
var import_node_fs23 = require("fs");
|
|
5628
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
5590
5629
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
5591
5630
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
5592
5631
|
|
|
5593
5632
|
// src/installers/package-manager.ts
|
|
5594
5633
|
init_cjs_shims();
|
|
5595
|
-
var
|
|
5596
|
-
var
|
|
5634
|
+
var import_node_fs22 = require("fs");
|
|
5635
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5597
5636
|
var import_node_child_process = require("child_process");
|
|
5598
5637
|
var LOCKFILE_PRIORITY = [
|
|
5599
5638
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -5608,29 +5647,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
5608
5647
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
5609
5648
|
async function exists2(p) {
|
|
5610
5649
|
try {
|
|
5611
|
-
await
|
|
5650
|
+
await import_node_fs22.promises.access(p);
|
|
5612
5651
|
return true;
|
|
5613
5652
|
} catch {
|
|
5614
5653
|
return false;
|
|
5615
5654
|
}
|
|
5616
5655
|
}
|
|
5617
5656
|
async function detectPackageManager(serviceDir) {
|
|
5618
|
-
let dir =
|
|
5657
|
+
let dir = import_node_path36.default.resolve(serviceDir);
|
|
5619
5658
|
const stops = /* @__PURE__ */ new Set();
|
|
5620
5659
|
for (let i = 0; i < 64; i++) {
|
|
5621
5660
|
if (stops.has(dir)) break;
|
|
5622
5661
|
stops.add(dir);
|
|
5623
5662
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
5624
|
-
const lockPath =
|
|
5663
|
+
const lockPath = import_node_path36.default.join(dir, candidate.lockfile);
|
|
5625
5664
|
if (await exists2(lockPath)) {
|
|
5626
5665
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
5627
5666
|
}
|
|
5628
5667
|
}
|
|
5629
|
-
const parent =
|
|
5668
|
+
const parent = import_node_path36.default.dirname(dir);
|
|
5630
5669
|
if (parent === dir) break;
|
|
5631
5670
|
dir = parent;
|
|
5632
5671
|
}
|
|
5633
|
-
return { pm: "npm", cwd:
|
|
5672
|
+
return { pm: "npm", cwd: import_node_path36.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
5634
5673
|
}
|
|
5635
5674
|
async function runPackageManagerInstall(cmd) {
|
|
5636
5675
|
return new Promise((resolve) => {
|
|
@@ -5672,30 +5711,30 @@ ${err.message}`
|
|
|
5672
5711
|
// src/extend/index.ts
|
|
5673
5712
|
async function fileExists2(p) {
|
|
5674
5713
|
try {
|
|
5675
|
-
await
|
|
5714
|
+
await import_node_fs23.promises.access(p);
|
|
5676
5715
|
return true;
|
|
5677
5716
|
} catch {
|
|
5678
5717
|
return false;
|
|
5679
5718
|
}
|
|
5680
5719
|
}
|
|
5681
5720
|
async function readPackageJson(scanPath) {
|
|
5682
|
-
const pkgPath =
|
|
5683
|
-
const raw = await
|
|
5721
|
+
const pkgPath = import_node_path37.default.join(scanPath, "package.json");
|
|
5722
|
+
const raw = await import_node_fs23.promises.readFile(pkgPath, "utf8");
|
|
5684
5723
|
return JSON.parse(raw);
|
|
5685
5724
|
}
|
|
5686
5725
|
async function findHookFiles(scanPath) {
|
|
5687
|
-
const entries = await
|
|
5726
|
+
const entries = await import_node_fs23.promises.readdir(scanPath);
|
|
5688
5727
|
return entries.filter(
|
|
5689
5728
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
5690
5729
|
).sort();
|
|
5691
5730
|
}
|
|
5692
5731
|
function extendLogPath() {
|
|
5693
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
5732
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path37.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
5694
5733
|
}
|
|
5695
5734
|
async function appendExtendLog(entry2) {
|
|
5696
5735
|
const logPath = extendLogPath();
|
|
5697
|
-
await
|
|
5698
|
-
await
|
|
5736
|
+
await import_node_fs23.promises.mkdir(import_node_path37.default.dirname(logPath), { recursive: true });
|
|
5737
|
+
await import_node_fs23.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
5699
5738
|
}
|
|
5700
5739
|
function splicedContent(fileContent, snippet2) {
|
|
5701
5740
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -5753,7 +5792,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
5753
5792
|
}
|
|
5754
5793
|
async function describeProjectInstrumentation(ctx) {
|
|
5755
5794
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5756
|
-
const envNeat = await fileExists2(
|
|
5795
|
+
const envNeat = await fileExists2(import_node_path37.default.join(ctx.scanPath, ".env.neat"));
|
|
5757
5796
|
const registryInstrPackages = new Set(
|
|
5758
5797
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
5759
5798
|
);
|
|
@@ -5775,31 +5814,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
5775
5814
|
);
|
|
5776
5815
|
}
|
|
5777
5816
|
for (const file of hookFiles) {
|
|
5778
|
-
const content = await
|
|
5817
|
+
const content = await import_node_fs23.promises.readFile(import_node_path37.default.join(ctx.scanPath, file), "utf8");
|
|
5779
5818
|
if (content.includes(args.registration_snippet)) {
|
|
5780
5819
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
5781
5820
|
}
|
|
5782
5821
|
}
|
|
5783
5822
|
const primaryFile = hookFiles[0];
|
|
5784
|
-
const primaryPath =
|
|
5823
|
+
const primaryPath = import_node_path37.default.join(ctx.scanPath, primaryFile);
|
|
5785
5824
|
const filesTouched = [];
|
|
5786
5825
|
const depsAdded = [];
|
|
5787
|
-
const pkgPath =
|
|
5826
|
+
const pkgPath = import_node_path37.default.join(ctx.scanPath, "package.json");
|
|
5788
5827
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5789
5828
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
5790
5829
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
5791
|
-
await
|
|
5830
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5792
5831
|
filesTouched.push("package.json");
|
|
5793
5832
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
5794
5833
|
}
|
|
5795
|
-
const hookContent = await
|
|
5834
|
+
const hookContent = await import_node_fs23.promises.readFile(primaryPath, "utf8");
|
|
5796
5835
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5797
5836
|
if (!patched) {
|
|
5798
5837
|
throw new Error(
|
|
5799
5838
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
5800
5839
|
);
|
|
5801
5840
|
}
|
|
5802
|
-
await
|
|
5841
|
+
await import_node_fs23.promises.writeFile(primaryPath, patched, "utf8");
|
|
5803
5842
|
filesTouched.push(primaryFile);
|
|
5804
5843
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
5805
5844
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -5830,7 +5869,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5830
5869
|
};
|
|
5831
5870
|
}
|
|
5832
5871
|
for (const file of hookFiles) {
|
|
5833
|
-
const content = await
|
|
5872
|
+
const content = await import_node_fs23.promises.readFile(import_node_path37.default.join(ctx.scanPath, file), "utf8");
|
|
5834
5873
|
if (content.includes(args.registration_snippet)) {
|
|
5835
5874
|
return {
|
|
5836
5875
|
library: args.library,
|
|
@@ -5852,7 +5891,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5852
5891
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
5853
5892
|
filesTouched.push("package.json");
|
|
5854
5893
|
}
|
|
5855
|
-
const hookContent = await
|
|
5894
|
+
const hookContent = await import_node_fs23.promises.readFile(import_node_path37.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
5856
5895
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5857
5896
|
if (patched) {
|
|
5858
5897
|
filesTouched.push(primaryFile);
|
|
@@ -5867,28 +5906,28 @@ async function rollbackExtension(ctx, args) {
|
|
|
5867
5906
|
if (!await fileExists2(logPath)) {
|
|
5868
5907
|
return { undone: false, message: "no apply found for library" };
|
|
5869
5908
|
}
|
|
5870
|
-
const raw = await
|
|
5909
|
+
const raw = await import_node_fs23.promises.readFile(logPath, "utf8");
|
|
5871
5910
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
5872
5911
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
5873
5912
|
if (!match) {
|
|
5874
5913
|
return { undone: false, message: "no apply found for library" };
|
|
5875
5914
|
}
|
|
5876
|
-
const pkgPath =
|
|
5915
|
+
const pkgPath = import_node_path37.default.join(ctx.scanPath, "package.json");
|
|
5877
5916
|
if (await fileExists2(pkgPath)) {
|
|
5878
5917
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5879
5918
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
5880
5919
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
5881
5920
|
pkg.dependencies = rest;
|
|
5882
|
-
await
|
|
5921
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5883
5922
|
}
|
|
5884
5923
|
}
|
|
5885
5924
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5886
5925
|
for (const file of hookFiles) {
|
|
5887
|
-
const filePath =
|
|
5888
|
-
const content = await
|
|
5926
|
+
const filePath = import_node_path37.default.join(ctx.scanPath, file);
|
|
5927
|
+
const content = await import_node_fs23.promises.readFile(filePath, "utf8");
|
|
5889
5928
|
if (content.includes(match.registration_snippet)) {
|
|
5890
5929
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
5891
|
-
await
|
|
5930
|
+
await import_node_fs23.promises.writeFile(filePath, filtered, "utf8");
|
|
5892
5931
|
break;
|
|
5893
5932
|
}
|
|
5894
5933
|
}
|
|
@@ -5900,7 +5939,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
5900
5939
|
|
|
5901
5940
|
// src/diff.ts
|
|
5902
5941
|
init_cjs_shims();
|
|
5903
|
-
var
|
|
5942
|
+
var import_node_fs24 = require("fs");
|
|
5904
5943
|
async function loadSnapshotForDiff(target) {
|
|
5905
5944
|
if (/^https?:\/\//i.test(target)) {
|
|
5906
5945
|
const res = await fetch(target);
|
|
@@ -5909,7 +5948,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
5909
5948
|
}
|
|
5910
5949
|
return await res.json();
|
|
5911
5950
|
}
|
|
5912
|
-
const raw = await
|
|
5951
|
+
const raw = await import_node_fs24.promises.readFile(target, "utf8");
|
|
5913
5952
|
return JSON.parse(raw);
|
|
5914
5953
|
}
|
|
5915
5954
|
function indexEntries(entries) {
|
|
@@ -5977,23 +6016,23 @@ function canonicalJson(value) {
|
|
|
5977
6016
|
|
|
5978
6017
|
// src/projects.ts
|
|
5979
6018
|
init_cjs_shims();
|
|
5980
|
-
var
|
|
6019
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
5981
6020
|
function pathsForProject(project, baseDir) {
|
|
5982
6021
|
if (project === DEFAULT_PROJECT) {
|
|
5983
6022
|
return {
|
|
5984
|
-
snapshotPath:
|
|
5985
|
-
errorsPath:
|
|
5986
|
-
staleEventsPath:
|
|
5987
|
-
embeddingsCachePath:
|
|
5988
|
-
policyViolationsPath:
|
|
6023
|
+
snapshotPath: import_node_path38.default.join(baseDir, "graph.json"),
|
|
6024
|
+
errorsPath: import_node_path38.default.join(baseDir, "errors.ndjson"),
|
|
6025
|
+
staleEventsPath: import_node_path38.default.join(baseDir, "stale-events.ndjson"),
|
|
6026
|
+
embeddingsCachePath: import_node_path38.default.join(baseDir, "embeddings.json"),
|
|
6027
|
+
policyViolationsPath: import_node_path38.default.join(baseDir, "policy-violations.ndjson")
|
|
5989
6028
|
};
|
|
5990
6029
|
}
|
|
5991
6030
|
return {
|
|
5992
|
-
snapshotPath:
|
|
5993
|
-
errorsPath:
|
|
5994
|
-
staleEventsPath:
|
|
5995
|
-
embeddingsCachePath:
|
|
5996
|
-
policyViolationsPath:
|
|
6031
|
+
snapshotPath: import_node_path38.default.join(baseDir, `${project}.json`),
|
|
6032
|
+
errorsPath: import_node_path38.default.join(baseDir, `errors.${project}.ndjson`),
|
|
6033
|
+
staleEventsPath: import_node_path38.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
6034
|
+
embeddingsCachePath: import_node_path38.default.join(baseDir, `embeddings.${project}.json`),
|
|
6035
|
+
policyViolationsPath: import_node_path38.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5997
6036
|
};
|
|
5998
6037
|
}
|
|
5999
6038
|
var Projects = class {
|
|
@@ -6029,25 +6068,25 @@ var Projects = class {
|
|
|
6029
6068
|
|
|
6030
6069
|
// src/registry.ts
|
|
6031
6070
|
init_cjs_shims();
|
|
6032
|
-
var
|
|
6071
|
+
var import_node_fs25 = require("fs");
|
|
6033
6072
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
6034
|
-
var
|
|
6073
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
6035
6074
|
var import_types24 = require("@neat.is/types");
|
|
6036
6075
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
6037
6076
|
var LOCK_RETRY_MS = 50;
|
|
6038
6077
|
function neatHome() {
|
|
6039
6078
|
const override = process.env.NEAT_HOME;
|
|
6040
|
-
if (override && override.length > 0) return
|
|
6041
|
-
return
|
|
6079
|
+
if (override && override.length > 0) return import_node_path39.default.resolve(override);
|
|
6080
|
+
return import_node_path39.default.join(import_node_os3.default.homedir(), ".neat");
|
|
6042
6081
|
}
|
|
6043
6082
|
function registryPath() {
|
|
6044
|
-
return
|
|
6083
|
+
return import_node_path39.default.join(neatHome(), "projects.json");
|
|
6045
6084
|
}
|
|
6046
6085
|
function registryLockPath() {
|
|
6047
|
-
return
|
|
6086
|
+
return import_node_path39.default.join(neatHome(), "projects.json.lock");
|
|
6048
6087
|
}
|
|
6049
6088
|
function daemonPidPath() {
|
|
6050
|
-
return
|
|
6089
|
+
return import_node_path39.default.join(neatHome(), "neatd.pid");
|
|
6051
6090
|
}
|
|
6052
6091
|
function isPidAliveDefault(pid) {
|
|
6053
6092
|
try {
|
|
@@ -6059,7 +6098,7 @@ function isPidAliveDefault(pid) {
|
|
|
6059
6098
|
}
|
|
6060
6099
|
async function readPidFile(file) {
|
|
6061
6100
|
try {
|
|
6062
|
-
const raw = await
|
|
6101
|
+
const raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
6063
6102
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
6064
6103
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
6065
6104
|
} catch {
|
|
@@ -6107,32 +6146,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
6107
6146
|
}
|
|
6108
6147
|
}
|
|
6109
6148
|
async function normalizeProjectPath(input) {
|
|
6110
|
-
const resolved =
|
|
6149
|
+
const resolved = import_node_path39.default.resolve(input);
|
|
6111
6150
|
try {
|
|
6112
|
-
return await
|
|
6151
|
+
return await import_node_fs25.promises.realpath(resolved);
|
|
6113
6152
|
} catch {
|
|
6114
6153
|
return resolved;
|
|
6115
6154
|
}
|
|
6116
6155
|
}
|
|
6117
6156
|
async function writeAtomically(target, contents) {
|
|
6118
|
-
await
|
|
6157
|
+
await import_node_fs25.promises.mkdir(import_node_path39.default.dirname(target), { recursive: true });
|
|
6119
6158
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
6120
|
-
const fd = await
|
|
6159
|
+
const fd = await import_node_fs25.promises.open(tmp, "w");
|
|
6121
6160
|
try {
|
|
6122
6161
|
await fd.writeFile(contents, "utf8");
|
|
6123
6162
|
await fd.sync();
|
|
6124
6163
|
} finally {
|
|
6125
6164
|
await fd.close();
|
|
6126
6165
|
}
|
|
6127
|
-
await
|
|
6166
|
+
await import_node_fs25.promises.rename(tmp, target);
|
|
6128
6167
|
}
|
|
6129
6168
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
6130
6169
|
const deadline = Date.now() + timeoutMs;
|
|
6131
|
-
await
|
|
6170
|
+
await import_node_fs25.promises.mkdir(import_node_path39.default.dirname(lockPath), { recursive: true });
|
|
6132
6171
|
let probedHolder = false;
|
|
6133
6172
|
while (true) {
|
|
6134
6173
|
try {
|
|
6135
|
-
const fd = await
|
|
6174
|
+
const fd = await import_node_fs25.promises.open(lockPath, "wx");
|
|
6136
6175
|
try {
|
|
6137
6176
|
await fd.writeFile(`${process.pid}
|
|
6138
6177
|
`, "utf8");
|
|
@@ -6157,7 +6196,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
6157
6196
|
}
|
|
6158
6197
|
}
|
|
6159
6198
|
async function releaseLock(lockPath) {
|
|
6160
|
-
await
|
|
6199
|
+
await import_node_fs25.promises.unlink(lockPath).catch(() => {
|
|
6161
6200
|
});
|
|
6162
6201
|
}
|
|
6163
6202
|
async function withLock(fn) {
|
|
@@ -6173,7 +6212,7 @@ async function readRegistry() {
|
|
|
6173
6212
|
const file = registryPath();
|
|
6174
6213
|
let raw;
|
|
6175
6214
|
try {
|
|
6176
|
-
raw = await
|
|
6215
|
+
raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
6177
6216
|
} catch (err) {
|
|
6178
6217
|
if (err.code === "ENOENT") {
|
|
6179
6218
|
return { version: 1, projects: [] };
|
|
@@ -6924,8 +6963,8 @@ init_otel_grpc();
|
|
|
6924
6963
|
|
|
6925
6964
|
// src/search.ts
|
|
6926
6965
|
init_cjs_shims();
|
|
6927
|
-
var
|
|
6928
|
-
var
|
|
6966
|
+
var import_node_fs26 = require("fs");
|
|
6967
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
6929
6968
|
var import_node_crypto3 = require("crypto");
|
|
6930
6969
|
var DEFAULT_LIMIT = 10;
|
|
6931
6970
|
var NOMIC_DIM = 768;
|
|
@@ -7055,7 +7094,7 @@ async function pickEmbedder() {
|
|
|
7055
7094
|
}
|
|
7056
7095
|
async function readCache(cachePath) {
|
|
7057
7096
|
try {
|
|
7058
|
-
const raw = await
|
|
7097
|
+
const raw = await import_node_fs26.promises.readFile(cachePath, "utf8");
|
|
7059
7098
|
const parsed = JSON.parse(raw);
|
|
7060
7099
|
if (parsed.version !== 1) return null;
|
|
7061
7100
|
return parsed;
|
|
@@ -7064,8 +7103,8 @@ async function readCache(cachePath) {
|
|
|
7064
7103
|
}
|
|
7065
7104
|
}
|
|
7066
7105
|
async function writeCache(cachePath, cache) {
|
|
7067
|
-
await
|
|
7068
|
-
await
|
|
7106
|
+
await import_node_fs26.promises.mkdir(import_node_path42.default.dirname(cachePath), { recursive: true });
|
|
7107
|
+
await import_node_fs26.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
7069
7108
|
}
|
|
7070
7109
|
var VectorIndex = class {
|
|
7071
7110
|
constructor(embedder, cachePath) {
|
|
@@ -7221,8 +7260,8 @@ var ALL_PHASES = [
|
|
|
7221
7260
|
];
|
|
7222
7261
|
function classifyChange(relPath) {
|
|
7223
7262
|
const phases = /* @__PURE__ */ new Set();
|
|
7224
|
-
const base =
|
|
7225
|
-
const segments = relPath.split(
|
|
7263
|
+
const base = import_node_path43.default.basename(relPath).toLowerCase();
|
|
7264
|
+
const segments = relPath.split(import_node_path43.default.sep).map((s) => s.toLowerCase());
|
|
7226
7265
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
7227
7266
|
phases.add("services");
|
|
7228
7267
|
phases.add("aliases");
|
|
@@ -7336,16 +7375,16 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
7336
7375
|
if (count >= limit) return;
|
|
7337
7376
|
let entries;
|
|
7338
7377
|
try {
|
|
7339
|
-
entries =
|
|
7378
|
+
entries = import_node_fs27.default.readdirSync(dir, { withFileTypes: true });
|
|
7340
7379
|
} catch {
|
|
7341
7380
|
return;
|
|
7342
7381
|
}
|
|
7343
7382
|
for (const e of entries) {
|
|
7344
7383
|
if (count >= limit) return;
|
|
7345
7384
|
if (!e.isDirectory()) continue;
|
|
7346
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
7385
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path43.default.join(dir, e.name) + import_node_path43.default.sep))) continue;
|
|
7347
7386
|
count++;
|
|
7348
|
-
if (depth < 2) visit(
|
|
7387
|
+
if (depth < 2) visit(import_node_path43.default.join(dir, e.name), depth + 1);
|
|
7349
7388
|
}
|
|
7350
7389
|
};
|
|
7351
7390
|
visit(scanPath, 0);
|
|
@@ -7363,8 +7402,8 @@ async function startWatch(graph, opts) {
|
|
|
7363
7402
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
7364
7403
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
7365
7404
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
7366
|
-
const policyFilePath =
|
|
7367
|
-
const policyViolationsPath =
|
|
7405
|
+
const policyFilePath = import_node_path43.default.join(opts.scanPath, "policy.json");
|
|
7406
|
+
const policyViolationsPath = import_node_path43.default.join(import_node_path43.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
7368
7407
|
let policies = [];
|
|
7369
7408
|
try {
|
|
7370
7409
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -7415,7 +7454,7 @@ async function startWatch(graph, opts) {
|
|
|
7415
7454
|
assertBindAuthority(host, auth.authToken);
|
|
7416
7455
|
const port = opts.port ?? 8080;
|
|
7417
7456
|
const otelPort = opts.otelPort ?? 4318;
|
|
7418
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
7457
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path43.default.join(import_node_path43.default.dirname(opts.outPath), "embeddings.json");
|
|
7419
7458
|
let searchIndex;
|
|
7420
7459
|
try {
|
|
7421
7460
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -7433,7 +7472,7 @@ async function startWatch(graph, opts) {
|
|
|
7433
7472
|
// Paths are derived from the explicit options the watch caller passes
|
|
7434
7473
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
7435
7474
|
// fields so the registry shape is complete.
|
|
7436
|
-
...pathsForProject(projectName,
|
|
7475
|
+
...pathsForProject(projectName, import_node_path43.default.dirname(opts.outPath)),
|
|
7437
7476
|
snapshotPath: opts.outPath,
|
|
7438
7477
|
errorsPath: opts.errorsPath,
|
|
7439
7478
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -7520,9 +7559,9 @@ async function startWatch(graph, opts) {
|
|
|
7520
7559
|
};
|
|
7521
7560
|
const onPath = (absPath) => {
|
|
7522
7561
|
if (shouldIgnore(absPath)) return;
|
|
7523
|
-
const rel =
|
|
7562
|
+
const rel = import_node_path43.default.relative(opts.scanPath, absPath);
|
|
7524
7563
|
if (!rel || rel.startsWith("..")) return;
|
|
7525
|
-
pendingPaths.add(rel.split(
|
|
7564
|
+
pendingPaths.add(rel.split(import_node_path43.default.sep).join("/"));
|
|
7526
7565
|
const phases = classifyChange(rel);
|
|
7527
7566
|
if (phases.size === 0) {
|
|
7528
7567
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -7576,8 +7615,8 @@ async function startWatch(graph, opts) {
|
|
|
7576
7615
|
|
|
7577
7616
|
// src/deploy/detect.ts
|
|
7578
7617
|
init_cjs_shims();
|
|
7579
|
-
var
|
|
7580
|
-
var
|
|
7618
|
+
var import_node_fs28 = require("fs");
|
|
7619
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
7581
7620
|
var import_node_child_process2 = require("child_process");
|
|
7582
7621
|
var import_node_crypto4 = require("crypto");
|
|
7583
7622
|
function generateToken() {
|
|
@@ -7677,21 +7716,21 @@ async function runDeploy(opts = {}) {
|
|
|
7677
7716
|
const token = generateToken();
|
|
7678
7717
|
switch (substrate) {
|
|
7679
7718
|
case "docker-compose": {
|
|
7680
|
-
const artifactPath =
|
|
7719
|
+
const artifactPath = import_node_path44.default.join(cwd, "docker-compose.neat.yml");
|
|
7681
7720
|
const contents = emitDockerCompose(cwd);
|
|
7682
|
-
await
|
|
7721
|
+
await import_node_fs28.promises.writeFile(artifactPath, contents, "utf8");
|
|
7683
7722
|
return {
|
|
7684
7723
|
substrate,
|
|
7685
7724
|
artifactPath,
|
|
7686
7725
|
token,
|
|
7687
7726
|
contents,
|
|
7688
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
7727
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path44.default.basename(artifactPath)} up -d`
|
|
7689
7728
|
};
|
|
7690
7729
|
}
|
|
7691
7730
|
case "systemd": {
|
|
7692
|
-
const artifactPath =
|
|
7731
|
+
const artifactPath = import_node_path44.default.join(cwd, "neat.service");
|
|
7693
7732
|
const contents = emitSystemdUnit(cwd);
|
|
7694
|
-
await
|
|
7733
|
+
await import_node_fs28.promises.writeFile(artifactPath, contents, "utf8");
|
|
7695
7734
|
return {
|
|
7696
7735
|
substrate,
|
|
7697
7736
|
artifactPath,
|
|
@@ -7724,8 +7763,8 @@ init_cjs_shims();
|
|
|
7724
7763
|
|
|
7725
7764
|
// src/installers/javascript.ts
|
|
7726
7765
|
init_cjs_shims();
|
|
7727
|
-
var
|
|
7728
|
-
var
|
|
7766
|
+
var import_node_fs29 = require("fs");
|
|
7767
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
7729
7768
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
7730
7769
|
|
|
7731
7770
|
// src/installers/templates.ts
|
|
@@ -8272,15 +8311,15 @@ var OTEL_ENV = {
|
|
|
8272
8311
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
8273
8312
|
};
|
|
8274
8313
|
function serviceNodeName(pkg, serviceDir) {
|
|
8275
|
-
return pkg.name ??
|
|
8314
|
+
return pkg.name ?? import_node_path45.default.basename(serviceDir);
|
|
8276
8315
|
}
|
|
8277
8316
|
function projectToken(pkg, serviceDir, project) {
|
|
8278
8317
|
if (project && project.length > 0) return project;
|
|
8279
|
-
return pkg.name ??
|
|
8318
|
+
return pkg.name ?? import_node_path45.default.basename(serviceDir);
|
|
8280
8319
|
}
|
|
8281
8320
|
async function readJsonFile(p) {
|
|
8282
8321
|
try {
|
|
8283
|
-
const raw = await
|
|
8322
|
+
const raw = await import_node_fs29.promises.readFile(p, "utf8");
|
|
8284
8323
|
return JSON.parse(raw);
|
|
8285
8324
|
} catch {
|
|
8286
8325
|
return null;
|
|
@@ -8289,16 +8328,16 @@ async function readJsonFile(p) {
|
|
|
8289
8328
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
8290
8329
|
const deps = allDeps(pkg);
|
|
8291
8330
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
8292
|
-
const appJson = await readJsonFile(
|
|
8331
|
+
const appJson = await readJsonFile(import_node_path45.default.join(pkgRoot, "app.json"));
|
|
8293
8332
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
8294
8333
|
return "react-native";
|
|
8295
8334
|
}
|
|
8296
|
-
if (await exists3(
|
|
8335
|
+
if (await exists3(import_node_path45.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path45.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path45.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
8297
8336
|
return "browser-bundle";
|
|
8298
8337
|
}
|
|
8299
|
-
if (await exists3(
|
|
8300
|
-
if (await exists3(
|
|
8301
|
-
if (await exists3(
|
|
8338
|
+
if (await exists3(import_node_path45.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
8339
|
+
if (await exists3(import_node_path45.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
8340
|
+
if (await exists3(import_node_path45.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path45.default.join(pkgRoot, "deno.lock"))) {
|
|
8302
8341
|
return "deno";
|
|
8303
8342
|
}
|
|
8304
8343
|
const engines = pkg.engines ?? {};
|
|
@@ -8307,7 +8346,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
8307
8346
|
}
|
|
8308
8347
|
async function readPackageJson2(serviceDir) {
|
|
8309
8348
|
try {
|
|
8310
|
-
const raw = await
|
|
8349
|
+
const raw = await import_node_fs29.promises.readFile(import_node_path45.default.join(serviceDir, "package.json"), "utf8");
|
|
8311
8350
|
return JSON.parse(raw);
|
|
8312
8351
|
} catch {
|
|
8313
8352
|
return null;
|
|
@@ -8315,7 +8354,7 @@ async function readPackageJson2(serviceDir) {
|
|
|
8315
8354
|
}
|
|
8316
8355
|
async function exists3(p) {
|
|
8317
8356
|
try {
|
|
8318
|
-
await
|
|
8357
|
+
await import_node_fs29.promises.stat(p);
|
|
8319
8358
|
return true;
|
|
8320
8359
|
} catch {
|
|
8321
8360
|
return false;
|
|
@@ -8323,7 +8362,7 @@ async function exists3(p) {
|
|
|
8323
8362
|
}
|
|
8324
8363
|
async function readFileMaybe(p) {
|
|
8325
8364
|
try {
|
|
8326
|
-
return await
|
|
8365
|
+
return await import_node_fs29.promises.readFile(p, "utf8");
|
|
8327
8366
|
} catch {
|
|
8328
8367
|
return null;
|
|
8329
8368
|
}
|
|
@@ -8351,7 +8390,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
8351
8390
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
8352
8391
|
async function findNextConfig(serviceDir) {
|
|
8353
8392
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
8354
|
-
const candidate =
|
|
8393
|
+
const candidate = import_node_path45.default.join(serviceDir, name);
|
|
8355
8394
|
if (await exists3(candidate)) return candidate;
|
|
8356
8395
|
}
|
|
8357
8396
|
return null;
|
|
@@ -8378,7 +8417,7 @@ function hasRemixDependency(pkg) {
|
|
|
8378
8417
|
}
|
|
8379
8418
|
async function findRemixEntry(serviceDir) {
|
|
8380
8419
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
8381
|
-
const candidate =
|
|
8420
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8382
8421
|
if (await exists3(candidate)) return candidate;
|
|
8383
8422
|
}
|
|
8384
8423
|
return null;
|
|
@@ -8390,14 +8429,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
8390
8429
|
}
|
|
8391
8430
|
async function findSvelteKitHooks(serviceDir) {
|
|
8392
8431
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
8393
|
-
const candidate =
|
|
8432
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8394
8433
|
if (await exists3(candidate)) return candidate;
|
|
8395
8434
|
}
|
|
8396
8435
|
return null;
|
|
8397
8436
|
}
|
|
8398
8437
|
async function findSvelteKitConfig(serviceDir) {
|
|
8399
8438
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
8400
|
-
const candidate =
|
|
8439
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8401
8440
|
if (await exists3(candidate)) return candidate;
|
|
8402
8441
|
}
|
|
8403
8442
|
return null;
|
|
@@ -8408,7 +8447,7 @@ function hasNuxtDependency(pkg) {
|
|
|
8408
8447
|
}
|
|
8409
8448
|
async function findNuxtConfig(serviceDir) {
|
|
8410
8449
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
8411
|
-
const candidate =
|
|
8450
|
+
const candidate = import_node_path45.default.join(serviceDir, name);
|
|
8412
8451
|
if (await exists3(candidate)) return candidate;
|
|
8413
8452
|
}
|
|
8414
8453
|
return null;
|
|
@@ -8419,7 +8458,7 @@ function hasAstroDependency(pkg) {
|
|
|
8419
8458
|
}
|
|
8420
8459
|
async function findAstroConfig(serviceDir) {
|
|
8421
8460
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
8422
|
-
const candidate =
|
|
8461
|
+
const candidate = import_node_path45.default.join(serviceDir, name);
|
|
8423
8462
|
if (await exists3(candidate)) return candidate;
|
|
8424
8463
|
}
|
|
8425
8464
|
return null;
|
|
@@ -8433,7 +8472,7 @@ function parseNextMajor(range) {
|
|
|
8433
8472
|
return Number.isFinite(n) ? n : null;
|
|
8434
8473
|
}
|
|
8435
8474
|
async function isTypeScriptProject(serviceDir) {
|
|
8436
|
-
return exists3(
|
|
8475
|
+
return exists3(import_node_path45.default.join(serviceDir, "tsconfig.json"));
|
|
8437
8476
|
}
|
|
8438
8477
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
8439
8478
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -8479,7 +8518,7 @@ function entryFromScript(script) {
|
|
|
8479
8518
|
}
|
|
8480
8519
|
async function resolveEntry(serviceDir, pkg) {
|
|
8481
8520
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
8482
|
-
const candidate =
|
|
8521
|
+
const candidate = import_node_path45.default.resolve(serviceDir, pkg.main);
|
|
8483
8522
|
if (await exists3(candidate)) return candidate;
|
|
8484
8523
|
}
|
|
8485
8524
|
if (pkg.bin) {
|
|
@@ -8493,36 +8532,36 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
8493
8532
|
if (typeof first === "string") binEntry = first;
|
|
8494
8533
|
}
|
|
8495
8534
|
if (binEntry) {
|
|
8496
|
-
const candidate =
|
|
8535
|
+
const candidate = import_node_path45.default.resolve(serviceDir, binEntry);
|
|
8497
8536
|
if (await exists3(candidate)) return candidate;
|
|
8498
8537
|
}
|
|
8499
8538
|
}
|
|
8500
8539
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
8501
8540
|
if (startEntry) {
|
|
8502
|
-
const candidate =
|
|
8541
|
+
const candidate = import_node_path45.default.resolve(serviceDir, startEntry);
|
|
8503
8542
|
if (await exists3(candidate)) return candidate;
|
|
8504
8543
|
}
|
|
8505
8544
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
8506
8545
|
if (devEntry) {
|
|
8507
|
-
const candidate =
|
|
8546
|
+
const candidate = import_node_path45.default.resolve(serviceDir, devEntry);
|
|
8508
8547
|
if (await exists3(candidate)) return candidate;
|
|
8509
8548
|
}
|
|
8510
8549
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
8511
|
-
const candidate =
|
|
8550
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8512
8551
|
if (await exists3(candidate)) return candidate;
|
|
8513
8552
|
}
|
|
8514
8553
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
8515
|
-
const candidate =
|
|
8554
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8516
8555
|
if (await exists3(candidate)) return candidate;
|
|
8517
8556
|
}
|
|
8518
8557
|
for (const name of INDEX_CANDIDATES) {
|
|
8519
|
-
const candidate =
|
|
8558
|
+
const candidate = import_node_path45.default.join(serviceDir, name);
|
|
8520
8559
|
if (await exists3(candidate)) return candidate;
|
|
8521
8560
|
}
|
|
8522
8561
|
return null;
|
|
8523
8562
|
}
|
|
8524
8563
|
function dispatchEntry(entryFile, pkg) {
|
|
8525
|
-
const ext =
|
|
8564
|
+
const ext = import_node_path45.default.extname(entryFile).toLowerCase();
|
|
8526
8565
|
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
8527
8566
|
if (ext === ".mjs") return "esm";
|
|
8528
8567
|
if (ext === ".cjs") return "cjs";
|
|
@@ -8539,9 +8578,9 @@ function otelInitContents(flavor) {
|
|
|
8539
8578
|
return OTEL_INIT_CJS;
|
|
8540
8579
|
}
|
|
8541
8580
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
8542
|
-
let rel =
|
|
8581
|
+
let rel = import_node_path45.default.relative(import_node_path45.default.dirname(entryFile), otelInitFile);
|
|
8543
8582
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
8544
|
-
rel = rel.split(
|
|
8583
|
+
rel = rel.split(import_node_path45.default.sep).join("/");
|
|
8545
8584
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
8546
8585
|
if (flavor === "esm") return `import '${rel}'`;
|
|
8547
8586
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -8554,23 +8593,23 @@ function lineIsOtelInjection(line) {
|
|
|
8554
8593
|
}
|
|
8555
8594
|
async function detectsSrcLayout(serviceDir) {
|
|
8556
8595
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
8557
|
-
exists3(
|
|
8558
|
-
exists3(
|
|
8559
|
-
exists3(
|
|
8560
|
-
exists3(
|
|
8596
|
+
exists3(import_node_path45.default.join(serviceDir, "src", "app")),
|
|
8597
|
+
exists3(import_node_path45.default.join(serviceDir, "src", "pages")),
|
|
8598
|
+
exists3(import_node_path45.default.join(serviceDir, "app")),
|
|
8599
|
+
exists3(import_node_path45.default.join(serviceDir, "pages"))
|
|
8561
8600
|
]);
|
|
8562
8601
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
8563
8602
|
}
|
|
8564
8603
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
8565
8604
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8566
8605
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
8567
|
-
const baseDir = srcLayout ?
|
|
8568
|
-
const instrumentationFile =
|
|
8569
|
-
const instrumentationNodeFile =
|
|
8606
|
+
const baseDir = srcLayout ? import_node_path45.default.join(serviceDir, "src") : serviceDir;
|
|
8607
|
+
const instrumentationFile = import_node_path45.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
8608
|
+
const instrumentationNodeFile = import_node_path45.default.join(
|
|
8570
8609
|
baseDir,
|
|
8571
8610
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
8572
8611
|
);
|
|
8573
|
-
const envNeatFile =
|
|
8612
|
+
const envNeatFile = import_node_path45.default.join(baseDir, ".env.neat");
|
|
8574
8613
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
8575
8614
|
const dependencyEdits = [];
|
|
8576
8615
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -8627,7 +8666,7 @@ async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project)
|
|
|
8627
8666
|
const nextMajor = parseNextMajor(nextRange);
|
|
8628
8667
|
if (nextMajor !== null && nextMajor < 15) {
|
|
8629
8668
|
try {
|
|
8630
|
-
const raw = await
|
|
8669
|
+
const raw = await import_node_fs29.promises.readFile(nextConfigPath, "utf8");
|
|
8631
8670
|
if (!raw.includes("instrumentationHook")) {
|
|
8632
8671
|
nextConfigEdit = {
|
|
8633
8672
|
file: nextConfigPath,
|
|
@@ -8675,7 +8714,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
8675
8714
|
return edits;
|
|
8676
8715
|
}
|
|
8677
8716
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
8678
|
-
const envNeatFile =
|
|
8717
|
+
const envNeatFile = import_node_path45.default.join(serviceDir, ".env.neat");
|
|
8679
8718
|
if (!await exists3(envNeatFile)) {
|
|
8680
8719
|
generatedFiles.push({
|
|
8681
8720
|
file: envNeatFile,
|
|
@@ -8710,7 +8749,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
8710
8749
|
}
|
|
8711
8750
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
8712
8751
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8713
|
-
const otelServerFile =
|
|
8752
|
+
const otelServerFile = import_node_path45.default.join(
|
|
8714
8753
|
serviceDir,
|
|
8715
8754
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
8716
8755
|
);
|
|
@@ -8731,7 +8770,7 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
8731
8770
|
await queueEnvNeat(serviceDir, pkg, project, generatedFiles);
|
|
8732
8771
|
const entrypointEdits = [];
|
|
8733
8772
|
try {
|
|
8734
|
-
const raw = await
|
|
8773
|
+
const raw = await import_node_fs29.promises.readFile(entryFile, "utf8");
|
|
8735
8774
|
if (!fileImportsOtelHook(raw, ["./otel.server"])) {
|
|
8736
8775
|
const lines = raw.split(/\r?\n/);
|
|
8737
8776
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8767,11 +8806,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
8767
8806
|
}
|
|
8768
8807
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
8769
8808
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8770
|
-
const otelInitFile =
|
|
8809
|
+
const otelInitFile = import_node_path45.default.join(
|
|
8771
8810
|
serviceDir,
|
|
8772
8811
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
8773
8812
|
);
|
|
8774
|
-
const resolvedHooksFile = hooksFile ??
|
|
8813
|
+
const resolvedHooksFile = hooksFile ?? import_node_path45.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
8775
8814
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8776
8815
|
const generatedFiles = [];
|
|
8777
8816
|
const entrypointEdits = [];
|
|
@@ -8796,7 +8835,7 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
8796
8835
|
});
|
|
8797
8836
|
} else {
|
|
8798
8837
|
try {
|
|
8799
|
-
const raw = await
|
|
8838
|
+
const raw = await import_node_fs29.promises.readFile(hooksFile, "utf8");
|
|
8800
8839
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8801
8840
|
const lines = raw.split(/\r?\n/);
|
|
8802
8841
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8833,11 +8872,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
8833
8872
|
}
|
|
8834
8873
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
8835
8874
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8836
|
-
const otelPluginFile =
|
|
8875
|
+
const otelPluginFile = import_node_path45.default.join(
|
|
8837
8876
|
serviceDir,
|
|
8838
8877
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
8839
8878
|
);
|
|
8840
|
-
const otelInitFile =
|
|
8879
|
+
const otelInitFile = import_node_path45.default.join(
|
|
8841
8880
|
serviceDir,
|
|
8842
8881
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
8843
8882
|
);
|
|
@@ -8888,19 +8927,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
8888
8927
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
8889
8928
|
async function findAstroMiddleware(serviceDir) {
|
|
8890
8929
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
8891
|
-
const candidate =
|
|
8930
|
+
const candidate = import_node_path45.default.join(serviceDir, rel);
|
|
8892
8931
|
if (await exists3(candidate)) return candidate;
|
|
8893
8932
|
}
|
|
8894
8933
|
return null;
|
|
8895
8934
|
}
|
|
8896
8935
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
8897
8936
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
8898
|
-
const otelInitFile =
|
|
8937
|
+
const otelInitFile = import_node_path45.default.join(
|
|
8899
8938
|
serviceDir,
|
|
8900
8939
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
8901
8940
|
);
|
|
8902
8941
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
8903
|
-
const middlewareFile = existingMiddleware ??
|
|
8942
|
+
const middlewareFile = existingMiddleware ?? import_node_path45.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
8904
8943
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
8905
8944
|
const generatedFiles = [];
|
|
8906
8945
|
const entrypointEdits = [];
|
|
@@ -8925,7 +8964,7 @@ async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
|
8925
8964
|
});
|
|
8926
8965
|
} else {
|
|
8927
8966
|
try {
|
|
8928
|
-
const raw = await
|
|
8967
|
+
const raw = await import_node_fs29.promises.readFile(existingMiddleware, "utf8");
|
|
8929
8968
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
8930
8969
|
const lines = raw.split(/\r?\n/);
|
|
8931
8970
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -8996,7 +9035,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
8996
9035
|
}
|
|
8997
9036
|
async function plan(serviceDir, opts) {
|
|
8998
9037
|
const pkg = await readPackageJson2(serviceDir);
|
|
8999
|
-
const manifestPath =
|
|
9038
|
+
const manifestPath = import_node_path45.default.join(serviceDir, "package.json");
|
|
9000
9039
|
const project = opts?.project;
|
|
9001
9040
|
const empty = {
|
|
9002
9041
|
language: "javascript",
|
|
@@ -9031,8 +9070,8 @@ async function plan(serviceDir, opts) {
|
|
|
9031
9070
|
return { ...empty, libOnly: true };
|
|
9032
9071
|
}
|
|
9033
9072
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
9034
|
-
const otelInitFile =
|
|
9035
|
-
const envNeatFile =
|
|
9073
|
+
const otelInitFile = import_node_path45.default.join(import_node_path45.default.dirname(entryFile), otelInitFilename(flavor));
|
|
9074
|
+
const envNeatFile = import_node_path45.default.join(serviceDir, ".env.neat");
|
|
9036
9075
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
9037
9076
|
const dependencyEdits = [];
|
|
9038
9077
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -9056,7 +9095,7 @@ async function plan(serviceDir, opts) {
|
|
|
9056
9095
|
}
|
|
9057
9096
|
const entrypointEdits = [];
|
|
9058
9097
|
try {
|
|
9059
|
-
const raw = await
|
|
9098
|
+
const raw = await import_node_fs29.promises.readFile(entryFile, "utf8");
|
|
9060
9099
|
const lines = raw.split(/\r?\n/);
|
|
9061
9100
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
9062
9101
|
if (!lineIsOtelInjection(firstReal)) {
|
|
@@ -9101,13 +9140,13 @@ async function plan(serviceDir, opts) {
|
|
|
9101
9140
|
};
|
|
9102
9141
|
}
|
|
9103
9142
|
function isAllowedWritePath(serviceDir, target) {
|
|
9104
|
-
const rel =
|
|
9143
|
+
const rel = import_node_path45.default.relative(serviceDir, target);
|
|
9105
9144
|
if (rel.startsWith("..")) return false;
|
|
9106
|
-
const base =
|
|
9145
|
+
const base = import_node_path45.default.basename(target);
|
|
9107
9146
|
if (base === "package.json") return true;
|
|
9108
9147
|
if (base === ".env.neat") return true;
|
|
9109
9148
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
9110
|
-
const relPosix = rel.split(
|
|
9149
|
+
const relPosix = rel.split(import_node_path45.default.sep).join("/");
|
|
9111
9150
|
if (/^instrumentation(?:\.node)?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
9112
9151
|
if (relPosix === base) return true;
|
|
9113
9152
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -9124,10 +9163,10 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
9124
9163
|
return false;
|
|
9125
9164
|
}
|
|
9126
9165
|
async function writeAtomic(file, contents) {
|
|
9127
|
-
await
|
|
9166
|
+
await import_node_fs29.promises.mkdir(import_node_path45.default.dirname(file), { recursive: true });
|
|
9128
9167
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
9129
|
-
await
|
|
9130
|
-
await
|
|
9168
|
+
await import_node_fs29.promises.writeFile(tmp, contents, "utf8");
|
|
9169
|
+
await import_node_fs29.promises.rename(tmp, file);
|
|
9131
9170
|
}
|
|
9132
9171
|
async function apply(installPlan) {
|
|
9133
9172
|
const { serviceDir } = installPlan;
|
|
@@ -9203,7 +9242,7 @@ async function apply(installPlan) {
|
|
|
9203
9242
|
for (const target of allTargets) {
|
|
9204
9243
|
if (await exists3(target)) {
|
|
9205
9244
|
try {
|
|
9206
|
-
originals.set(target, await
|
|
9245
|
+
originals.set(target, await import_node_fs29.promises.readFile(target, "utf8"));
|
|
9207
9246
|
} catch {
|
|
9208
9247
|
}
|
|
9209
9248
|
}
|
|
@@ -9286,14 +9325,14 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
9286
9325
|
const removed = [];
|
|
9287
9326
|
for (const [file, raw] of originals.entries()) {
|
|
9288
9327
|
try {
|
|
9289
|
-
await
|
|
9328
|
+
await import_node_fs29.promises.writeFile(file, raw, "utf8");
|
|
9290
9329
|
restored.push(file);
|
|
9291
9330
|
} catch {
|
|
9292
9331
|
}
|
|
9293
9332
|
}
|
|
9294
9333
|
for (const file of createdFiles) {
|
|
9295
9334
|
try {
|
|
9296
|
-
await
|
|
9335
|
+
await import_node_fs29.promises.unlink(file);
|
|
9297
9336
|
removed.push(file);
|
|
9298
9337
|
} catch {
|
|
9299
9338
|
}
|
|
@@ -9308,8 +9347,8 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
9308
9347
|
...removed.map((f) => `removed: ${f}`),
|
|
9309
9348
|
""
|
|
9310
9349
|
];
|
|
9311
|
-
const rollbackPath =
|
|
9312
|
-
await
|
|
9350
|
+
const rollbackPath = import_node_path45.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
9351
|
+
await import_node_fs29.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
9313
9352
|
}
|
|
9314
9353
|
function injectInstrumentationHook(raw) {
|
|
9315
9354
|
if (raw.includes("instrumentationHook")) return raw;
|
|
@@ -9338,8 +9377,8 @@ var javascriptInstaller = {
|
|
|
9338
9377
|
|
|
9339
9378
|
// src/installers/python.ts
|
|
9340
9379
|
init_cjs_shims();
|
|
9341
|
-
var
|
|
9342
|
-
var
|
|
9380
|
+
var import_node_fs30 = require("fs");
|
|
9381
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
9343
9382
|
var SDK_PACKAGES2 = [
|
|
9344
9383
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
9345
9384
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -9351,7 +9390,7 @@ var OTEL_ENV2 = {
|
|
|
9351
9390
|
};
|
|
9352
9391
|
async function exists4(p) {
|
|
9353
9392
|
try {
|
|
9354
|
-
await
|
|
9393
|
+
await import_node_fs30.promises.stat(p);
|
|
9355
9394
|
return true;
|
|
9356
9395
|
} catch {
|
|
9357
9396
|
return false;
|
|
@@ -9360,7 +9399,7 @@ async function exists4(p) {
|
|
|
9360
9399
|
async function detect2(serviceDir) {
|
|
9361
9400
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
9362
9401
|
for (const m of markers) {
|
|
9363
|
-
if (await exists4(
|
|
9402
|
+
if (await exists4(import_node_path46.default.join(serviceDir, m))) return true;
|
|
9364
9403
|
}
|
|
9365
9404
|
return false;
|
|
9366
9405
|
}
|
|
@@ -9370,9 +9409,9 @@ function reqPackageName(line) {
|
|
|
9370
9409
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
9371
9410
|
}
|
|
9372
9411
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
9373
|
-
const file =
|
|
9412
|
+
const file = import_node_path46.default.join(serviceDir, "requirements.txt");
|
|
9374
9413
|
if (!await exists4(file)) return null;
|
|
9375
|
-
const raw = await
|
|
9414
|
+
const raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
9376
9415
|
const presentNames = new Set(
|
|
9377
9416
|
raw.split(/\r?\n/).map(reqPackageName).filter((n) => n.length > 0)
|
|
9378
9417
|
);
|
|
@@ -9380,9 +9419,9 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
9380
9419
|
return { manifest: file, missing: [...missing] };
|
|
9381
9420
|
}
|
|
9382
9421
|
async function planProcfileEdits(serviceDir) {
|
|
9383
|
-
const procfile =
|
|
9422
|
+
const procfile = import_node_path46.default.join(serviceDir, "Procfile");
|
|
9384
9423
|
if (!await exists4(procfile)) return [];
|
|
9385
|
-
const raw = await
|
|
9424
|
+
const raw = await import_node_fs30.promises.readFile(procfile, "utf8");
|
|
9386
9425
|
const edits = [];
|
|
9387
9426
|
for (const line of raw.split(/\r?\n/)) {
|
|
9388
9427
|
if (line.length === 0) continue;
|
|
@@ -9434,8 +9473,8 @@ async function applyRequirementsTxt(manifest, edits, original) {
|
|
|
9434
9473
|
const next = `${original}${trailing}${newlines.join("\n")}
|
|
9435
9474
|
`;
|
|
9436
9475
|
const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`;
|
|
9437
|
-
await
|
|
9438
|
-
await
|
|
9476
|
+
await import_node_fs30.promises.writeFile(tmp, next, "utf8");
|
|
9477
|
+
await import_node_fs30.promises.rename(tmp, manifest);
|
|
9439
9478
|
}
|
|
9440
9479
|
async function applyProcfile(procfile, edits, original) {
|
|
9441
9480
|
let next = original;
|
|
@@ -9444,8 +9483,8 @@ async function applyProcfile(procfile, edits, original) {
|
|
|
9444
9483
|
next = next.replace(e.before, e.after);
|
|
9445
9484
|
}
|
|
9446
9485
|
const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`;
|
|
9447
|
-
await
|
|
9448
|
-
await
|
|
9486
|
+
await import_node_fs30.promises.writeFile(tmp, next, "utf8");
|
|
9487
|
+
await import_node_fs30.promises.rename(tmp, procfile);
|
|
9449
9488
|
}
|
|
9450
9489
|
async function apply2(installPlan) {
|
|
9451
9490
|
const { serviceDir } = installPlan;
|
|
@@ -9458,7 +9497,7 @@ async function apply2(installPlan) {
|
|
|
9458
9497
|
const originals = /* @__PURE__ */ new Map();
|
|
9459
9498
|
for (const file of touched) {
|
|
9460
9499
|
try {
|
|
9461
|
-
originals.set(file, await
|
|
9500
|
+
originals.set(file, await import_node_fs30.promises.readFile(file, "utf8"));
|
|
9462
9501
|
} catch {
|
|
9463
9502
|
}
|
|
9464
9503
|
}
|
|
@@ -9469,7 +9508,7 @@ async function apply2(installPlan) {
|
|
|
9469
9508
|
if (raw === void 0) {
|
|
9470
9509
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
9471
9510
|
}
|
|
9472
|
-
const base =
|
|
9511
|
+
const base = import_node_path46.default.basename(file);
|
|
9473
9512
|
if (base === "requirements.txt") {
|
|
9474
9513
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
9475
9514
|
if (edits.length > 0) {
|
|
@@ -9494,7 +9533,7 @@ async function rollback2(installPlan, originals) {
|
|
|
9494
9533
|
const restored = [];
|
|
9495
9534
|
for (const [file, raw] of originals.entries()) {
|
|
9496
9535
|
try {
|
|
9497
|
-
await
|
|
9536
|
+
await import_node_fs30.promises.writeFile(file, raw, "utf8");
|
|
9498
9537
|
restored.push(file);
|
|
9499
9538
|
} catch {
|
|
9500
9539
|
}
|
|
@@ -9508,8 +9547,8 @@ async function rollback2(installPlan, originals) {
|
|
|
9508
9547
|
...restored.map((f) => `restored: ${f}`),
|
|
9509
9548
|
""
|
|
9510
9549
|
];
|
|
9511
|
-
const rollbackPath =
|
|
9512
|
-
await
|
|
9550
|
+
const rollbackPath = import_node_path46.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
9551
|
+
await import_node_fs30.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
9513
9552
|
}
|
|
9514
9553
|
var pythonInstaller = {
|
|
9515
9554
|
name: "python",
|
|
@@ -9632,10 +9671,10 @@ function renderPatch(sections) {
|
|
|
9632
9671
|
|
|
9633
9672
|
// src/orchestrator.ts
|
|
9634
9673
|
init_cjs_shims();
|
|
9635
|
-
var
|
|
9674
|
+
var import_node_fs31 = require("fs");
|
|
9636
9675
|
var import_node_http = __toESM(require("http"), 1);
|
|
9637
9676
|
var import_node_net = __toESM(require("net"), 1);
|
|
9638
|
-
var
|
|
9677
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9639
9678
|
var import_node_child_process3 = require("child_process");
|
|
9640
9679
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
9641
9680
|
async function extractAndPersist(opts) {
|
|
@@ -9644,7 +9683,7 @@ async function extractAndPersist(opts) {
|
|
|
9644
9683
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
9645
9684
|
resetGraph(graphKey);
|
|
9646
9685
|
const graph = getGraph(graphKey);
|
|
9647
|
-
const projectPaths = pathsForProject(graphKey,
|
|
9686
|
+
const projectPaths = pathsForProject(graphKey, import_node_path47.default.join(opts.scanPath, "neat-out"));
|
|
9648
9687
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
9649
9688
|
errorsPath: projectPaths.errorsPath
|
|
9650
9689
|
});
|
|
@@ -9698,7 +9737,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9698
9737
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
9699
9738
|
} else if (outcome.outcome === "react-native") {
|
|
9700
9739
|
reactNative++;
|
|
9701
|
-
const svcName =
|
|
9740
|
+
const svcName = import_node_path47.default.basename(svc.dir);
|
|
9702
9741
|
console.log(
|
|
9703
9742
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
9704
9743
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9709,7 +9748,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9709
9748
|
);
|
|
9710
9749
|
} else if (outcome.outcome === "bun") {
|
|
9711
9750
|
bun++;
|
|
9712
|
-
const svcName =
|
|
9751
|
+
const svcName = import_node_path47.default.basename(svc.dir);
|
|
9713
9752
|
console.log(
|
|
9714
9753
|
`neat: ${svc.dir} detected as Bun
|
|
9715
9754
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9720,7 +9759,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9720
9759
|
);
|
|
9721
9760
|
} else if (outcome.outcome === "deno") {
|
|
9722
9761
|
deno++;
|
|
9723
|
-
const svcName =
|
|
9762
|
+
const svcName = import_node_path47.default.basename(svc.dir);
|
|
9724
9763
|
console.log(
|
|
9725
9764
|
`neat: ${svc.dir} detected as Deno
|
|
9726
9765
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9731,7 +9770,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9731
9770
|
);
|
|
9732
9771
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
9733
9772
|
cloudflareWorkers++;
|
|
9734
|
-
const svcName =
|
|
9773
|
+
const svcName = import_node_path47.default.basename(svc.dir);
|
|
9735
9774
|
console.log(
|
|
9736
9775
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
9737
9776
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9742,7 +9781,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
9742
9781
|
);
|
|
9743
9782
|
} else if (outcome.outcome === "electron") {
|
|
9744
9783
|
electron++;
|
|
9745
|
-
const svcName =
|
|
9784
|
+
const svcName = import_node_path47.default.basename(svc.dir);
|
|
9746
9785
|
console.log(
|
|
9747
9786
|
`neat: ${svc.dir} detected as Electron
|
|
9748
9787
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -9916,10 +9955,10 @@ function formatPortCollisionMessage(port) {
|
|
|
9916
9955
|
];
|
|
9917
9956
|
}
|
|
9918
9957
|
function spawnDaemonDetached() {
|
|
9919
|
-
const here =
|
|
9958
|
+
const here = import_node_path47.default.dirname(new URL(importMetaUrl).pathname);
|
|
9920
9959
|
const candidates = [
|
|
9921
|
-
|
|
9922
|
-
|
|
9960
|
+
import_node_path47.default.join(here, "neatd.cjs"),
|
|
9961
|
+
import_node_path47.default.join(here, "neatd.js")
|
|
9923
9962
|
];
|
|
9924
9963
|
let entry2 = null;
|
|
9925
9964
|
const fsSync = require("fs");
|
|
@@ -9977,12 +10016,13 @@ async function runOrchestrator(opts) {
|
|
|
9977
10016
|
browser: "skipped"
|
|
9978
10017
|
}
|
|
9979
10018
|
};
|
|
9980
|
-
const stat = await
|
|
10019
|
+
const stat = await import_node_fs31.promises.stat(opts.scanPath).catch(() => null);
|
|
9981
10020
|
if (!stat || !stat.isDirectory()) {
|
|
9982
10021
|
console.error(`neat: ${opts.scanPath} is not a directory`);
|
|
9983
10022
|
result.exitCode = 2;
|
|
9984
10023
|
return result;
|
|
9985
10024
|
}
|
|
10025
|
+
printBanner();
|
|
9986
10026
|
console.log(`neat: ${opts.scanPath}`);
|
|
9987
10027
|
console.log("");
|
|
9988
10028
|
const persisted = await extractAndPersist({
|
|
@@ -9993,6 +10033,13 @@ async function runOrchestrator(opts) {
|
|
|
9993
10033
|
const { graph, services, languages } = persisted;
|
|
9994
10034
|
result.steps.discovery = { services: services.length, languages };
|
|
9995
10035
|
console.log(`discovered ${services.length} service(s) across ${languages.length} language(s)`);
|
|
10036
|
+
if (services.length === 0) {
|
|
10037
|
+
console.error(
|
|
10038
|
+
`neat: no services found in ${opts.scanPath} \u2014 run from inside your project root, or \`npx neat.is <path>\``
|
|
10039
|
+
);
|
|
10040
|
+
result.exitCode = 2;
|
|
10041
|
+
return result;
|
|
10042
|
+
}
|
|
9996
10043
|
let runApply = !opts.noInstrument;
|
|
9997
10044
|
if (runApply && !opts.yes && process.stdout.isTTY && process.stdin.isTTY) {
|
|
9998
10045
|
runApply = await promptYesNo("instrument your services and open the dashboard?");
|
|
@@ -10116,11 +10163,17 @@ function printSummary(result, graph, dashboardUrl) {
|
|
|
10116
10163
|
for (const [t, c] of [...byEdge.entries()].sort()) console.log(` ${t}: ${c}`);
|
|
10117
10164
|
console.log("");
|
|
10118
10165
|
console.log(`dashboard: ${dashboardUrl}`);
|
|
10166
|
+
const token = process.env.NEAT_AUTH_TOKEN;
|
|
10167
|
+
if (typeof token === "string" && token.length > 0) {
|
|
10168
|
+
console.log(`auth token: ${token}`);
|
|
10169
|
+
} else {
|
|
10170
|
+
console.log("running locally \u2014 open the dashboard, no token needed");
|
|
10171
|
+
}
|
|
10119
10172
|
}
|
|
10120
10173
|
|
|
10121
10174
|
// src/cli-verbs.ts
|
|
10122
10175
|
init_cjs_shims();
|
|
10123
|
-
var
|
|
10176
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
10124
10177
|
|
|
10125
10178
|
// src/cli-client.ts
|
|
10126
10179
|
init_cjs_shims();
|
|
@@ -10149,10 +10202,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
10149
10202
|
const root = baseUrl.replace(/\/$/, "");
|
|
10150
10203
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
10151
10204
|
return {
|
|
10152
|
-
async get(
|
|
10205
|
+
async get(path50) {
|
|
10153
10206
|
let res;
|
|
10154
10207
|
try {
|
|
10155
|
-
res = await fetch(`${root}${
|
|
10208
|
+
res = await fetch(`${root}${path50}`, {
|
|
10156
10209
|
headers: { ...authHeader }
|
|
10157
10210
|
});
|
|
10158
10211
|
} catch (err) {
|
|
@@ -10164,16 +10217,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
10164
10217
|
const body = await res.text().catch(() => "");
|
|
10165
10218
|
throw new HttpError(
|
|
10166
10219
|
res.status,
|
|
10167
|
-
`${res.status} ${res.statusText} on GET ${
|
|
10220
|
+
`${res.status} ${res.statusText} on GET ${path50}: ${body}`,
|
|
10168
10221
|
body
|
|
10169
10222
|
);
|
|
10170
10223
|
}
|
|
10171
10224
|
return await res.json();
|
|
10172
10225
|
},
|
|
10173
|
-
async post(
|
|
10226
|
+
async post(path50, body) {
|
|
10174
10227
|
let res;
|
|
10175
10228
|
try {
|
|
10176
|
-
res = await fetch(`${root}${
|
|
10229
|
+
res = await fetch(`${root}${path50}`, {
|
|
10177
10230
|
method: "POST",
|
|
10178
10231
|
headers: { "content-type": "application/json", ...authHeader },
|
|
10179
10232
|
body: JSON.stringify(body)
|
|
@@ -10187,7 +10240,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
10187
10240
|
const text = await res.text().catch(() => "");
|
|
10188
10241
|
throw new HttpError(
|
|
10189
10242
|
res.status,
|
|
10190
|
-
`${res.status} ${res.statusText} on POST ${
|
|
10243
|
+
`${res.status} ${res.statusText} on POST ${path50}: ${text}`,
|
|
10191
10244
|
text
|
|
10192
10245
|
);
|
|
10193
10246
|
}
|
|
@@ -10201,12 +10254,12 @@ function projectPath(project, suffix) {
|
|
|
10201
10254
|
}
|
|
10202
10255
|
async function runRootCause(client, input) {
|
|
10203
10256
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
10204
|
-
const
|
|
10257
|
+
const path50 = projectPath(
|
|
10205
10258
|
input.project,
|
|
10206
10259
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
10207
10260
|
);
|
|
10208
10261
|
try {
|
|
10209
|
-
const result = await client.get(
|
|
10262
|
+
const result = await client.get(path50);
|
|
10210
10263
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
10211
10264
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
10212
10265
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -10232,12 +10285,12 @@ async function runRootCause(client, input) {
|
|
|
10232
10285
|
}
|
|
10233
10286
|
async function runBlastRadius(client, input) {
|
|
10234
10287
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
10235
|
-
const
|
|
10288
|
+
const path50 = projectPath(
|
|
10236
10289
|
input.project,
|
|
10237
10290
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
10238
10291
|
);
|
|
10239
10292
|
try {
|
|
10240
|
-
const result = await client.get(
|
|
10293
|
+
const result = await client.get(path50);
|
|
10241
10294
|
if (result.totalAffected === 0) {
|
|
10242
10295
|
return {
|
|
10243
10296
|
summary: `${result.origin} has no downstream dependencies. Nothing else would break if it failed.`
|
|
@@ -10271,12 +10324,12 @@ function formatBlastEntry(n) {
|
|
|
10271
10324
|
}
|
|
10272
10325
|
async function runDependencies(client, input) {
|
|
10273
10326
|
const depth = input.depth ?? 3;
|
|
10274
|
-
const
|
|
10327
|
+
const path50 = projectPath(
|
|
10275
10328
|
input.project,
|
|
10276
10329
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
10277
10330
|
);
|
|
10278
10331
|
try {
|
|
10279
|
-
const result = await client.get(
|
|
10332
|
+
const result = await client.get(path50);
|
|
10280
10333
|
if (result.total === 0) {
|
|
10281
10334
|
return {
|
|
10282
10335
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -10357,9 +10410,9 @@ function formatDuration(ms) {
|
|
|
10357
10410
|
return `${Math.round(h / 24)}d`;
|
|
10358
10411
|
}
|
|
10359
10412
|
async function runIncidents(client, input) {
|
|
10360
|
-
const
|
|
10413
|
+
const path50 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
10361
10414
|
try {
|
|
10362
|
-
const body = await client.get(
|
|
10415
|
+
const body = await client.get(path50);
|
|
10363
10416
|
const events = body.events;
|
|
10364
10417
|
if (events.length === 0) {
|
|
10365
10418
|
return {
|
|
@@ -10649,7 +10702,7 @@ async function resolveProjectEntry(opts) {
|
|
|
10649
10702
|
const cwd = opts.cwd ?? process.cwd();
|
|
10650
10703
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
10651
10704
|
for (const entry2 of entries) {
|
|
10652
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
10705
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path48.default.sep}`)) {
|
|
10653
10706
|
return entry2;
|
|
10654
10707
|
}
|
|
10655
10708
|
}
|
|
@@ -10800,8 +10853,24 @@ async function runSync(opts) {
|
|
|
10800
10853
|
|
|
10801
10854
|
// src/cli.ts
|
|
10802
10855
|
var import_types27 = require("@neat.is/types");
|
|
10856
|
+
function isNpxInvocation() {
|
|
10857
|
+
if (process.env.npm_command === "exec") return true;
|
|
10858
|
+
const execpath = process.env.npm_execpath ?? "";
|
|
10859
|
+
if (execpath.includes("npx")) return true;
|
|
10860
|
+
const entry2 = process.argv[1] ?? "";
|
|
10861
|
+
if (entry2.includes("/_npx/") || entry2.includes("\\_npx\\")) return true;
|
|
10862
|
+
return false;
|
|
10863
|
+
}
|
|
10864
|
+
function commandPrefix() {
|
|
10865
|
+
return isNpxInvocation() ? "npx neat.is" : "neat";
|
|
10866
|
+
}
|
|
10803
10867
|
function usage() {
|
|
10804
|
-
|
|
10868
|
+
const neat = commandPrefix();
|
|
10869
|
+
console.log("Installed via npx? Prefix commands with `npx neat.is`, or install once: `npm i -g neat.is`.");
|
|
10870
|
+
console.log("");
|
|
10871
|
+
console.log(`usage: ${neat} <command> [args] [--project <name>]`);
|
|
10872
|
+
console.log("");
|
|
10873
|
+
console.log(`Run \`${neat}\` with no command from inside your project to go zero-to-graph in one step.`);
|
|
10805
10874
|
console.log("");
|
|
10806
10875
|
console.log("lifecycle commands:");
|
|
10807
10876
|
console.log(" init <path> One-time install: discover, extract, register, plan SDK install.");
|
|
@@ -10841,30 +10910,30 @@ function usage() {
|
|
|
10841
10910
|
console.log("");
|
|
10842
10911
|
console.log("query commands (mirror the MCP tools, ADR-050):");
|
|
10843
10912
|
console.log(" root-cause <node-id> Walk inbound edges to find what broke first.");
|
|
10844
|
-
console.log(
|
|
10913
|
+
console.log(` example: ${neat} root-cause service:<name>`);
|
|
10845
10914
|
console.log(" blast-radius <node-id> BFS outbound \u2014 what would break if this dies.");
|
|
10846
|
-
console.log(
|
|
10915
|
+
console.log(` example: ${neat} blast-radius database:<host>`);
|
|
10847
10916
|
console.log(" dependencies <node-id> Transitive outbound dependencies.");
|
|
10848
10917
|
console.log(" Flags: --depth N (default 3, max 10)");
|
|
10849
|
-
console.log(
|
|
10918
|
+
console.log(` example: ${neat} dependencies service:<name> --depth 2`);
|
|
10850
10919
|
console.log(" observed-dependencies <node-id> OBSERVED-only outbound edges (runtime traffic).");
|
|
10851
|
-
console.log(
|
|
10920
|
+
console.log(` example: ${neat} observed-dependencies service:<name>`);
|
|
10852
10921
|
console.log(" incidents [<node-id>] Recent error events; per-node when an id is given.");
|
|
10853
10922
|
console.log(" Flags: --limit N (default 20)");
|
|
10854
|
-
console.log(
|
|
10923
|
+
console.log(` example: ${neat} incidents service:<name> --limit 5`);
|
|
10855
10924
|
console.log(" search <query> Semantic (or substring) match on node names/ids.");
|
|
10856
|
-
console.log(
|
|
10925
|
+
console.log(` example: ${neat} search "checkout"`);
|
|
10857
10926
|
console.log(" diff --against <snapshot> Compare the live graph to a saved snapshot.");
|
|
10858
|
-
console.log(
|
|
10927
|
+
console.log(` example: ${neat} diff --against ./snapshots/baseline.json`);
|
|
10859
10928
|
console.log(" stale-edges Recent OBSERVED \u2192 STALE transitions.");
|
|
10860
10929
|
console.log(" Flags: --limit N, --edge-type CALLS|CONNECTS_TO|...");
|
|
10861
|
-
console.log(
|
|
10930
|
+
console.log(` example: ${neat} stale-edges --edge-type CALLS`);
|
|
10862
10931
|
console.log(" policies Current policy violations.");
|
|
10863
10932
|
console.log(" Flags: --node <id>, --hypothetical-action <json>");
|
|
10864
|
-
console.log(
|
|
10933
|
+
console.log(` example: ${neat} policies --node service:<name> --json`);
|
|
10865
10934
|
console.log(" divergences Where code (EXTRACTED) and production (OBSERVED) disagree.");
|
|
10866
10935
|
console.log(" Flags: --type <list>, --min-confidence <0..1>, --node <id>");
|
|
10867
|
-
console.log(
|
|
10936
|
+
console.log(` example: ${neat} divergences --min-confidence 0.7`);
|
|
10868
10937
|
console.log("");
|
|
10869
10938
|
console.log("flags:");
|
|
10870
10939
|
console.log(' --project <name> Name the project this command targets. Default: "default".');
|
|
@@ -11008,40 +11077,10 @@ function assignFlag(out, field, value) {
|
|
|
11008
11077
|
;
|
|
11009
11078
|
out[field] = value;
|
|
11010
11079
|
}
|
|
11011
|
-
function readPackageVersion() {
|
|
11012
|
-
const here = typeof __dirname !== "undefined" ? __dirname : import_node_path48.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
11013
|
-
const candidates = [
|
|
11014
|
-
import_node_path48.default.resolve(here, "../package.json"),
|
|
11015
|
-
import_node_path48.default.resolve(here, "../../package.json")
|
|
11016
|
-
];
|
|
11017
|
-
for (const candidate of candidates) {
|
|
11018
|
-
try {
|
|
11019
|
-
const raw = (0, import_node_fs31.readFileSync)(candidate, "utf8");
|
|
11020
|
-
const parsed = JSON.parse(raw);
|
|
11021
|
-
if (parsed.name === "@neat.is/core" && typeof parsed.version === "string") {
|
|
11022
|
-
return parsed.version;
|
|
11023
|
-
}
|
|
11024
|
-
} catch {
|
|
11025
|
-
}
|
|
11026
|
-
}
|
|
11027
|
-
return "unknown";
|
|
11028
|
-
}
|
|
11029
11080
|
function printVersion() {
|
|
11030
11081
|
process.stdout.write(`${readPackageVersion()}
|
|
11031
11082
|
`);
|
|
11032
11083
|
}
|
|
11033
|
-
function printBanner() {
|
|
11034
|
-
console.log("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557");
|
|
11035
|
-
console.log("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D");
|
|
11036
|
-
console.log("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
11037
|
-
console.log("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
11038
|
-
console.log("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 ");
|
|
11039
|
-
console.log("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D ");
|
|
11040
|
-
console.log("");
|
|
11041
|
-
console.log(" Network Expressive Architecting Tool");
|
|
11042
|
-
console.log(` neat.is \xB7 v${readPackageVersion()} \xB7 Apache 2.0`);
|
|
11043
|
-
console.log("");
|
|
11044
|
-
}
|
|
11045
11084
|
function printDiscoveryReport(opts, services) {
|
|
11046
11085
|
const languages = [...new Set(services.map((s) => s.node.language))].sort();
|
|
11047
11086
|
const mode = opts.dryRun ? "dry-run" : opts.apply ? "apply" : "patch-only";
|
|
@@ -11080,7 +11119,7 @@ async function buildPatchSections(services, project) {
|
|
|
11080
11119
|
}
|
|
11081
11120
|
async function runInit(opts) {
|
|
11082
11121
|
const written = [];
|
|
11083
|
-
const stat = await
|
|
11122
|
+
const stat = await import_node_fs32.promises.stat(opts.scanPath).catch(() => null);
|
|
11084
11123
|
if (!stat || !stat.isDirectory()) {
|
|
11085
11124
|
console.error(`neat init: ${opts.scanPath} is not a directory`);
|
|
11086
11125
|
return { exitCode: 2, writtenFiles: written };
|
|
@@ -11089,13 +11128,13 @@ async function runInit(opts) {
|
|
|
11089
11128
|
printDiscoveryReport(opts, services);
|
|
11090
11129
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
11091
11130
|
const patch = renderPatch(sections);
|
|
11092
|
-
const patchPath =
|
|
11131
|
+
const patchPath = import_node_path49.default.join(opts.scanPath, "neat.patch");
|
|
11093
11132
|
if (opts.dryRun) {
|
|
11094
|
-
await
|
|
11133
|
+
await import_node_fs32.promises.writeFile(patchPath, patch, "utf8");
|
|
11095
11134
|
written.push(patchPath);
|
|
11096
11135
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
11097
|
-
const gitignorePath =
|
|
11098
|
-
const gitignoreExists = await
|
|
11136
|
+
const gitignorePath = import_node_path49.default.join(opts.scanPath, ".gitignore");
|
|
11137
|
+
const gitignoreExists = await import_node_fs32.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
11099
11138
|
const verb = gitignoreExists ? "append" : "create";
|
|
11100
11139
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
11101
11140
|
console.log("rerun without --dry-run to register and snapshot.");
|
|
@@ -11106,9 +11145,9 @@ async function runInit(opts) {
|
|
|
11106
11145
|
const graph = getGraph(graphKey);
|
|
11107
11146
|
const projectPaths = pathsForProject(
|
|
11108
11147
|
graphKey,
|
|
11109
|
-
|
|
11148
|
+
import_node_path49.default.join(opts.scanPath, "neat-out")
|
|
11110
11149
|
);
|
|
11111
|
-
const errorsPath =
|
|
11150
|
+
const errorsPath = import_node_path49.default.join(import_node_path49.default.dirname(opts.outPath), import_node_path49.default.basename(projectPaths.errorsPath));
|
|
11112
11151
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
11113
11152
|
await saveGraphToDisk(graph, opts.outPath);
|
|
11114
11153
|
written.push(opts.outPath);
|
|
@@ -11187,7 +11226,7 @@ async function runInit(opts) {
|
|
|
11187
11226
|
console.log("Run `npm install` (or your language equivalent) to refresh lockfiles.");
|
|
11188
11227
|
}
|
|
11189
11228
|
} else {
|
|
11190
|
-
await
|
|
11229
|
+
await import_node_fs32.promises.writeFile(patchPath, patch, "utf8");
|
|
11191
11230
|
written.push(patchPath);
|
|
11192
11231
|
}
|
|
11193
11232
|
}
|
|
@@ -11227,9 +11266,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
11227
11266
|
};
|
|
11228
11267
|
function claudeConfigPath() {
|
|
11229
11268
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
11230
|
-
if (override && override.length > 0) return
|
|
11269
|
+
if (override && override.length > 0) return import_node_path49.default.resolve(override);
|
|
11231
11270
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
11232
|
-
return
|
|
11271
|
+
return import_node_path49.default.join(home, ".claude.json");
|
|
11233
11272
|
}
|
|
11234
11273
|
async function runSkill(opts) {
|
|
11235
11274
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -11241,7 +11280,7 @@ async function runSkill(opts) {
|
|
|
11241
11280
|
const target = claudeConfigPath();
|
|
11242
11281
|
let existing = {};
|
|
11243
11282
|
try {
|
|
11244
|
-
existing = JSON.parse(await
|
|
11283
|
+
existing = JSON.parse(await import_node_fs32.promises.readFile(target, "utf8"));
|
|
11245
11284
|
} catch (err) {
|
|
11246
11285
|
if (err.code !== "ENOENT") {
|
|
11247
11286
|
console.error(`neat skill: failed to read ${target} \u2014 ${err.message}`);
|
|
@@ -11253,8 +11292,8 @@ async function runSkill(opts) {
|
|
|
11253
11292
|
...existing,
|
|
11254
11293
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
11255
11294
|
};
|
|
11256
|
-
await
|
|
11257
|
-
await
|
|
11295
|
+
await import_node_fs32.promises.mkdir(import_node_path49.default.dirname(target), { recursive: true });
|
|
11296
|
+
await import_node_fs32.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
11258
11297
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
11259
11298
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
11260
11299
|
return { exitCode: 0 };
|
|
@@ -11269,16 +11308,24 @@ async function runSkill(opts) {
|
|
|
11269
11308
|
return { exitCode: 0 };
|
|
11270
11309
|
}
|
|
11271
11310
|
async function main() {
|
|
11272
|
-
const
|
|
11273
|
-
|
|
11311
|
+
const argv = process.argv.slice(2);
|
|
11312
|
+
const cmd0 = argv[0];
|
|
11313
|
+
if (cmd0 === "-h" || cmd0 === "--help") {
|
|
11274
11314
|
usage();
|
|
11275
11315
|
process.exit(0);
|
|
11276
11316
|
}
|
|
11277
|
-
if (
|
|
11317
|
+
if (cmd0 === "--version" || cmd0 === "-v" || cmd0 === "version") {
|
|
11278
11318
|
printVersion();
|
|
11279
11319
|
process.exit(0);
|
|
11280
11320
|
}
|
|
11281
|
-
const
|
|
11321
|
+
const argvParsed = parseArgs(argv);
|
|
11322
|
+
if (argvParsed.positional.length === 0) {
|
|
11323
|
+
const orchestratorCode2 = await tryOrchestrator(process.cwd(), argvParsed);
|
|
11324
|
+
if (orchestratorCode2 !== null && orchestratorCode2 !== 0) process.exit(orchestratorCode2);
|
|
11325
|
+
return;
|
|
11326
|
+
}
|
|
11327
|
+
const cmd = argvParsed.positional[0];
|
|
11328
|
+
const parsed = { ...argvParsed, positional: argvParsed.positional.slice(1) };
|
|
11282
11329
|
const { positional, apply: apply3, dryRun, noInstall } = parsed;
|
|
11283
11330
|
const project = parsed.project ?? DEFAULT_PROJECT;
|
|
11284
11331
|
if (cmd === "init") {
|
|
@@ -11292,12 +11339,12 @@ async function main() {
|
|
|
11292
11339
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
11293
11340
|
process.exit(2);
|
|
11294
11341
|
}
|
|
11295
|
-
const scanPath =
|
|
11342
|
+
const scanPath = import_node_path49.default.resolve(target);
|
|
11296
11343
|
const projectExplicit = parsed.project !== null;
|
|
11297
|
-
const projectName = projectExplicit ? project :
|
|
11344
|
+
const projectName = projectExplicit ? project : import_node_path49.default.basename(scanPath);
|
|
11298
11345
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
11299
|
-
const fallback = pathsForProject(projectKey,
|
|
11300
|
-
const outPath =
|
|
11346
|
+
const fallback = pathsForProject(projectKey, import_node_path49.default.join(scanPath, "neat-out")).snapshotPath;
|
|
11347
|
+
const outPath = import_node_path49.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
11301
11348
|
const result = await runInit({
|
|
11302
11349
|
scanPath,
|
|
11303
11350
|
outPath,
|
|
@@ -11318,21 +11365,21 @@ async function main() {
|
|
|
11318
11365
|
usage();
|
|
11319
11366
|
process.exit(2);
|
|
11320
11367
|
}
|
|
11321
|
-
const scanPath =
|
|
11322
|
-
const stat = await
|
|
11368
|
+
const scanPath = import_node_path49.default.resolve(target);
|
|
11369
|
+
const stat = await import_node_fs32.promises.stat(scanPath).catch(() => null);
|
|
11323
11370
|
if (!stat || !stat.isDirectory()) {
|
|
11324
11371
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
11325
11372
|
process.exit(2);
|
|
11326
11373
|
}
|
|
11327
|
-
const projectPaths = pathsForProject(project,
|
|
11328
|
-
const outPath =
|
|
11329
|
-
const errorsPath =
|
|
11330
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
11374
|
+
const projectPaths = pathsForProject(project, import_node_path49.default.join(scanPath, "neat-out"));
|
|
11375
|
+
const outPath = import_node_path49.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
11376
|
+
const errorsPath = import_node_path49.default.resolve(
|
|
11377
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path49.default.join(import_node_path49.default.dirname(outPath), import_node_path49.default.basename(projectPaths.errorsPath))
|
|
11331
11378
|
);
|
|
11332
|
-
const staleEventsPath =
|
|
11333
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
11379
|
+
const staleEventsPath = import_node_path49.default.resolve(
|
|
11380
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path49.default.join(import_node_path49.default.dirname(outPath), import_node_path49.default.basename(projectPaths.staleEventsPath))
|
|
11334
11381
|
);
|
|
11335
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
11382
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path49.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
11336
11383
|
const handle = await startWatch(getGraph(project), {
|
|
11337
11384
|
scanPath,
|
|
11338
11385
|
outPath,
|
|
@@ -11478,11 +11525,11 @@ async function main() {
|
|
|
11478
11525
|
process.exit(1);
|
|
11479
11526
|
}
|
|
11480
11527
|
async function tryOrchestrator(cmd, parsed) {
|
|
11481
|
-
const scanPath =
|
|
11482
|
-
const stat = await
|
|
11528
|
+
const scanPath = import_node_path49.default.resolve(cmd);
|
|
11529
|
+
const stat = await import_node_fs32.promises.stat(scanPath).catch(() => null);
|
|
11483
11530
|
if (!stat || !stat.isDirectory()) return null;
|
|
11484
11531
|
const projectExplicit = parsed.project !== null;
|
|
11485
|
-
const projectName = projectExplicit ? parsed.project :
|
|
11532
|
+
const projectName = projectExplicit ? parsed.project : import_node_path49.default.basename(scanPath);
|
|
11486
11533
|
const result = await runOrchestrator({
|
|
11487
11534
|
scanPath,
|
|
11488
11535
|
project: projectName,
|
|
@@ -11683,11 +11730,15 @@ if (/[\\/]cli\.(?:cjs|js)$/.test(entry) || entry.endsWith("/cli") || entry.endsW
|
|
|
11683
11730
|
0 && (module.exports = {
|
|
11684
11731
|
CLAUDE_SKILL_CONFIG,
|
|
11685
11732
|
QUERY_VERBS,
|
|
11733
|
+
commandPrefix,
|
|
11734
|
+
isNpxInvocation,
|
|
11735
|
+
main,
|
|
11686
11736
|
parseArgs,
|
|
11687
11737
|
printBanner,
|
|
11688
11738
|
readPackageVersion,
|
|
11689
11739
|
runInit,
|
|
11690
11740
|
runQueryVerb,
|
|
11691
|
-
runSkill
|
|
11741
|
+
runSkill,
|
|
11742
|
+
usage
|
|
11692
11743
|
});
|
|
11693
11744
|
//# sourceMappingURL=cli.cjs.map
|