@neat.is/core 0.9.8-dev.20260829 → 0.9.9
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-KZBFP7L6.js → chunk-B6KJG5KN.js} +219 -13
- package/dist/chunk-B6KJG5KN.js.map +1 -0
- package/dist/{chunk-JSUPWMH3.js → chunk-QETJIA2Q.js} +14 -4
- package/dist/{chunk-JSUPWMH3.js.map → chunk-QETJIA2Q.js.map} +1 -1
- package/dist/cli.cjs +343 -98
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +46 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +294 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +294 -82
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +280 -80
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-KZBFP7L6.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -6366,11 +6366,25 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
6366
6366
|
};
|
|
6367
6367
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
6368
6368
|
}
|
|
6369
|
+
function emitIncidentEvent(project, ev) {
|
|
6370
|
+
emitNeatEvent({
|
|
6371
|
+
type: "incident",
|
|
6372
|
+
project,
|
|
6373
|
+
payload: {
|
|
6374
|
+
incidentId: ev.id,
|
|
6375
|
+
affectedNode: ev.affectedNode,
|
|
6376
|
+
service: ev.service,
|
|
6377
|
+
incidentKind: (0, import_types8.incidentKindOf)(ev),
|
|
6378
|
+
at: ev.timestamp
|
|
6379
|
+
}
|
|
6380
|
+
});
|
|
6381
|
+
}
|
|
6369
6382
|
async function appendErrorEvent(ctx, ev) {
|
|
6370
6383
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(ctx.errorsPath), { recursive: true });
|
|
6371
6384
|
await import_node_fs8.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6385
|
+
emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
|
|
6372
6386
|
}
|
|
6373
|
-
async function appendConnectorIncident(errorsPath, input) {
|
|
6387
|
+
async function appendConnectorIncident(errorsPath, input, project) {
|
|
6374
6388
|
const ev = {
|
|
6375
6389
|
id: input.id,
|
|
6376
6390
|
timestamp: input.timestamp,
|
|
@@ -6384,6 +6398,7 @@ async function appendConnectorIncident(errorsPath, input) {
|
|
|
6384
6398
|
};
|
|
6385
6399
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(errorsPath), { recursive: true });
|
|
6386
6400
|
await import_node_fs8.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6401
|
+
if (project) emitIncidentEvent(project, ev);
|
|
6387
6402
|
}
|
|
6388
6403
|
function landIncidentCallSite(span, callSite, trusted, graph) {
|
|
6389
6404
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
@@ -6477,12 +6492,13 @@ function buildErrorEventForReceiver(span, graph, scanPath) {
|
|
|
6477
6492
|
affectedNode: locus.affectedNode
|
|
6478
6493
|
};
|
|
6479
6494
|
}
|
|
6480
|
-
function makeErrorSpanWriter(errorsPath, graph, scanPath) {
|
|
6495
|
+
function makeErrorSpanWriter(errorsPath, graph, scanPath, project = DEFAULT_PROJECT) {
|
|
6481
6496
|
return async (span) => {
|
|
6482
6497
|
const ev = buildErrorEventForReceiver(span, graph, scanPath);
|
|
6483
6498
|
if (!ev) return;
|
|
6484
6499
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(errorsPath), { recursive: true });
|
|
6485
6500
|
await import_node_fs8.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6501
|
+
emitIncidentEvent(project, ev);
|
|
6486
6502
|
};
|
|
6487
6503
|
}
|
|
6488
6504
|
async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp, statusCode, count, firstTimestamp) {
|
|
@@ -16943,7 +16959,7 @@ var import_chokidar = __toESM(require("chokidar"), 1);
|
|
|
16943
16959
|
init_cjs_shims();
|
|
16944
16960
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
16945
16961
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
16946
|
-
var
|
|
16962
|
+
var import_types99 = require("@neat.is/types");
|
|
16947
16963
|
|
|
16948
16964
|
// src/extend/index.ts
|
|
16949
16965
|
init_cjs_shims();
|
|
@@ -17333,9 +17349,160 @@ function queryLogEntries(opts) {
|
|
|
17333
17349
|
return merged;
|
|
17334
17350
|
}
|
|
17335
17351
|
|
|
17336
|
-
// src/
|
|
17352
|
+
// src/goodybag.ts
|
|
17337
17353
|
init_cjs_shims();
|
|
17338
17354
|
var import_types60 = require("@neat.is/types");
|
|
17355
|
+
var CODE_FILEPATH_ATTR2 = "code.filepath";
|
|
17356
|
+
var CODE_LINENO_ATTR2 = "code.lineno";
|
|
17357
|
+
var BLAST_NEAREST_LIMIT = 5;
|
|
17358
|
+
function grainOf2(graph, nodeId) {
|
|
17359
|
+
if (graph.hasNode(nodeId)) {
|
|
17360
|
+
const t = graph.getNodeAttributes(nodeId).type;
|
|
17361
|
+
if (typeof t === "string" && t.length > 0) {
|
|
17362
|
+
return (t.endsWith("Node") ? t.slice(0, -4) : t).toLowerCase();
|
|
17363
|
+
}
|
|
17364
|
+
}
|
|
17365
|
+
const colon = nodeId.indexOf(":");
|
|
17366
|
+
return colon > 0 ? nodeId.slice(0, colon) : "unknown";
|
|
17367
|
+
}
|
|
17368
|
+
function locusOf(graph, ev) {
|
|
17369
|
+
const file = ev.attributes?.[CODE_FILEPATH_ATTR2];
|
|
17370
|
+
if (typeof file !== "string" || file.length === 0) return null;
|
|
17371
|
+
const rawLine = ev.attributes?.[CODE_LINENO_ATTR2];
|
|
17372
|
+
const line = typeof rawLine === "number" ? rawLine : Number(rawLine);
|
|
17373
|
+
const node = graph.hasNode(ev.affectedNode) ? graph.getNodeAttributes(ev.affectedNode) : void 0;
|
|
17374
|
+
return {
|
|
17375
|
+
file,
|
|
17376
|
+
...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
|
|
17377
|
+
...node?.name ? { symbol: node.name } : {},
|
|
17378
|
+
service: node?.service ?? ev.service,
|
|
17379
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17380
|
+
};
|
|
17381
|
+
}
|
|
17382
|
+
function locusFromNode(graph, nodeId) {
|
|
17383
|
+
if (!graph.hasNode(nodeId)) return null;
|
|
17384
|
+
const n = graph.getNodeAttributes(nodeId);
|
|
17385
|
+
const file = n.relPath ?? n.path;
|
|
17386
|
+
if (typeof file !== "string" || file.length === 0) return null;
|
|
17387
|
+
const start = n.span?.startLine;
|
|
17388
|
+
const end = n.span?.endLine;
|
|
17389
|
+
return {
|
|
17390
|
+
file,
|
|
17391
|
+
...typeof start === "number" ? { lineStart: start } : {},
|
|
17392
|
+
...typeof end === "number" ? { lineEnd: end } : {},
|
|
17393
|
+
...n.qualname ? { symbol: shortLabel(graph, nodeId) } : {},
|
|
17394
|
+
...n.service ? { service: n.service } : {},
|
|
17395
|
+
provenance: import_types60.Provenance.INFERRED
|
|
17396
|
+
};
|
|
17397
|
+
}
|
|
17398
|
+
function promoteCauseLocus(graph, causeNode, incidents) {
|
|
17399
|
+
const native = incidents.find(
|
|
17400
|
+
(e) => e.affectedNode === causeNode && typeof e.attributes?.[CODE_FILEPATH_ATTR2] === "string"
|
|
17401
|
+
);
|
|
17402
|
+
if (native) {
|
|
17403
|
+
const l = locusOf(graph, native);
|
|
17404
|
+
if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance: import_types60.Provenance.INFERRED };
|
|
17405
|
+
}
|
|
17406
|
+
return locusFromNode(graph, causeNode);
|
|
17407
|
+
}
|
|
17408
|
+
function divergenceSummary(d) {
|
|
17409
|
+
const column = "column" in d && d.column ? `.${d.column}` : "";
|
|
17410
|
+
const label = "table" in d && d.table ? `${d.table}${column}` : `${d.source} \u2192 ${d.target}`;
|
|
17411
|
+
return label;
|
|
17412
|
+
}
|
|
17413
|
+
function baseName(p) {
|
|
17414
|
+
const parts = p.split(/[\\/]/);
|
|
17415
|
+
return parts[parts.length - 1] || p;
|
|
17416
|
+
}
|
|
17417
|
+
function shortLabel(graph, nodeId) {
|
|
17418
|
+
if (graph.hasNode(nodeId)) {
|
|
17419
|
+
const name = graph.getNodeAttributes(nodeId).name;
|
|
17420
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
17421
|
+
}
|
|
17422
|
+
const afterHash = nodeId.includes("#") ? nodeId.slice(nodeId.lastIndexOf("#") + 1) : nodeId;
|
|
17423
|
+
return afterHash.includes(":") ? afterHash.slice(afterHash.lastIndexOf(":") + 1) : afterHash;
|
|
17424
|
+
}
|
|
17425
|
+
function renderHeadline(graph, ev, locus, causeNode) {
|
|
17426
|
+
const what = ev.exceptionType ? `raised ${ev.exceptionType}` : ev.errorMessage || "failed";
|
|
17427
|
+
const causeLabel = causeNode && causeNode !== ev.affectedNode ? shortLabel(graph, causeNode) : "";
|
|
17428
|
+
if (locus) {
|
|
17429
|
+
const base = baseName(locus.file);
|
|
17430
|
+
const lines = locus.lineStart != null ? locus.lineEnd && locus.lineEnd !== locus.lineStart ? `LINES ${locus.lineStart}-${locus.lineEnd}` : `LINE ${locus.lineStart}` : "";
|
|
17431
|
+
const symbol = locus.symbol ?? (grainOf2(graph, ev.affectedNode) === "symbol" ? shortLabel(graph, ev.affectedNode) : void 0);
|
|
17432
|
+
const subject = symbol ? `SYMBOL ${symbol}` : `FILE ${base}`;
|
|
17433
|
+
const at = symbol ? `${lines ? `${lines} in ` : ""}${base}` : lines;
|
|
17434
|
+
const where = at ? ` at ${at}` : "";
|
|
17435
|
+
const svc = locus.service ?? ev.service;
|
|
17436
|
+
const cause2 = causeLabel && causeLabel !== symbol ? ` \u2192 root cause ${causeLabel}` : "";
|
|
17437
|
+
return `${subject}${where} (SERVICE ${svc}) ${what} at ${ev.timestamp}${cause2}`;
|
|
17438
|
+
}
|
|
17439
|
+
const cause = causeLabel ? ` \u2192 root cause ${causeLabel}` : "";
|
|
17440
|
+
return `SERVICE ${ev.service} ${what} at ${ev.timestamp}${cause}`;
|
|
17441
|
+
}
|
|
17442
|
+
function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
17443
|
+
const affected = errorEvent.affectedNode;
|
|
17444
|
+
let locus = locusOf(graph, errorEvent);
|
|
17445
|
+
const inGraph = graph.hasNode(affected);
|
|
17446
|
+
const rc = inGraph ? getRootCause(graph, affected, errorEvent, incidents) : null;
|
|
17447
|
+
let rootCause = null;
|
|
17448
|
+
if (rc) {
|
|
17449
|
+
const provs = rc.edgeProvenances ?? [];
|
|
17450
|
+
const chain = (rc.traversalPath ?? []).map((node, i) => ({
|
|
17451
|
+
node,
|
|
17452
|
+
grain: grainOf2(graph, node),
|
|
17453
|
+
provenance: provs[i] ?? provs[provs.length - 1] ?? import_types60.Provenance.INFERRED
|
|
17454
|
+
}));
|
|
17455
|
+
rootCause = {
|
|
17456
|
+
node: rc.rootCauseNode,
|
|
17457
|
+
...rc.candidates?.[0]?.classification ? { classification: rc.candidates[0].classification } : {},
|
|
17458
|
+
reason: rc.rootCauseReason,
|
|
17459
|
+
confidence: rc.confidence,
|
|
17460
|
+
fix: rc.fixRecommendation ?? null,
|
|
17461
|
+
chain
|
|
17462
|
+
};
|
|
17463
|
+
}
|
|
17464
|
+
if (locus === null && rootCause) {
|
|
17465
|
+
locus = promoteCauseLocus(graph, rootCause.node, incidents);
|
|
17466
|
+
}
|
|
17467
|
+
const blast = inGraph ? getBlastRadius(graph, affected) : { origin: affected, affectedNodes: [], totalAffected: 0 };
|
|
17468
|
+
const nearest = [...blast.affectedNodes].sort((a, b) => a.distance - b.distance).slice(0, BLAST_NEAREST_LIMIT).map((n) => ({ node: n.nodeId, distance: n.distance, provenance: n.edgeProvenance }));
|
|
17469
|
+
const applicable = inGraph ? selectApplicablePolicies(graph, policies, affected) : [];
|
|
17470
|
+
const policyCards = applicable.map((p) => ({
|
|
17471
|
+
policyName: p.policyName,
|
|
17472
|
+
severity: p.severity,
|
|
17473
|
+
message: p.reason
|
|
17474
|
+
}));
|
|
17475
|
+
const divergences = inGraph ? computeDivergences(graph, { node: affected, incidents }).divergences.map((d) => ({
|
|
17476
|
+
type: d.type,
|
|
17477
|
+
summary: divergenceSummary(d)
|
|
17478
|
+
})) : [];
|
|
17479
|
+
const card = {
|
|
17480
|
+
kind: "incident",
|
|
17481
|
+
id: errorEvent.id,
|
|
17482
|
+
at: errorEvent.timestamp,
|
|
17483
|
+
incidentKind: (0, import_types60.incidentKindOf)(errorEvent),
|
|
17484
|
+
service: errorEvent.service,
|
|
17485
|
+
affectedNode: affected,
|
|
17486
|
+
message: errorEvent.errorMessage,
|
|
17487
|
+
...errorEvent.exceptionType ? { exceptionType: errorEvent.exceptionType } : {},
|
|
17488
|
+
...errorEvent.httpStatusCode !== void 0 ? { httpStatusCode: errorEvent.httpStatusCode } : {},
|
|
17489
|
+
...errorEvent.incidentCount !== void 0 ? { count: errorEvent.incidentCount } : {},
|
|
17490
|
+
...errorEvent.firstTimestamp && errorEvent.lastTimestamp ? { window: { first: errorEvent.firstTimestamp, last: errorEvent.lastTimestamp } } : {},
|
|
17491
|
+
...errorEvent.traceId ? { traceId: errorEvent.traceId } : {},
|
|
17492
|
+
...errorEvent.spanId ? { spanId: errorEvent.spanId } : {},
|
|
17493
|
+
locus,
|
|
17494
|
+
rootCause,
|
|
17495
|
+
...nearest.length > 0 ? { blastRadius: { totalAffected: blast.totalAffected, nearest } } : {},
|
|
17496
|
+
...policyCards.length > 0 ? { policies: policyCards } : {},
|
|
17497
|
+
...divergences.length > 0 ? { divergence: divergences } : {},
|
|
17498
|
+
headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
|
|
17499
|
+
};
|
|
17500
|
+
return import_types60.IncidentCardSchema.parse(card);
|
|
17501
|
+
}
|
|
17502
|
+
|
|
17503
|
+
// src/ask.ts
|
|
17504
|
+
init_cjs_shims();
|
|
17505
|
+
var import_types61 = require("@neat.is/types");
|
|
17339
17506
|
var DEFAULT_MAX_NODES = 3;
|
|
17340
17507
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17341
17508
|
var INTENT_RULES = [
|
|
@@ -17563,7 +17730,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17563
17730
|
};
|
|
17564
17731
|
graph.forEachNode((id, attrs) => {
|
|
17565
17732
|
const node = attrs;
|
|
17566
|
-
if (node.type ===
|
|
17733
|
+
if (node.type === import_types61.NodeType.FrontierNode) return;
|
|
17567
17734
|
const name = nodeName(node);
|
|
17568
17735
|
const body = idBody(id);
|
|
17569
17736
|
const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
|
|
@@ -17582,7 +17749,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17582
17749
|
const res = await searchIndex.search(question, 10);
|
|
17583
17750
|
if (res.provider !== "substring") {
|
|
17584
17751
|
for (const m of res.matches) {
|
|
17585
|
-
if (m.node.type ===
|
|
17752
|
+
if (m.node.type === import_types61.NodeType.FrontierNode) continue;
|
|
17586
17753
|
const already = best.get(m.node.id);
|
|
17587
17754
|
if (!already && m.score < EMBED_MIN_SCORE) continue;
|
|
17588
17755
|
consider({
|
|
@@ -17620,7 +17787,7 @@ function edgeSignalNote(e) {
|
|
|
17620
17787
|
function buildRootCauseSection(graph, node, incidents, now) {
|
|
17621
17788
|
const result = getRootCause(graph, node, void 0, incidents, { now });
|
|
17622
17789
|
if (!result) return null;
|
|
17623
|
-
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ??
|
|
17790
|
+
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types61.Provenance.OBSERVED;
|
|
17624
17791
|
const facts = [
|
|
17625
17792
|
{
|
|
17626
17793
|
text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
|
|
@@ -17670,7 +17837,7 @@ function buildObservedSection(graph, node) {
|
|
|
17670
17837
|
if (result.observed && result.inboundObservedCount > 0) {
|
|
17671
17838
|
facts.push({
|
|
17672
17839
|
text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
|
|
17673
|
-
provenance:
|
|
17840
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17674
17841
|
});
|
|
17675
17842
|
} else {
|
|
17676
17843
|
return null;
|
|
@@ -17698,7 +17865,7 @@ function buildIncidentsSection(node, incidents) {
|
|
|
17698
17865
|
const facts = ordered.map((ev) => ({
|
|
17699
17866
|
text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
|
|
17700
17867
|
// ErrorEvents are observation records — OBSERVED by definition.
|
|
17701
|
-
provenance:
|
|
17868
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17702
17869
|
}));
|
|
17703
17870
|
return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
|
|
17704
17871
|
}
|
|
@@ -17758,7 +17925,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17758
17925
|
}
|
|
17759
17926
|
const byKey = /* @__PURE__ */ new Map();
|
|
17760
17927
|
for (const ev of incidents) {
|
|
17761
|
-
const key = ev.affectedNode || (0,
|
|
17928
|
+
const key = ev.affectedNode || (0, import_types61.serviceId)(ev.service);
|
|
17762
17929
|
const cur = byKey.get(key);
|
|
17763
17930
|
if (!cur) {
|
|
17764
17931
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17773,7 +17940,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17773
17940
|
const rows = [...byKey.values()].sort((a, b) => b.count - a.count || b.latest.localeCompare(a.latest) || a.key.localeCompare(b.key)).slice(0, MAX_FACTS_PER_SECTION);
|
|
17774
17941
|
const facts = rows.map((r) => ({
|
|
17775
17942
|
text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
|
|
17776
|
-
provenance:
|
|
17943
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17777
17944
|
}));
|
|
17778
17945
|
return {
|
|
17779
17946
|
heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
|
|
@@ -17786,7 +17953,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17786
17953
|
graph.forEachNode((_id, attrs) => {
|
|
17787
17954
|
const node = attrs;
|
|
17788
17955
|
nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
|
|
17789
|
-
if (node.type ===
|
|
17956
|
+
if (node.type === import_types61.NodeType.ServiceNode) services.push(node.id);
|
|
17790
17957
|
});
|
|
17791
17958
|
const edgeByProv = /* @__PURE__ */ new Map();
|
|
17792
17959
|
graph.forEachEdge((_id, attrs) => {
|
|
@@ -17798,10 +17965,10 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17798
17965
|
const shapeFacts = [
|
|
17799
17966
|
{ text: `${graph.order} nodes, ${graph.size} edges` },
|
|
17800
17967
|
{
|
|
17801
|
-
text: `${count(
|
|
17968
|
+
text: `${count(import_types61.NodeType.ServiceNode)} services, ${count(import_types61.NodeType.FileNode)} files, ${count(import_types61.NodeType.SymbolNode)} symbols, ${count(import_types61.NodeType.DatabaseNode)} databases`
|
|
17802
17969
|
}
|
|
17803
17970
|
];
|
|
17804
|
-
for (const p of [
|
|
17971
|
+
for (const p of [import_types61.Provenance.EXTRACTED, import_types61.Provenance.OBSERVED, import_types61.Provenance.INFERRED, import_types61.Provenance.STALE]) {
|
|
17805
17972
|
const n = edgeByProv.get(p) ?? 0;
|
|
17806
17973
|
if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
|
|
17807
17974
|
}
|
|
@@ -17818,7 +17985,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17818
17985
|
if (incidents && incidents.length > 0) {
|
|
17819
17986
|
const incCount = /* @__PURE__ */ new Map();
|
|
17820
17987
|
for (const ev of incidents) {
|
|
17821
|
-
const key = ev.affectedNode || (0,
|
|
17988
|
+
const key = ev.affectedNode || (0, import_types61.serviceId)(ev.service);
|
|
17822
17989
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17823
17990
|
}
|
|
17824
17991
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17826,7 +17993,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17826
17993
|
heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
|
|
17827
17994
|
facts: top.map(([k, n]) => ({
|
|
17828
17995
|
text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
|
|
17829
|
-
provenance:
|
|
17996
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17830
17997
|
}))
|
|
17831
17998
|
});
|
|
17832
17999
|
}
|
|
@@ -17962,7 +18129,7 @@ async function askGraph(graph, question, opts = {}) {
|
|
|
17962
18129
|
const provSet = /* @__PURE__ */ new Set();
|
|
17963
18130
|
for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
|
|
17964
18131
|
const confidence = sections[0]?.facts[0]?.confidence;
|
|
17965
|
-
return
|
|
18132
|
+
return import_types61.AskResultSchema.parse({
|
|
17966
18133
|
question,
|
|
17967
18134
|
intent,
|
|
17968
18135
|
matched,
|
|
@@ -18109,7 +18276,7 @@ init_cjs_shims();
|
|
|
18109
18276
|
var import_node_fs39 = require("fs");
|
|
18110
18277
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
18111
18278
|
var import_node_path74 = __toESM(require("path"), 1);
|
|
18112
|
-
var
|
|
18279
|
+
var import_types62 = require("@neat.is/types");
|
|
18113
18280
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
18114
18281
|
var LOCK_RETRY_MS = 50;
|
|
18115
18282
|
function neatHome() {
|
|
@@ -18363,10 +18530,10 @@ async function readRegistry() {
|
|
|
18363
18530
|
throw err;
|
|
18364
18531
|
}
|
|
18365
18532
|
const parsed = JSON.parse(raw);
|
|
18366
|
-
return
|
|
18533
|
+
return import_types62.RegistryFileSchema.parse(parsed);
|
|
18367
18534
|
}
|
|
18368
18535
|
async function writeRegistry(reg) {
|
|
18369
|
-
const validated =
|
|
18536
|
+
const validated = import_types62.RegistryFileSchema.parse(reg);
|
|
18370
18537
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
18371
18538
|
}
|
|
18372
18539
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -18879,15 +19046,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
18879
19046
|
|
|
18880
19047
|
// src/connectors/index.ts
|
|
18881
19048
|
init_cjs_shims();
|
|
18882
|
-
var
|
|
19049
|
+
var import_types63 = require("@neat.is/types");
|
|
18883
19050
|
var NO_ENV = "unknown";
|
|
18884
19051
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
18885
19052
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18886
19053
|
const sites = [];
|
|
18887
19054
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
18888
19055
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18889
|
-
if (edge.provenance !==
|
|
18890
|
-
const parsed = (0,
|
|
19056
|
+
if (edge.provenance !== import_types63.Provenance.EXTRACTED) continue;
|
|
19057
|
+
const parsed = (0, import_types63.parseFileId)(edge.source);
|
|
18891
19058
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
18892
19059
|
const site = { relPath: edge.evidence.file };
|
|
18893
19060
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -18898,7 +19065,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
18898
19065
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
18899
19066
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18900
19067
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
18901
|
-
if (attrs.type !==
|
|
19068
|
+
if (attrs.type !== import_types63.NodeType.RouteNode || !attrs.path) return void 0;
|
|
18902
19069
|
const site = { relPath: attrs.path };
|
|
18903
19070
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
18904
19071
|
return site;
|
|
@@ -18928,7 +19095,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
18928
19095
|
errorMessage: signal.incident.errorMessage,
|
|
18929
19096
|
...signal.incident.attributes ? { attributes: signal.incident.attributes } : {},
|
|
18930
19097
|
affectedNode: resolved.targetNodeId
|
|
18931
|
-
});
|
|
19098
|
+
}, ctx.project);
|
|
18932
19099
|
continue;
|
|
18933
19100
|
}
|
|
18934
19101
|
if (resolved.ensureInfraNode) {
|
|
@@ -19510,23 +19677,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
19510
19677
|
|
|
19511
19678
|
// src/connectors/supabase/resolve.ts
|
|
19512
19679
|
init_cjs_shims();
|
|
19513
|
-
var
|
|
19680
|
+
var import_types65 = require("@neat.is/types");
|
|
19514
19681
|
function createSupabaseResolveTarget(graph, config) {
|
|
19515
19682
|
return (signal, _ctx) => {
|
|
19516
19683
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
19517
19684
|
return null;
|
|
19518
19685
|
}
|
|
19519
|
-
const subResourceId = (0,
|
|
19686
|
+
const subResourceId = (0, import_types65.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
19520
19687
|
if (graph.hasNode(subResourceId)) {
|
|
19521
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
19688
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19522
19689
|
}
|
|
19523
|
-
const bareResourceId = (0,
|
|
19690
|
+
const bareResourceId = (0, import_types65.infraId)(signal.targetKind, signal.targetName);
|
|
19524
19691
|
if (graph.hasNode(bareResourceId)) {
|
|
19525
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
19692
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19526
19693
|
}
|
|
19527
|
-
const projectLevelId = (0,
|
|
19694
|
+
const projectLevelId = (0, import_types65.infraId)("supabase", config.nodeRef);
|
|
19528
19695
|
if (graph.hasNode(projectLevelId)) {
|
|
19529
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
19696
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19530
19697
|
}
|
|
19531
19698
|
return null;
|
|
19532
19699
|
};
|
|
@@ -19619,7 +19786,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
19619
19786
|
|
|
19620
19787
|
// src/connectors/railway/index.ts
|
|
19621
19788
|
init_cjs_shims();
|
|
19622
|
-
var
|
|
19789
|
+
var import_types69 = require("@neat.is/types");
|
|
19623
19790
|
|
|
19624
19791
|
// src/connectors/railway/client.ts
|
|
19625
19792
|
init_cjs_shims();
|
|
@@ -19770,7 +19937,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
19770
19937
|
const out = [];
|
|
19771
19938
|
graph.forEachNode((_id, attrs) => {
|
|
19772
19939
|
const node = attrs;
|
|
19773
|
-
if (node.type !==
|
|
19940
|
+
if (node.type !== import_types69.NodeType.RouteNode) return;
|
|
19774
19941
|
const route = attrs;
|
|
19775
19942
|
if (route.service !== serviceName) return;
|
|
19776
19943
|
out.push({
|
|
@@ -19874,12 +20041,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19874
20041
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19875
20042
|
if (!serviceName) return null;
|
|
19876
20043
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19877
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
20044
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types69.EdgeType.CALLS };
|
|
19878
20045
|
}
|
|
19879
20046
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19880
20047
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19881
20048
|
if (!peerName) return null;
|
|
19882
|
-
return { targetNodeId: (0,
|
|
20049
|
+
return { targetNodeId: (0, import_types69.serviceId)(peerName), serviceName, edgeType: import_types69.EdgeType.CONNECTS_TO };
|
|
19883
20050
|
}
|
|
19884
20051
|
return null;
|
|
19885
20052
|
};
|
|
@@ -20067,7 +20234,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
20067
20234
|
|
|
20068
20235
|
// src/connectors/firebase/resolve.ts
|
|
20069
20236
|
init_cjs_shims();
|
|
20070
|
-
var
|
|
20237
|
+
var import_types70 = require("@neat.is/types");
|
|
20071
20238
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
20072
20239
|
switch (resourceType) {
|
|
20073
20240
|
case "cloud_function":
|
|
@@ -20082,7 +20249,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
20082
20249
|
const entries = [];
|
|
20083
20250
|
graph.forEachNode((_id, attrs) => {
|
|
20084
20251
|
const node = attrs;
|
|
20085
|
-
if (node.type !==
|
|
20252
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
20086
20253
|
const route = attrs;
|
|
20087
20254
|
if (route.service !== serviceName) return;
|
|
20088
20255
|
entries.push({
|
|
@@ -20114,7 +20281,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
20114
20281
|
return {
|
|
20115
20282
|
targetNodeId: match.routeNodeId,
|
|
20116
20283
|
serviceName,
|
|
20117
|
-
edgeType:
|
|
20284
|
+
edgeType: import_types70.EdgeType.CALLS
|
|
20118
20285
|
};
|
|
20119
20286
|
};
|
|
20120
20287
|
}
|
|
@@ -20141,7 +20308,7 @@ init_cjs_shims();
|
|
|
20141
20308
|
|
|
20142
20309
|
// src/connectors/cloudflare/connector.ts
|
|
20143
20310
|
init_cjs_shims();
|
|
20144
|
-
var
|
|
20311
|
+
var import_types72 = require("@neat.is/types");
|
|
20145
20312
|
|
|
20146
20313
|
// src/connectors/cloudflare/client.ts
|
|
20147
20314
|
init_cjs_shims();
|
|
@@ -20305,7 +20472,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
20305
20472
|
graph.forEachNode((id, attrs) => {
|
|
20306
20473
|
if (found) return;
|
|
20307
20474
|
const a = attrs;
|
|
20308
|
-
if (a.type ===
|
|
20475
|
+
if (a.type === import_types72.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
20309
20476
|
found = id;
|
|
20310
20477
|
}
|
|
20311
20478
|
});
|
|
@@ -20317,7 +20484,7 @@ function findMatchingRouteNode(graph, serviceName, method, path94) {
|
|
|
20317
20484
|
graph.forEachNode((id, attrs) => {
|
|
20318
20485
|
if (found) return;
|
|
20319
20486
|
const a = attrs;
|
|
20320
|
-
if (a.type !==
|
|
20487
|
+
if (a.type !== import_types72.NodeType.RouteNode || a.service !== serviceName) return;
|
|
20321
20488
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
20322
20489
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
20323
20490
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -20336,11 +20503,11 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20336
20503
|
};
|
|
20337
20504
|
const mapping = config.workers?.[scriptName];
|
|
20338
20505
|
if (mapping) {
|
|
20339
|
-
const wholeFileId = (0,
|
|
20506
|
+
const wholeFileId = (0, import_types72.fileId)(mapping.service, mapping.entryFile);
|
|
20340
20507
|
return {
|
|
20341
20508
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
20342
20509
|
serviceName: mapping.service,
|
|
20343
|
-
edgeType:
|
|
20510
|
+
edgeType: import_types72.EdgeType.CALLS
|
|
20344
20511
|
};
|
|
20345
20512
|
}
|
|
20346
20513
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -20349,13 +20516,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20349
20516
|
return {
|
|
20350
20517
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
20351
20518
|
serviceName: fileNode.service,
|
|
20352
|
-
edgeType:
|
|
20519
|
+
edgeType: import_types72.EdgeType.CALLS
|
|
20353
20520
|
};
|
|
20354
20521
|
}
|
|
20355
20522
|
return {
|
|
20356
|
-
targetNodeId: (0,
|
|
20523
|
+
targetNodeId: (0, import_types72.infraId)("cloudflare-worker", scriptName),
|
|
20357
20524
|
serviceName: scriptName,
|
|
20358
|
-
edgeType:
|
|
20525
|
+
edgeType: import_types72.EdgeType.CALLS,
|
|
20359
20526
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
20360
20527
|
};
|
|
20361
20528
|
};
|
|
@@ -20551,14 +20718,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
20551
20718
|
|
|
20552
20719
|
// src/connectors/neon/resolve.ts
|
|
20553
20720
|
init_cjs_shims();
|
|
20554
|
-
var
|
|
20721
|
+
var import_types76 = require("@neat.is/types");
|
|
20555
20722
|
function createNeonResolveTarget(config) {
|
|
20556
20723
|
return (signal) => {
|
|
20557
20724
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20558
20725
|
return {
|
|
20559
|
-
targetNodeId: (0,
|
|
20726
|
+
targetNodeId: (0, import_types76.infraId)("sql-table", signal.targetName),
|
|
20560
20727
|
serviceName: config.serviceName,
|
|
20561
|
-
edgeType:
|
|
20728
|
+
edgeType: import_types76.EdgeType.CALLS,
|
|
20562
20729
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
20563
20730
|
};
|
|
20564
20731
|
};
|
|
@@ -20739,14 +20906,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20739
20906
|
|
|
20740
20907
|
// src/connectors/cloud-run/resolve.ts
|
|
20741
20908
|
init_cjs_shims();
|
|
20742
|
-
var
|
|
20909
|
+
var import_types80 = require("@neat.is/types");
|
|
20743
20910
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20744
20911
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20745
20912
|
let found = null;
|
|
20746
20913
|
graph.forEachNode((_id, attrs) => {
|
|
20747
20914
|
if (found) return;
|
|
20748
20915
|
const node = attrs;
|
|
20749
|
-
if (node.type !==
|
|
20916
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
20750
20917
|
const route = attrs;
|
|
20751
20918
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20752
20919
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20771,13 +20938,13 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20771
20938
|
normalizePathTemplate(path94)
|
|
20772
20939
|
);
|
|
20773
20940
|
if (routeNodeId) {
|
|
20774
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20941
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types80.EdgeType.CALLS };
|
|
20775
20942
|
}
|
|
20776
20943
|
}
|
|
20777
20944
|
return {
|
|
20778
|
-
targetNodeId: (0,
|
|
20945
|
+
targetNodeId: (0, import_types80.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20779
20946
|
serviceName: mappedService ?? gcpServiceName,
|
|
20780
|
-
edgeType:
|
|
20947
|
+
edgeType: import_types80.EdgeType.CALLS,
|
|
20781
20948
|
ensureInfraNode: {
|
|
20782
20949
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20783
20950
|
name: gcpServiceName,
|
|
@@ -20959,14 +21126,14 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20959
21126
|
|
|
20960
21127
|
// src/connectors/gcp-lb/resolve.ts
|
|
20961
21128
|
init_cjs_shims();
|
|
20962
|
-
var
|
|
21129
|
+
var import_types84 = require("@neat.is/types");
|
|
20963
21130
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20964
21131
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20965
21132
|
let found = null;
|
|
20966
21133
|
graph.forEachNode((_id, attrs) => {
|
|
20967
21134
|
if (found) return;
|
|
20968
21135
|
const node = attrs;
|
|
20969
|
-
if (node.type !==
|
|
21136
|
+
if (node.type !== import_types84.NodeType.RouteNode) return;
|
|
20970
21137
|
const route = attrs;
|
|
20971
21138
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20972
21139
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20991,13 +21158,13 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20991
21158
|
normalizePathTemplate(path94)
|
|
20992
21159
|
);
|
|
20993
21160
|
if (routeNodeId) {
|
|
20994
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
21161
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types84.EdgeType.CALLS };
|
|
20995
21162
|
}
|
|
20996
21163
|
}
|
|
20997
21164
|
return {
|
|
20998
|
-
targetNodeId: (0,
|
|
21165
|
+
targetNodeId: (0, import_types84.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20999
21166
|
serviceName: mappedService ?? backendServiceName,
|
|
21000
|
-
edgeType:
|
|
21167
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
21001
21168
|
ensureInfraNode: {
|
|
21002
21169
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
21003
21170
|
name: backendServiceName,
|
|
@@ -21038,7 +21205,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
21038
21205
|
|
|
21039
21206
|
// src/connectors/render/index.ts
|
|
21040
21207
|
init_cjs_shims();
|
|
21041
|
-
var
|
|
21208
|
+
var import_types87 = require("@neat.is/types");
|
|
21042
21209
|
|
|
21043
21210
|
// src/connectors/render/types.ts
|
|
21044
21211
|
init_cjs_shims();
|
|
@@ -21116,7 +21283,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
21116
21283
|
const out = [];
|
|
21117
21284
|
graph.forEachNode((_id, attrs) => {
|
|
21118
21285
|
const node = attrs;
|
|
21119
|
-
if (node.type !==
|
|
21286
|
+
if (node.type !== import_types87.NodeType.RouteNode) return;
|
|
21120
21287
|
const route = attrs;
|
|
21121
21288
|
if (route.service !== serviceName) return;
|
|
21122
21289
|
out.push({
|
|
@@ -21201,7 +21368,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
21201
21368
|
function createRenderResolveTarget(config) {
|
|
21202
21369
|
return (signal) => {
|
|
21203
21370
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
21204
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
21371
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types87.EdgeType.CALLS };
|
|
21205
21372
|
}
|
|
21206
21373
|
return null;
|
|
21207
21374
|
};
|
|
@@ -21339,21 +21506,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
21339
21506
|
|
|
21340
21507
|
// src/connectors/planetscale/resolve.ts
|
|
21341
21508
|
init_cjs_shims();
|
|
21342
|
-
var
|
|
21509
|
+
var import_types91 = require("@neat.is/types");
|
|
21343
21510
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
21344
21511
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
21345
21512
|
const databaseName = `${config.organization}/${config.database}`;
|
|
21346
21513
|
return (signal, _ctx) => {
|
|
21347
21514
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
21348
|
-
const tableId = (0,
|
|
21515
|
+
const tableId = (0, import_types91.infraId)("sql-table", signal.targetName);
|
|
21349
21516
|
if (graph.hasNode(tableId)) {
|
|
21350
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
21517
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types91.EdgeType.CALLS };
|
|
21351
21518
|
}
|
|
21352
|
-
const providerId = (0,
|
|
21519
|
+
const providerId = (0, import_types91.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
21353
21520
|
return {
|
|
21354
21521
|
targetNodeId: providerId,
|
|
21355
21522
|
serviceName: config.serviceName,
|
|
21356
|
-
edgeType:
|
|
21523
|
+
edgeType: import_types91.EdgeType.CALLS,
|
|
21357
21524
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
21358
21525
|
};
|
|
21359
21526
|
};
|
|
@@ -21618,7 +21785,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
21618
21785
|
|
|
21619
21786
|
// src/connectors/eas/resolve.ts
|
|
21620
21787
|
init_cjs_shims();
|
|
21621
|
-
var
|
|
21788
|
+
var import_types96 = require("@neat.is/types");
|
|
21622
21789
|
var NO_ENV2 = "unknown";
|
|
21623
21790
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
21624
21791
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -21634,8 +21801,8 @@ function configBasenamesForPhase(phase) {
|
|
|
21634
21801
|
function configNodeService(graph, configNodeId) {
|
|
21635
21802
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
21636
21803
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
21637
|
-
if (edge.type !==
|
|
21638
|
-
const parsed = (0,
|
|
21804
|
+
if (edge.type !== import_types96.EdgeType.CONFIGURED_BY) continue;
|
|
21805
|
+
const parsed = (0, import_types96.parseFileId)(edge.source);
|
|
21639
21806
|
if (parsed) return parsed.service;
|
|
21640
21807
|
}
|
|
21641
21808
|
return null;
|
|
@@ -21646,7 +21813,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
21646
21813
|
graph.forEachNode((id, attrs) => {
|
|
21647
21814
|
if (scoped) return;
|
|
21648
21815
|
const node = attrs;
|
|
21649
|
-
if (node.type !==
|
|
21816
|
+
if (node.type !== import_types96.NodeType.ConfigNode) return;
|
|
21650
21817
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
21651
21818
|
if (anyMatch === null) anyMatch = id;
|
|
21652
21819
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -21663,13 +21830,13 @@ function createEasResolveTarget(graph) {
|
|
|
21663
21830
|
if (basenames.length > 0) {
|
|
21664
21831
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
21665
21832
|
if (configNodeId) {
|
|
21666
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21833
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types96.EdgeType.CALLS };
|
|
21667
21834
|
}
|
|
21668
21835
|
}
|
|
21669
21836
|
return {
|
|
21670
21837
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
21671
21838
|
serviceName,
|
|
21672
|
-
edgeType:
|
|
21839
|
+
edgeType: import_types96.EdgeType.CALLS
|
|
21673
21840
|
};
|
|
21674
21841
|
};
|
|
21675
21842
|
}
|
|
@@ -22287,6 +22454,7 @@ async function startConnectorPolling(input) {
|
|
|
22287
22454
|
registration.connector,
|
|
22288
22455
|
{
|
|
22289
22456
|
projectDir: input.projectDir,
|
|
22457
|
+
project: input.project,
|
|
22290
22458
|
credentials: registration.credentials,
|
|
22291
22459
|
...input.errorsPath ? { errorsPath: input.errorsPath } : {}
|
|
22292
22460
|
},
|
|
@@ -22509,11 +22677,11 @@ function registerRoutes(scope, ctx) {
|
|
|
22509
22677
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22510
22678
|
const parsed = [];
|
|
22511
22679
|
for (const c of candidates) {
|
|
22512
|
-
const r =
|
|
22680
|
+
const r = import_types99.DivergenceTypeSchema.safeParse(c);
|
|
22513
22681
|
if (!r.success) {
|
|
22514
22682
|
return reply.code(400).send({
|
|
22515
22683
|
error: `unknown divergence type "${c}"`,
|
|
22516
|
-
allowed:
|
|
22684
|
+
allowed: import_types99.DivergenceTypeSchema.options
|
|
22517
22685
|
});
|
|
22518
22686
|
}
|
|
22519
22687
|
parsed.push(r.data);
|
|
@@ -22630,6 +22798,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22630
22798
|
reg.connector,
|
|
22631
22799
|
{
|
|
22632
22800
|
projectDir: proj.scanPath ?? "",
|
|
22801
|
+
project: proj.name,
|
|
22633
22802
|
credentials: reg.credentials,
|
|
22634
22803
|
...incidentsPath ? { errorsPath: incidentsPath } : {}
|
|
22635
22804
|
},
|
|
@@ -22693,6 +22862,39 @@ function registerRoutes(scope, ctx) {
|
|
|
22693
22862
|
if (!result) return reply.code(404).send({ error: "no root cause found", id: nodeId });
|
|
22694
22863
|
return result;
|
|
22695
22864
|
});
|
|
22865
|
+
scope.get("/graph/incident-card/:nodeId", async (req, reply) => {
|
|
22866
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22867
|
+
if (!proj) return;
|
|
22868
|
+
const { nodeId } = req.params;
|
|
22869
|
+
if (!proj.graph.hasNode(nodeId)) {
|
|
22870
|
+
return reply.code(404).send({ error: "node not found", id: nodeId });
|
|
22871
|
+
}
|
|
22872
|
+
const epath = errorsPathFor(proj);
|
|
22873
|
+
const incidents = epath ? await readErrorEvents(epath) : [];
|
|
22874
|
+
let errorEvent;
|
|
22875
|
+
if (req.query.errorId) {
|
|
22876
|
+
errorEvent = incidents.find((e) => e.id === req.query.errorId);
|
|
22877
|
+
if (!errorEvent) {
|
|
22878
|
+
return reply.code(404).send({ error: "error event not found", id: req.query.errorId });
|
|
22879
|
+
}
|
|
22880
|
+
} else {
|
|
22881
|
+
const svc = nodeId.replace(/^service:/, "");
|
|
22882
|
+
errorEvent = [...incidents].filter((e) => e.affectedNode === nodeId || e.service === svc).sort((a, b) => (b.timestamp ?? "").localeCompare(a.timestamp ?? ""))[0];
|
|
22883
|
+
if (!errorEvent) {
|
|
22884
|
+
return reply.code(404).send({ error: "no incident found for node", id: nodeId });
|
|
22885
|
+
}
|
|
22886
|
+
}
|
|
22887
|
+
const policyPath = ctx.policyFilePathFor(proj);
|
|
22888
|
+
let policies = [];
|
|
22889
|
+
if (policyPath) {
|
|
22890
|
+
try {
|
|
22891
|
+
policies = await loadPolicyFile(policyPath);
|
|
22892
|
+
} catch {
|
|
22893
|
+
policies = [];
|
|
22894
|
+
}
|
|
22895
|
+
}
|
|
22896
|
+
return buildIncidentCard(proj.graph, errorEvent, incidents, policies);
|
|
22897
|
+
});
|
|
22696
22898
|
scope.get("/graph/blast-radius/:nodeId", async (req, reply) => {
|
|
22697
22899
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22698
22900
|
if (!proj) return;
|
|
@@ -22875,7 +23077,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22875
23077
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
22876
23078
|
let violations = await log.readAll();
|
|
22877
23079
|
if (req.query.severity) {
|
|
22878
|
-
const sev =
|
|
23080
|
+
const sev = import_types99.PolicySeveritySchema.safeParse(req.query.severity);
|
|
22879
23081
|
if (!sev.success) {
|
|
22880
23082
|
return reply.code(400).send({
|
|
22881
23083
|
error: "invalid severity",
|
|
@@ -22914,7 +23116,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22914
23116
|
scope.post("/policies/check", async (req, reply) => {
|
|
22915
23117
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22916
23118
|
if (!proj) return;
|
|
22917
|
-
const parsed =
|
|
23119
|
+
const parsed = import_types99.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
22918
23120
|
if (!parsed.success) {
|
|
22919
23121
|
return reply.code(400).send({
|
|
22920
23122
|
error: "invalid /policies/check body",
|
|
@@ -23247,7 +23449,7 @@ var import_node_fs41 = require("fs");
|
|
|
23247
23449
|
var import_node_path76 = __toESM(require("path"), 1);
|
|
23248
23450
|
|
|
23249
23451
|
// src/daemon.ts
|
|
23250
|
-
var
|
|
23452
|
+
var import_types100 = require("@neat.is/types");
|
|
23251
23453
|
function daemonJsonPath(scanPath) {
|
|
23252
23454
|
return import_node_path77.default.join(scanPath, "neat-out", "daemon.json");
|
|
23253
23455
|
}
|
|
@@ -23957,7 +24159,7 @@ async function startWatch(graph, opts) {
|
|
|
23957
24159
|
writeErrorEventInline: false,
|
|
23958
24160
|
onPolicyTrigger
|
|
23959
24161
|
});
|
|
23960
|
-
const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath, graph, opts.scanPath);
|
|
24162
|
+
const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath, graph, opts.scanPath, projectName);
|
|
23961
24163
|
const otelHttp = await buildOtelReceiver({ onSpan, onErrorSpanSync });
|
|
23962
24164
|
const otelAddress = await listenSteppingOtlp(otelHttp, otelPort, host);
|
|
23963
24165
|
const boundOtelPort = portFromListenAddress(otelAddress, otelPort);
|
|
@@ -28264,7 +28466,7 @@ var import_node_path87 = __toESM(require("path"), 1);
|
|
|
28264
28466
|
|
|
28265
28467
|
// src/cli-client.ts
|
|
28266
28468
|
init_cjs_shims();
|
|
28267
|
-
var
|
|
28469
|
+
var import_types101 = require("@neat.is/types");
|
|
28268
28470
|
var HttpError = class extends Error {
|
|
28269
28471
|
constructor(status2, message, responseBody = "") {
|
|
28270
28472
|
super(message);
|
|
@@ -28406,7 +28608,7 @@ async function runBlastRadius(client, input) {
|
|
|
28406
28608
|
}
|
|
28407
28609
|
}
|
|
28408
28610
|
function formatBlastEntry(n) {
|
|
28409
|
-
const tag = n.edgeProvenance ===
|
|
28611
|
+
const tag = n.edgeProvenance === import_types101.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
28410
28612
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
28411
28613
|
}
|
|
28412
28614
|
async function runDependencies(client, input) {
|
|
@@ -28463,7 +28665,7 @@ async function runObservedDependencies(client, input) {
|
|
|
28463
28665
|
if (result.observed) {
|
|
28464
28666
|
return {
|
|
28465
28667
|
summary: `${input.nodeId} makes no outbound runtime calls, but OTel has observed it receiving traffic on ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 it's a pure receiver.`,
|
|
28466
|
-
provenance:
|
|
28668
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28467
28669
|
};
|
|
28468
28670
|
}
|
|
28469
28671
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -28473,7 +28675,7 @@ async function runObservedDependencies(client, input) {
|
|
|
28473
28675
|
return {
|
|
28474
28676
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
28475
28677
|
block: blockLines.join("\n"),
|
|
28476
|
-
provenance:
|
|
28678
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28477
28679
|
};
|
|
28478
28680
|
} catch (err) {
|
|
28479
28681
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -28527,7 +28729,7 @@ async function runIncidents(client, input) {
|
|
|
28527
28729
|
return {
|
|
28528
28730
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
28529
28731
|
block: blockLines.join("\n"),
|
|
28530
|
-
provenance:
|
|
28732
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28531
28733
|
};
|
|
28532
28734
|
} catch (err) {
|
|
28533
28735
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -28636,7 +28838,7 @@ async function runStaleEdges(client, input) {
|
|
|
28636
28838
|
return {
|
|
28637
28839
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
28638
28840
|
block: blockLines.join("\n"),
|
|
28639
|
-
provenance:
|
|
28841
|
+
provenance: import_types101.Provenance.STALE
|
|
28640
28842
|
};
|
|
28641
28843
|
}
|
|
28642
28844
|
async function runPolicies(client, input) {
|
|
@@ -29927,12 +30129,12 @@ async function runEditorCommand(clientId, args, projectDir = process.cwd()) {
|
|
|
29927
30129
|
|
|
29928
30130
|
// src/monitor.ts
|
|
29929
30131
|
init_cjs_shims();
|
|
29930
|
-
var
|
|
30132
|
+
var import_types102 = require("@neat.is/types");
|
|
29931
30133
|
var OBSERVED_DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
29932
|
-
|
|
29933
|
-
|
|
29934
|
-
|
|
29935
|
-
|
|
30134
|
+
import_types102.EdgeType.CALLS,
|
|
30135
|
+
import_types102.EdgeType.CONNECTS_TO,
|
|
30136
|
+
import_types102.EdgeType.PUBLISHES_TO,
|
|
30137
|
+
import_types102.EdgeType.CONSUMES_FROM
|
|
29936
30138
|
]);
|
|
29937
30139
|
function divergenceKey(d) {
|
|
29938
30140
|
const column = "column" in d && d.column ? d.column : "";
|
|
@@ -29993,7 +30195,7 @@ function formatDivergenceLine2(d) {
|
|
|
29993
30195
|
}
|
|
29994
30196
|
}
|
|
29995
30197
|
function formatStaleLine(edgeId) {
|
|
29996
|
-
const parsed = (0,
|
|
30198
|
+
const parsed = (0, import_types102.parseEdgeId)(edgeId);
|
|
29997
30199
|
if (parsed) {
|
|
29998
30200
|
return `\u22EF stale ${parsed.source} \u2192 ${parsed.target} (observed edge went quiet)`;
|
|
29999
30201
|
}
|
|
@@ -30006,7 +30208,7 @@ function divergenceJson(d) {
|
|
|
30006
30208
|
return JSON.stringify({ kind: "divergence", ...d });
|
|
30007
30209
|
}
|
|
30008
30210
|
function staleJson(edgeId) {
|
|
30009
|
-
const parsed = (0,
|
|
30211
|
+
const parsed = (0, import_types102.parseEdgeId)(edgeId);
|
|
30010
30212
|
return JSON.stringify({
|
|
30011
30213
|
kind: "stale",
|
|
30012
30214
|
edgeId,
|
|
@@ -30041,6 +30243,19 @@ function formatPolicyLine(v) {
|
|
|
30041
30243
|
function policyJson(v) {
|
|
30042
30244
|
return JSON.stringify({ kind: "policy", ...v });
|
|
30043
30245
|
}
|
|
30246
|
+
function formatIncidentLine(card) {
|
|
30247
|
+
let tag = "";
|
|
30248
|
+
if (card.rootCause) {
|
|
30249
|
+
const rc = card.rootCause;
|
|
30250
|
+
const provs = rc.chain.map((h) => h.provenance).join("\xB7");
|
|
30251
|
+
const cls = rc.classification ? `${rc.classification} ` : "";
|
|
30252
|
+
tag = ` \xB7 ${cls}${rc.confidence.toFixed(2)}${provs ? ` [${provs}]` : ""}`;
|
|
30253
|
+
}
|
|
30254
|
+
return `\u2716 incident [${card.incidentKind}] ${card.headline}${tag}`;
|
|
30255
|
+
}
|
|
30256
|
+
function incidentJson(card) {
|
|
30257
|
+
return JSON.stringify(card);
|
|
30258
|
+
}
|
|
30044
30259
|
var MonitorEmitter = class {
|
|
30045
30260
|
constructor(opts) {
|
|
30046
30261
|
this.opts = opts;
|
|
@@ -30076,7 +30291,7 @@ var MonitorEmitter = class {
|
|
|
30076
30291
|
// ignores non-OBSERVED edges and non-dependency edge types (structural
|
|
30077
30292
|
// ownership), so only real runtime dependencies reach stdout.
|
|
30078
30293
|
emitObservedEdge(edge) {
|
|
30079
|
-
if (edge.provenance !==
|
|
30294
|
+
if (edge.provenance !== import_types102.Provenance.OBSERVED) return false;
|
|
30080
30295
|
if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false;
|
|
30081
30296
|
const key = `edge|${edge.id}`;
|
|
30082
30297
|
if (this.seen.has(key)) return false;
|
|
@@ -30098,6 +30313,17 @@ var MonitorEmitter = class {
|
|
|
30098
30313
|
}
|
|
30099
30314
|
return emitted;
|
|
30100
30315
|
}
|
|
30316
|
+
// Emit one incident card once, keyed on the incident id. Unlike the other
|
|
30317
|
+
// facts this is event-driven, not a re-read of derivable state, so there is no
|
|
30318
|
+
// baseline dump on connect — only incidents that arrive live after the monitor
|
|
30319
|
+
// is watching reach stdout.
|
|
30320
|
+
emitIncident(card) {
|
|
30321
|
+
const key = `incident|${card.id}`;
|
|
30322
|
+
if (this.seen.has(key)) return false;
|
|
30323
|
+
this.seen.add(key);
|
|
30324
|
+
this.out(this.opts.json ? incidentJson(card) : formatIncidentLine(card));
|
|
30325
|
+
return true;
|
|
30326
|
+
}
|
|
30101
30327
|
};
|
|
30102
30328
|
function parseFrame(raw) {
|
|
30103
30329
|
let event = "message";
|
|
@@ -30219,6 +30445,18 @@ async function runMonitor(opts) {
|
|
|
30219
30445
|
const result = await client.get(policiesPath);
|
|
30220
30446
|
emitter.emitPolicies(result);
|
|
30221
30447
|
}, debounceMs);
|
|
30448
|
+
const readIncidentCard = async (incidentId, affectedNode) => {
|
|
30449
|
+
try {
|
|
30450
|
+
const card = await client.get(
|
|
30451
|
+
projectPath2(
|
|
30452
|
+
opts.project,
|
|
30453
|
+
`/graph/incident-card/${encodeURIComponent(affectedNode)}?errorId=${encodeURIComponent(incidentId)}`
|
|
30454
|
+
)
|
|
30455
|
+
);
|
|
30456
|
+
emitter.emitIncident(card);
|
|
30457
|
+
} catch {
|
|
30458
|
+
}
|
|
30459
|
+
};
|
|
30222
30460
|
const onFrame = (frame) => {
|
|
30223
30461
|
switch (frame.event) {
|
|
30224
30462
|
case "extraction-complete":
|
|
@@ -30234,7 +30472,7 @@ async function runMonitor(opts) {
|
|
|
30234
30472
|
case "edge-added": {
|
|
30235
30473
|
const payload = safeParse(frame.data);
|
|
30236
30474
|
const edge = payload?.edge;
|
|
30237
|
-
if (edge && edge.provenance ===
|
|
30475
|
+
if (edge && edge.provenance === import_types102.Provenance.OBSERVED) {
|
|
30238
30476
|
emitter.emitObservedEdge(edge);
|
|
30239
30477
|
divergences.schedule();
|
|
30240
30478
|
}
|
|
@@ -30243,6 +30481,13 @@ async function runMonitor(opts) {
|
|
|
30243
30481
|
case "policy-violation":
|
|
30244
30482
|
policies.schedule();
|
|
30245
30483
|
break;
|
|
30484
|
+
case "incident": {
|
|
30485
|
+
const payload = safeParse(frame.data);
|
|
30486
|
+
const incidentId = payload && typeof payload.incidentId === "string" ? payload.incidentId : void 0;
|
|
30487
|
+
const affectedNode = payload && typeof payload.affectedNode === "string" ? payload.affectedNode : void 0;
|
|
30488
|
+
if (incidentId && affectedNode) void readIncidentCard(incidentId, affectedNode);
|
|
30489
|
+
break;
|
|
30490
|
+
}
|
|
30246
30491
|
default:
|
|
30247
30492
|
break;
|
|
30248
30493
|
}
|
|
@@ -30477,7 +30722,7 @@ async function runSync(opts) {
|
|
|
30477
30722
|
}
|
|
30478
30723
|
|
|
30479
30724
|
// src/cli.ts
|
|
30480
|
-
var
|
|
30725
|
+
var import_types103 = require("@neat.is/types");
|
|
30481
30726
|
function isNpxInvocation() {
|
|
30482
30727
|
if (process.env.npm_command === "exec") return true;
|
|
30483
30728
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -31561,10 +31806,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
31561
31806
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
31562
31807
|
const out = [];
|
|
31563
31808
|
for (const p of parts) {
|
|
31564
|
-
const r =
|
|
31809
|
+
const r = import_types103.DivergenceTypeSchema.safeParse(p);
|
|
31565
31810
|
if (!r.success) {
|
|
31566
31811
|
console.error(
|
|
31567
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
31812
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types103.DivergenceTypeSchema.options.join(", ")}`
|
|
31568
31813
|
);
|
|
31569
31814
|
return 2;
|
|
31570
31815
|
}
|