@neat.is/core 0.10.1-dev.20260927 → 0.10.1-dev.20260928
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-J3VVEB45.js → chunk-CNOJ4T6I.js} +135 -7
- package/dist/chunk-CNOJ4T6I.js.map +1 -0
- package/dist/{chunk-EJPNEEJA.js → chunk-HVBD4ULO.js} +94 -48
- package/dist/chunk-HVBD4ULO.js.map +1 -0
- package/dist/cli.cjs +465 -202
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +265 -129
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +226 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +226 -52
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +134 -6
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-EJPNEEJA.js.map +0 -1
- package/dist/chunk-J3VVEB45.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path99 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path99) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path99)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
415
415
|
const v = attrs[key];
|
|
416
416
|
if (typeof v === "string" && v.length > 0) {
|
|
417
417
|
const q = v.indexOf("?");
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
418
|
+
const path99 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path99.length > 0) return path99;
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
return void 0;
|
|
@@ -805,9 +805,9 @@ __export(cli_exports, {
|
|
|
805
805
|
});
|
|
806
806
|
module.exports = __toCommonJS(cli_exports);
|
|
807
807
|
init_cjs_shims();
|
|
808
|
-
var
|
|
808
|
+
var import_node_path99 = __toESM(require("path"), 1);
|
|
809
809
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
810
|
-
var
|
|
810
|
+
var import_node_fs60 = require("fs");
|
|
811
811
|
|
|
812
812
|
// src/banner.ts
|
|
813
813
|
init_cjs_shims();
|
|
@@ -1490,19 +1490,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1490
1490
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1491
1491
|
let best = { path: [start], edges: [] };
|
|
1492
1492
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1493
|
-
function step(node,
|
|
1494
|
-
if (
|
|
1495
|
-
best = { path: [...
|
|
1493
|
+
function step(node, path99, edges) {
|
|
1494
|
+
if (path99.length > best.path.length) {
|
|
1495
|
+
best = { path: [...path99], edges: [...edges] };
|
|
1496
1496
|
}
|
|
1497
|
-
if (
|
|
1497
|
+
if (path99.length - 1 >= maxDepth) return;
|
|
1498
1498
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1499
1499
|
for (const [srcId, edge] of incoming) {
|
|
1500
1500
|
if (visited.has(srcId)) continue;
|
|
1501
1501
|
visited.add(srcId);
|
|
1502
|
-
|
|
1502
|
+
path99.push(srcId);
|
|
1503
1503
|
edges.push(edge);
|
|
1504
|
-
step(srcId,
|
|
1505
|
-
|
|
1504
|
+
step(srcId, path99, edges);
|
|
1505
|
+
path99.pop();
|
|
1506
1506
|
edges.pop();
|
|
1507
1507
|
visited.delete(srcId);
|
|
1508
1508
|
}
|
|
@@ -1717,20 +1717,20 @@ function dominantFailingCall(graph, serviceId17, visited) {
|
|
|
1717
1717
|
return best;
|
|
1718
1718
|
}
|
|
1719
1719
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1720
|
-
const
|
|
1720
|
+
const path99 = [originServiceId];
|
|
1721
1721
|
const edges = [];
|
|
1722
1722
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1723
1723
|
let current = originServiceId;
|
|
1724
1724
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1725
1725
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1726
1726
|
if (!hop) break;
|
|
1727
|
-
|
|
1727
|
+
path99.push(hop.nextService);
|
|
1728
1728
|
edges.push(hop.edge);
|
|
1729
1729
|
visited.add(hop.nextService);
|
|
1730
1730
|
current = hop.nextService;
|
|
1731
1731
|
}
|
|
1732
1732
|
if (edges.length === 0) return null;
|
|
1733
|
-
return { path:
|
|
1733
|
+
return { path: path99, edges, culprit: current };
|
|
1734
1734
|
}
|
|
1735
1735
|
function isStaleCallEdge(e) {
|
|
1736
1736
|
return e.type === import_types2.EdgeType.CALLS && e.provenance === import_types2.Provenance.STALE;
|
|
@@ -1766,26 +1766,26 @@ function dominantStaleCall(graph, serviceId17, visited) {
|
|
|
1766
1766
|
return best;
|
|
1767
1767
|
}
|
|
1768
1768
|
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
1769
|
-
const
|
|
1769
|
+
const path99 = [originServiceId];
|
|
1770
1770
|
const edges = [];
|
|
1771
1771
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1772
1772
|
let current = originServiceId;
|
|
1773
1773
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1774
1774
|
const hop = dominantStaleCall(graph, current, visited);
|
|
1775
1775
|
if (!hop) break;
|
|
1776
|
-
|
|
1776
|
+
path99.push(hop.nextService);
|
|
1777
1777
|
edges.push(hop.edge);
|
|
1778
1778
|
visited.add(hop.nextService);
|
|
1779
1779
|
current = hop.nextService;
|
|
1780
1780
|
}
|
|
1781
1781
|
if (edges.length === 0) return null;
|
|
1782
|
-
return { path:
|
|
1782
|
+
return { path: path99, edges, culprit: current };
|
|
1783
1783
|
}
|
|
1784
1784
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1785
1785
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1786
1786
|
if (!chain) return null;
|
|
1787
1787
|
const culprit = chain.culprit;
|
|
1788
|
-
const
|
|
1788
|
+
const path99 = [...chain.path];
|
|
1789
1789
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1790
1790
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1791
1791
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1793,14 +1793,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1793
1793
|
if (loc) {
|
|
1794
1794
|
let rootCauseNode = culprit;
|
|
1795
1795
|
if (loc.fileNode) {
|
|
1796
|
-
|
|
1796
|
+
path99.push(loc.fileNode);
|
|
1797
1797
|
edgeProvenances.push(import_types2.Provenance.OBSERVED);
|
|
1798
1798
|
rootCauseNode = loc.fileNode;
|
|
1799
1799
|
}
|
|
1800
1800
|
return import_types2.RootCauseResultSchema.parse({
|
|
1801
1801
|
rootCauseNode,
|
|
1802
1802
|
rootCauseReason: loc.rootCauseReason,
|
|
1803
|
-
traversalPath:
|
|
1803
|
+
traversalPath: path99,
|
|
1804
1804
|
edgeProvenances,
|
|
1805
1805
|
confidence,
|
|
1806
1806
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1812,7 +1812,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1812
1812
|
return import_types2.RootCauseResultSchema.parse({
|
|
1813
1813
|
rootCauseNode: culprit,
|
|
1814
1814
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1815
|
-
traversalPath:
|
|
1815
|
+
traversalPath: path99,
|
|
1816
1816
|
edgeProvenances,
|
|
1817
1817
|
confidence,
|
|
1818
1818
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2465,10 +2465,10 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
|
2465
2465
|
traversalPath = staleChain.path;
|
|
2466
2466
|
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
2467
2467
|
} else if (top.node !== seedNode) {
|
|
2468
|
-
const
|
|
2469
|
-
if (
|
|
2470
|
-
traversalPath =
|
|
2471
|
-
edgeProvenances =
|
|
2468
|
+
const path99 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
2469
|
+
if (path99) {
|
|
2470
|
+
traversalPath = path99.nodes;
|
|
2471
|
+
edgeProvenances = path99.edges.map((e) => e.provenance);
|
|
2472
2472
|
} else {
|
|
2473
2473
|
traversalPath = [errorNodeId, top.node];
|
|
2474
2474
|
edgeProvenances = [top.provenance ?? import_types2.Provenance.OBSERVED];
|
|
@@ -3919,8 +3919,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
3919
3919
|
chiWalk(tree.rootNode, "", out);
|
|
3920
3920
|
return out;
|
|
3921
3921
|
}
|
|
3922
|
-
function stripChiRegex(
|
|
3923
|
-
return
|
|
3922
|
+
function stripChiRegex(path99) {
|
|
3923
|
+
return path99.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3924
3924
|
}
|
|
3925
3925
|
function chiWalk(node, prefix, out) {
|
|
3926
3926
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -4592,9 +4592,9 @@ function rubyRocketRoute(args) {
|
|
|
4592
4592
|
if (!pair || pair.type !== "pair") continue;
|
|
4593
4593
|
const k = pair.childForFieldName("key");
|
|
4594
4594
|
if (k?.type !== "string") continue;
|
|
4595
|
-
const
|
|
4596
|
-
if (
|
|
4597
|
-
return { path:
|
|
4595
|
+
const path99 = rubyLiteral(k);
|
|
4596
|
+
if (path99 === null) continue;
|
|
4597
|
+
return { path: path99, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
4598
4598
|
}
|
|
4599
4599
|
return null;
|
|
4600
4600
|
}
|
|
@@ -12002,13 +12002,16 @@ function objectKeys(obj) {
|
|
|
12002
12002
|
var MODULAR_WRITES = /* @__PURE__ */ new Set(["addDoc", "setDoc", "updateDoc"]);
|
|
12003
12003
|
var NAMESPACED_WRITES = /* @__PURE__ */ new Set(["add", "set", "update"]);
|
|
12004
12004
|
var READ_CLAUSES = /* @__PURE__ */ new Set(["where", "orderBy"]);
|
|
12005
|
-
function firestoreEndpointsFromFile(file, serviceDir) {
|
|
12005
|
+
function firestoreEndpointsFromFile(file, serviceDir, imported) {
|
|
12006
12006
|
const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(file.content);
|
|
12007
12007
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
12008
|
-
|
|
12009
|
-
|
|
12008
|
+
const importedNames = imported?.names ?? /* @__PURE__ */ new Set();
|
|
12009
|
+
if (!hasClient && !hasAdmin && importedNames.size === 0) return [];
|
|
12010
|
+
const ownSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
12011
|
+
const fileSdk = !hasClient && !hasAdmin ? imported?.sdk ?? null : ownSdk;
|
|
12010
12012
|
const tree = parseSource3(parserForExt2(import_node_path45.default.extname(file.path)), file.content);
|
|
12011
12013
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
12014
|
+
for (const n of importedNames) clientVars.add(n);
|
|
12012
12015
|
const collLine = /* @__PURE__ */ new Map();
|
|
12013
12016
|
const writes = /* @__PURE__ */ new Map();
|
|
12014
12017
|
const reads = /* @__PURE__ */ new Map();
|
|
@@ -12119,6 +12122,99 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
12119
12122
|
}
|
|
12120
12123
|
return out;
|
|
12121
12124
|
}
|
|
12125
|
+
function exportedFirestoreClients(root) {
|
|
12126
|
+
const out = /* @__PURE__ */ new Set();
|
|
12127
|
+
const collect = (node) => {
|
|
12128
|
+
if (node.type === "variable_declarator") {
|
|
12129
|
+
const name = node.childForFieldName("name");
|
|
12130
|
+
let value = node.childForFieldName("value");
|
|
12131
|
+
if (value?.type === "await_expression") value = namedChildren(value)[0] ?? null;
|
|
12132
|
+
if (name?.type === "identifier" && isFirestoreClientFactory(value)) out.add(name.text);
|
|
12133
|
+
}
|
|
12134
|
+
for (const c of namedChildren(node)) collect(c);
|
|
12135
|
+
};
|
|
12136
|
+
const walk11 = (node) => {
|
|
12137
|
+
if (node.type === "export_statement") collect(node);
|
|
12138
|
+
else for (const c of namedChildren(node)) walk11(c);
|
|
12139
|
+
};
|
|
12140
|
+
walk11(root);
|
|
12141
|
+
return out;
|
|
12142
|
+
}
|
|
12143
|
+
function namedImportBindings(root) {
|
|
12144
|
+
const out = [];
|
|
12145
|
+
const walk11 = (node) => {
|
|
12146
|
+
if (node.type === "import_statement") {
|
|
12147
|
+
const src = node.childForFieldName("source");
|
|
12148
|
+
const specifier = src ? src.text.slice(1, -1) : "";
|
|
12149
|
+
if (specifier.length > 0) {
|
|
12150
|
+
const stack = [node];
|
|
12151
|
+
while (stack.length > 0) {
|
|
12152
|
+
const n = stack.pop();
|
|
12153
|
+
if (n.type === "import_specifier") {
|
|
12154
|
+
const nameNode = n.childForFieldName("name");
|
|
12155
|
+
const aliasNode = n.childForFieldName("alias");
|
|
12156
|
+
const importedName = nameNode?.text;
|
|
12157
|
+
if (importedName) {
|
|
12158
|
+
out.push({ local: aliasNode?.text ?? importedName, imported: importedName, specifier });
|
|
12159
|
+
}
|
|
12160
|
+
continue;
|
|
12161
|
+
}
|
|
12162
|
+
for (const c of namedChildren(n)) stack.push(c);
|
|
12163
|
+
}
|
|
12164
|
+
}
|
|
12165
|
+
}
|
|
12166
|
+
for (const c of namedChildren(node)) walk11(c);
|
|
12167
|
+
};
|
|
12168
|
+
walk11(root);
|
|
12169
|
+
return out;
|
|
12170
|
+
}
|
|
12171
|
+
function sdkOf(content) {
|
|
12172
|
+
const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(content);
|
|
12173
|
+
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(content);
|
|
12174
|
+
return hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
12175
|
+
}
|
|
12176
|
+
function parseOrNull(file) {
|
|
12177
|
+
const ext = import_node_path45.default.extname(file.path);
|
|
12178
|
+
if (!(ext in GRAMMAR_BY_EXT)) return null;
|
|
12179
|
+
try {
|
|
12180
|
+
return parseSource3(parserForExt2(ext), file.content).rootNode;
|
|
12181
|
+
} catch {
|
|
12182
|
+
return null;
|
|
12183
|
+
}
|
|
12184
|
+
}
|
|
12185
|
+
async function firestoreCrossFileEndpoints(files, serviceDir) {
|
|
12186
|
+
const registry = /* @__PURE__ */ new Map();
|
|
12187
|
+
for (const f of files) {
|
|
12188
|
+
if (sdkOf(f.content) === null && !FIRESTORE_CLIENT_IMPORT_RE.test(f.content)) continue;
|
|
12189
|
+
const root = parseOrNull(f);
|
|
12190
|
+
if (!root) continue;
|
|
12191
|
+
const names = exportedFirestoreClients(root);
|
|
12192
|
+
if (names.size === 0) continue;
|
|
12193
|
+
registry.set(toPosix(import_node_path45.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
|
|
12194
|
+
}
|
|
12195
|
+
if (registry.size === 0) return [];
|
|
12196
|
+
const out = [];
|
|
12197
|
+
for (const f of files) {
|
|
12198
|
+
const root = parseOrNull(f);
|
|
12199
|
+
if (!root) continue;
|
|
12200
|
+
if (firestoreClientVars(root).size > 0) continue;
|
|
12201
|
+
const bindings = namedImportBindings(root);
|
|
12202
|
+
if (bindings.length === 0) continue;
|
|
12203
|
+
const names = /* @__PURE__ */ new Set();
|
|
12204
|
+
let sdk = null;
|
|
12205
|
+
for (const b of bindings) {
|
|
12206
|
+
const rel = await resolveJsImport(b.specifier, import_node_path45.default.dirname(f.path), serviceDir, null);
|
|
12207
|
+
if (!rel) continue;
|
|
12208
|
+
const entry2 = registry.get(rel);
|
|
12209
|
+
if (!entry2 || !entry2.names.has(b.imported)) continue;
|
|
12210
|
+
names.add(b.local);
|
|
12211
|
+
sdk ??= entry2.sdk;
|
|
12212
|
+
}
|
|
12213
|
+
if (names.size === 0) continue;
|
|
12214
|
+
out.push(...firestoreEndpointsFromFile(f, serviceDir, { names, sdk }));
|
|
12215
|
+
}
|
|
12216
|
+
return out;
|
|
12217
|
+
}
|
|
12122
12218
|
|
|
12123
12219
|
// src/extract/calls/mongoose.ts
|
|
12124
12220
|
init_cjs_shims();
|
|
@@ -14928,6 +15024,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14928
15024
|
recordExtractionError("python socket call extraction", file.path, err);
|
|
14929
15025
|
}
|
|
14930
15026
|
}
|
|
15027
|
+
endpoints.push(...await firestoreCrossFileEndpoints(maskedFiles, service.dir));
|
|
14931
15028
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
14932
15029
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
14933
15030
|
endpoints.push(...await prismaColumnEndpoints(service.dir));
|
|
@@ -16223,6 +16320,9 @@ function stripComments(src) {
|
|
|
16223
16320
|
function segmentsFromMatchPath(pathToken) {
|
|
16224
16321
|
return pathToken.split("/").filter((s) => s.length > 0);
|
|
16225
16322
|
}
|
|
16323
|
+
function isRecursiveWildcard(seg) {
|
|
16324
|
+
return /^\{[^}]*=\s*\*\*\}$/.test(seg);
|
|
16325
|
+
}
|
|
16226
16326
|
function collectionKeyFromSegments(segments) {
|
|
16227
16327
|
let segs = segments;
|
|
16228
16328
|
if (segs.length >= 3 && segs[0] === "databases" && /^\{.*\}$/.test(segs[1]) && segs[2] === "documents") {
|
|
@@ -16235,10 +16335,11 @@ function collectionKeyFromName(name) {
|
|
|
16235
16335
|
}
|
|
16236
16336
|
function fieldsFromCondition(cond) {
|
|
16237
16337
|
const out = [];
|
|
16238
|
-
const callRe =
|
|
16338
|
+
const callRe = /(!\s*)?\b(?:hasAll|hasOnly|hasAny)\s*\(\s*\[([^\]]*)\]\s*\)/g;
|
|
16239
16339
|
let m;
|
|
16240
16340
|
while ((m = callRe.exec(cond)) !== null) {
|
|
16241
|
-
|
|
16341
|
+
if (m[1] !== void 0 || isNegatedAt(cond, m.index)) continue;
|
|
16342
|
+
const inner = m[2];
|
|
16242
16343
|
const litRe = /'([^']*)'|"([^"]*)"/g;
|
|
16243
16344
|
let lm;
|
|
16244
16345
|
while ((lm = litRe.exec(inner)) !== null) {
|
|
@@ -16248,6 +16349,28 @@ function fieldsFromCondition(cond) {
|
|
|
16248
16349
|
}
|
|
16249
16350
|
return out;
|
|
16250
16351
|
}
|
|
16352
|
+
function isNegatedAt(cond, idx) {
|
|
16353
|
+
let i = idx - 1;
|
|
16354
|
+
while (i >= 0) {
|
|
16355
|
+
const ch = cond[i];
|
|
16356
|
+
if (ch === ")") {
|
|
16357
|
+
let depth = 1;
|
|
16358
|
+
i--;
|
|
16359
|
+
while (i >= 0 && depth > 0) {
|
|
16360
|
+
if (cond[i] === ")") depth++;
|
|
16361
|
+
else if (cond[i] === "(") depth--;
|
|
16362
|
+
i--;
|
|
16363
|
+
}
|
|
16364
|
+
continue;
|
|
16365
|
+
}
|
|
16366
|
+
if (/[A-Za-z0-9_$.\]['"]/.test(ch) || ch === " ") {
|
|
16367
|
+
i--;
|
|
16368
|
+
continue;
|
|
16369
|
+
}
|
|
16370
|
+
return ch === "!";
|
|
16371
|
+
}
|
|
16372
|
+
return false;
|
|
16373
|
+
}
|
|
16251
16374
|
function parseFirestoreRules(content) {
|
|
16252
16375
|
const src = stripComments(content);
|
|
16253
16376
|
const tokenRe = /match\s+((?:\/(?:\{[^}]*\}|[^\s/{}]+))+)\s*\{|allow\b([^;{}]*);|(\{)|(\})/g;
|
|
@@ -16260,7 +16383,8 @@ function parseFirestoreRules(content) {
|
|
|
16260
16383
|
while ((m = tokenRe.exec(src)) !== null) {
|
|
16261
16384
|
if (m[1] !== void 0) {
|
|
16262
16385
|
depth++;
|
|
16263
|
-
|
|
16386
|
+
const segs = segmentsFromMatchPath(m[1]);
|
|
16387
|
+
matchStack.push({ depth, segs, recursive: segs.some(isRecursiveWildcard) });
|
|
16264
16388
|
continue;
|
|
16265
16389
|
}
|
|
16266
16390
|
if (m[2] !== void 0) {
|
|
@@ -16271,6 +16395,10 @@ function parseFirestoreRules(content) {
|
|
|
16271
16395
|
if (!methods.some((mm) => WRITE_METHODS.has(mm))) continue;
|
|
16272
16396
|
const key = currentKey();
|
|
16273
16397
|
if (key.length === 0) continue;
|
|
16398
|
+
if (matchStack.some((f) => f.recursive)) {
|
|
16399
|
+
indeterminate.add(key);
|
|
16400
|
+
continue;
|
|
16401
|
+
}
|
|
16274
16402
|
const cond = colon === -1 ? "" : body.slice(colon + 1);
|
|
16275
16403
|
const fields = fieldsFromCondition(cond);
|
|
16276
16404
|
if (fields.length > 0) {
|
|
@@ -20325,10 +20453,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
20325
20453
|
// src/connectors/supabase/map.ts
|
|
20326
20454
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
20327
20455
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
20328
|
-
function targetFromRestPath(
|
|
20329
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
20456
|
+
function targetFromRestPath(path99) {
|
|
20457
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path99);
|
|
20330
20458
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
20331
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
20459
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path99);
|
|
20332
20460
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
20333
20461
|
return null;
|
|
20334
20462
|
}
|
|
@@ -20932,9 +21060,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
20932
21060
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
20933
21061
|
if (secondSep === -1) return null;
|
|
20934
21062
|
const method = rest.slice(0, secondSep);
|
|
20935
|
-
const
|
|
20936
|
-
if (!resourceName || !method || !
|
|
20937
|
-
return { resourceName, method, path:
|
|
21063
|
+
const path99 = rest.slice(secondSep + 1);
|
|
21064
|
+
if (!resourceName || !method || !path99) return null;
|
|
21065
|
+
return { resourceName, method, path: path99 };
|
|
20938
21066
|
}
|
|
20939
21067
|
function resourceNameFor(type, labels) {
|
|
20940
21068
|
if (!labels) return null;
|
|
@@ -20972,14 +21100,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
20972
21100
|
if (!req) return null;
|
|
20973
21101
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
20974
21102
|
const method = req.requestMethod.toUpperCase();
|
|
20975
|
-
const
|
|
20976
|
-
if (
|
|
21103
|
+
const path99 = pathFromRequestUrl(req.requestUrl);
|
|
21104
|
+
if (path99 === null) return null;
|
|
20977
21105
|
const timestamp = entry2.timestamp;
|
|
20978
21106
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
20979
21107
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
20980
21108
|
return {
|
|
20981
21109
|
targetKind: resourceType,
|
|
20982
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
21110
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path99 }),
|
|
20983
21111
|
callCount: 1,
|
|
20984
21112
|
errorCount: isError ? 1 : 0,
|
|
20985
21113
|
lastObservedIso: timestamp
|
|
@@ -21004,9 +21132,9 @@ var import_types73 = require("@neat.is/types");
|
|
|
21004
21132
|
function normalizeName(name) {
|
|
21005
21133
|
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
21006
21134
|
}
|
|
21007
|
-
function inferServiceName(graph, resourceName, method,
|
|
21135
|
+
function inferServiceName(graph, resourceName, method, path99) {
|
|
21008
21136
|
const wantedMethod = method.toUpperCase();
|
|
21009
|
-
const wantedPath = normalizePathTemplate(
|
|
21137
|
+
const wantedPath = normalizePathTemplate(path99);
|
|
21010
21138
|
const services = [];
|
|
21011
21139
|
const owners = /* @__PURE__ */ new Set();
|
|
21012
21140
|
graph.forEachNode((_id, attrs) => {
|
|
@@ -21223,7 +21351,7 @@ function mapEventToSignal(event) {
|
|
|
21223
21351
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
21224
21352
|
const statusCode = metadata?.statusCode;
|
|
21225
21353
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
21226
|
-
const
|
|
21354
|
+
const path99 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
21227
21355
|
return {
|
|
21228
21356
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
21229
21357
|
targetName: scriptName,
|
|
@@ -21231,7 +21359,7 @@ function mapEventToSignal(event) {
|
|
|
21231
21359
|
errorCount: isError ? 1 : 0,
|
|
21232
21360
|
lastObservedIso: observedAt.toISOString(),
|
|
21233
21361
|
method,
|
|
21234
|
-
...
|
|
21362
|
+
...path99 ? { path: path99 } : {},
|
|
21235
21363
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
21236
21364
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
21237
21365
|
};
|
|
@@ -21277,8 +21405,8 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
21277
21405
|
});
|
|
21278
21406
|
return found;
|
|
21279
21407
|
}
|
|
21280
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
21281
|
-
const normalizedPath = normalizePathTemplate(
|
|
21408
|
+
function findMatchingRouteNode(graph, serviceName, method, path99) {
|
|
21409
|
+
const normalizedPath = normalizePathTemplate(path99);
|
|
21282
21410
|
let found = null;
|
|
21283
21411
|
graph.forEachNode((id, attrs) => {
|
|
21284
21412
|
if (found) return;
|
|
@@ -21295,10 +21423,10 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
21295
21423
|
return (signal) => {
|
|
21296
21424
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
21297
21425
|
const scriptName = signal.targetName;
|
|
21298
|
-
const { method, path:
|
|
21426
|
+
const { method, path: path99 } = signal;
|
|
21299
21427
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
21300
|
-
if (!method || !
|
|
21301
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
21428
|
+
if (!method || !path99) return wholeFileId;
|
|
21429
|
+
return findMatchingRouteNode(graph, serviceName, method, path99) ?? wholeFileId;
|
|
21302
21430
|
};
|
|
21303
21431
|
const mapping = config.workers?.[scriptName];
|
|
21304
21432
|
if (mapping) {
|
|
@@ -21650,9 +21778,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
21650
21778
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
21651
21779
|
if (secondSep === -1) return null;
|
|
21652
21780
|
const method = rest.slice(0, secondSep);
|
|
21653
|
-
const
|
|
21654
|
-
if (!serviceName || !method || !
|
|
21655
|
-
return { serviceName, method, path:
|
|
21781
|
+
const path99 = rest.slice(secondSep + 1);
|
|
21782
|
+
if (!serviceName || !method || !path99) return null;
|
|
21783
|
+
return { serviceName, method, path: path99 };
|
|
21656
21784
|
}
|
|
21657
21785
|
|
|
21658
21786
|
// src/connectors/cloud-run/map.ts
|
|
@@ -21681,14 +21809,14 @@ function mapLogEntryToSignal2(entry2) {
|
|
|
21681
21809
|
if (!req) return null;
|
|
21682
21810
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
21683
21811
|
const method = req.requestMethod.toUpperCase();
|
|
21684
|
-
const
|
|
21685
|
-
if (
|
|
21812
|
+
const path99 = pathFromRequestUrl2(req.requestUrl);
|
|
21813
|
+
if (path99 === null) return null;
|
|
21686
21814
|
const timestamp = entry2.timestamp;
|
|
21687
21815
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
21688
21816
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
21689
21817
|
return {
|
|
21690
21818
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
21691
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
21819
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path99 }),
|
|
21692
21820
|
callCount: 1,
|
|
21693
21821
|
errorCount: isError ? 1 : 0,
|
|
21694
21822
|
lastObservedIso: timestamp
|
|
@@ -21727,14 +21855,14 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
21727
21855
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
21728
21856
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
21729
21857
|
if (!identity) return null;
|
|
21730
|
-
const { serviceName: gcpServiceName, method, path:
|
|
21731
|
-
const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method,
|
|
21858
|
+
const { serviceName: gcpServiceName, method, path: path99 } = identity;
|
|
21859
|
+
const mappedService = config.serviceMap?.[gcpServiceName] ?? (config.inferServices ? inferServiceName(graph, gcpServiceName, method, path99) ?? void 0 : void 0);
|
|
21732
21860
|
if (mappedService) {
|
|
21733
21861
|
const routeNodeId = findMatchingRouteNode2(
|
|
21734
21862
|
graph,
|
|
21735
21863
|
mappedService,
|
|
21736
21864
|
method,
|
|
21737
|
-
normalizePathTemplate(
|
|
21865
|
+
normalizePathTemplate(path99)
|
|
21738
21866
|
);
|
|
21739
21867
|
if (routeNodeId) {
|
|
21740
21868
|
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types84.EdgeType.CALLS };
|
|
@@ -21870,9 +21998,9 @@ function parseGcpLbTargetName(targetName) {
|
|
|
21870
21998
|
const secondSep = rest.indexOf(FIELD_SEP3);
|
|
21871
21999
|
if (secondSep === -1) return null;
|
|
21872
22000
|
const method = rest.slice(0, secondSep);
|
|
21873
|
-
const
|
|
21874
|
-
if (!backendServiceName || !method || !
|
|
21875
|
-
return { backendServiceName, method, path:
|
|
22001
|
+
const path99 = rest.slice(secondSep + 1);
|
|
22002
|
+
if (!backendServiceName || !method || !path99) return null;
|
|
22003
|
+
return { backendServiceName, method, path: path99 };
|
|
21876
22004
|
}
|
|
21877
22005
|
|
|
21878
22006
|
// src/connectors/gcp-lb/map.ts
|
|
@@ -21901,14 +22029,14 @@ function mapLogEntryToSignal3(entry2) {
|
|
|
21901
22029
|
if (!req) return null;
|
|
21902
22030
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
21903
22031
|
const method = req.requestMethod.toUpperCase();
|
|
21904
|
-
const
|
|
21905
|
-
if (
|
|
22032
|
+
const path99 = pathFromRequestUrl3(req.requestUrl);
|
|
22033
|
+
if (path99 === null) return null;
|
|
21906
22034
|
const timestamp = entry2.timestamp;
|
|
21907
22035
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
21908
22036
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD5;
|
|
21909
22037
|
return {
|
|
21910
22038
|
targetKind: GCP_LB_TARGET_KIND,
|
|
21911
|
-
targetName: packGcpLbTargetName({ backendServiceName, method, path:
|
|
22039
|
+
targetName: packGcpLbTargetName({ backendServiceName, method, path: path99 }),
|
|
21912
22040
|
callCount: 1,
|
|
21913
22041
|
errorCount: isError ? 1 : 0,
|
|
21914
22042
|
lastObservedIso: timestamp
|
|
@@ -21947,14 +22075,14 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
21947
22075
|
if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
|
|
21948
22076
|
const identity = parseGcpLbTargetName(signal.targetName);
|
|
21949
22077
|
if (!identity) return null;
|
|
21950
|
-
const { backendServiceName, method, path:
|
|
21951
|
-
const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method,
|
|
22078
|
+
const { backendServiceName, method, path: path99 } = identity;
|
|
22079
|
+
const mappedService = config.backendServiceMap?.[backendServiceName] ?? (config.inferServices ? inferServiceName(graph, backendServiceName, method, path99) ?? void 0 : void 0);
|
|
21952
22080
|
if (mappedService) {
|
|
21953
22081
|
const routeNodeId = findMatchingRouteNode3(
|
|
21954
22082
|
graph,
|
|
21955
22083
|
mappedService,
|
|
21956
22084
|
method,
|
|
21957
|
-
normalizePathTemplate(
|
|
22085
|
+
normalizePathTemplate(path99)
|
|
21958
22086
|
);
|
|
21959
22087
|
if (routeNodeId) {
|
|
21960
22088
|
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types88.EdgeType.CALLS };
|
|
@@ -24346,9 +24474,9 @@ function makeK8sFetchImpl(transport) {
|
|
|
24346
24474
|
req.end();
|
|
24347
24475
|
}));
|
|
24348
24476
|
}
|
|
24349
|
-
async function listResource(transport, namespace,
|
|
24477
|
+
async function listResource(transport, namespace, path99, opts = {}) {
|
|
24350
24478
|
const base = opts.apiUrl ?? transport.server;
|
|
24351
|
-
const url = `${base.replace(/\/$/, "")}${
|
|
24479
|
+
const url = `${base.replace(/\/$/, "")}${path99}`;
|
|
24352
24480
|
const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport);
|
|
24353
24481
|
const res = await junctionFetch(
|
|
24354
24482
|
url,
|
|
@@ -24358,7 +24486,7 @@ async function listResource(transport, namespace, path98, opts = {}) {
|
|
|
24358
24486
|
{ provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, fetchImpl }
|
|
24359
24487
|
);
|
|
24360
24488
|
if (!res.ok) {
|
|
24361
|
-
throw new Error(`kubernetes ${
|
|
24489
|
+
throw new Error(`kubernetes ${path99} failed: ${res.status} ${res.statusText}`);
|
|
24362
24490
|
}
|
|
24363
24491
|
const json = await res.json();
|
|
24364
24492
|
return Array.isArray(json.items) ? json.items : [];
|
|
@@ -30047,7 +30175,7 @@ async function clearActiveProfile(home = neatHome3()) {
|
|
|
30047
30175
|
}
|
|
30048
30176
|
|
|
30049
30177
|
// src/login-sso.ts
|
|
30050
|
-
var DEFAULT_CP_URL = "https://neat
|
|
30178
|
+
var DEFAULT_CP_URL = "https://api.neat.is";
|
|
30051
30179
|
var DEFAULT_WEB_URL = "https://app.neat.is";
|
|
30052
30180
|
var CALLBACK_TIMEOUT_MS = 5 * 6e4;
|
|
30053
30181
|
function resolveCpUrl(env = process.env, override) {
|
|
@@ -30236,6 +30364,11 @@ async function runSsoLogin(opts, deps) {
|
|
|
30236
30364
|
out(` OTEL_EXPORTER_OTLP_ENDPOINT=${cred.ingestEndpoint}`);
|
|
30237
30365
|
out(` OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer ${cred.otelToken}`);
|
|
30238
30366
|
}
|
|
30367
|
+
out("");
|
|
30368
|
+
out("This directory isn't part of that graph yet \u2014 logging in connected your account,");
|
|
30369
|
+
out("not this repo, and nothing here has been uploaded.");
|
|
30370
|
+
out(` Manage projects and repos: ${opts.webUrl}`);
|
|
30371
|
+
out("");
|
|
30239
30372
|
out("Run `neat logout` to switch back to your local daemon.");
|
|
30240
30373
|
}
|
|
30241
30374
|
return 0;
|
|
@@ -30372,10 +30505,10 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
|
|
|
30372
30505
|
const root = baseUrl.replace(/\/$/, "");
|
|
30373
30506
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
30374
30507
|
return {
|
|
30375
|
-
async get(
|
|
30508
|
+
async get(path99) {
|
|
30376
30509
|
let res;
|
|
30377
30510
|
try {
|
|
30378
|
-
res = await fetchImpl(`${root}${
|
|
30511
|
+
res = await fetchImpl(`${root}${path99}`, {
|
|
30379
30512
|
headers: { ...authHeader }
|
|
30380
30513
|
});
|
|
30381
30514
|
} catch (err) {
|
|
@@ -30387,16 +30520,16 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
|
|
|
30387
30520
|
const body = await res.text().catch(() => "");
|
|
30388
30521
|
throw new HttpError(
|
|
30389
30522
|
res.status,
|
|
30390
|
-
`${res.status} ${res.statusText} on GET ${
|
|
30523
|
+
`${res.status} ${res.statusText} on GET ${path99}: ${body}`,
|
|
30391
30524
|
body
|
|
30392
30525
|
);
|
|
30393
30526
|
}
|
|
30394
30527
|
return await res.json();
|
|
30395
30528
|
},
|
|
30396
|
-
async post(
|
|
30529
|
+
async post(path99, body) {
|
|
30397
30530
|
let res;
|
|
30398
30531
|
try {
|
|
30399
|
-
res = await fetchImpl(`${root}${
|
|
30532
|
+
res = await fetchImpl(`${root}${path99}`, {
|
|
30400
30533
|
method: "POST",
|
|
30401
30534
|
headers: { "content-type": "application/json", ...authHeader },
|
|
30402
30535
|
body: JSON.stringify(body)
|
|
@@ -30410,7 +30543,7 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
|
|
|
30410
30543
|
const text = await res.text().catch(() => "");
|
|
30411
30544
|
throw new HttpError(
|
|
30412
30545
|
res.status,
|
|
30413
|
-
`${res.status} ${res.statusText} on POST ${
|
|
30546
|
+
`${res.status} ${res.statusText} on POST ${path99}: ${text}`,
|
|
30414
30547
|
text
|
|
30415
30548
|
);
|
|
30416
30549
|
}
|
|
@@ -30424,12 +30557,12 @@ function projectPath(project, suffix) {
|
|
|
30424
30557
|
}
|
|
30425
30558
|
async function runRootCause(client, input) {
|
|
30426
30559
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
30427
|
-
const
|
|
30560
|
+
const path99 = projectPath(
|
|
30428
30561
|
input.project,
|
|
30429
30562
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
30430
30563
|
);
|
|
30431
30564
|
try {
|
|
30432
|
-
const result = await client.get(
|
|
30565
|
+
const result = await client.get(path99);
|
|
30433
30566
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
30434
30567
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
30435
30568
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -30455,12 +30588,12 @@ async function runRootCause(client, input) {
|
|
|
30455
30588
|
}
|
|
30456
30589
|
async function runBlastRadius(client, input) {
|
|
30457
30590
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
30458
|
-
const
|
|
30591
|
+
const path99 = projectPath(
|
|
30459
30592
|
input.project,
|
|
30460
30593
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
30461
30594
|
);
|
|
30462
30595
|
try {
|
|
30463
|
-
const result = await client.get(
|
|
30596
|
+
const result = await client.get(path99);
|
|
30464
30597
|
if (result.totalAffected === 0) {
|
|
30465
30598
|
return {
|
|
30466
30599
|
summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
|
|
@@ -30494,12 +30627,12 @@ function formatBlastEntry(n) {
|
|
|
30494
30627
|
}
|
|
30495
30628
|
async function runDependencies(client, input) {
|
|
30496
30629
|
const depth = input.depth ?? 3;
|
|
30497
|
-
const
|
|
30630
|
+
const path99 = projectPath(
|
|
30498
30631
|
input.project,
|
|
30499
30632
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
30500
30633
|
);
|
|
30501
30634
|
try {
|
|
30502
|
-
const result = await client.get(
|
|
30635
|
+
const result = await client.get(path99);
|
|
30503
30636
|
if (result.total === 0) {
|
|
30504
30637
|
return {
|
|
30505
30638
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -30591,9 +30724,9 @@ function formatDuration(ms) {
|
|
|
30591
30724
|
return `${Math.round(h / 24)}d`;
|
|
30592
30725
|
}
|
|
30593
30726
|
async function runIncidents(client, input) {
|
|
30594
|
-
const
|
|
30727
|
+
const path99 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
30595
30728
|
try {
|
|
30596
|
-
const body = await client.get(
|
|
30729
|
+
const body = await client.get(path99);
|
|
30597
30730
|
const events = body.events;
|
|
30598
30731
|
if (events.length === 0) {
|
|
30599
30732
|
return {
|
|
@@ -31372,6 +31505,8 @@ async function defaultReadSecret(prompt) {
|
|
|
31372
31505
|
|
|
31373
31506
|
// src/welcome.ts
|
|
31374
31507
|
init_cjs_shims();
|
|
31508
|
+
var import_node_fs55 = require("fs");
|
|
31509
|
+
var import_node_path93 = __toESM(require("path"), 1);
|
|
31375
31510
|
var import_promises5 = __toESM(require("readline/promises"), 1);
|
|
31376
31511
|
var WORDMARK = [
|
|
31377
31512
|
"\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",
|
|
@@ -31404,6 +31539,28 @@ function printHeader(out) {
|
|
|
31404
31539
|
}
|
|
31405
31540
|
async function runWelcome(deps = {}) {
|
|
31406
31541
|
const out = deps.out ?? ((line) => console.log(line));
|
|
31542
|
+
try {
|
|
31543
|
+
return await runFrontDoor(deps, out);
|
|
31544
|
+
} catch (err) {
|
|
31545
|
+
if (isPromptCancelled(err)) {
|
|
31546
|
+
out("");
|
|
31547
|
+
return 130;
|
|
31548
|
+
}
|
|
31549
|
+
throw err;
|
|
31550
|
+
}
|
|
31551
|
+
}
|
|
31552
|
+
var PromptCancelled = class extends Error {
|
|
31553
|
+
constructor() {
|
|
31554
|
+
super("prompt cancelled");
|
|
31555
|
+
this.name = "PromptCancelled";
|
|
31556
|
+
}
|
|
31557
|
+
};
|
|
31558
|
+
function isPromptCancelled(err) {
|
|
31559
|
+
if (err instanceof PromptCancelled) return true;
|
|
31560
|
+
const e = err;
|
|
31561
|
+
return e?.code === "ABORT_ERR" || e?.name === "AbortError";
|
|
31562
|
+
}
|
|
31563
|
+
async function runFrontDoor(deps, out) {
|
|
31407
31564
|
const readLine = deps.readLine ?? defaultReadLine2;
|
|
31408
31565
|
const login = deps.login ?? (() => Promise.resolve(0));
|
|
31409
31566
|
const orchestrator = deps.orchestrator ?? (() => Promise.resolve(0));
|
|
@@ -31411,21 +31568,114 @@ async function runWelcome(deps = {}) {
|
|
|
31411
31568
|
printHeader(out);
|
|
31412
31569
|
out("Welcome to NEAT. Let's get you a graph of this system.");
|
|
31413
31570
|
out("");
|
|
31414
|
-
|
|
31415
|
-
|
|
31571
|
+
const keyReader = deps.readKey !== void 0 ? { read: deps.readKey, done: () => {
|
|
31572
|
+
} } : createKeyReader();
|
|
31573
|
+
const picked = keyReader !== null ? await selectOption(out, keyReader, deps.moveCursorUp ?? defaultMoveCursorUp) : await selectByNumber(out, readLine);
|
|
31574
|
+
if (picked === void 0) return runSelfHosted(out, readLine, orchestrator, cwd);
|
|
31575
|
+
if (picked === 0) return login(["--browser"]);
|
|
31576
|
+
return runSelfHosted(out, readLine, orchestrator, cwd);
|
|
31577
|
+
}
|
|
31578
|
+
var MENU_OPTIONS = [
|
|
31579
|
+
"Log me into Hosted Neat",
|
|
31580
|
+
"I'd like to self-host or use it locally (copy a prompt)"
|
|
31581
|
+
];
|
|
31582
|
+
async function selectOption(out, reader, moveCursorUp) {
|
|
31583
|
+
let cursor = 0;
|
|
31584
|
+
const render = () => {
|
|
31585
|
+
for (const [i, label] of MENU_OPTIONS.entries()) {
|
|
31586
|
+
out(i === cursor ? ` \u276F ${i + 1}) ${label}` : ` ${i + 1}) ${label}`);
|
|
31587
|
+
}
|
|
31588
|
+
};
|
|
31589
|
+
try {
|
|
31590
|
+
render();
|
|
31591
|
+
out("");
|
|
31592
|
+
out(" \u2191/\u2193 to move \xB7 Enter to choose \xB7 1 or 2 to jump");
|
|
31593
|
+
for (; ; ) {
|
|
31594
|
+
const key = await reader.read();
|
|
31595
|
+
if (key === void 0) return void 0;
|
|
31596
|
+
if (key === "cancel") throw new PromptCancelled();
|
|
31597
|
+
if (key === "enter") return cursor;
|
|
31598
|
+
if (key === "select-1") return 0;
|
|
31599
|
+
if (key === "select-2") return 1;
|
|
31600
|
+
if (key === "up") cursor = (cursor + MENU_OPTIONS.length - 1) % MENU_OPTIONS.length;
|
|
31601
|
+
else if (key === "down") cursor = (cursor + 1) % MENU_OPTIONS.length;
|
|
31602
|
+
else continue;
|
|
31603
|
+
moveCursorUp(MENU_OPTIONS.length + 2);
|
|
31604
|
+
render();
|
|
31605
|
+
out("");
|
|
31606
|
+
out(" \u2191/\u2193 to move \xB7 Enter to choose \xB7 1 or 2 to jump");
|
|
31607
|
+
}
|
|
31608
|
+
} finally {
|
|
31609
|
+
reader.done();
|
|
31610
|
+
}
|
|
31611
|
+
}
|
|
31612
|
+
async function selectByNumber(out, readLine) {
|
|
31613
|
+
for (const [i, label] of MENU_OPTIONS.entries()) out(` ${i + 1}) ${label}`);
|
|
31416
31614
|
out("");
|
|
31417
31615
|
for (; ; ) {
|
|
31418
31616
|
const choice = (await readLine("Choose 1 or 2 (default 2): "))?.trim();
|
|
31419
|
-
if (choice === void 0) return
|
|
31420
|
-
if (choice === "1")
|
|
31421
|
-
|
|
31422
|
-
}
|
|
31423
|
-
if (choice === "2" || choice === "") {
|
|
31424
|
-
return runSelfHosted(out, readLine, orchestrator, cwd);
|
|
31425
|
-
}
|
|
31426
|
-
out(`"${choice}" isn't 1 or 2 \u2014 try again, or press Enter for self-hosted.`);
|
|
31617
|
+
if (choice === void 0) return void 0;
|
|
31618
|
+
if (choice === "1") return 0;
|
|
31619
|
+
if (choice === "2" || choice === "") return 1;
|
|
31620
|
+
out(`"${choice}" isn't 1 or 2 \u2014 try again, or press Enter for the local path.`);
|
|
31427
31621
|
}
|
|
31428
31622
|
}
|
|
31623
|
+
function createKeyReader() {
|
|
31624
|
+
const stdin = process.stdin;
|
|
31625
|
+
if (!stdin.isTTY || typeof stdin.setRawMode !== "function") return null;
|
|
31626
|
+
stdin.setRawMode(true);
|
|
31627
|
+
stdin.resume();
|
|
31628
|
+
let closed = false;
|
|
31629
|
+
let ended = false;
|
|
31630
|
+
const markEnded = () => {
|
|
31631
|
+
ended = true;
|
|
31632
|
+
};
|
|
31633
|
+
stdin.once("end", markEnded);
|
|
31634
|
+
stdin.once("close", markEnded);
|
|
31635
|
+
return {
|
|
31636
|
+
read: () => new Promise((resolve) => {
|
|
31637
|
+
if (ended) {
|
|
31638
|
+
resolve(void 0);
|
|
31639
|
+
return;
|
|
31640
|
+
}
|
|
31641
|
+
const finish = (value) => {
|
|
31642
|
+
stdin.removeListener("data", onData);
|
|
31643
|
+
stdin.removeListener("end", onClosed);
|
|
31644
|
+
stdin.removeListener("close", onClosed);
|
|
31645
|
+
resolve(value);
|
|
31646
|
+
};
|
|
31647
|
+
const onData = (buf) => finish(decodeKey(buf));
|
|
31648
|
+
const onClosed = () => {
|
|
31649
|
+
ended = true;
|
|
31650
|
+
finish(void 0);
|
|
31651
|
+
};
|
|
31652
|
+
stdin.on("data", onData);
|
|
31653
|
+
stdin.once("end", onClosed);
|
|
31654
|
+
stdin.once("close", onClosed);
|
|
31655
|
+
}),
|
|
31656
|
+
done: () => {
|
|
31657
|
+
if (closed) return;
|
|
31658
|
+
closed = true;
|
|
31659
|
+
stdin.removeListener("end", markEnded);
|
|
31660
|
+
stdin.removeListener("close", markEnded);
|
|
31661
|
+
stdin.setRawMode(false);
|
|
31662
|
+
stdin.pause();
|
|
31663
|
+
}
|
|
31664
|
+
};
|
|
31665
|
+
}
|
|
31666
|
+
function decodeKey(buf) {
|
|
31667
|
+
const s = buf.toString("utf8");
|
|
31668
|
+
if (s === "\x1B[A" || s === "k") return "up";
|
|
31669
|
+
if (s === "\x1B[B" || s === "j") return "down";
|
|
31670
|
+
if (s === "\r" || s === "\n") return "enter";
|
|
31671
|
+
if (s === "1") return "select-1";
|
|
31672
|
+
if (s === "2") return "select-2";
|
|
31673
|
+
if (s === "" || s === "\x1B") return "cancel";
|
|
31674
|
+
return "ignore";
|
|
31675
|
+
}
|
|
31676
|
+
function defaultMoveCursorUp(rows) {
|
|
31677
|
+
if (rows > 0) process.stdout.write(`\x1B[${rows}A`);
|
|
31678
|
+
}
|
|
31429
31679
|
async function runSelfHosted(out, readLine, orchestrator, cwd) {
|
|
31430
31680
|
const wantsPrompt = (await readLine("Print a copy-paste setup prompt for your coding agent? [Y/n]: "))?.trim().toLowerCase();
|
|
31431
31681
|
if (wantsPrompt !== "n" && wantsPrompt !== "no") {
|
|
@@ -31445,10 +31695,23 @@ async function shouldShowWelcome(deps = {}) {
|
|
|
31445
31695
|
const stdinTTY = deps.stdinIsTTY ?? Boolean(process.stdin.isTTY);
|
|
31446
31696
|
const stdoutTTY = deps.stdoutIsTTY ?? Boolean(process.stdout.isTTY);
|
|
31447
31697
|
if (!stdinTTY || !stdoutTTY) return false;
|
|
31448
|
-
const
|
|
31698
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
31699
|
+
const readRegistry2 = deps.readRegistry ?? (() => readRegistry());
|
|
31700
|
+
const hasSnapshot = deps.hasSnapshot ?? defaultHasSnapshot;
|
|
31701
|
+
try {
|
|
31702
|
+
const here = import_node_path93.default.resolve(cwd);
|
|
31703
|
+
const { projects } = await readRegistry2();
|
|
31704
|
+
if (projects.some((p) => import_node_path93.default.resolve(p.path) === here)) return false;
|
|
31705
|
+
if (await hasSnapshot(here)) return false;
|
|
31706
|
+
return true;
|
|
31707
|
+
} catch {
|
|
31708
|
+
return false;
|
|
31709
|
+
}
|
|
31710
|
+
}
|
|
31711
|
+
async function defaultHasSnapshot(cwd) {
|
|
31449
31712
|
try {
|
|
31450
|
-
const
|
|
31451
|
-
return
|
|
31713
|
+
const entries = await import_node_fs55.promises.readdir(import_node_path93.default.join(cwd, "neat-out"));
|
|
31714
|
+
return entries.some((e) => e.endsWith(".json"));
|
|
31452
31715
|
} catch {
|
|
31453
31716
|
return false;
|
|
31454
31717
|
}
|
|
@@ -31465,27 +31728,27 @@ async function defaultReadLine2(prompt) {
|
|
|
31465
31728
|
|
|
31466
31729
|
// src/hooks-cli.ts
|
|
31467
31730
|
init_cjs_shims();
|
|
31468
|
-
var
|
|
31731
|
+
var import_node_path94 = __toESM(require("path"), 1);
|
|
31469
31732
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
31470
|
-
var
|
|
31733
|
+
var import_node_fs56 = require("fs");
|
|
31471
31734
|
var import_node_url5 = require("url");
|
|
31472
31735
|
var HOOK_FILENAME = "neat-search-nudge.mjs";
|
|
31473
31736
|
var GUIDE_FILENAME = "GRAPH_FIRST.md";
|
|
31474
31737
|
var GUIDE_INSTALL_NAME = "neat-graph-first.md";
|
|
31475
31738
|
var HOOK_MATCHER = "Grep|Glob|Bash";
|
|
31476
31739
|
function moduleDir() {
|
|
31477
|
-
return typeof __dirname !== "undefined" ? __dirname :
|
|
31740
|
+
return typeof __dirname !== "undefined" ? __dirname : import_node_path94.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
|
|
31478
31741
|
}
|
|
31479
31742
|
async function readSkillAsset(rel) {
|
|
31480
31743
|
const here = moduleDir();
|
|
31481
31744
|
const candidates = [
|
|
31482
|
-
|
|
31483
|
-
|
|
31484
|
-
|
|
31745
|
+
import_node_path94.default.resolve(here, "../../claude-skill", rel),
|
|
31746
|
+
import_node_path94.default.resolve(here, "../../../claude-skill", rel),
|
|
31747
|
+
import_node_path94.default.resolve(here, "../claude-skill", rel)
|
|
31485
31748
|
];
|
|
31486
31749
|
for (const candidate of candidates) {
|
|
31487
31750
|
try {
|
|
31488
|
-
return await
|
|
31751
|
+
return await import_node_fs56.promises.readFile(candidate, "utf8");
|
|
31489
31752
|
} catch {
|
|
31490
31753
|
}
|
|
31491
31754
|
}
|
|
@@ -31495,20 +31758,20 @@ async function readSkillAsset(rel) {
|
|
|
31495
31758
|
}
|
|
31496
31759
|
function neatHome4() {
|
|
31497
31760
|
const override = process.env.NEAT_HOME;
|
|
31498
|
-
if (override && override.length > 0) return
|
|
31499
|
-
return
|
|
31761
|
+
if (override && override.length > 0) return import_node_path94.default.resolve(override);
|
|
31762
|
+
return import_node_path94.default.join(import_node_os8.default.homedir(), ".neat");
|
|
31500
31763
|
}
|
|
31501
31764
|
function claudeSettingsPath() {
|
|
31502
31765
|
const override = process.env.NEAT_CLAUDE_SETTINGS;
|
|
31503
|
-
if (override && override.length > 0) return
|
|
31766
|
+
if (override && override.length > 0) return import_node_path94.default.resolve(override);
|
|
31504
31767
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os8.default.homedir();
|
|
31505
|
-
return
|
|
31768
|
+
return import_node_path94.default.join(home, ".claude", "settings.json");
|
|
31506
31769
|
}
|
|
31507
31770
|
function installedHookPath() {
|
|
31508
|
-
return
|
|
31771
|
+
return import_node_path94.default.join(neatHome4(), "hooks", HOOK_FILENAME);
|
|
31509
31772
|
}
|
|
31510
31773
|
function gateFlagPath() {
|
|
31511
|
-
return
|
|
31774
|
+
return import_node_path94.default.join(neatHome4(), "hooks", "gate-enabled");
|
|
31512
31775
|
}
|
|
31513
31776
|
function isNeatSearchEntry(entry2) {
|
|
31514
31777
|
return (entry2.hooks ?? []).some(
|
|
@@ -31541,14 +31804,14 @@ async function runHooks(opts) {
|
|
|
31541
31804
|
const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
|
|
31542
31805
|
const guide = await readSkillAsset(GUIDE_FILENAME);
|
|
31543
31806
|
const scriptPath = installedHookPath();
|
|
31544
|
-
await
|
|
31545
|
-
await
|
|
31546
|
-
const guidePath =
|
|
31547
|
-
await
|
|
31807
|
+
await import_node_fs56.promises.mkdir(import_node_path94.default.dirname(scriptPath), { recursive: true });
|
|
31808
|
+
await import_node_fs56.promises.writeFile(scriptPath, hookScript, { mode: 493 });
|
|
31809
|
+
const guidePath = import_node_path94.default.join(neatHome4(), GUIDE_INSTALL_NAME);
|
|
31810
|
+
await import_node_fs56.promises.writeFile(guidePath, guide, "utf8");
|
|
31548
31811
|
const settingsFile = claudeSettingsPath();
|
|
31549
31812
|
let settings = {};
|
|
31550
31813
|
try {
|
|
31551
|
-
settings = JSON.parse(await
|
|
31814
|
+
settings = JSON.parse(await import_node_fs56.promises.readFile(settingsFile, "utf8"));
|
|
31552
31815
|
} catch (err) {
|
|
31553
31816
|
if (err.code !== "ENOENT") {
|
|
31554
31817
|
console.error(
|
|
@@ -31570,14 +31833,14 @@ async function runHooks(opts) {
|
|
|
31570
31833
|
...settings,
|
|
31571
31834
|
hooks: { ...hooks, PreToolUse: preToolUse }
|
|
31572
31835
|
};
|
|
31573
|
-
await
|
|
31574
|
-
await
|
|
31836
|
+
await import_node_fs56.promises.mkdir(import_node_path94.default.dirname(settingsFile), { recursive: true });
|
|
31837
|
+
await import_node_fs56.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
31575
31838
|
const flag = gateFlagPath();
|
|
31576
31839
|
if (opts.gate) {
|
|
31577
|
-
await
|
|
31578
|
-
await
|
|
31840
|
+
await import_node_fs56.promises.mkdir(import_node_path94.default.dirname(flag), { recursive: true });
|
|
31841
|
+
await import_node_fs56.promises.writeFile(flag, "1\n", "utf8");
|
|
31579
31842
|
} else {
|
|
31580
|
-
await
|
|
31843
|
+
await import_node_fs56.promises.rm(flag, { force: true });
|
|
31581
31844
|
}
|
|
31582
31845
|
const mode = opts.gate ? "GATE (deny search until you ask the graph)" : "nudge (search still runs)";
|
|
31583
31846
|
console.log(`neat hooks: installed the search hook in ${opts.gate ? "gate" : "nudge"} mode`);
|
|
@@ -31667,8 +31930,8 @@ async function runHooksCommand(args) {
|
|
|
31667
31930
|
|
|
31668
31931
|
// src/claude-cli.ts
|
|
31669
31932
|
init_cjs_shims();
|
|
31670
|
-
var
|
|
31671
|
-
var
|
|
31933
|
+
var import_node_path95 = __toESM(require("path"), 1);
|
|
31934
|
+
var import_node_fs57 = require("fs");
|
|
31672
31935
|
var NEAT_SECTION_HEADING = "## neat";
|
|
31673
31936
|
var NEAT_DIRECTIVE_BODY = `This project has NEAT wired in: a live, fused semantic graph of the system \u2014
|
|
31674
31937
|
code and runtime behaviour (OpenTelemetry) in one model, every fact tagged with
|
|
@@ -31702,8 +31965,8 @@ ${NEAT_DIRECTIVE_BODY}
|
|
|
31702
31965
|
}
|
|
31703
31966
|
function claudeMdPath() {
|
|
31704
31967
|
const override = process.env.NEAT_CLAUDE_MD;
|
|
31705
|
-
if (override && override.length > 0) return
|
|
31706
|
-
return
|
|
31968
|
+
if (override && override.length > 0) return import_node_path95.default.resolve(override);
|
|
31969
|
+
return import_node_path95.default.join(process.cwd(), "CLAUDE.md");
|
|
31707
31970
|
}
|
|
31708
31971
|
function splitAroundSection(raw) {
|
|
31709
31972
|
const lines = raw.split("\n");
|
|
@@ -31731,7 +31994,7 @@ function compose(before, after) {
|
|
|
31731
31994
|
}
|
|
31732
31995
|
async function readIfExists2(file) {
|
|
31733
31996
|
try {
|
|
31734
|
-
return await
|
|
31997
|
+
return await import_node_fs57.promises.readFile(file, "utf8");
|
|
31735
31998
|
} catch (err) {
|
|
31736
31999
|
if (err.code === "ENOENT") return null;
|
|
31737
32000
|
throw err;
|
|
@@ -31742,8 +32005,8 @@ async function runInstall() {
|
|
|
31742
32005
|
const raw = await readIfExists2(file) ?? "";
|
|
31743
32006
|
const { before, after, found } = splitAroundSection(raw);
|
|
31744
32007
|
const next = compose(before, after);
|
|
31745
|
-
await
|
|
31746
|
-
await
|
|
32008
|
+
await import_node_fs57.promises.mkdir(import_node_path95.default.dirname(file), { recursive: true });
|
|
32009
|
+
await import_node_fs57.promises.writeFile(file, next, "utf8");
|
|
31747
32010
|
const verb = raw.length === 0 ? "created" : found ? "refreshed" : "added";
|
|
31748
32011
|
console.log(`neat claude: ${verb} the \`${NEAT_SECTION_HEADING}\` section in ${file}`);
|
|
31749
32012
|
console.log("Your agent will now reach for `neat ask` before Read/Grep/Bash. Restart the");
|
|
@@ -31764,7 +32027,7 @@ async function runUninstall() {
|
|
|
31764
32027
|
}
|
|
31765
32028
|
const remaining = [before, after].filter((s) => s.length > 0).join("\n\n");
|
|
31766
32029
|
const next = remaining.length > 0 ? remaining.replace(/\n*$/, "") + "\n" : "";
|
|
31767
|
-
await
|
|
32030
|
+
await import_node_fs57.promises.writeFile(file, next, "utf8");
|
|
31768
32031
|
console.log(`neat claude: removed the \`${NEAT_SECTION_HEADING}\` section from ${file}.`);
|
|
31769
32032
|
return { exitCode: 0 };
|
|
31770
32033
|
}
|
|
@@ -31807,9 +32070,9 @@ async function runClaudeCommand(args) {
|
|
|
31807
32070
|
|
|
31808
32071
|
// src/codex-cli.ts
|
|
31809
32072
|
init_cjs_shims();
|
|
31810
|
-
var
|
|
32073
|
+
var import_node_path96 = __toESM(require("path"), 1);
|
|
31811
32074
|
var import_node_os9 = __toESM(require("os"), 1);
|
|
31812
|
-
var
|
|
32075
|
+
var import_node_fs58 = require("fs");
|
|
31813
32076
|
var import_node_util = require("util");
|
|
31814
32077
|
var import_smol_toml6 = require("smol-toml");
|
|
31815
32078
|
var CODEX_MCP_SERVER = {
|
|
@@ -31827,14 +32090,14 @@ var NEAT_GRAPH_FIRST_START = "<!-- neat:graph-first -->";
|
|
|
31827
32090
|
var NEAT_GRAPH_FIRST_END = "<!-- /neat:graph-first -->";
|
|
31828
32091
|
function codexConfigPath() {
|
|
31829
32092
|
const override = process.env.NEAT_CODEX_CONFIG;
|
|
31830
|
-
if (override && override.length > 0) return
|
|
32093
|
+
if (override && override.length > 0) return import_node_path96.default.resolve(override);
|
|
31831
32094
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os9.default.homedir();
|
|
31832
|
-
return
|
|
32095
|
+
return import_node_path96.default.join(home, ".codex", "config.toml");
|
|
31833
32096
|
}
|
|
31834
32097
|
function agentsFilePath() {
|
|
31835
32098
|
const override = process.env.NEAT_CODEX_AGENTS;
|
|
31836
|
-
if (override && override.length > 0) return
|
|
31837
|
-
return
|
|
32099
|
+
if (override && override.length > 0) return import_node_path96.default.resolve(override);
|
|
32100
|
+
return import_node_path96.default.join(process.cwd(), "AGENTS.md");
|
|
31838
32101
|
}
|
|
31839
32102
|
function isTableHeader(line) {
|
|
31840
32103
|
return /^\s*\[\[?[^\]]+\]\]?\s*$/.test(line);
|
|
@@ -31968,7 +32231,7 @@ async function runCodex(opts) {
|
|
|
31968
32231
|
const agentsPath = agentsFilePath();
|
|
31969
32232
|
let configRaw = "";
|
|
31970
32233
|
try {
|
|
31971
|
-
configRaw = await
|
|
32234
|
+
configRaw = await import_node_fs58.promises.readFile(configPath, "utf8");
|
|
31972
32235
|
} catch (err) {
|
|
31973
32236
|
if (err.code !== "ENOENT") {
|
|
31974
32237
|
console.error(`neat codex: failed to read ${configPath} \u2014 ${err.message}`);
|
|
@@ -31977,7 +32240,7 @@ async function runCodex(opts) {
|
|
|
31977
32240
|
}
|
|
31978
32241
|
let agentsRaw = "";
|
|
31979
32242
|
try {
|
|
31980
|
-
agentsRaw = await
|
|
32243
|
+
agentsRaw = await import_node_fs58.promises.readFile(agentsPath, "utf8");
|
|
31981
32244
|
} catch (err) {
|
|
31982
32245
|
if (err.code !== "ENOENT") {
|
|
31983
32246
|
console.error(`neat codex: failed to read ${agentsPath} \u2014 ${err.message}`);
|
|
@@ -32017,15 +32280,15 @@ async function runCodex(opts) {
|
|
|
32017
32280
|
return { exitCode: 0 };
|
|
32018
32281
|
}
|
|
32019
32282
|
if (config.changed) {
|
|
32020
|
-
await
|
|
32021
|
-
await
|
|
32283
|
+
await import_node_fs58.promises.mkdir(import_node_path96.default.dirname(configPath), { recursive: true });
|
|
32284
|
+
await import_node_fs58.promises.writeFile(configPath, config.text, "utf8");
|
|
32022
32285
|
console.log(`neat codex: wrote [mcp_servers.neat] to ${configPath}`);
|
|
32023
32286
|
} else {
|
|
32024
32287
|
console.log(`neat codex: ${configPath} already has NEAT's MCP server`);
|
|
32025
32288
|
}
|
|
32026
32289
|
if (agents.changed) {
|
|
32027
|
-
await
|
|
32028
|
-
await
|
|
32290
|
+
await import_node_fs58.promises.mkdir(import_node_path96.default.dirname(agentsPath), { recursive: true });
|
|
32291
|
+
await import_node_fs58.promises.writeFile(agentsPath, agents.text, "utf8");
|
|
32029
32292
|
console.log(`neat codex: wrote the graph-first block to ${agentsPath}`);
|
|
32030
32293
|
} else {
|
|
32031
32294
|
console.log(`neat codex: ${agentsPath} already has the graph-first block`);
|
|
@@ -32082,9 +32345,9 @@ async function runCodexCommand(args) {
|
|
|
32082
32345
|
|
|
32083
32346
|
// src/editors-cli.ts
|
|
32084
32347
|
init_cjs_shims();
|
|
32085
|
-
var
|
|
32348
|
+
var import_node_path97 = __toESM(require("path"), 1);
|
|
32086
32349
|
var import_node_os10 = __toESM(require("os"), 1);
|
|
32087
|
-
var
|
|
32350
|
+
var import_node_fs59 = require("fs");
|
|
32088
32351
|
var import_node_util2 = require("util");
|
|
32089
32352
|
var jsonc = __toESM(require("jsonc-parser"), 1);
|
|
32090
32353
|
var NEAT_MCP_SERVER = {
|
|
@@ -32108,17 +32371,17 @@ function homeDir() {
|
|
|
32108
32371
|
}
|
|
32109
32372
|
function xdgConfigDir() {
|
|
32110
32373
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
32111
|
-
return xdg && xdg.length > 0 ?
|
|
32374
|
+
return xdg && xdg.length > 0 ? import_node_path97.default.resolve(xdg) : import_node_path97.default.join(homeDir(), ".config");
|
|
32112
32375
|
}
|
|
32113
32376
|
function envOverride(name) {
|
|
32114
32377
|
const v = process.env[name];
|
|
32115
|
-
return v && v.length > 0 ?
|
|
32378
|
+
return v && v.length > 0 ? import_node_path97.default.resolve(v) : void 0;
|
|
32116
32379
|
}
|
|
32117
32380
|
var CURSOR_CLIENT = {
|
|
32118
32381
|
id: "cursor",
|
|
32119
32382
|
label: "Cursor",
|
|
32120
32383
|
docsUrl: "https://docs.cursor.com/context/mcp",
|
|
32121
|
-
mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ??
|
|
32384
|
+
mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? import_node_path97.default.join(homeDir(), ".cursor", "mcp.json"),
|
|
32122
32385
|
mcpContainerKey: "mcpServers",
|
|
32123
32386
|
format: "json",
|
|
32124
32387
|
// Cursor still reads a single `.cursorrules` at the project root (the modern
|
|
@@ -32130,7 +32393,7 @@ var DEVIN_CLIENT = {
|
|
|
32130
32393
|
id: "devin",
|
|
32131
32394
|
label: "Devin Desktop (Cascade)",
|
|
32132
32395
|
docsUrl: "https://docs.devin.ai/desktop/cascade/mcp",
|
|
32133
|
-
mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ??
|
|
32396
|
+
mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? import_node_path97.default.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
32134
32397
|
mcpContainerKey: "mcpServers",
|
|
32135
32398
|
format: "json",
|
|
32136
32399
|
rulesFileName: ".windsurfrules"
|
|
@@ -32139,7 +32402,7 @@ var GEMINI_CLIENT = {
|
|
|
32139
32402
|
id: "gemini",
|
|
32140
32403
|
label: "Gemini CLI",
|
|
32141
32404
|
docsUrl: "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
|
|
32142
|
-
mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ??
|
|
32405
|
+
mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? import_node_path97.default.join(homeDir(), ".gemini", "settings.json"),
|
|
32143
32406
|
mcpContainerKey: "mcpServers",
|
|
32144
32407
|
format: "json",
|
|
32145
32408
|
rulesFileName: "GEMINI.md"
|
|
@@ -32148,7 +32411,7 @@ var QWEN_CLIENT = {
|
|
|
32148
32411
|
id: "qwen",
|
|
32149
32412
|
label: "Qwen Code",
|
|
32150
32413
|
docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/",
|
|
32151
|
-
mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ??
|
|
32414
|
+
mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? import_node_path97.default.join(homeDir(), ".qwen", "settings.json"),
|
|
32152
32415
|
mcpContainerKey: "mcpServers",
|
|
32153
32416
|
format: "json",
|
|
32154
32417
|
rulesFileName: "QWEN.md"
|
|
@@ -32157,7 +32420,7 @@ var AMAZONQ_CLIENT = {
|
|
|
32157
32420
|
id: "amazonq",
|
|
32158
32421
|
label: "Amazon Q Developer CLI",
|
|
32159
32422
|
docsUrl: "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html",
|
|
32160
|
-
mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ??
|
|
32423
|
+
mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? import_node_path97.default.join(homeDir(), ".aws", "amazonq", "mcp.json"),
|
|
32161
32424
|
mcpContainerKey: "mcpServers",
|
|
32162
32425
|
format: "json"
|
|
32163
32426
|
};
|
|
@@ -32165,7 +32428,7 @@ var ROOCODE_CLIENT = {
|
|
|
32165
32428
|
id: "roocode",
|
|
32166
32429
|
label: "Roo Code",
|
|
32167
32430
|
docsUrl: "https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo",
|
|
32168
|
-
mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ??
|
|
32431
|
+
mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? import_node_path97.default.join(process.cwd(), ".roo", "mcp.json"),
|
|
32169
32432
|
mcpContainerKey: "mcpServers",
|
|
32170
32433
|
format: "json"
|
|
32171
32434
|
};
|
|
@@ -32178,9 +32441,9 @@ var ZED_CLIENT = {
|
|
|
32178
32441
|
if (override) return override;
|
|
32179
32442
|
if (process.platform === "win32") {
|
|
32180
32443
|
const appData = process.env.APPDATA;
|
|
32181
|
-
if (appData && appData.length > 0) return
|
|
32444
|
+
if (appData && appData.length > 0) return import_node_path97.default.join(appData, "Zed", "settings.json");
|
|
32182
32445
|
}
|
|
32183
|
-
return
|
|
32446
|
+
return import_node_path97.default.join(homeDir(), ".config", "zed", "settings.json");
|
|
32184
32447
|
},
|
|
32185
32448
|
mcpContainerKey: "context_servers",
|
|
32186
32449
|
format: "jsonc",
|
|
@@ -32190,7 +32453,7 @@ var OPENCODE_CLIENT = {
|
|
|
32190
32453
|
id: "opencode",
|
|
32191
32454
|
label: "OpenCode",
|
|
32192
32455
|
docsUrl: "https://opencode.ai/docs/mcp-servers/",
|
|
32193
|
-
mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ??
|
|
32456
|
+
mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? import_node_path97.default.join(xdgConfigDir(), "opencode", "opencode.json"),
|
|
32194
32457
|
mcpContainerKey: "mcp",
|
|
32195
32458
|
format: "json",
|
|
32196
32459
|
serverEntry: NEAT_OPENCODE_SERVER,
|
|
@@ -32200,7 +32463,7 @@ var CRUSH_CLIENT = {
|
|
|
32200
32463
|
id: "crush",
|
|
32201
32464
|
label: "Crush",
|
|
32202
32465
|
docsUrl: "https://charmbracelet-crush.mintlify.app/configuration/mcp",
|
|
32203
|
-
mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ??
|
|
32466
|
+
mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? import_node_path97.default.join(xdgConfigDir(), "crush", "crush.json"),
|
|
32204
32467
|
mcpContainerKey: "mcp",
|
|
32205
32468
|
format: "json",
|
|
32206
32469
|
serverEntry: NEAT_CRUSH_SERVER,
|
|
@@ -32263,7 +32526,7 @@ async function planMcp(client, mcpPath) {
|
|
|
32263
32526
|
const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER;
|
|
32264
32527
|
let raw = "";
|
|
32265
32528
|
try {
|
|
32266
|
-
raw = await
|
|
32529
|
+
raw = await import_node_fs59.promises.readFile(mcpPath, "utf8");
|
|
32267
32530
|
} catch (err) {
|
|
32268
32531
|
const e = err;
|
|
32269
32532
|
if (e.code === "ENOENT") {
|
|
@@ -32305,7 +32568,7 @@ async function runEditorInstall(client, opts) {
|
|
|
32305
32568
|
const mcpPath = client.mcpConfigPath();
|
|
32306
32569
|
const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER;
|
|
32307
32570
|
const hasRules = typeof client.rulesFileName === "string";
|
|
32308
|
-
const rulesPath = hasRules ?
|
|
32571
|
+
const rulesPath = hasRules ? import_node_path97.default.join(opts.projectDir, client.rulesFileName) : "";
|
|
32309
32572
|
const mcp = await planMcp(client, mcpPath);
|
|
32310
32573
|
if (mcp === null) return { exitCode: 1 };
|
|
32311
32574
|
let existingRules = "";
|
|
@@ -32314,7 +32577,7 @@ async function runEditorInstall(client, opts) {
|
|
|
32314
32577
|
let block = "";
|
|
32315
32578
|
if (hasRules) {
|
|
32316
32579
|
try {
|
|
32317
|
-
existingRules = await
|
|
32580
|
+
existingRules = await import_node_fs59.promises.readFile(rulesPath, "utf8");
|
|
32318
32581
|
} catch (err) {
|
|
32319
32582
|
if (err.code !== "ENOENT") {
|
|
32320
32583
|
console.error(`neat ${client.id}: failed to read ${rulesPath} \u2014 ${err.message}`);
|
|
@@ -32348,11 +32611,11 @@ async function runEditorInstall(client, opts) {
|
|
|
32348
32611
|
);
|
|
32349
32612
|
return { exitCode: 0 };
|
|
32350
32613
|
}
|
|
32351
|
-
await
|
|
32352
|
-
await
|
|
32614
|
+
await import_node_fs59.promises.mkdir(import_node_path97.default.dirname(mcpPath), { recursive: true });
|
|
32615
|
+
await import_node_fs59.promises.writeFile(mcpPath, mcp.text, "utf8");
|
|
32353
32616
|
if (hasRules) {
|
|
32354
|
-
await
|
|
32355
|
-
await
|
|
32617
|
+
await import_node_fs59.promises.mkdir(import_node_path97.default.dirname(rulesPath), { recursive: true });
|
|
32618
|
+
await import_node_fs59.promises.writeFile(rulesPath, newRules, "utf8");
|
|
32356
32619
|
}
|
|
32357
32620
|
console.log(`neat ${client.id}: wired NEAT into ${client.label}`);
|
|
32358
32621
|
console.log(` MCP server: ${mcpPath} (${client.mcpContainerKey}.neat \u2192 npx -y @neat.is/mcp)`);
|
|
@@ -32854,7 +33117,7 @@ function sleep(ms, signal) {
|
|
|
32854
33117
|
|
|
32855
33118
|
// src/cli-verbs.ts
|
|
32856
33119
|
init_cjs_shims();
|
|
32857
|
-
var
|
|
33120
|
+
var import_node_path98 = __toESM(require("path"), 1);
|
|
32858
33121
|
async function resolveProjectEntry(opts) {
|
|
32859
33122
|
const entries = await listProjects();
|
|
32860
33123
|
if (opts.project) {
|
|
@@ -32864,7 +33127,7 @@ async function resolveProjectEntry(opts) {
|
|
|
32864
33127
|
const cwd = opts.cwd ?? process.cwd();
|
|
32865
33128
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
32866
33129
|
for (const entry2 of entries) {
|
|
32867
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
33130
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path98.default.sep}`)) {
|
|
32868
33131
|
return entry2;
|
|
32869
33132
|
}
|
|
32870
33133
|
}
|
|
@@ -33441,7 +33704,7 @@ async function buildPatchSections(services, project) {
|
|
|
33441
33704
|
}
|
|
33442
33705
|
async function runInit(opts) {
|
|
33443
33706
|
const written = [];
|
|
33444
|
-
const stat = await
|
|
33707
|
+
const stat = await import_node_fs60.promises.stat(opts.scanPath).catch(() => null);
|
|
33445
33708
|
if (!stat || !stat.isDirectory()) {
|
|
33446
33709
|
console.error(`neat init: ${opts.scanPath} is not a directory`);
|
|
33447
33710
|
return { exitCode: 2, writtenFiles: written };
|
|
@@ -33450,13 +33713,13 @@ async function runInit(opts) {
|
|
|
33450
33713
|
printDiscoveryReport(opts, services);
|
|
33451
33714
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
33452
33715
|
const patch = renderPatch(sections);
|
|
33453
|
-
const patchPath =
|
|
33716
|
+
const patchPath = import_node_path99.default.join(opts.scanPath, "neat.patch");
|
|
33454
33717
|
if (opts.dryRun) {
|
|
33455
|
-
await
|
|
33718
|
+
await import_node_fs60.promises.writeFile(patchPath, patch, "utf8");
|
|
33456
33719
|
written.push(patchPath);
|
|
33457
33720
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
33458
|
-
const gitignorePath =
|
|
33459
|
-
const gitignoreExists = await
|
|
33721
|
+
const gitignorePath = import_node_path99.default.join(opts.scanPath, ".gitignore");
|
|
33722
|
+
const gitignoreExists = await import_node_fs60.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
33460
33723
|
const verb = gitignoreExists ? "append" : "create";
|
|
33461
33724
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
33462
33725
|
console.log("rerun without --dry-run to register and snapshot.");
|
|
@@ -33467,9 +33730,9 @@ async function runInit(opts) {
|
|
|
33467
33730
|
const graph = getGraph(graphKey);
|
|
33468
33731
|
const projectPaths = pathsForProject(
|
|
33469
33732
|
graphKey,
|
|
33470
|
-
|
|
33733
|
+
import_node_path99.default.join(opts.scanPath, "neat-out")
|
|
33471
33734
|
);
|
|
33472
|
-
const errorsPath =
|
|
33735
|
+
const errorsPath = import_node_path99.default.join(import_node_path99.default.dirname(opts.outPath), import_node_path99.default.basename(projectPaths.errorsPath));
|
|
33473
33736
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
33474
33737
|
await saveGraphToDisk(graph, opts.outPath);
|
|
33475
33738
|
written.push(opts.outPath);
|
|
@@ -33548,7 +33811,7 @@ async function runInit(opts) {
|
|
|
33548
33811
|
console.log("Run `npm install` (or your language equivalent) to refresh lockfiles.");
|
|
33549
33812
|
}
|
|
33550
33813
|
} else {
|
|
33551
|
-
await
|
|
33814
|
+
await import_node_fs60.promises.writeFile(patchPath, patch, "utf8");
|
|
33552
33815
|
written.push(patchPath);
|
|
33553
33816
|
}
|
|
33554
33817
|
}
|
|
@@ -33589,9 +33852,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
33589
33852
|
};
|
|
33590
33853
|
function claudeConfigPath() {
|
|
33591
33854
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
33592
|
-
if (override && override.length > 0) return
|
|
33855
|
+
if (override && override.length > 0) return import_node_path99.default.resolve(override);
|
|
33593
33856
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
33594
|
-
return
|
|
33857
|
+
return import_node_path99.default.join(home, ".claude.json");
|
|
33595
33858
|
}
|
|
33596
33859
|
async function runSkill(opts) {
|
|
33597
33860
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -33603,7 +33866,7 @@ async function runSkill(opts) {
|
|
|
33603
33866
|
const target = claudeConfigPath();
|
|
33604
33867
|
let existing = {};
|
|
33605
33868
|
try {
|
|
33606
|
-
existing = JSON.parse(await
|
|
33869
|
+
existing = JSON.parse(await import_node_fs60.promises.readFile(target, "utf8"));
|
|
33607
33870
|
} catch (err) {
|
|
33608
33871
|
if (err.code !== "ENOENT") {
|
|
33609
33872
|
console.error(`neat skill: failed to read ${target} \u2014 ${err.message}`);
|
|
@@ -33615,8 +33878,8 @@ async function runSkill(opts) {
|
|
|
33615
33878
|
...existing,
|
|
33616
33879
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
33617
33880
|
};
|
|
33618
|
-
await
|
|
33619
|
-
await
|
|
33881
|
+
await import_node_fs60.promises.mkdir(import_node_path99.default.dirname(target), { recursive: true });
|
|
33882
|
+
await import_node_fs60.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
33620
33883
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
33621
33884
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
33622
33885
|
console.log("");
|
|
@@ -33642,7 +33905,7 @@ async function runSkill(opts) {
|
|
|
33642
33905
|
async function main() {
|
|
33643
33906
|
const argv = process.argv.slice(2);
|
|
33644
33907
|
const cmd0 = argv[0];
|
|
33645
|
-
if (
|
|
33908
|
+
if (argv.some((a) => a === "-h" || a === "--help")) {
|
|
33646
33909
|
usage5();
|
|
33647
33910
|
process.exit(0);
|
|
33648
33911
|
}
|
|
@@ -33737,12 +34000,12 @@ async function main() {
|
|
|
33737
34000
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
33738
34001
|
process.exit(2);
|
|
33739
34002
|
}
|
|
33740
|
-
const scanPath =
|
|
34003
|
+
const scanPath = import_node_path99.default.resolve(target);
|
|
33741
34004
|
const projectExplicit = parsed.project !== null;
|
|
33742
|
-
const projectName = projectExplicit ? project :
|
|
34005
|
+
const projectName = projectExplicit ? project : import_node_path99.default.basename(scanPath);
|
|
33743
34006
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
33744
|
-
const fallback = pathsForProject(projectKey,
|
|
33745
|
-
const outPath =
|
|
34007
|
+
const fallback = pathsForProject(projectKey, import_node_path99.default.join(scanPath, "neat-out")).snapshotPath;
|
|
34008
|
+
const outPath = import_node_path99.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
33746
34009
|
const result = await runInit({
|
|
33747
34010
|
scanPath,
|
|
33748
34011
|
outPath,
|
|
@@ -33763,21 +34026,21 @@ async function main() {
|
|
|
33763
34026
|
usage5();
|
|
33764
34027
|
process.exit(2);
|
|
33765
34028
|
}
|
|
33766
|
-
const scanPath =
|
|
33767
|
-
const stat = await
|
|
34029
|
+
const scanPath = import_node_path99.default.resolve(target);
|
|
34030
|
+
const stat = await import_node_fs60.promises.stat(scanPath).catch(() => null);
|
|
33768
34031
|
if (!stat || !stat.isDirectory()) {
|
|
33769
34032
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
33770
34033
|
process.exit(2);
|
|
33771
34034
|
}
|
|
33772
|
-
const projectPaths = pathsForProject(project,
|
|
33773
|
-
const outPath =
|
|
33774
|
-
const errorsPath =
|
|
33775
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
34035
|
+
const projectPaths = pathsForProject(project, import_node_path99.default.join(scanPath, "neat-out"));
|
|
34036
|
+
const outPath = import_node_path99.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
34037
|
+
const errorsPath = import_node_path99.default.resolve(
|
|
34038
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path99.default.join(import_node_path99.default.dirname(outPath), import_node_path99.default.basename(projectPaths.errorsPath))
|
|
33776
34039
|
);
|
|
33777
|
-
const staleEventsPath =
|
|
33778
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
34040
|
+
const staleEventsPath = import_node_path99.default.resolve(
|
|
34041
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path99.default.join(import_node_path99.default.dirname(outPath), import_node_path99.default.basename(projectPaths.staleEventsPath))
|
|
33779
34042
|
);
|
|
33780
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
34043
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path99.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
33781
34044
|
const handle = await startWatch(getGraph(project), {
|
|
33782
34045
|
scanPath,
|
|
33783
34046
|
outPath,
|
|
@@ -33786,7 +34049,7 @@ async function main() {
|
|
|
33786
34049
|
project,
|
|
33787
34050
|
// Resolve NEAT_HOME so a `neat watch` picks up connectors added to
|
|
33788
34051
|
// ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
|
|
33789
|
-
neatHome: process.env.NEAT_HOME ?
|
|
34052
|
+
neatHome: process.env.NEAT_HOME ? import_node_path99.default.resolve(process.env.NEAT_HOME) : import_node_path99.default.join(import_node_os11.default.homedir(), ".neat"),
|
|
33790
34053
|
...embeddingsCachePath ? { embeddingsCachePath } : {},
|
|
33791
34054
|
host: process.env.HOST ?? "0.0.0.0",
|
|
33792
34055
|
port: Number(process.env.PORT ?? 8080),
|
|
@@ -33968,11 +34231,11 @@ async function main() {
|
|
|
33968
34231
|
process.exit(1);
|
|
33969
34232
|
}
|
|
33970
34233
|
async function tryOrchestrator(cmd, parsed) {
|
|
33971
|
-
const scanPath =
|
|
33972
|
-
const stat = await
|
|
34234
|
+
const scanPath = import_node_path99.default.resolve(cmd);
|
|
34235
|
+
const stat = await import_node_fs60.promises.stat(scanPath).catch(() => null);
|
|
33973
34236
|
if (!stat || !stat.isDirectory()) return null;
|
|
33974
34237
|
const projectExplicit = parsed.project !== null;
|
|
33975
|
-
const projectName = projectExplicit ? parsed.project :
|
|
34238
|
+
const projectName = projectExplicit ? parsed.project : import_node_path99.default.basename(scanPath);
|
|
33976
34239
|
const result = await runOrchestrator({
|
|
33977
34240
|
scanPath,
|
|
33978
34241
|
project: projectName,
|