@neat.is/core 0.7.6 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs 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 path81 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
65
- if (exactUnauthPaths.has(path81) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path81)) {
64
+ const path82 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
65
+ if (exactUnauthPaths.has(path82) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path82)) {
66
66
  done();
67
67
  return;
68
68
  }
@@ -343,7 +343,7 @@ function pickEnv(spanAttrs, resourceAttrs) {
343
343
  return ENV_FALLBACK;
344
344
  }
345
345
  function normalizeDbSystem(attrs) {
346
- const raw = attrs["db.system"];
346
+ const raw = attrs["db.system"] ?? attrs["db.system.name"];
347
347
  if (typeof raw !== "string") return void 0;
348
348
  return raw === "mongoose" ? "mongodb" : raw;
349
349
  }
@@ -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 path81 = q === -1 ? v : v.slice(0, q);
419
- if (path81.length > 0) return path81;
418
+ const path82 = q === -1 ? v : v.slice(0, q);
419
+ if (path82.length > 0) return path82;
420
420
  }
421
421
  }
422
422
  return void 0;
@@ -435,6 +435,9 @@ function parseOtlpRequest(body) {
435
435
  for (const ss of rs.scopeSpans ?? []) {
436
436
  for (const span of ss.spans ?? []) {
437
437
  const attrs = attrsToRecord(span.attributes);
438
+ const dbSqlText = typeof attrs["db.statement"] === "string" ? attrs["db.statement"] : typeof attrs["db.query.text"] === "string" ? attrs["db.query.text"] : void 0;
439
+ const dbSystemName = normalizeDbSystem(attrs);
440
+ const directDbTable = typeof attrs["db.sql.table"] === "string" ? attrs["db.sql.table"] : dbSystemName !== "mongodb" && typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : void 0;
438
441
  const parsed = {
439
442
  service,
440
443
  resourceServiceNamePresent,
@@ -449,11 +452,11 @@ function parseOtlpRequest(body) {
449
452
  durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
450
453
  env: pickEnv(attrs, resourceAttrs),
451
454
  attributes: attrs,
452
- dbSystem: normalizeDbSystem(attrs),
455
+ dbSystem: dbSystemName,
453
456
  dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
454
457
  dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
455
- dbTable: typeof attrs["db.statement"] === "string" ? tableFromSqlStatement(attrs["db.statement"]) ?? void 0 : void 0,
456
- dbColumns: typeof attrs["db.statement"] === "string" ? columnsFromSqlStatement(attrs["db.statement"]) : void 0,
458
+ dbTable: directDbTable ?? (dbSqlText ? tableFromSqlStatement(dbSqlText) ?? void 0 : void 0),
459
+ dbColumns: dbSqlText ? columnsFromSqlStatement(dbSqlText) : void 0,
457
460
  httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
458
461
  httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
459
462
  messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
@@ -752,7 +755,7 @@ __export(cli_exports, {
752
755
  });
753
756
  module.exports = __toCommonJS(cli_exports);
754
757
  init_cjs_shims();
755
- var import_node_path80 = __toESM(require("path"), 1);
758
+ var import_node_path81 = __toESM(require("path"), 1);
756
759
  var import_node_os8 = __toESM(require("os"), 1);
757
760
  var import_node_fs46 = require("fs");
758
761
 
@@ -1322,19 +1325,19 @@ function confidenceFromMix(edges, now = Date.now()) {
1322
1325
  function longestIncomingWalk(graph, start, maxDepth) {
1323
1326
  let best = { path: [start], edges: [] };
1324
1327
  const visited = /* @__PURE__ */ new Set([start]);
1325
- function step(node, path81, edges) {
1326
- if (path81.length > best.path.length) {
1327
- best = { path: [...path81], edges: [...edges] };
1328
+ function step(node, path82, edges) {
1329
+ if (path82.length > best.path.length) {
1330
+ best = { path: [...path82], edges: [...edges] };
1328
1331
  }
1329
- if (path81.length - 1 >= maxDepth) return;
1332
+ if (path82.length - 1 >= maxDepth) return;
1330
1333
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
1331
1334
  for (const [srcId, edge] of incoming) {
1332
1335
  if (visited.has(srcId)) continue;
1333
1336
  visited.add(srcId);
1334
- path81.push(srcId);
1337
+ path82.push(srcId);
1335
1338
  edges.push(edge);
1336
- step(srcId, path81, edges);
1337
- path81.pop();
1339
+ step(srcId, path82, edges);
1340
+ path82.pop();
1338
1341
  edges.pop();
1339
1342
  visited.delete(srcId);
1340
1343
  }
@@ -1342,11 +1345,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
1342
1345
  step(start, [start], []);
1343
1346
  return best;
1344
1347
  }
1345
- function databaseRootCauseShape(graph, origin, walk8) {
1348
+ function databaseRootCauseShape(graph, origin, walk9) {
1346
1349
  const targetDb = origin;
1347
1350
  const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
1348
1351
  if (candidatePairs.length === 0) return null;
1349
- for (const id of walk8.path) {
1352
+ for (const id of walk9.path) {
1350
1353
  const owner = resolveOwningService(graph, id);
1351
1354
  if (!owner) continue;
1352
1355
  const { id: serviceId9, svc } = owner;
@@ -1373,8 +1376,8 @@ function databaseRootCauseShape(graph, origin, walk8) {
1373
1376
  }
1374
1377
  return null;
1375
1378
  }
1376
- function serviceRootCauseShape(graph, _origin, walk8) {
1377
- for (const id of walk8.path) {
1379
+ function serviceRootCauseShape(graph, _origin, walk9) {
1380
+ for (const id of walk9.path) {
1378
1381
  const owner = resolveOwningService(graph, id);
1379
1382
  if (!owner) continue;
1380
1383
  const { id: serviceId9, svc } = owner;
@@ -1410,15 +1413,15 @@ function serviceRootCauseShape(graph, _origin, walk8) {
1410
1413
  }
1411
1414
  return null;
1412
1415
  }
1413
- function fileRootCauseShape(graph, origin, walk8) {
1416
+ function fileRootCauseShape(graph, origin, walk9) {
1414
1417
  const owner = resolveOwningService(graph, origin.id);
1415
1418
  if (!owner) return null;
1416
- return serviceRootCauseShape(graph, owner.svc, walk8);
1419
+ return serviceRootCauseShape(graph, owner.svc, walk9);
1417
1420
  }
1418
- function symbolRootCauseShape(graph, origin, walk8) {
1421
+ function symbolRootCauseShape(graph, origin, walk9) {
1419
1422
  const owner = resolveOwningService(graph, origin.id);
1420
1423
  if (!owner) return null;
1421
- return serviceRootCauseShape(graph, owner.svc, walk8);
1424
+ return serviceRootCauseShape(graph, owner.svc, walk9);
1422
1425
  }
1423
1426
  var rootCauseShapes = {
1424
1427
  [import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
@@ -1431,16 +1434,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
1431
1434
  const origin = graph.getNodeAttributes(errorNodeId);
1432
1435
  const shape = rootCauseShapes[origin.type];
1433
1436
  if (shape) {
1434
- const walk8 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
1435
- const match = shape(graph, origin, walk8);
1437
+ const walk9 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
1438
+ const match = shape(graph, origin, walk9);
1436
1439
  if (match) {
1437
1440
  const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
1438
1441
  return import_types.RootCauseResultSchema.parse({
1439
1442
  rootCauseNode: match.rootCauseNode,
1440
1443
  rootCauseReason: reason,
1441
- traversalPath: walk8.path,
1442
- edgeProvenances: walk8.edges.map((e) => e.provenance),
1443
- confidence: confidenceFromMix(walk8.edges),
1444
+ traversalPath: walk9.path,
1445
+ edgeProvenances: walk9.edges.map((e) => e.provenance),
1446
+ confidence: confidenceFromMix(walk9.edges),
1444
1447
  fixRecommendation: match.fixRecommendation
1445
1448
  });
1446
1449
  }
@@ -1541,26 +1544,26 @@ function dominantFailingCall(graph, serviceId9, visited) {
1541
1544
  return best;
1542
1545
  }
1543
1546
  function followFailingCallChain(graph, originServiceId, maxDepth) {
1544
- const path81 = [originServiceId];
1547
+ const path82 = [originServiceId];
1545
1548
  const edges = [];
1546
1549
  const visited = /* @__PURE__ */ new Set([originServiceId]);
1547
1550
  let current = originServiceId;
1548
1551
  for (let depth = 0; depth < maxDepth; depth++) {
1549
1552
  const hop = dominantFailingCall(graph, current, visited);
1550
1553
  if (!hop) break;
1551
- path81.push(hop.nextService);
1554
+ path82.push(hop.nextService);
1552
1555
  edges.push(hop.edge);
1553
1556
  visited.add(hop.nextService);
1554
1557
  current = hop.nextService;
1555
1558
  }
1556
1559
  if (edges.length === 0) return null;
1557
- return { path: path81, edges, culprit: current };
1560
+ return { path: path82, edges, culprit: current };
1558
1561
  }
1559
1562
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1560
1563
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
1561
1564
  if (!chain) return null;
1562
1565
  const culprit = chain.culprit;
1563
- const path81 = [...chain.path];
1566
+ const path82 = [...chain.path];
1564
1567
  const edgeProvenances = chain.edges.map((e) => e.provenance);
1565
1568
  const baseConfidence = confidenceFromMix(chain.edges);
1566
1569
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -1568,14 +1571,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1568
1571
  if (loc) {
1569
1572
  let rootCauseNode = culprit;
1570
1573
  if (loc.fileNode) {
1571
- path81.push(loc.fileNode);
1574
+ path82.push(loc.fileNode);
1572
1575
  edgeProvenances.push(import_types.Provenance.OBSERVED);
1573
1576
  rootCauseNode = loc.fileNode;
1574
1577
  }
1575
1578
  return import_types.RootCauseResultSchema.parse({
1576
1579
  rootCauseNode,
1577
1580
  rootCauseReason: loc.rootCauseReason,
1578
- traversalPath: path81,
1581
+ traversalPath: path82,
1579
1582
  edgeProvenances,
1580
1583
  confidence,
1581
1584
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -1587,7 +1590,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1587
1590
  return import_types.RootCauseResultSchema.parse({
1588
1591
  rootCauseNode: culprit,
1589
1592
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
1590
- traversalPath: path81,
1593
+ traversalPath: path82,
1591
1594
  edgeProvenances,
1592
1595
  confidence,
1593
1596
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -2534,14 +2537,14 @@ function buildServiceHostIndex(services) {
2534
2537
  }
2535
2538
  async function walkSourceFiles(dir) {
2536
2539
  const out = [];
2537
- async function walk8(current) {
2540
+ async function walk9(current) {
2538
2541
  const entries = await import_node_fs6.promises.readdir(current, { withFileTypes: true }).catch(() => []);
2539
2542
  for (const entry2 of entries) {
2540
2543
  const full = import_node_path6.default.join(current, entry2.name);
2541
2544
  if (entry2.isDirectory()) {
2542
2545
  if (IGNORED_DIRS.has(entry2.name)) continue;
2543
2546
  if (await isPythonVenvDir(full)) continue;
2544
- await walk8(full);
2547
+ await walk9(full);
2545
2548
  } else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path6.default.extname(entry2.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
2546
2549
  // would attribute our instrumentation imports to the user's service.
2547
2550
  !isNeatAuthoredSourceFile(entry2.name)) {
@@ -2549,7 +2552,7 @@ async function walkSourceFiles(dir) {
2549
2552
  }
2550
2553
  }
2551
2554
  }
2552
- await walk8(dir);
2555
+ await walk9(dir);
2553
2556
  return out;
2554
2557
  }
2555
2558
  async function loadSourceFiles(dir) {
@@ -3062,8 +3065,9 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
3062
3065
  "all"
3063
3066
  ]);
3064
3067
  var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
3068
+ var NET_HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
3065
3069
  var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
3066
- function ginRoutesFromSource(source, parser) {
3070
+ function goRouterRoutesFromSource(source, parser, framework) {
3067
3071
  const tree = parseSource2(parser, source);
3068
3072
  const prefixes = /* @__PURE__ */ new Map();
3069
3073
  const out = [];
@@ -3073,10 +3077,12 @@ function ginRoutesFromSource(source, parser) {
3073
3077
  const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
3074
3078
  if (name && value?.type === "call_expression") {
3075
3079
  const fn2 = value.childForFieldName("function");
3076
- const field = fn2?.childForFieldName("field")?.text;
3077
- const first2 = value.childForFieldName("arguments")?.namedChild(0);
3078
- if (field === "Group" && first2?.type === "interpreted_string_literal") {
3079
- prefixes.set(name, first2.text.slice(1, -1));
3080
+ if (fn2?.childForFieldName("field")?.text === "Group") {
3081
+ const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
3082
+ if (leaf2 !== null) {
3083
+ const parent = fn2.childForFieldName("operand")?.text ?? "";
3084
+ prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
3085
+ }
3080
3086
  }
3081
3087
  }
3082
3088
  return;
@@ -3087,18 +3093,127 @@ function ginRoutesFromSource(source, parser) {
3087
3093
  const method = fn.childForFieldName("field")?.text?.toUpperCase();
3088
3094
  if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
3089
3095
  const receiver = fn.childForFieldName("operand")?.text ?? "";
3090
- const first = node.childForFieldName("arguments")?.namedChild(0);
3091
- if (first?.type !== "interpreted_string_literal") return;
3092
- const leaf = first.text.slice(1, -1);
3096
+ const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
3097
+ if (leaf === null) return;
3093
3098
  out.push({
3094
- method: method === "ALL" ? "ALL" : method,
3099
+ method,
3095
3100
  pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
3096
3101
  line: node.startPosition.row + 1,
3097
- framework: "gin"
3102
+ framework
3098
3103
  });
3099
3104
  });
3100
3105
  return out;
3101
3106
  }
3107
+ function goStringLiteral(node) {
3108
+ if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
3109
+ return node.text.slice(1, -1);
3110
+ }
3111
+ return null;
3112
+ }
3113
+ function ginRoutesFromSource(source, parser) {
3114
+ return goRouterRoutesFromSource(source, parser, "gin");
3115
+ }
3116
+ function echoRoutesFromSource(source, parser) {
3117
+ return goRouterRoutesFromSource(source, parser, "echo");
3118
+ }
3119
+ function fiberRoutesFromSource(source, parser) {
3120
+ return goRouterRoutesFromSource(source, parser, "fiber");
3121
+ }
3122
+ function chiRoutesFromSource(source, parser) {
3123
+ const tree = parseSource2(parser, source);
3124
+ const out = [];
3125
+ chiWalk(tree.rootNode, "", out);
3126
+ return out;
3127
+ }
3128
+ function stripChiRegex(path82) {
3129
+ return path82.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
3130
+ }
3131
+ function chiWalk(node, prefix, out) {
3132
+ for (let i = 0; i < node.namedChildCount; i++) {
3133
+ const child = node.namedChild(i);
3134
+ if (child) chiHandle(child, prefix, out);
3135
+ }
3136
+ }
3137
+ function chiHandle(node, prefix, out) {
3138
+ if (node.type === "call_expression") {
3139
+ const fn = node.childForFieldName("function");
3140
+ if (fn?.type === "selector_expression") {
3141
+ const field = fn.childForFieldName("field")?.text;
3142
+ const args = node.childForFieldName("arguments");
3143
+ if (field === "Route") {
3144
+ const leaf = goStringLiteral(args?.namedChild(0));
3145
+ const closure = args?.namedChild(1);
3146
+ if (leaf !== null && closure?.type === "func_literal") {
3147
+ const body = closure.childForFieldName("body");
3148
+ if (body) chiWalk(body, prefix + leaf, out);
3149
+ }
3150
+ return;
3151
+ }
3152
+ if (field === "Group") {
3153
+ const closure = args?.namedChild(0);
3154
+ if (closure?.type === "func_literal") {
3155
+ const body = closure.childForFieldName("body");
3156
+ if (body) chiWalk(body, prefix, out);
3157
+ }
3158
+ return;
3159
+ }
3160
+ if (field === "Mount") {
3161
+ return;
3162
+ }
3163
+ if (field && ROUTER_METHODS.has(field.toLowerCase())) {
3164
+ const leaf = goStringLiteral(args?.namedChild(0));
3165
+ if (leaf !== null) {
3166
+ out.push({
3167
+ method: field.toUpperCase(),
3168
+ pathTemplate: canonicalizeTemplate(stripChiRegex(prefix + leaf)),
3169
+ line: node.startPosition.row + 1,
3170
+ framework: "chi"
3171
+ });
3172
+ }
3173
+ return;
3174
+ }
3175
+ }
3176
+ }
3177
+ chiWalk(node, prefix, out);
3178
+ }
3179
+ function netHttpRoutesFromSource(source, parser) {
3180
+ const tree = parseSource2(parser, source);
3181
+ if (!goImportsNetHttp(tree.rootNode)) return [];
3182
+ const out = [];
3183
+ walk(tree.rootNode, (node) => {
3184
+ if (node.type !== "call_expression") return;
3185
+ const fn = node.childForFieldName("function");
3186
+ if (fn?.type !== "selector_expression") return;
3187
+ const field = fn.childForFieldName("field")?.text;
3188
+ if (field !== "HandleFunc" && field !== "Handle") return;
3189
+ const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
3190
+ if (leaf === null) return;
3191
+ const sp = leaf.indexOf(" ");
3192
+ if (sp < 0) return;
3193
+ const method = leaf.slice(0, sp);
3194
+ const rest = leaf.slice(sp + 1);
3195
+ if (!NET_HTTP_METHODS.has(method)) return;
3196
+ if (!rest.startsWith("/")) return;
3197
+ out.push({
3198
+ method,
3199
+ pathTemplate: canonicalizeTemplate(rest),
3200
+ line: node.startPosition.row + 1,
3201
+ framework: "net/http"
3202
+ });
3203
+ });
3204
+ return out;
3205
+ }
3206
+ function goImportsNetHttp(root) {
3207
+ let found = false;
3208
+ walk(root, (node) => {
3209
+ if (found || node.type !== "import_spec") return;
3210
+ for (let i = 0; i < node.namedChildCount; i++) {
3211
+ const child = node.namedChild(i);
3212
+ if (goStringLiteral(child) === "net/http") found = true;
3213
+ }
3214
+ });
3215
+ return found;
3216
+ }
3102
3217
  var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
3103
3218
  var NESTJS_METHODS = /* @__PURE__ */ new Map([
3104
3219
  ["Get", "GET"],
@@ -3683,9 +3798,9 @@ function rubyRocketRoute(args) {
3683
3798
  if (!pair || pair.type !== "pair") continue;
3684
3799
  const k = pair.childForFieldName("key");
3685
3800
  if (k?.type !== "string") continue;
3686
- const path81 = rubyLiteral(k);
3687
- if (path81 === null) continue;
3688
- return { path: path81, target: rubyLiteral(pair.childForFieldName("value")) };
3801
+ const path82 = rubyLiteral(k);
3802
+ if (path82 === null) continue;
3803
+ return { path: path82, target: rubyLiteral(pair.childForFieldName("value")) };
3689
3804
  }
3690
3805
  return null;
3691
3806
  }
@@ -4362,9 +4477,13 @@ async function addRoutes(graph, services) {
4362
4477
  const hasFlask = deps["flask"] !== void 0;
4363
4478
  const hasDjango = deps["django"] !== void 0;
4364
4479
  const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
4480
+ const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
4481
+ const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
4482
+ const hasChi = deps["github.com/go-chi/chi/v5"] !== void 0 || deps["github.com/go-chi/chi"] !== void 0;
4483
+ const isGoService = service.node.language === "go";
4365
4484
  const hasRails = deps["rails"] !== void 0;
4366
4485
  const hasLaravel = deps["laravel/framework"] !== void 0;
4367
- if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
4486
+ if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel)
4368
4487
  continue;
4369
4488
  const files = await loadSourceFiles(service.dir);
4370
4489
  const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
@@ -4388,7 +4507,12 @@ async function addRoutes(graph, services) {
4388
4507
  } else if (isRb) {
4389
4508
  routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
4390
4509
  } else if (isGo) {
4391
- routes = hasGin ? ginRoutesFromSource(file.content, goParser) : [];
4510
+ if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
4511
+ else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
4512
+ else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
4513
+ else if (hasChi) routes = chiRoutesFromSource(file.content, goParser);
4514
+ else routes = [];
4515
+ routes = routes.concat(netHttpRoutesFromSource(file.content, goParser));
4392
4516
  } else if (isPy) {
4393
4517
  routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
4394
4518
  if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
@@ -5998,6 +6122,13 @@ function parseGoMod(source) {
5998
6122
  }
5999
6123
  return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
6000
6124
  }
6125
+ function goFramework(deps) {
6126
+ if (deps["github.com/gin-gonic/gin"]) return "gin";
6127
+ if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
6128
+ if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
6129
+ if (deps["github.com/go-chi/chi/v5"] || deps["github.com/go-chi/chi"]) return "chi";
6130
+ return void 0;
6131
+ }
6001
6132
  async function discoverGoService(scanPath, dir) {
6002
6133
  let raw;
6003
6134
  try {
@@ -6009,6 +6140,7 @@ async function discoverGoService(scanPath, dir) {
6009
6140
  if (!mod) return null;
6010
6141
  const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
6011
6142
  const pkg = { name, dependencies: mod.dependencies };
6143
+ const framework = goFramework(mod.dependencies);
6012
6144
  const node = {
6013
6145
  id: (0, import_types9.serviceId)(name),
6014
6146
  type: import_types9.NodeType.ServiceNode,
@@ -6016,7 +6148,7 @@ async function discoverGoService(scanPath, dir) {
6016
6148
  language: "go",
6017
6149
  dependencies: mod.dependencies,
6018
6150
  repoPath: import_node_path11.default.relative(scanPath, dir),
6019
- ...mod.dependencies["github.com/gin-gonic/gin"] ? { framework: "gin" } : {}
6151
+ ...framework ? { framework } : {}
6020
6152
  };
6021
6153
  return { pkg, dir, node };
6022
6154
  }
@@ -6916,7 +7048,7 @@ async function addSymbolEdges(graph, services) {
6916
7048
  return best;
6917
7049
  };
6918
7050
  const requests = [];
6919
- const walk8 = (node) => {
7051
+ const walk9 = (node) => {
6920
7052
  if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
6921
7053
  const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
6922
7054
  if (self && self.kind === "class") {
@@ -6962,10 +7094,10 @@ async function addSymbolEdges(graph, services) {
6962
7094
  }
6963
7095
  for (let i = 0; i < node.namedChildCount; i++) {
6964
7096
  const child = node.namedChild(i);
6965
- if (child) walk8(child);
7097
+ if (child) walk9(child);
6966
7098
  }
6967
7099
  };
6968
- walk8(root);
7100
+ walk9(root);
6969
7101
  for (const req of requests) {
6970
7102
  const targetSid = resolveTarget(req.targetName, req.wantKind);
6971
7103
  if (!targetSid) continue;
@@ -7978,20 +8110,20 @@ var import_node_path29 = __toESM(require("path"), 1);
7978
8110
  var import_types18 = require("@neat.is/types");
7979
8111
  async function walkConfigFiles(dir) {
7980
8112
  const out = [];
7981
- async function walk8(current) {
8113
+ async function walk9(current) {
7982
8114
  const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true });
7983
8115
  for (const entry2 of entries) {
7984
8116
  const full = import_node_path29.default.join(current, entry2.name);
7985
8117
  if (entry2.isDirectory()) {
7986
8118
  if (IGNORED_DIRS.has(entry2.name)) continue;
7987
8119
  if (await isPythonVenvDir(full)) continue;
7988
- await walk8(full);
8120
+ await walk9(full);
7989
8121
  } else if (entry2.isFile() && isConfigFile(entry2.name).match) {
7990
8122
  out.push(full);
7991
8123
  }
7992
8124
  }
7993
8125
  }
7994
- await walk8(dir);
8126
+ await walk9(dir);
7995
8127
  return out;
7996
8128
  }
7997
8129
  async function addConfigNodes(graph, services, scanPath) {
@@ -8081,20 +8213,20 @@ function grpcMethodsFromProto(content, fqPackage) {
8081
8213
  }
8082
8214
  async function walkProtoFiles(dir) {
8083
8215
  const out = [];
8084
- async function walk8(current) {
8216
+ async function walk9(current) {
8085
8217
  const entries = await import_node_fs18.promises.readdir(current, { withFileTypes: true }).catch(() => []);
8086
8218
  for (const entry2 of entries) {
8087
8219
  const full = import_node_path30.default.join(current, entry2.name);
8088
8220
  if (entry2.isDirectory()) {
8089
8221
  if (IGNORED_DIRS.has(entry2.name)) continue;
8090
8222
  if (await isPythonVenvDir(full)) continue;
8091
- await walk8(full);
8223
+ await walk9(full);
8092
8224
  } else if (entry2.isFile() && import_node_path30.default.extname(entry2.name) === PROTO_EXTENSION) {
8093
8225
  out.push(full);
8094
8226
  }
8095
8227
  }
8096
8228
  }
8097
- await walk8(dir);
8229
+ await walk9(dir);
8098
8230
  return out;
8099
8231
  }
8100
8232
  async function addGrpcMethods(graph, services) {
@@ -8162,7 +8294,7 @@ async function addGrpcMethods(graph, services) {
8162
8294
 
8163
8295
  // src/extract/calls/index.ts
8164
8296
  init_cjs_shims();
8165
- var import_types36 = require("@neat.is/types");
8297
+ var import_types37 = require("@neat.is/types");
8166
8298
 
8167
8299
  // src/extract/calls/http.ts
8168
8300
  init_cjs_shims();
@@ -8916,7 +9048,7 @@ function isFirestoreClientFactory(node) {
8916
9048
  }
8917
9049
  function firestoreClientVars(root) {
8918
9050
  const vars = /* @__PURE__ */ new Set();
8919
- const walk8 = (node) => {
9051
+ const walk9 = (node) => {
8920
9052
  if (node.type === "variable_declarator") {
8921
9053
  const name = node.childForFieldName("name");
8922
9054
  let value = node.childForFieldName("value");
@@ -8925,9 +9057,9 @@ function firestoreClientVars(root) {
8925
9057
  vars.add(name.text);
8926
9058
  }
8927
9059
  }
8928
- for (const c of namedChildren(node)) walk8(c);
9060
+ for (const c of namedChildren(node)) walk9(c);
8929
9061
  };
8930
- walk8(root);
9062
+ walk9(root);
8931
9063
  return vars;
8932
9064
  }
8933
9065
  function isClientExpr(node, clientVars) {
@@ -9082,7 +9214,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
9082
9214
  }
9083
9215
  s.add(field);
9084
9216
  };
9085
- const walk8 = (node) => {
9217
+ const walk9 = (node) => {
9086
9218
  if (node.type === "call_expression") {
9087
9219
  const fn = node.childForFieldName("function");
9088
9220
  const line = node.startPosition.row + 1;
@@ -9122,9 +9254,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
9122
9254
  }
9123
9255
  }
9124
9256
  }
9125
- for (const c of namedChildren(node)) walk8(c);
9257
+ for (const c of namedChildren(node)) walk9(c);
9126
9258
  };
9127
- walk8(tree.rootNode);
9259
+ walk9(tree.rootNode);
9128
9260
  const out = [];
9129
9261
  for (const [collPath, line] of collLine) {
9130
9262
  const byField = writes.get(collPath);
@@ -9919,7 +10051,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
9919
10051
  const tree = parseSource3(parserForExt2(import_node_path42.default.extname(file.path)), file.content);
9920
10052
  const out = [];
9921
10053
  const seen = /* @__PURE__ */ new Set();
9922
- const walk8 = (node) => {
10054
+ const walk9 = (node) => {
9923
10055
  if (node.type === "call_expression") {
9924
10056
  const fn = node.childForFieldName("function");
9925
10057
  if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
@@ -9947,9 +10079,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
9947
10079
  }
9948
10080
  }
9949
10081
  }
9950
- for (const c of namedChildren4(node)) walk8(c);
10082
+ for (const c of namedChildren4(node)) walk9(c);
9951
10083
  };
9952
- walk8(tree.rootNode);
10084
+ walk9(tree.rootNode);
9953
10085
  return out;
9954
10086
  }
9955
10087
  function enclosingVarName(call) {
@@ -9971,7 +10103,7 @@ function enclosingVarName(call) {
9971
10103
  function collectDrizzleTables(root) {
9972
10104
  const tables = [];
9973
10105
  const varToTable = /* @__PURE__ */ new Map();
9974
- const walk8 = (node) => {
10106
+ const walk9 = (node) => {
9975
10107
  if (node.type === "call_expression") {
9976
10108
  const fn = node.childForFieldName("function");
9977
10109
  if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
@@ -9986,9 +10118,9 @@ function collectDrizzleTables(root) {
9986
10118
  }
9987
10119
  }
9988
10120
  }
9989
- for (const c of namedChildren4(node)) walk8(c);
10121
+ for (const c of namedChildren4(node)) walk9(c);
9990
10122
  };
9991
- walk8(root);
10123
+ walk9(root);
9992
10124
  return { tables, varToTable };
9993
10125
  }
9994
10126
  function referencesTargetVar(call) {
@@ -10011,7 +10143,7 @@ function drizzleForeignKeys(file, serviceDir) {
10011
10143
  const seen = /* @__PURE__ */ new Set();
10012
10144
  for (const table of tables) {
10013
10145
  if (!table.object) continue;
10014
- const walk8 = (node) => {
10146
+ const walk9 = (node) => {
10015
10147
  if (node.type === "call_expression") {
10016
10148
  const targetVar = referencesTargetVar(node);
10017
10149
  const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
@@ -10032,9 +10164,9 @@ function drizzleForeignKeys(file, serviceDir) {
10032
10164
  }
10033
10165
  }
10034
10166
  }
10035
- for (const c of namedChildren4(node)) walk8(c);
10167
+ for (const c of namedChildren4(node)) walk9(c);
10036
10168
  };
10037
- walk8(table.object);
10169
+ walk9(table.object);
10038
10170
  }
10039
10171
  return out;
10040
10172
  }
@@ -11114,15 +11246,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
11114
11246
  return out;
11115
11247
  }
11116
11248
 
11249
+ // src/extract/calls/gorm.ts
11250
+ init_cjs_shims();
11251
+ var import_node_path49 = __toESM(require("path"), 1);
11252
+ var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
11253
+ var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
11254
+ var import_types36 = require("@neat.is/types");
11255
+ var GORM_IMPORT_RE = /gorm\.io\/gorm/;
11256
+ var PARSE_CHUNK11 = 16384;
11257
+ function makeGoParser3() {
11258
+ const p = new import_tree_sitter15.default();
11259
+ p.setLanguage(import_tree_sitter_go4.default);
11260
+ return p;
11261
+ }
11262
+ function parseSource10(parser, source) {
11263
+ return parser.parse(
11264
+ (index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
11265
+ );
11266
+ }
11267
+ function walk8(node, visit) {
11268
+ visit(node);
11269
+ for (let i = 0; i < node.namedChildCount; i++) {
11270
+ const c = node.namedChild(i);
11271
+ if (c) walk8(c, visit);
11272
+ }
11273
+ }
11274
+ var COMMON_INITIALISMS = [
11275
+ "ASCII",
11276
+ "HTTPS",
11277
+ "UTF8",
11278
+ "XSRF",
11279
+ "HTML",
11280
+ "HTTP",
11281
+ "JSON",
11282
+ "UUID",
11283
+ "XMPP",
11284
+ "ACL",
11285
+ "API",
11286
+ "CPU",
11287
+ "CSS",
11288
+ "DNS",
11289
+ "EOF",
11290
+ "GUID",
11291
+ "LHS",
11292
+ "QPS",
11293
+ "RAM",
11294
+ "RHS",
11295
+ "RPC",
11296
+ "SLA",
11297
+ "SQL",
11298
+ "SSH",
11299
+ "TCP",
11300
+ "TLS",
11301
+ "TTL",
11302
+ "UDP",
11303
+ "UID",
11304
+ "URI",
11305
+ "URL",
11306
+ "UID",
11307
+ "XSS",
11308
+ "ID",
11309
+ "IP",
11310
+ "UI",
11311
+ "VM",
11312
+ "XML"
11313
+ ].sort((a, b) => b.length - a.length);
11314
+ function titleCase(word) {
11315
+ return word.charAt(0) + word.slice(1).toLowerCase();
11316
+ }
11317
+ function replaceInitialisms(name) {
11318
+ let out = "";
11319
+ let i = 0;
11320
+ while (i < name.length) {
11321
+ let matched = false;
11322
+ for (const init of COMMON_INITIALISMS) {
11323
+ if (name.startsWith(init, i)) {
11324
+ out += titleCase(init);
11325
+ i += init.length;
11326
+ matched = true;
11327
+ break;
11328
+ }
11329
+ }
11330
+ if (!matched) {
11331
+ out += name[i];
11332
+ i++;
11333
+ }
11334
+ }
11335
+ return out;
11336
+ }
11337
+ var isUpper = (c) => c >= "A" && c <= "Z";
11338
+ var isDigit = (c) => c >= "0" && c <= "9";
11339
+ function toDBName(name) {
11340
+ if (name === "") return "";
11341
+ const value = replaceInitialisms(name);
11342
+ if (value.length === 1) return value.toLowerCase();
11343
+ let buf = "";
11344
+ let lastCase = false;
11345
+ let curCase = isUpper(value[0]);
11346
+ for (let i = 0; i < value.length - 1; i++) {
11347
+ const v = value[i];
11348
+ const nextCase = isUpper(value[i + 1]);
11349
+ const nextNumber = isDigit(value[i + 1]);
11350
+ if (curCase) {
11351
+ if (lastCase && (nextCase || nextNumber)) {
11352
+ buf += v.toLowerCase();
11353
+ } else {
11354
+ if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
11355
+ buf += v.toLowerCase();
11356
+ }
11357
+ } else {
11358
+ buf += v;
11359
+ }
11360
+ lastCase = curCase;
11361
+ curCase = nextCase;
11362
+ }
11363
+ const last = value[value.length - 1];
11364
+ if (curCase) {
11365
+ if (!lastCase && value.length > 1) buf += "_";
11366
+ buf += last.toLowerCase();
11367
+ } else {
11368
+ buf += last;
11369
+ }
11370
+ return buf;
11371
+ }
11372
+ var UNCOUNTABLE = /* @__PURE__ */ new Set([
11373
+ "equipment",
11374
+ "information",
11375
+ "rice",
11376
+ "money",
11377
+ "species",
11378
+ "series",
11379
+ "fish",
11380
+ "sheep",
11381
+ "jeans",
11382
+ "police"
11383
+ ]);
11384
+ var IRREGULAR = [
11385
+ ["person", "people"],
11386
+ ["man", "men"],
11387
+ ["child", "children"],
11388
+ ["sex", "sexes"],
11389
+ ["move", "moves"]
11390
+ ];
11391
+ var PLURAL_RULES = [
11392
+ [/(quiz)$/i, "$1zes"],
11393
+ [/^(ox)$/i, "$1en"],
11394
+ [/([ml])ouse$/i, "$1ice"],
11395
+ [/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
11396
+ [/(x|ch|ss|sh)$/i, "$1es"],
11397
+ [/([^aeiouy]|qu)y$/i, "$1ies"],
11398
+ [/(hive)$/i, "$1s"],
11399
+ [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
11400
+ [/sis$/i, "ses"],
11401
+ [/([ti])um$/i, "$1a"],
11402
+ [/([ti])a$/i, "$1a"],
11403
+ [/(buffal|tomat)o$/i, "$1oes"],
11404
+ [/(bu)s$/i, "$1ses"],
11405
+ [/(alias|status)$/i, "$1es"],
11406
+ [/(octop|vir)i$/i, "$1i"],
11407
+ [/(octop|vir)us$/i, "$1i"],
11408
+ [/(ax|test)is$/i, "$1es"],
11409
+ [/s$/i, "s"]
11410
+ ];
11411
+ function pluralize3(word) {
11412
+ if (word === "") return word;
11413
+ const lower = word.toLowerCase();
11414
+ for (const u of UNCOUNTABLE) {
11415
+ if (lower === u || lower.endsWith("_" + u)) return word;
11416
+ }
11417
+ for (const [sing, plur] of IRREGULAR) {
11418
+ const re = new RegExp(sing + "$", "i");
11419
+ if (re.test(word)) return word.replace(re, plur);
11420
+ }
11421
+ for (const [re, rep] of PLURAL_RULES) {
11422
+ if (re.test(word)) return word.replace(re, rep);
11423
+ }
11424
+ return word + "s";
11425
+ }
11426
+ function deriveTableName(structName) {
11427
+ return pluralize3(toDBName(structName));
11428
+ }
11429
+ function stringLiteralValue(node) {
11430
+ if (!node) return null;
11431
+ if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
11432
+ const t = node.text;
11433
+ return t.length >= 2 ? t.slice(1, -1) : "";
11434
+ }
11435
+ return null;
11436
+ }
11437
+ function parseGormTag(tagNode) {
11438
+ const tag = {};
11439
+ if (!tagNode) return tag;
11440
+ let inner = tagNode.text;
11441
+ if (inner.length >= 2) inner = inner.slice(1, -1);
11442
+ if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
11443
+ const m = inner.match(/gorm:"([^"]*)"/);
11444
+ if (!m) return tag;
11445
+ for (const part of m[1].split(";")) {
11446
+ if (part === "") continue;
11447
+ const idx = part.indexOf(":");
11448
+ const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
11449
+ const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
11450
+ if (key === "-") tag.skip = true;
11451
+ else if (key === "column") tag.column = value;
11452
+ else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
11453
+ else if (key === "foreignkey") tag.foreignKey = value;
11454
+ else if (key === "many2many") tag.many2many = value;
11455
+ else if (key === "embedded") tag.embedded = true;
11456
+ else if (key === "embeddedprefix") tag.embeddedPrefix = value;
11457
+ }
11458
+ return tag;
11459
+ }
11460
+ function unwrapType(typeNode) {
11461
+ let isSlice = false;
11462
+ let isPointer = false;
11463
+ let n = typeNode;
11464
+ while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
11465
+ if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
11466
+ if (n.type === "pointer_type") isPointer = true;
11467
+ n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
11468
+ }
11469
+ if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
11470
+ if (n.type === "type_identifier") {
11471
+ return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
11472
+ }
11473
+ if (n.type === "qualified_type") {
11474
+ const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
11475
+ const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
11476
+ return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
11477
+ }
11478
+ return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
11479
+ }
11480
+ function readField(fieldDecl) {
11481
+ const names = [];
11482
+ let tagNode = null;
11483
+ for (let i = 0; i < fieldDecl.namedChildCount; i++) {
11484
+ const c = fieldDecl.namedChild(i);
11485
+ if (!c) continue;
11486
+ if (c.type === "field_identifier") names.push(c.text);
11487
+ else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
11488
+ }
11489
+ const typeNode = fieldDecl.childForFieldName("type");
11490
+ const t = unwrapType(typeNode);
11491
+ return {
11492
+ names,
11493
+ typeName: t.name,
11494
+ qualifier: t.qualifier,
11495
+ isSlice: t.isSlice,
11496
+ isPointer: t.isPointer,
11497
+ isQualified: t.isQualified,
11498
+ tag: parseGormTag(tagNode),
11499
+ line: fieldDecl.startPosition.row + 1
11500
+ };
11501
+ }
11502
+ function collectStructs(tree) {
11503
+ const structs = /* @__PURE__ */ new Map();
11504
+ walk8(tree.rootNode, (node) => {
11505
+ if (node.type !== "type_spec") return;
11506
+ const nameNode = node.childForFieldName("name");
11507
+ const typeNode = node.childForFieldName("type");
11508
+ if (!nameNode || typeNode?.type !== "struct_type") return;
11509
+ const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
11510
+ const fields = [];
11511
+ if (list && list.type === "field_declaration_list") {
11512
+ for (let i = 0; i < list.namedChildCount; i++) {
11513
+ const fd = list.namedChild(i);
11514
+ if (fd?.type === "field_declaration") fields.push(readField(fd));
11515
+ }
11516
+ }
11517
+ structs.set(nameNode.text, {
11518
+ name: nameNode.text,
11519
+ fields,
11520
+ line: node.startPosition.row + 1
11521
+ });
11522
+ });
11523
+ return structs;
11524
+ }
11525
+ var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
11526
+ "AutoMigrate",
11527
+ "Model",
11528
+ "Create",
11529
+ "Find",
11530
+ "First",
11531
+ "Take",
11532
+ "Last",
11533
+ "Save",
11534
+ "Delete",
11535
+ "Where",
11536
+ "FirstOrCreate",
11537
+ "FirstOrInit"
11538
+ ]);
11539
+ function compositeStructName(arg) {
11540
+ let n = arg;
11541
+ if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
11542
+ if (!n || n.type !== "composite_literal") return null;
11543
+ const typeNode = n.childForFieldName("type");
11544
+ if (!typeNode) return null;
11545
+ if (typeNode.type === "type_identifier") return typeNode.text;
11546
+ if (typeNode.type === "qualified_type") {
11547
+ return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
11548
+ }
11549
+ return null;
11550
+ }
11551
+ function collectCallModels(tree) {
11552
+ const models = /* @__PURE__ */ new Set();
11553
+ walk8(tree.rootNode, (node) => {
11554
+ if (node.type !== "call_expression") return;
11555
+ const fn = node.childForFieldName("function");
11556
+ if (fn?.type !== "selector_expression") return;
11557
+ const method = fn.childForFieldName("field")?.text;
11558
+ if (!method || !GORM_MODEL_METHODS.has(method)) return;
11559
+ const args = node.childForFieldName("arguments");
11560
+ if (!args) return;
11561
+ for (let i = 0; i < args.namedChildCount; i++) {
11562
+ const arg = args.namedChild(i);
11563
+ if (!arg) continue;
11564
+ const name = compositeStructName(arg);
11565
+ if (name) models.add(name);
11566
+ }
11567
+ });
11568
+ return models;
11569
+ }
11570
+ function collectTableNameOverrides(tree) {
11571
+ const overrides = /* @__PURE__ */ new Map();
11572
+ const declarers = /* @__PURE__ */ new Set();
11573
+ walk8(tree.rootNode, (node) => {
11574
+ if (node.type !== "method_declaration") return;
11575
+ if (node.childForFieldName("name")?.text !== "TableName") return;
11576
+ const receiver = node.childForFieldName("receiver");
11577
+ if (!receiver) return;
11578
+ let recvType = null;
11579
+ for (let i = 0; i < receiver.namedChildCount; i++) {
11580
+ const pd = receiver.namedChild(i);
11581
+ if (pd?.type !== "parameter_declaration") continue;
11582
+ const t = unwrapType(pd.childForFieldName("type"));
11583
+ recvType = t.name;
11584
+ }
11585
+ if (!recvType) return;
11586
+ declarers.add(recvType);
11587
+ const body = node.childForFieldName("body");
11588
+ if (!body) return;
11589
+ let literal = null;
11590
+ walk8(body, (n) => {
11591
+ if (literal !== null) return;
11592
+ if (n.type !== "return_statement") return;
11593
+ const exprList = n.namedChild(0);
11594
+ const first = exprList?.namedChild(0) ?? exprList;
11595
+ const v = stringLiteralValue(first);
11596
+ if (v) literal = v;
11597
+ });
11598
+ if (literal !== null) overrides.set(recvType, literal);
11599
+ });
11600
+ return { overrides, declarers };
11601
+ }
11602
+ function isRelationField(field, structs) {
11603
+ if (field.names.length === 0) return false;
11604
+ if (field.isQualified) return false;
11605
+ if (!field.typeName) return false;
11606
+ return structs.has(field.typeName);
11607
+ }
11608
+ function isGormModelEmbed(field) {
11609
+ return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
11610
+ }
11611
+ function analyze(tree) {
11612
+ const structs = collectStructs(tree);
11613
+ const { overrides, declarers } = collectTableNameOverrides(tree);
11614
+ const callModels = collectCallModels(tree);
11615
+ const models = /* @__PURE__ */ new Set();
11616
+ for (const [name, info] of structs) {
11617
+ if (info.fields.some(isGormModelEmbed)) models.add(name);
11618
+ }
11619
+ for (const name of callModels) if (structs.has(name)) models.add(name);
11620
+ for (const name of declarers) if (structs.has(name)) models.add(name);
11621
+ let grew = true;
11622
+ while (grew) {
11623
+ grew = false;
11624
+ for (const name of Array.from(models)) {
11625
+ const info = structs.get(name);
11626
+ if (!info) continue;
11627
+ for (const field of info.fields) {
11628
+ if (!isRelationField(field, structs)) continue;
11629
+ const target = field.typeName;
11630
+ if (!models.has(target) && structs.has(target)) {
11631
+ models.add(target);
11632
+ grew = true;
11633
+ }
11634
+ }
11635
+ }
11636
+ }
11637
+ const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
11638
+ return { structs, models, tableFor };
11639
+ }
11640
+ function collectColumns(struct, structs, seen, prefix, out, emitted) {
11641
+ if (seen.has(struct.name)) return;
11642
+ seen.add(struct.name);
11643
+ const add = (col) => {
11644
+ const full = prefix + col;
11645
+ if (!emitted.has(full)) {
11646
+ emitted.add(full);
11647
+ out.push(full);
11648
+ }
11649
+ };
11650
+ for (const field of struct.fields) {
11651
+ if (field.tag.skip) continue;
11652
+ if (field.names.length === 0) {
11653
+ if (isGormModelEmbed(field)) {
11654
+ add("id");
11655
+ add("created_at");
11656
+ add("updated_at");
11657
+ add("deleted_at");
11658
+ } else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
11659
+ collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
11660
+ }
11661
+ continue;
11662
+ }
11663
+ if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
11664
+ collectColumns(
11665
+ structs.get(field.typeName),
11666
+ structs,
11667
+ seen,
11668
+ prefix + (field.tag.embeddedPrefix ?? ""),
11669
+ out,
11670
+ emitted
11671
+ );
11672
+ continue;
11673
+ }
11674
+ if (isRelationField(field, structs)) continue;
11675
+ if (field.names.length === 1 && field.tag.column) {
11676
+ add(field.tag.column);
11677
+ } else {
11678
+ for (const n of field.names) add(toDBName(n));
11679
+ }
11680
+ }
11681
+ seen.delete(struct.name);
11682
+ }
11683
+ function gormEndpointsFromFile(file, serviceDir) {
11684
+ if (import_node_path49.default.extname(file.path) !== ".go") return [];
11685
+ if (!GORM_IMPORT_RE.test(file.content)) return [];
11686
+ const tree = parseSource10(makeGoParser3(), file.content);
11687
+ const { structs, models, tableFor } = analyze(tree);
11688
+ const out = [];
11689
+ const seenTables = /* @__PURE__ */ new Set();
11690
+ for (const name of models) {
11691
+ const struct = structs.get(name);
11692
+ if (!struct) continue;
11693
+ const table = tableFor(name);
11694
+ if (seenTables.has(table)) continue;
11695
+ seenTables.add(table);
11696
+ const columns = [];
11697
+ collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
11698
+ out.push({
11699
+ infraId: (0, import_types36.infraId)("sql-table", table),
11700
+ name: table,
11701
+ kind: "sql-table",
11702
+ edgeType: "CALLS",
11703
+ confidenceKind: "structural",
11704
+ ...columns.length > 0 ? { columns } : {},
11705
+ evidence: {
11706
+ file: toPosix(import_node_path49.default.relative(serviceDir, file.path)),
11707
+ line: struct.line,
11708
+ snippet: snippet(file.content, struct.line)
11709
+ }
11710
+ });
11711
+ }
11712
+ return out;
11713
+ }
11714
+ function gormForeignKeys(file, serviceDir) {
11715
+ if (import_node_path49.default.extname(file.path) !== ".go") return [];
11716
+ if (!GORM_IMPORT_RE.test(file.content)) return [];
11717
+ const tree = parseSource10(makeGoParser3(), file.content);
11718
+ const { structs, models, tableFor } = analyze(tree);
11719
+ const out = [];
11720
+ const seen = /* @__PURE__ */ new Set();
11721
+ const emit = (childTable, parentTable, line) => {
11722
+ if (!childTable || !parentTable || childTable === parentTable) return;
11723
+ const key = `${childTable}->${parentTable}`;
11724
+ if (seen.has(key)) return;
11725
+ seen.add(key);
11726
+ out.push({
11727
+ childTable,
11728
+ parentTable,
11729
+ evidence: {
11730
+ file: toPosix(import_node_path49.default.relative(serviceDir, file.path)),
11731
+ line,
11732
+ snippet: snippet(file.content, line)
11733
+ }
11734
+ });
11735
+ };
11736
+ for (const name of models) {
11737
+ const struct = structs.get(name);
11738
+ if (!struct) continue;
11739
+ const thisTable = tableFor(name);
11740
+ const scalarNames = new Set(
11741
+ struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
11742
+ );
11743
+ for (const field of struct.fields) {
11744
+ if (field.tag.skip) continue;
11745
+ if (!isRelationField(field, structs)) continue;
11746
+ const relTable = tableFor(field.typeName);
11747
+ if (field.tag.many2many) {
11748
+ emit(field.tag.many2many, thisTable, field.line);
11749
+ emit(field.tag.many2many, relTable, field.line);
11750
+ continue;
11751
+ }
11752
+ if (field.isSlice) {
11753
+ emit(relTable, thisTable, field.line);
11754
+ continue;
11755
+ }
11756
+ const convFk = field.names[0] + "ID";
11757
+ const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
11758
+ if (belongsTo) emit(thisTable, relTable, field.line);
11759
+ else emit(relTable, thisTable, field.line);
11760
+ }
11761
+ }
11762
+ return out;
11763
+ }
11764
+
11117
11765
  // src/extract/calls/index.ts
11118
11766
  function edgeTypeFromEndpoint(ep) {
11119
11767
  switch (ep.edgeType) {
11120
11768
  case "PUBLISHES_TO":
11121
- return import_types36.EdgeType.PUBLISHES_TO;
11769
+ return import_types37.EdgeType.PUBLISHES_TO;
11122
11770
  case "CONSUMES_FROM":
11123
- return import_types36.EdgeType.CONSUMES_FROM;
11771
+ return import_types37.EdgeType.CONSUMES_FROM;
11124
11772
  default:
11125
- return import_types36.EdgeType.CALLS;
11773
+ return import_types37.EdgeType.CALLS;
11126
11774
  }
11127
11775
  }
11128
11776
  function isAwsKind(kind) {
@@ -11155,6 +11803,11 @@ async function addExternalEndpointEdges(graph, services) {
11155
11803
  } catch (err) {
11156
11804
  recordExtractionError("go SQL call extraction", file.path, err);
11157
11805
  }
11806
+ try {
11807
+ endpoints.push(...gormEndpointsFromFile(file, service.dir));
11808
+ } catch (err) {
11809
+ recordExtractionError("gorm data-axis extraction", file.path, err);
11810
+ }
11158
11811
  try {
11159
11812
  endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
11160
11813
  endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
@@ -11177,7 +11830,7 @@ async function addExternalEndpointEdges(graph, services) {
11177
11830
  if (!graph.hasNode(ep.infraId)) {
11178
11831
  const node = {
11179
11832
  id: ep.infraId,
11180
- type: import_types36.NodeType.InfraNode,
11833
+ type: import_types37.NodeType.InfraNode,
11181
11834
  name: ep.name,
11182
11835
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
11183
11836
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -11190,21 +11843,21 @@ async function addExternalEndpointEdges(graph, services) {
11190
11843
  }
11191
11844
  if (ep.columns && ep.columns.length > 0) {
11192
11845
  const node = graph.getNodeAttributes(ep.infraId);
11193
- if (node.type === import_types36.NodeType.InfraNode) {
11846
+ if (node.type === import_types37.NodeType.InfraNode) {
11194
11847
  graph.replaceNodeAttributes(ep.infraId, {
11195
11848
  ...node,
11196
11849
  columns: foldColumns(
11197
11850
  node.columns,
11198
11851
  ep.columns,
11199
- import_types36.Provenance.EXTRACTED,
11200
- (0, import_types36.confidenceForExtracted)(ep.confidenceKind)
11852
+ import_types37.Provenance.EXTRACTED,
11853
+ (0, import_types37.confidenceForExtracted)(ep.confidenceKind)
11201
11854
  )
11202
11855
  });
11203
11856
  }
11204
11857
  }
11205
11858
  if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
11206
11859
  const node = graph.getNodeAttributes(ep.infraId);
11207
- if (node.type === import_types36.NodeType.InfraNode) {
11860
+ if (node.type === import_types37.NodeType.InfraNode) {
11208
11861
  graph.replaceNodeAttributes(ep.infraId, {
11209
11862
  ...node,
11210
11863
  columns: foldSdkWrites(node.columns, ep.sdkWrites)
@@ -11212,7 +11865,7 @@ async function addExternalEndpointEdges(graph, services) {
11212
11865
  }
11213
11866
  }
11214
11867
  const edgeType = edgeTypeFromEndpoint(ep);
11215
- const confidence = (0, import_types36.confidenceForExtracted)(ep.confidenceKind);
11868
+ const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
11216
11869
  const relFile = toPosix(ep.evidence.file);
11217
11870
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
11218
11871
  graph,
@@ -11222,7 +11875,7 @@ async function addExternalEndpointEdges(graph, services) {
11222
11875
  );
11223
11876
  nodesAdded += n;
11224
11877
  edgesAdded += e;
11225
- if (!(0, import_types36.passesExtractedFloor)(confidence)) {
11878
+ if (!(0, import_types37.passesExtractedFloor)(confidence)) {
11226
11879
  noteExtractedDropped({
11227
11880
  source: fileNodeId,
11228
11881
  target: ep.infraId,
@@ -11242,7 +11895,7 @@ async function addExternalEndpointEdges(graph, services) {
11242
11895
  source: fileNodeId,
11243
11896
  target: ep.infraId,
11244
11897
  type: edgeType,
11245
- provenance: import_types36.Provenance.EXTRACTED,
11898
+ provenance: import_types37.Provenance.EXTRACTED,
11246
11899
  confidence,
11247
11900
  evidence: ep.evidence
11248
11901
  };
@@ -11265,7 +11918,7 @@ async function addCallEdges(graph, services) {
11265
11918
 
11266
11919
  // src/extract/table-edges.ts
11267
11920
  init_cjs_shims();
11268
- var import_types37 = require("@neat.is/types");
11921
+ var import_types38 = require("@neat.is/types");
11269
11922
  async function addTableEdges(graph, services) {
11270
11923
  let nodesAdded = 0;
11271
11924
  let edgesAdded = 0;
@@ -11279,6 +11932,7 @@ async function addTableEdges(graph, services) {
11279
11932
  refs.push(...sqlalchemyForeignKeys(file, service.dir));
11280
11933
  refs.push(...railsSchemaForeignKeys(file, service.dir));
11281
11934
  refs.push(...laravelMigrationForeignKeys(file, service.dir));
11935
+ refs.push(...gormForeignKeys(file, service.dir));
11282
11936
  modelRefs.push(...railsModelForeignKeys(file, service.dir));
11283
11937
  modelRefs.push(...laravelModelForeignKeys(file, service.dir));
11284
11938
  } catch (err) {
@@ -11292,20 +11946,20 @@ async function addTableEdges(graph, services) {
11292
11946
  }
11293
11947
  refs.push(...modelRefs);
11294
11948
  for (const ref of refs) {
11295
- const childId = (0, import_types37.infraId)("sql-table", ref.childTable);
11296
- const parentId = (0, import_types37.infraId)("sql-table", ref.parentTable);
11949
+ const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
11950
+ const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
11297
11951
  if (childId === parentId) continue;
11298
11952
  nodesAdded += ensureTableNode(graph, childId, ref.childTable);
11299
11953
  nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
11300
- const edgeId = (0, import_types37.extractedEdgeId)(childId, parentId, import_types37.EdgeType.REFERENCES);
11954
+ const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
11301
11955
  if (graph.hasEdge(edgeId)) continue;
11302
11956
  const edge = {
11303
11957
  id: edgeId,
11304
11958
  source: childId,
11305
11959
  target: parentId,
11306
- type: import_types37.EdgeType.REFERENCES,
11307
- provenance: import_types37.Provenance.EXTRACTED,
11308
- confidence: (0, import_types37.confidenceForExtracted)("structural"),
11960
+ type: import_types38.EdgeType.REFERENCES,
11961
+ provenance: import_types38.Provenance.EXTRACTED,
11962
+ confidence: (0, import_types38.confidenceForExtracted)("structural"),
11309
11963
  evidence: ref.evidence
11310
11964
  };
11311
11965
  graph.addEdgeWithKey(edgeId, childId, parentId, edge);
@@ -11318,7 +11972,7 @@ function ensureTableNode(graph, id, name) {
11318
11972
  if (graph.hasNode(id)) return 0;
11319
11973
  const node = {
11320
11974
  id,
11321
- type: import_types37.NodeType.InfraNode,
11975
+ type: import_types38.NodeType.InfraNode,
11322
11976
  name,
11323
11977
  provider: "self",
11324
11978
  kind: "sql-table"
@@ -11332,16 +11986,16 @@ init_cjs_shims();
11332
11986
 
11333
11987
  // src/extract/infra/docker-compose.ts
11334
11988
  init_cjs_shims();
11335
- var import_node_path49 = __toESM(require("path"), 1);
11336
- var import_types39 = require("@neat.is/types");
11989
+ var import_node_path50 = __toESM(require("path"), 1);
11990
+ var import_types40 = require("@neat.is/types");
11337
11991
 
11338
11992
  // src/extract/infra/shared.ts
11339
11993
  init_cjs_shims();
11340
- var import_types38 = require("@neat.is/types");
11994
+ var import_types39 = require("@neat.is/types");
11341
11995
  function makeInfraNode(kind, name, provider = "self", extras) {
11342
11996
  return {
11343
- id: (0, import_types38.infraId)(kind, name),
11344
- type: import_types38.NodeType.InfraNode,
11997
+ id: (0, import_types39.infraId)(kind, name),
11998
+ type: import_types39.NodeType.InfraNode,
11345
11999
  name,
11346
12000
  provider,
11347
12001
  kind,
@@ -11385,8 +12039,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
11385
12039
  source: anchorId,
11386
12040
  target: node.id,
11387
12041
  type: edgeType,
11388
- provenance: import_types38.Provenance.EXTRACTED,
11389
- confidence: (0, import_types38.confidenceForExtracted)("structural"),
12042
+ provenance: import_types39.Provenance.EXTRACTED,
12043
+ confidence: (0, import_types39.confidenceForExtracted)("structural"),
11390
12044
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
11391
12045
  };
11392
12046
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -11403,7 +12057,7 @@ function dependsOnList(value) {
11403
12057
  }
11404
12058
  function serviceNameToServiceNode(name, services) {
11405
12059
  for (const s of services) {
11406
- if (s.node.name === name || import_node_path49.default.basename(s.dir) === name) return s.node.id;
12060
+ if (s.node.name === name || import_node_path50.default.basename(s.dir) === name) return s.node.id;
11407
12061
  }
11408
12062
  return null;
11409
12063
  }
@@ -11412,7 +12066,7 @@ async function addComposeInfra(graph, scanPath, services) {
11412
12066
  let edgesAdded = 0;
11413
12067
  let composePath = null;
11414
12068
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
11415
- const abs = import_node_path49.default.join(scanPath, name);
12069
+ const abs = import_node_path50.default.join(scanPath, name);
11416
12070
  if (await exists(abs)) {
11417
12071
  composePath = abs;
11418
12072
  break;
@@ -11425,13 +12079,13 @@ async function addComposeInfra(graph, scanPath, services) {
11425
12079
  } catch (err) {
11426
12080
  recordExtractionError(
11427
12081
  "infra docker-compose",
11428
- import_node_path49.default.relative(scanPath, composePath),
12082
+ import_node_path50.default.relative(scanPath, composePath),
11429
12083
  err
11430
12084
  );
11431
12085
  return { nodesAdded, edgesAdded };
11432
12086
  }
11433
12087
  if (!compose?.services) return { nodesAdded, edgesAdded };
11434
- const evidenceFile = import_node_path49.default.relative(scanPath, composePath).split(import_node_path49.default.sep).join("/");
12088
+ const evidenceFile = import_node_path50.default.relative(scanPath, composePath).split(import_node_path50.default.sep).join("/");
11435
12089
  const composeNameToNodeId = /* @__PURE__ */ new Map();
11436
12090
  for (const [composeName, svc] of Object.entries(compose.services)) {
11437
12091
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -11453,15 +12107,15 @@ async function addComposeInfra(graph, scanPath, services) {
11453
12107
  for (const dep of dependsOnList(svc.depends_on)) {
11454
12108
  const targetId = composeNameToNodeId.get(dep);
11455
12109
  if (!targetId) continue;
11456
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types39.EdgeType.DEPENDS_ON);
12110
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
11457
12111
  if (graph.hasEdge(edgeId)) continue;
11458
12112
  const edge = {
11459
12113
  id: edgeId,
11460
12114
  source: sourceId,
11461
12115
  target: targetId,
11462
- type: import_types39.EdgeType.DEPENDS_ON,
11463
- provenance: import_types39.Provenance.EXTRACTED,
11464
- confidence: (0, import_types39.confidenceForExtracted)("structural"),
12116
+ type: import_types40.EdgeType.DEPENDS_ON,
12117
+ provenance: import_types40.Provenance.EXTRACTED,
12118
+ confidence: (0, import_types40.confidenceForExtracted)("structural"),
11465
12119
  evidence: { file: evidenceFile }
11466
12120
  };
11467
12121
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -11473,9 +12127,9 @@ async function addComposeInfra(graph, scanPath, services) {
11473
12127
 
11474
12128
  // src/extract/infra/dockerfile.ts
11475
12129
  init_cjs_shims();
11476
- var import_node_path50 = __toESM(require("path"), 1);
12130
+ var import_node_path51 = __toESM(require("path"), 1);
11477
12131
  var import_node_fs19 = require("fs");
11478
- var import_types40 = require("@neat.is/types");
12132
+ var import_types41 = require("@neat.is/types");
11479
12133
  function readDockerfile(content) {
11480
12134
  let image = null;
11481
12135
  const ports = [];
@@ -11504,7 +12158,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11504
12158
  let nodesAdded = 0;
11505
12159
  let edgesAdded = 0;
11506
12160
  for (const service of services) {
11507
- const dockerfilePath = import_node_path50.default.join(service.dir, "Dockerfile");
12161
+ const dockerfilePath = import_node_path51.default.join(service.dir, "Dockerfile");
11508
12162
  if (!await exists(dockerfilePath)) continue;
11509
12163
  let content;
11510
12164
  try {
@@ -11512,7 +12166,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11512
12166
  } catch (err) {
11513
12167
  recordExtractionError(
11514
12168
  "infra dockerfile",
11515
- import_node_path50.default.relative(scanPath, dockerfilePath),
12169
+ import_node_path51.default.relative(scanPath, dockerfilePath),
11516
12170
  err
11517
12171
  );
11518
12172
  continue;
@@ -11524,8 +12178,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11524
12178
  graph.addNode(node.id, node);
11525
12179
  nodesAdded++;
11526
12180
  }
11527
- const relDockerfile = toPosix(import_node_path50.default.relative(service.dir, dockerfilePath));
11528
- const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, dockerfilePath));
12181
+ const relDockerfile = toPosix(import_node_path51.default.relative(service.dir, dockerfilePath));
12182
+ const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, dockerfilePath));
11529
12183
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11530
12184
  graph,
11531
12185
  service.pkg.name,
@@ -11534,15 +12188,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11534
12188
  );
11535
12189
  nodesAdded += fn;
11536
12190
  edgesAdded += fe;
11537
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types40.EdgeType.RUNS_ON);
12191
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
11538
12192
  if (!graph.hasEdge(edgeId)) {
11539
12193
  const edge = {
11540
12194
  id: edgeId,
11541
12195
  source: fileNodeId,
11542
12196
  target: node.id,
11543
- type: import_types40.EdgeType.RUNS_ON,
11544
- provenance: import_types40.Provenance.EXTRACTED,
11545
- confidence: (0, import_types40.confidenceForExtracted)("structural"),
12197
+ type: import_types41.EdgeType.RUNS_ON,
12198
+ provenance: import_types41.Provenance.EXTRACTED,
12199
+ confidence: (0, import_types41.confidenceForExtracted)("structural"),
11546
12200
  evidence: {
11547
12201
  file: evidenceFile,
11548
12202
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -11557,15 +12211,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11557
12211
  graph.addNode(portNode.id, portNode);
11558
12212
  nodesAdded++;
11559
12213
  }
11560
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types40.EdgeType.CONNECTS_TO);
12214
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
11561
12215
  if (graph.hasEdge(portEdgeId)) continue;
11562
12216
  const portEdge = {
11563
12217
  id: portEdgeId,
11564
12218
  source: fileNodeId,
11565
12219
  target: portNode.id,
11566
- type: import_types40.EdgeType.CONNECTS_TO,
11567
- provenance: import_types40.Provenance.EXTRACTED,
11568
- confidence: (0, import_types40.confidenceForExtracted)("structural"),
12220
+ type: import_types41.EdgeType.CONNECTS_TO,
12221
+ provenance: import_types41.Provenance.EXTRACTED,
12222
+ confidence: (0, import_types41.confidenceForExtracted)("structural"),
11569
12223
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
11570
12224
  };
11571
12225
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -11578,8 +12232,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
11578
12232
  // src/extract/infra/terraform.ts
11579
12233
  init_cjs_shims();
11580
12234
  var import_node_fs20 = require("fs");
11581
- var import_node_path51 = __toESM(require("path"), 1);
11582
- var import_types41 = require("@neat.is/types");
12235
+ var import_node_path52 = __toESM(require("path"), 1);
12236
+ var import_types42 = require("@neat.is/types");
11583
12237
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
11584
12238
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
11585
12239
  async function walkTfFiles(start, depth = 0, max = 5) {
@@ -11589,11 +12243,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
11589
12243
  for (const entry2 of entries) {
11590
12244
  if (entry2.isDirectory()) {
11591
12245
  if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
11592
- const child = import_node_path51.default.join(start, entry2.name);
12246
+ const child = import_node_path52.default.join(start, entry2.name);
11593
12247
  if (await isPythonVenvDir(child)) continue;
11594
12248
  out.push(...await walkTfFiles(child, depth + 1, max));
11595
12249
  } else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
11596
- out.push(import_node_path51.default.join(start, entry2.name));
12250
+ out.push(import_node_path52.default.join(start, entry2.name));
11597
12251
  }
11598
12252
  }
11599
12253
  return out;
@@ -11625,7 +12279,7 @@ async function addTerraformResources(graph, scanPath) {
11625
12279
  const files = await walkTfFiles(scanPath);
11626
12280
  for (const file of files) {
11627
12281
  const content = await import_node_fs20.promises.readFile(file, "utf8");
11628
- const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, file));
12282
+ const evidenceFile = toPosix(import_node_path52.default.relative(scanPath, file));
11629
12283
  const resources = [];
11630
12284
  const byKey = /* @__PURE__ */ new Map();
11631
12285
  RESOURCE_RE.lastIndex = 0;
@@ -11660,16 +12314,16 @@ async function addTerraformResources(graph, scanPath) {
11660
12314
  if (!target) continue;
11661
12315
  if (seen.has(target.nodeId)) continue;
11662
12316
  seen.add(target.nodeId);
11663
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types41.EdgeType.DEPENDS_ON);
12317
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
11664
12318
  if (graph.hasEdge(edgeId)) continue;
11665
12319
  const line = lineAt2(content, resource.bodyOffset + ref.index);
11666
12320
  const edge = {
11667
12321
  id: edgeId,
11668
12322
  source: resource.nodeId,
11669
12323
  target: target.nodeId,
11670
- type: import_types41.EdgeType.DEPENDS_ON,
11671
- provenance: import_types41.Provenance.EXTRACTED,
11672
- confidence: (0, import_types41.confidenceForExtracted)("structural"),
12324
+ type: import_types42.EdgeType.DEPENDS_ON,
12325
+ provenance: import_types42.Provenance.EXTRACTED,
12326
+ confidence: (0, import_types42.confidenceForExtracted)("structural"),
11673
12327
  evidence: { file: evidenceFile, line, snippet: key }
11674
12328
  };
11675
12329
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -11683,7 +12337,7 @@ async function addTerraformResources(graph, scanPath) {
11683
12337
  // src/extract/infra/k8s.ts
11684
12338
  init_cjs_shims();
11685
12339
  var import_node_fs21 = require("fs");
11686
- var import_node_path52 = __toESM(require("path"), 1);
12340
+ var import_node_path53 = __toESM(require("path"), 1);
11687
12341
  var import_yaml3 = require("yaml");
11688
12342
  var K8S_KIND_TO_INFRA_KIND = {
11689
12343
  Service: "k8s-service",
@@ -11701,11 +12355,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
11701
12355
  for (const entry2 of entries) {
11702
12356
  if (entry2.isDirectory()) {
11703
12357
  if (IGNORED_DIRS.has(entry2.name)) continue;
11704
- const child = import_node_path52.default.join(start, entry2.name);
12358
+ const child = import_node_path53.default.join(start, entry2.name);
11705
12359
  if (await isPythonVenvDir(child)) continue;
11706
12360
  out.push(...await walkYamlFiles2(child, depth + 1, max));
11707
- } else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path52.default.extname(entry2.name))) {
11708
- out.push(import_node_path52.default.join(start, entry2.name));
12361
+ } else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path53.default.extname(entry2.name))) {
12362
+ out.push(import_node_path53.default.join(start, entry2.name));
11709
12363
  }
11710
12364
  }
11711
12365
  return out;
@@ -11739,13 +12393,13 @@ async function addK8sResources(graph, scanPath) {
11739
12393
  // src/extract/infra/cloudflare.ts
11740
12394
  init_cjs_shims();
11741
12395
  var import_node_fs22 = require("fs");
11742
- var import_node_path53 = __toESM(require("path"), 1);
12396
+ var import_node_path54 = __toESM(require("path"), 1);
11743
12397
  var import_smol_toml2 = require("smol-toml");
11744
- var import_types42 = require("@neat.is/types");
12398
+ var import_types43 = require("@neat.is/types");
11745
12399
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
11746
12400
  async function readWranglerConfig(dir) {
11747
12401
  for (const filename of WRANGLER_FILENAMES) {
11748
- const abs = import_node_path53.default.join(dir, filename);
12402
+ const abs = import_node_path54.default.join(dir, filename);
11749
12403
  if (!await exists(abs)) continue;
11750
12404
  const raw = await import_node_fs22.promises.readFile(abs, "utf8");
11751
12405
  const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -11789,8 +12443,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
11789
12443
  source: anchorId,
11790
12444
  target: node.id,
11791
12445
  type: edgeType,
11792
- provenance: import_types42.Provenance.EXTRACTED,
11793
- confidence: (0, import_types42.confidenceForExtracted)("structural"),
12446
+ provenance: import_types43.Provenance.EXTRACTED,
12447
+ confidence: (0, import_types43.confidenceForExtracted)("structural"),
11794
12448
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
11795
12449
  };
11796
12450
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -11808,11 +12462,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11808
12462
  try {
11809
12463
  read = await readWranglerConfig(service.dir);
11810
12464
  } catch (err) {
11811
- recordExtractionError("infra cloudflare", import_node_path53.default.relative(scanPath, service.dir), err);
12465
+ recordExtractionError("infra cloudflare", import_node_path54.default.relative(scanPath, service.dir), err);
11812
12466
  continue;
11813
12467
  }
11814
12468
  if (!read || !read.config.name) continue;
11815
- const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, import_node_path53.default.join(service.dir, read.relFile)));
12469
+ const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, read.relFile)));
11816
12470
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
11817
12471
  }
11818
12472
  for (const worker of discovered) {
@@ -11824,7 +12478,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11824
12478
  }
11825
12479
  let anchorId = service.node.id;
11826
12480
  if (config.main) {
11827
- const entryRelPath = toPosix(import_node_path53.default.normalize(config.main));
12481
+ const entryRelPath = toPosix(import_node_path54.default.normalize(config.main));
11828
12482
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
11829
12483
  graph,
11830
12484
  service.pkg.name,
@@ -11851,15 +12505,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11851
12505
  nodesAdded++;
11852
12506
  }
11853
12507
  if (runtimeNode.id !== anchorId) {
11854
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types42.EdgeType.RUNS_ON);
12508
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
11855
12509
  if (!graph.hasEdge(runsOnId)) {
11856
12510
  const edge = {
11857
12511
  id: runsOnId,
11858
12512
  source: anchorId,
11859
12513
  target: runtimeNode.id,
11860
- type: import_types42.EdgeType.RUNS_ON,
11861
- provenance: import_types42.Provenance.EXTRACTED,
11862
- confidence: (0, import_types42.confidenceForExtracted)("structural"),
12514
+ type: import_types43.EdgeType.RUNS_ON,
12515
+ provenance: import_types43.Provenance.EXTRACTED,
12516
+ confidence: (0, import_types43.confidenceForExtracted)("structural"),
11863
12517
  evidence: {
11864
12518
  file: evidenceFile,
11865
12519
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -11873,7 +12527,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11873
12527
  const result = addResourceEdge(
11874
12528
  graph,
11875
12529
  anchorId,
11876
- import_types42.EdgeType.CONNECTS_TO,
12530
+ import_types43.EdgeType.CONNECTS_TO,
11877
12531
  "cloudflare-route",
11878
12532
  route,
11879
12533
  evidenceFile,
@@ -11897,7 +12551,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11897
12551
  const result = addResourceEdge(
11898
12552
  graph,
11899
12553
  anchorId,
11900
- import_types42.EdgeType.DEPENDS_ON,
12554
+ import_types43.EdgeType.DEPENDS_ON,
11901
12555
  group.kind,
11902
12556
  name,
11903
12557
  evidenceFile,
@@ -11911,7 +12565,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11911
12565
  const result = addResourceEdge(
11912
12566
  graph,
11913
12567
  anchorId,
11914
- import_types42.EdgeType.DEPENDS_ON,
12568
+ import_types43.EdgeType.DEPENDS_ON,
11915
12569
  "cloudflare-cron",
11916
12570
  cron,
11917
12571
  evidenceFile,
@@ -11924,7 +12578,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11924
12578
  const result = addResourceEdge(
11925
12579
  graph,
11926
12580
  anchorId,
11927
- import_types42.EdgeType.DEPENDS_ON,
12581
+ import_types43.EdgeType.DEPENDS_ON,
11928
12582
  "cloudflare-env-var",
11929
12583
  varName,
11930
12584
  evidenceFile,
@@ -11937,15 +12591,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11937
12591
  if (!svc.service) continue;
11938
12592
  const target = workerIndex.get(svc.service);
11939
12593
  if (target && target.anchorId !== anchorId) {
11940
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types42.EdgeType.CALLS);
12594
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
11941
12595
  if (!graph.hasEdge(edgeId)) {
11942
12596
  const edge = {
11943
12597
  id: edgeId,
11944
12598
  source: anchorId,
11945
12599
  target: target.anchorId,
11946
- type: import_types42.EdgeType.CALLS,
11947
- provenance: import_types42.Provenance.EXTRACTED,
11948
- confidence: (0, import_types42.confidenceForExtracted)("structural"),
12600
+ type: import_types43.EdgeType.CALLS,
12601
+ provenance: import_types43.Provenance.EXTRACTED,
12602
+ confidence: (0, import_types43.confidenceForExtracted)("structural"),
11949
12603
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
11950
12604
  };
11951
12605
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -11956,7 +12610,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11956
12610
  const result = addResourceEdge(
11957
12611
  graph,
11958
12612
  anchorId,
11959
- import_types42.EdgeType.DEPENDS_ON,
12613
+ import_types43.EdgeType.DEPENDS_ON,
11960
12614
  "cloudflare-service-binding",
11961
12615
  svc.service,
11962
12616
  evidenceFile,
@@ -11972,12 +12626,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
11972
12626
  // src/extract/infra/vercel.ts
11973
12627
  init_cjs_shims();
11974
12628
  var import_node_fs23 = require("fs");
11975
- var import_node_path54 = __toESM(require("path"), 1);
11976
- var import_types43 = require("@neat.is/types");
12629
+ var import_node_path55 = __toESM(require("path"), 1);
12630
+ var import_types44 = require("@neat.is/types");
11977
12631
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
11978
12632
  async function readVercelConfig(dir) {
11979
12633
  for (const filename of VERCEL_CONFIG_FILENAMES) {
11980
- const abs = import_node_path54.default.join(dir, filename);
12634
+ const abs = import_node_path55.default.join(dir, filename);
11981
12635
  if (!await exists(abs)) continue;
11982
12636
  const raw = await import_node_fs23.promises.readFile(abs, "utf8");
11983
12637
  const config = JSON.parse(maskCommentsInSource(raw));
@@ -11986,7 +12640,7 @@ async function readVercelConfig(dir) {
11986
12640
  return null;
11987
12641
  }
11988
12642
  async function readLinkedProjectName(dir) {
11989
- const abs = import_node_path54.default.join(dir, ".vercel", "project.json");
12643
+ const abs = import_node_path55.default.join(dir, ".vercel", "project.json");
11990
12644
  if (!await exists(abs)) return void 0;
11991
12645
  const parsed = JSON.parse(await import_node_fs23.promises.readFile(abs, "utf8"));
11992
12646
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
@@ -12004,7 +12658,7 @@ async function addVercelServices(graph, services, scanPath) {
12004
12658
  read = await readVercelConfig(service.dir);
12005
12659
  projectName = await readLinkedProjectName(service.dir);
12006
12660
  } catch (err) {
12007
- recordExtractionError("infra vercel", import_node_path54.default.relative(scanPath, service.dir), err);
12661
+ recordExtractionError("infra vercel", import_node_path55.default.relative(scanPath, service.dir), err);
12008
12662
  continue;
12009
12663
  }
12010
12664
  if (!read && !projectName) continue;
@@ -12020,7 +12674,7 @@ async function addVercelServices(graph, services, scanPath) {
12020
12674
  const anchorId = service.node.id;
12021
12675
  if (!read) continue;
12022
12676
  const { config, relFile, raw } = read;
12023
- const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, relFile)));
12677
+ const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
12024
12678
  const add = (edgeType, kind, name) => {
12025
12679
  if (!name) return;
12026
12680
  const result = emitPlatformResourceEdge(
@@ -12036,12 +12690,12 @@ async function addVercelServices(graph, services, scanPath) {
12036
12690
  nodesAdded += result.nodesAdded;
12037
12691
  edgesAdded += result.edgesAdded;
12038
12692
  };
12039
- add(import_types43.EdgeType.RUNS_ON, "vercel", "vercel");
12040
- for (const cron of config.crons ?? []) add(import_types43.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
12041
- for (const varName of Object.keys(config.env ?? {})) add(import_types43.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
12042
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types43.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
12693
+ add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
12694
+ for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
12695
+ for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
12696
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
12043
12697
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
12044
- add(import_types43.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
12698
+ add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
12045
12699
  }
12046
12700
  }
12047
12701
  return { nodesAdded, edgesAdded };
@@ -12050,13 +12704,13 @@ async function addVercelServices(graph, services, scanPath) {
12050
12704
  // src/extract/infra/railway.ts
12051
12705
  init_cjs_shims();
12052
12706
  var import_node_fs24 = require("fs");
12053
- var import_node_path55 = __toESM(require("path"), 1);
12707
+ var import_node_path56 = __toESM(require("path"), 1);
12054
12708
  var import_smol_toml3 = require("smol-toml");
12055
- var import_types44 = require("@neat.is/types");
12709
+ var import_types45 = require("@neat.is/types");
12056
12710
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
12057
12711
  async function readRailwayConfig(dir) {
12058
12712
  for (const filename of RAILWAY_FILENAMES) {
12059
- const abs = import_node_path55.default.join(dir, filename);
12713
+ const abs = import_node_path56.default.join(dir, filename);
12060
12714
  if (!await exists(abs)) continue;
12061
12715
  const raw = await import_node_fs24.promises.readFile(abs, "utf8");
12062
12716
  const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -12072,7 +12726,7 @@ async function addRailwayServices(graph, services, scanPath) {
12072
12726
  try {
12073
12727
  read = await readRailwayConfig(service.dir);
12074
12728
  } catch (err) {
12075
- recordExtractionError("infra railway", import_node_path55.default.relative(scanPath, service.dir), err);
12729
+ recordExtractionError("infra railway", import_node_path56.default.relative(scanPath, service.dir), err);
12076
12730
  continue;
12077
12731
  }
12078
12732
  if (!read) continue;
@@ -12082,7 +12736,7 @@ async function addRailwayServices(graph, services, scanPath) {
12082
12736
  }
12083
12737
  const anchorId = service.node.id;
12084
12738
  const { config, relFile, raw } = read;
12085
- const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
12739
+ const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
12086
12740
  const add = (edgeType, kind, name) => {
12087
12741
  if (!name) return;
12088
12742
  const result = emitPlatformResourceEdge(
@@ -12098,9 +12752,9 @@ async function addRailwayServices(graph, services, scanPath) {
12098
12752
  nodesAdded += result.nodesAdded;
12099
12753
  edgesAdded += result.edgesAdded;
12100
12754
  };
12101
- add(import_types44.EdgeType.RUNS_ON, "railway", "railway");
12102
- add(import_types44.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
12103
- add(import_types44.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
12755
+ add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
12756
+ add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
12757
+ add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
12104
12758
  }
12105
12759
  return { nodesAdded, edgesAdded };
12106
12760
  }
@@ -12108,12 +12762,12 @@ async function addRailwayServices(graph, services, scanPath) {
12108
12762
  // src/extract/infra/supabase.ts
12109
12763
  init_cjs_shims();
12110
12764
  var import_node_fs25 = require("fs");
12111
- var import_node_path56 = __toESM(require("path"), 1);
12765
+ var import_node_path57 = __toESM(require("path"), 1);
12112
12766
  var import_smol_toml4 = require("smol-toml");
12113
- var import_types45 = require("@neat.is/types");
12767
+ var import_types46 = require("@neat.is/types");
12114
12768
  async function readSupabaseConfig(dir) {
12115
- const relFile = import_node_path56.default.join("supabase", "config.toml");
12116
- const abs = import_node_path56.default.join(dir, relFile);
12769
+ const relFile = import_node_path57.default.join("supabase", "config.toml");
12770
+ const abs = import_node_path57.default.join(dir, relFile);
12117
12771
  if (!await exists(abs)) return null;
12118
12772
  const raw = await import_node_fs25.promises.readFile(abs, "utf8");
12119
12773
  const config = (0, import_smol_toml4.parse)(raw);
@@ -12127,7 +12781,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
12127
12781
  try {
12128
12782
  read = await readSupabaseConfig(service.dir);
12129
12783
  } catch (err) {
12130
- recordExtractionError("infra supabase", import_node_path56.default.relative(scanPath, service.dir), err);
12784
+ recordExtractionError("infra supabase", import_node_path57.default.relative(scanPath, service.dir), err);
12131
12785
  continue;
12132
12786
  }
12133
12787
  if (!read) continue;
@@ -12142,7 +12796,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
12142
12796
  });
12143
12797
  }
12144
12798
  const anchorId = service.node.id;
12145
- const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
12799
+ const evidenceFile = toPosix(import_node_path57.default.relative(scanPath, import_node_path57.default.join(service.dir, relFile)));
12146
12800
  const add = (edgeType, kind, name) => {
12147
12801
  if (!name) return;
12148
12802
  const result = emitPlatformResourceEdge(
@@ -12158,10 +12812,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
12158
12812
  nodesAdded += result.nodesAdded;
12159
12813
  edgesAdded += result.edgesAdded;
12160
12814
  };
12161
- add(import_types45.EdgeType.RUNS_ON, "supabase", "supabase");
12162
- for (const fn of Object.keys(config.functions ?? {})) add(import_types45.EdgeType.DEPENDS_ON, "supabase-function", fn);
12163
- if (config.storage) add(import_types45.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
12164
- if (config.auth) add(import_types45.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
12815
+ add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
12816
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
12817
+ if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
12818
+ if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
12165
12819
  }
12166
12820
  return { nodesAdded, edgesAdded };
12167
12821
  }
@@ -12184,14 +12838,14 @@ async function addInfra(graph, scanPath, services) {
12184
12838
 
12185
12839
  // src/extract/zod-shapes.ts
12186
12840
  init_cjs_shims();
12187
- var import_node_path57 = __toESM(require("path"), 1);
12188
- var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
12841
+ var import_node_path58 = __toESM(require("path"), 1);
12842
+ var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
12189
12843
  var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
12190
- var import_types46 = require("@neat.is/types");
12844
+ var import_types47 = require("@neat.is/types");
12191
12845
  var ZOD_IMPORT_RE = /\bzod\b/;
12192
12846
  var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
12193
12847
  function parserForExt3(ext) {
12194
- const p = new import_tree_sitter15.default();
12848
+ const p = new import_tree_sitter16.default();
12195
12849
  p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
12196
12850
  return p;
12197
12851
  }
@@ -12279,7 +12933,7 @@ function topLevelSchemas(root) {
12279
12933
  }
12280
12934
  function zodShapesFromFile(file, serviceDir) {
12281
12935
  if (!ZOD_IMPORT_RE.test(file.content)) return [];
12282
- const tree = parseSource3(parserForExt3(import_node_path57.default.extname(file.path)), file.content);
12936
+ const tree = parseSource3(parserForExt3(import_node_path58.default.extname(file.path)), file.content);
12283
12937
  const out = [];
12284
12938
  const seen = /* @__PURE__ */ new Set();
12285
12939
  for (const { name, call } of topLevelSchemas(tree.rootNode)) {
@@ -12293,11 +12947,11 @@ function zodShapesFromFile(file, serviceDir) {
12293
12947
  seen.add(name);
12294
12948
  const line = call.startPosition.row + 1;
12295
12949
  out.push({
12296
- infraId: (0, import_types46.infraId)("zod-schema", name),
12950
+ infraId: (0, import_types47.infraId)("zod-schema", name),
12297
12951
  name,
12298
12952
  fields,
12299
12953
  evidence: {
12300
- file: import_node_path57.default.relative(serviceDir, file.path),
12954
+ file: import_node_path58.default.relative(serviceDir, file.path),
12301
12955
  line,
12302
12956
  snippet: snippet(file.content, line)
12303
12957
  }
@@ -12328,7 +12982,7 @@ async function addZodShapes(graph, services) {
12328
12982
  if (!graph.hasNode(shape.infraId)) {
12329
12983
  const node = {
12330
12984
  id: shape.infraId,
12331
- type: import_types46.NodeType.InfraNode,
12985
+ type: import_types47.NodeType.InfraNode,
12332
12986
  name: shape.name,
12333
12987
  provider: "self",
12334
12988
  kind: "zod-schema"
@@ -12338,14 +12992,14 @@ async function addZodShapes(graph, services) {
12338
12992
  }
12339
12993
  if (shape.fields.length > 0) {
12340
12994
  const node = graph.getNodeAttributes(shape.infraId);
12341
- if (node.type === import_types46.NodeType.InfraNode) {
12995
+ if (node.type === import_types47.NodeType.InfraNode) {
12342
12996
  graph.replaceNodeAttributes(shape.infraId, {
12343
12997
  ...node,
12344
12998
  columns: foldColumns(
12345
12999
  node.columns,
12346
13000
  shape.fields,
12347
- import_types46.Provenance.EXTRACTED,
12348
- (0, import_types46.confidenceForExtracted)("structural")
13001
+ import_types47.Provenance.EXTRACTED,
13002
+ (0, import_types47.confidenceForExtracted)("structural")
12349
13003
  )
12350
13004
  });
12351
13005
  }
@@ -12359,15 +13013,15 @@ async function addZodShapes(graph, services) {
12359
13013
  );
12360
13014
  nodesAdded += n;
12361
13015
  edgesAdded += e;
12362
- const edgeId = (0, import_types46.extractedEdgeId)(fileNodeId, shape.infraId, import_types46.EdgeType.CONTAINS);
13016
+ const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
12363
13017
  if (!graph.hasEdge(edgeId)) {
12364
13018
  const edge = {
12365
13019
  id: edgeId,
12366
13020
  source: fileNodeId,
12367
13021
  target: shape.infraId,
12368
- type: import_types46.EdgeType.CONTAINS,
12369
- provenance: import_types46.Provenance.EXTRACTED,
12370
- confidence: (0, import_types46.confidenceForExtracted)("structural"),
13022
+ type: import_types47.EdgeType.CONTAINS,
13023
+ provenance: import_types47.Provenance.EXTRACTED,
13024
+ confidence: (0, import_types47.confidenceForExtracted)("structural"),
12371
13025
  evidence: shape.evidence
12372
13026
  };
12373
13027
  graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
@@ -12381,7 +13035,7 @@ async function addZodShapes(graph, services) {
12381
13035
 
12382
13036
  // src/extract/firestore-rules.ts
12383
13037
  init_cjs_shims();
12384
- var import_types47 = require("@neat.is/types");
13038
+ var import_types48 = require("@neat.is/types");
12385
13039
  var FIRESTORE_COLLECTION_KIND = "firestore-collection";
12386
13040
  var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
12387
13041
  function stripComments(src) {
@@ -12521,7 +13175,7 @@ async function addFirestoreRules(graph, services) {
12521
13175
  if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
12522
13176
  graph.forEachNode((id, attrs) => {
12523
13177
  const node = attrs;
12524
- if (node.type !== import_types47.NodeType.InfraNode) return;
13178
+ if (node.type !== import_types48.NodeType.InfraNode) return;
12525
13179
  if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
12526
13180
  const fields = guards.get(collectionKeyFromName(node.name));
12527
13181
  if (!fields || fields.size === 0) return;
@@ -12534,17 +13188,17 @@ async function addFirestoreRules(graph, services) {
12534
13188
  }
12535
13189
 
12536
13190
  // src/extract/index.ts
12537
- var import_node_path59 = __toESM(require("path"), 1);
13191
+ var import_node_path60 = __toESM(require("path"), 1);
12538
13192
 
12539
13193
  // src/extract/retire.ts
12540
13194
  init_cjs_shims();
12541
13195
  var import_node_fs26 = require("fs");
12542
- var import_node_path58 = __toESM(require("path"), 1);
12543
- var import_types48 = require("@neat.is/types");
13196
+ var import_node_path59 = __toESM(require("path"), 1);
13197
+ var import_types49 = require("@neat.is/types");
12544
13198
  function dropOrphanedFileNodes(graph) {
12545
13199
  const orphans = [];
12546
13200
  graph.forEachNode((id, attrs) => {
12547
- if (attrs.type !== import_types48.NodeType.FileNode) return;
13201
+ if (attrs.type !== import_types49.NodeType.FileNode) return;
12548
13202
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
12549
13203
  orphans.push(id);
12550
13204
  }
@@ -12557,7 +13211,7 @@ function retireEdgesByFile(graph, file) {
12557
13211
  const toDrop = [];
12558
13212
  graph.forEachEdge((id, attrs) => {
12559
13213
  const edge = attrs;
12560
- if (edge.provenance !== import_types48.Provenance.EXTRACTED) return;
13214
+ if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
12561
13215
  if (!edge.evidence?.file) return;
12562
13216
  if (edge.evidence.file === normalized) toDrop.push(id);
12563
13217
  });
@@ -12570,14 +13224,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
12570
13224
  const bases = [scanPath, ...serviceDirs];
12571
13225
  graph.forEachEdge((id, attrs) => {
12572
13226
  const edge = attrs;
12573
- if (edge.provenance !== import_types48.Provenance.EXTRACTED) return;
13227
+ if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
12574
13228
  const evidenceFile = edge.evidence?.file;
12575
13229
  if (!evidenceFile) return;
12576
- if (import_node_path58.default.isAbsolute(evidenceFile)) {
13230
+ if (import_node_path59.default.isAbsolute(evidenceFile)) {
12577
13231
  if (!(0, import_node_fs26.existsSync)(evidenceFile)) toDrop.push(id);
12578
13232
  return;
12579
13233
  }
12580
- const found = bases.some((base) => (0, import_node_fs26.existsSync)(import_node_path58.default.join(base, evidenceFile)));
13234
+ const found = bases.some((base) => (0, import_node_fs26.existsSync)(import_node_path59.default.join(base, evidenceFile)));
12581
13235
  if (!found) toDrop.push(id);
12582
13236
  });
12583
13237
  for (const id of toDrop) graph.dropEdge(id);
@@ -12634,7 +13288,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
12634
13288
  }
12635
13289
  const droppedEntries = drainDroppedExtracted();
12636
13290
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
12637
- const rejectedPath = import_node_path59.default.join(import_node_path59.default.dirname(opts.errorsPath), "rejected.ndjson");
13291
+ const rejectedPath = import_node_path60.default.join(import_node_path60.default.dirname(opts.errorsPath), "rejected.ndjson");
12638
13292
  try {
12639
13293
  await writeRejectedExtracted(droppedEntries, rejectedPath);
12640
13294
  } catch (err) {
@@ -12668,39 +13322,39 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
12668
13322
 
12669
13323
  // src/divergences.ts
12670
13324
  init_cjs_shims();
12671
- var import_types49 = require("@neat.is/types");
13325
+ var import_types50 = require("@neat.is/types");
12672
13326
  function bucketKey(source, target, type) {
12673
13327
  return `${type}|${source}|${target}`;
12674
13328
  }
12675
13329
  function bucketSourceFor(graph, edge) {
12676
- if (edge.type !== import_types49.EdgeType.CONNECTS_TO) return edge.source;
12677
- const parsed = (0, import_types49.parseFileId)(edge.source);
13330
+ if (edge.type !== import_types50.EdgeType.CONNECTS_TO) return edge.source;
13331
+ const parsed = (0, import_types50.parseFileId)(edge.source);
12678
13332
  if (!parsed || !graph.hasNode(edge.target)) return edge.source;
12679
13333
  const target = graph.getNodeAttributes(edge.target);
12680
- if (target.type !== import_types49.NodeType.DatabaseNode) return edge.source;
12681
- return (0, import_types49.serviceId)(parsed.service);
13334
+ if (target.type !== import_types50.NodeType.DatabaseNode) return edge.source;
13335
+ return (0, import_types50.serviceId)(parsed.service);
12682
13336
  }
12683
13337
  function bucketEdges(graph) {
12684
13338
  const buckets2 = /* @__PURE__ */ new Map();
12685
13339
  graph.forEachEdge((id, attrs) => {
12686
13340
  const e = attrs;
12687
- const parsed = (0, import_types49.parseEdgeId)(id);
13341
+ const parsed = (0, import_types50.parseEdgeId)(id);
12688
13342
  const provenance = parsed?.provenance ?? e.provenance;
12689
13343
  const source = bucketSourceFor(graph, e);
12690
13344
  const key = bucketKey(source, e.target, e.type);
12691
13345
  const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
12692
13346
  switch (provenance) {
12693
- case import_types49.Provenance.EXTRACTED:
13347
+ case import_types50.Provenance.EXTRACTED:
12694
13348
  cur.extracted = e;
12695
13349
  break;
12696
- case import_types49.Provenance.OBSERVED:
13350
+ case import_types50.Provenance.OBSERVED:
12697
13351
  cur.observed = e;
12698
13352
  break;
12699
- case import_types49.Provenance.INFERRED:
13353
+ case import_types50.Provenance.INFERRED:
12700
13354
  cur.inferred = e;
12701
13355
  break;
12702
13356
  default:
12703
- if (e.provenance === import_types49.Provenance.STALE) cur.stale = e;
13357
+ if (e.provenance === import_types50.Provenance.STALE) cur.stale = e;
12704
13358
  }
12705
13359
  buckets2.set(key, cur);
12706
13360
  });
@@ -12709,22 +13363,22 @@ function bucketEdges(graph) {
12709
13363
  function nodeIsFrontier(graph, nodeId) {
12710
13364
  if (!graph.hasNode(nodeId)) return false;
12711
13365
  const attrs = graph.getNodeAttributes(nodeId);
12712
- return attrs.type === import_types49.NodeType.FrontierNode;
13366
+ return attrs.type === import_types50.NodeType.FrontierNode;
12713
13367
  }
12714
13368
  function nodeIsWebsocketChannel(graph, nodeId) {
12715
13369
  if (!graph.hasNode(nodeId)) return false;
12716
13370
  const attrs = graph.getNodeAttributes(nodeId);
12717
- return attrs.type === import_types49.NodeType.WebSocketChannelNode;
13371
+ return attrs.type === import_types50.NodeType.WebSocketChannelNode;
12718
13372
  }
12719
13373
  function nodeIsServerAction(graph, nodeId) {
12720
13374
  if (!graph.hasNode(nodeId)) return false;
12721
13375
  const attrs = graph.getNodeAttributes(nodeId);
12722
- return attrs.type === import_types49.NodeType.ServerActionNode;
13376
+ return attrs.type === import_types50.NodeType.ServerActionNode;
12723
13377
  }
12724
13378
  function nodeIsSymbol(graph, nodeId) {
12725
13379
  if (!graph.hasNode(nodeId)) return false;
12726
13380
  const attrs = graph.getNodeAttributes(nodeId);
12727
- return attrs.type === import_types49.NodeType.SymbolNode;
13381
+ return attrs.type === import_types50.NodeType.SymbolNode;
12728
13382
  }
12729
13383
  function clampConfidence(n) {
12730
13384
  if (!Number.isFinite(n)) return 0;
@@ -12744,14 +13398,14 @@ function gradedConfidence(edge) {
12744
13398
  return clampConfidence(confidenceForEdge(edge));
12745
13399
  }
12746
13400
  var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
12747
- import_types49.EdgeType.CALLS,
12748
- import_types49.EdgeType.CONNECTS_TO,
12749
- import_types49.EdgeType.PUBLISHES_TO,
12750
- import_types49.EdgeType.CONSUMES_FROM
13401
+ import_types50.EdgeType.CALLS,
13402
+ import_types50.EdgeType.CONNECTS_TO,
13403
+ import_types50.EdgeType.PUBLISHES_TO,
13404
+ import_types50.EdgeType.CONSUMES_FROM
12751
13405
  ]);
12752
13406
  function detectMissingDivergences(graph, bucket) {
12753
13407
  const out = [];
12754
- if (bucket.type === import_types49.EdgeType.CONTAINS) return out;
13408
+ if (bucket.type === import_types50.EdgeType.CONTAINS) return out;
12755
13409
  if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
12756
13410
  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
12757
13411
  if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
@@ -12793,7 +13447,7 @@ function declaredHostFor(svc) {
12793
13447
  function hasExtractedConfiguredBy(graph, svcId) {
12794
13448
  for (const edgeId of graph.outboundEdges(svcId)) {
12795
13449
  const e = graph.getEdgeAttributes(edgeId);
12796
- if (e.type === import_types49.EdgeType.CONFIGURED_BY && e.provenance === import_types49.Provenance.EXTRACTED) {
13450
+ if (e.type === import_types50.EdgeType.CONFIGURED_BY && e.provenance === import_types50.Provenance.EXTRACTED) {
12797
13451
  return true;
12798
13452
  }
12799
13453
  }
@@ -12806,10 +13460,10 @@ function detectHostMismatch(graph, svcId, svc) {
12806
13460
  const out = [];
12807
13461
  for (const edgeId of graph.outboundEdges(svcId)) {
12808
13462
  const edge = graph.getEdgeAttributes(edgeId);
12809
- if (edge.type !== import_types49.EdgeType.CONNECTS_TO) continue;
12810
- if (edge.provenance !== import_types49.Provenance.OBSERVED) continue;
13463
+ if (edge.type !== import_types50.EdgeType.CONNECTS_TO) continue;
13464
+ if (edge.provenance !== import_types50.Provenance.OBSERVED) continue;
12811
13465
  const target = graph.getNodeAttributes(edge.target);
12812
- if (target.type !== import_types49.NodeType.DatabaseNode) continue;
13466
+ if (target.type !== import_types50.NodeType.DatabaseNode) continue;
12813
13467
  const observedHost = target.host?.trim();
12814
13468
  if (!observedHost) continue;
12815
13469
  if (observedHost === declaredHost) continue;
@@ -12831,10 +13485,10 @@ function detectCompatDivergences(graph, svcId, svc) {
12831
13485
  const deps = svc.dependencies ?? {};
12832
13486
  for (const edgeId of graph.outboundEdges(svcId)) {
12833
13487
  const edge = graph.getEdgeAttributes(edgeId);
12834
- if (edge.type !== import_types49.EdgeType.CONNECTS_TO) continue;
12835
- if (edge.provenance !== import_types49.Provenance.OBSERVED) continue;
13488
+ if (edge.type !== import_types50.EdgeType.CONNECTS_TO) continue;
13489
+ if (edge.provenance !== import_types50.Provenance.OBSERVED) continue;
12836
13490
  const target = graph.getNodeAttributes(edge.target);
12837
- if (target.type !== import_types49.NodeType.DatabaseNode) continue;
13491
+ if (target.type !== import_types50.NodeType.DatabaseNode) continue;
12838
13492
  for (const pair of compatPairs()) {
12839
13493
  if (pair.engine !== target.engine) continue;
12840
13494
  const declared = deps[pair.driver];
@@ -12931,7 +13585,7 @@ function suppressHostMismatchHalves(all) {
12931
13585
  for (const d of all) {
12932
13586
  if (d.type !== "host-mismatch") continue;
12933
13587
  observedHalf.add(`${d.source}->${d.target}`);
12934
- declaredHalf.add((0, import_types49.databaseId)(d.extractedHost));
13588
+ declaredHalf.add((0, import_types50.databaseId)(d.extractedHost));
12935
13589
  }
12936
13590
  if (observedHalf.size === 0) return all;
12937
13591
  return all.filter((d) => {
@@ -12950,13 +13604,13 @@ function computeDivergences(graph, opts = {}) {
12950
13604
  }
12951
13605
  graph.forEachNode((nodeId, attrs) => {
12952
13606
  const n = attrs;
12953
- if (n.type === import_types49.NodeType.ServiceNode) {
13607
+ if (n.type === import_types50.NodeType.ServiceNode) {
12954
13608
  const svc = n;
12955
13609
  for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
12956
13610
  for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
12957
13611
  return;
12958
13612
  }
12959
- if (n.type === import_types49.NodeType.InfraNode && n.kind === "sql-table") {
13613
+ if (n.type === import_types50.NodeType.InfraNode && n.kind === "sql-table") {
12960
13614
  for (const d of detectColumnDrift(n)) all.push(d);
12961
13615
  }
12962
13616
  });
@@ -12992,7 +13646,7 @@ function computeDivergences(graph, opts = {}) {
12992
13646
  const bc = "column" in b && b.column ? b.column : "";
12993
13647
  return ac.localeCompare(bc);
12994
13648
  });
12995
- return import_types49.DivergenceResultSchema.parse({
13649
+ return import_types50.DivergenceResultSchema.parse({
12996
13650
  divergences: filtered,
12997
13651
  totalAffected: filtered.length,
12998
13652
  computedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -13002,8 +13656,8 @@ function computeDivergences(graph, opts = {}) {
13002
13656
  // src/persist.ts
13003
13657
  init_cjs_shims();
13004
13658
  var import_node_fs27 = require("fs");
13005
- var import_node_path60 = __toESM(require("path"), 1);
13006
- var import_types50 = require("@neat.is/types");
13659
+ var import_node_path61 = __toESM(require("path"), 1);
13660
+ var import_types51 = require("@neat.is/types");
13007
13661
  var SCHEMA_VERSION = 7;
13008
13662
  function migrateV1ToV2(payload) {
13009
13663
  const nodes = payload.graph.nodes;
@@ -13027,7 +13681,7 @@ function migrateV5ToV6(payload) {
13027
13681
  if (Array.isArray(nodes)) {
13028
13682
  for (const node of nodes) {
13029
13683
  const attrs = node.attributes;
13030
- if (!attrs || attrs.type !== import_types50.NodeType.InfraNode) continue;
13684
+ if (!attrs || attrs.type !== import_types51.NodeType.InfraNode) continue;
13031
13685
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
13032
13686
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
13033
13687
  }
@@ -13043,12 +13697,12 @@ function migrateV2ToV3(payload) {
13043
13697
  for (const edge of edges) {
13044
13698
  const attrs = edge.attributes;
13045
13699
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
13046
- attrs.provenance = import_types50.Provenance.OBSERVED;
13700
+ attrs.provenance = import_types51.Provenance.OBSERVED;
13047
13701
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
13048
13702
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
13049
13703
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
13050
13704
  if (type && source && target) {
13051
- const newId = (0, import_types50.observedEdgeId)(source, target, type);
13705
+ const newId = (0, import_types51.observedEdgeId)(source, target, type);
13052
13706
  attrs.id = newId;
13053
13707
  if (edge.key) edge.key = newId;
13054
13708
  }
@@ -13057,7 +13711,7 @@ function migrateV2ToV3(payload) {
13057
13711
  return { ...payload, schemaVersion: 3 };
13058
13712
  }
13059
13713
  async function ensureDir(filePath) {
13060
- await import_node_fs27.promises.mkdir(import_node_path60.default.dirname(filePath), { recursive: true });
13714
+ await import_node_fs27.promises.mkdir(import_node_path61.default.dirname(filePath), { recursive: true });
13061
13715
  }
13062
13716
  async function saveGraphToDisk(graph, outPath) {
13063
13717
  await ensureDir(outPath);
@@ -13148,7 +13802,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
13148
13802
  // src/gitignore.ts
13149
13803
  init_cjs_shims();
13150
13804
  var import_node_fs28 = require("fs");
13151
- var import_node_path61 = __toESM(require("path"), 1);
13805
+ var import_node_path62 = __toESM(require("path"), 1);
13152
13806
  var NEAT_OUT_LINE = "neat-out/";
13153
13807
  var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
13154
13808
  function isNeatOutLine(line) {
@@ -13156,7 +13810,7 @@ function isNeatOutLine(line) {
13156
13810
  return trimmed === "neat-out/" || trimmed === "neat-out";
13157
13811
  }
13158
13812
  async function ensureNeatOutIgnored(projectDir) {
13159
- const file = import_node_path61.default.join(projectDir, ".gitignore");
13813
+ const file = import_node_path62.default.join(projectDir, ".gitignore");
13160
13814
  let existing = null;
13161
13815
  try {
13162
13816
  existing = await import_node_fs28.promises.readFile(file, "utf8");
@@ -13183,7 +13837,7 @@ ${NEAT_OUT_LINE}
13183
13837
 
13184
13838
  // src/summary.ts
13185
13839
  init_cjs_shims();
13186
- var import_types51 = require("@neat.is/types");
13840
+ var import_types52 = require("@neat.is/types");
13187
13841
  function renderOtelEnvBlock() {
13188
13842
  return [
13189
13843
  "for prod OTel routing, set these in your deploy platform's env:",
@@ -13193,19 +13847,19 @@ function renderOtelEnvBlock() {
13193
13847
  }
13194
13848
  function findIncompatServices(nodes) {
13195
13849
  return nodes.filter(
13196
- (n) => n.type === import_types51.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
13850
+ (n) => n.type === import_types52.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
13197
13851
  );
13198
13852
  }
13199
13853
  function servicesWithoutObserved(nodes, edges) {
13200
13854
  const seen = /* @__PURE__ */ new Set();
13201
13855
  for (const e of edges) {
13202
- if (e.provenance === import_types51.Provenance.OBSERVED) {
13856
+ if (e.provenance === import_types52.Provenance.OBSERVED) {
13203
13857
  seen.add(e.source);
13204
13858
  seen.add(e.target);
13205
13859
  }
13206
13860
  }
13207
13861
  return nodes.filter(
13208
- (n) => n.type === import_types51.NodeType.ServiceNode && !seen.has(n.id)
13862
+ (n) => n.type === import_types52.NodeType.ServiceNode && !seen.has(n.id)
13209
13863
  );
13210
13864
  }
13211
13865
  function formatDivergence(d) {
@@ -13280,26 +13934,26 @@ function formatIncompat(inc) {
13280
13934
  // src/watch.ts
13281
13935
  init_cjs_shims();
13282
13936
  var import_node_fs37 = __toESM(require("fs"), 1);
13283
- var import_node_path70 = __toESM(require("path"), 1);
13937
+ var import_node_path71 = __toESM(require("path"), 1);
13284
13938
  var import_chokidar = __toESM(require("chokidar"), 1);
13285
13939
 
13286
13940
  // src/api.ts
13287
13941
  init_cjs_shims();
13288
13942
  var import_fastify2 = __toESM(require("fastify"), 1);
13289
13943
  var import_cors = __toESM(require("@fastify/cors"), 1);
13290
- var import_types80 = require("@neat.is/types");
13944
+ var import_types81 = require("@neat.is/types");
13291
13945
 
13292
13946
  // src/extend/index.ts
13293
13947
  init_cjs_shims();
13294
13948
  var import_node_fs30 = require("fs");
13295
- var import_node_path63 = __toESM(require("path"), 1);
13949
+ var import_node_path64 = __toESM(require("path"), 1);
13296
13950
  var import_node_os2 = __toESM(require("os"), 1);
13297
13951
  var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
13298
13952
 
13299
13953
  // src/installers/package-manager.ts
13300
13954
  init_cjs_shims();
13301
13955
  var import_node_fs29 = require("fs");
13302
- var import_node_path62 = __toESM(require("path"), 1);
13956
+ var import_node_path63 = __toESM(require("path"), 1);
13303
13957
  var import_node_child_process = require("child_process");
13304
13958
  var LOCKFILE_PRIORITY = [
13305
13959
  { lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
@@ -13321,22 +13975,22 @@ async function exists2(p) {
13321
13975
  }
13322
13976
  }
13323
13977
  async function detectPackageManager(serviceDir) {
13324
- let dir = import_node_path62.default.resolve(serviceDir);
13978
+ let dir = import_node_path63.default.resolve(serviceDir);
13325
13979
  const stops = /* @__PURE__ */ new Set();
13326
13980
  for (let i = 0; i < 64; i++) {
13327
13981
  if (stops.has(dir)) break;
13328
13982
  stops.add(dir);
13329
13983
  for (const candidate of LOCKFILE_PRIORITY) {
13330
- const lockPath = import_node_path62.default.join(dir, candidate.lockfile);
13984
+ const lockPath = import_node_path63.default.join(dir, candidate.lockfile);
13331
13985
  if (await exists2(lockPath)) {
13332
13986
  return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
13333
13987
  }
13334
13988
  }
13335
- const parent = import_node_path62.default.dirname(dir);
13989
+ const parent = import_node_path63.default.dirname(dir);
13336
13990
  if (parent === dir) break;
13337
13991
  dir = parent;
13338
13992
  }
13339
- return { pm: "npm", cwd: import_node_path62.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
13993
+ return { pm: "npm", cwd: import_node_path63.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
13340
13994
  }
13341
13995
  async function runPackageManagerInstall(cmd) {
13342
13996
  return new Promise((resolve) => {
@@ -13385,7 +14039,7 @@ async function fileExists2(p) {
13385
14039
  }
13386
14040
  }
13387
14041
  async function readPackageJson(scanPath) {
13388
- const pkgPath = import_node_path63.default.join(scanPath, "package.json");
14042
+ const pkgPath = import_node_path64.default.join(scanPath, "package.json");
13389
14043
  const raw = await import_node_fs30.promises.readFile(pkgPath, "utf8");
13390
14044
  return JSON.parse(raw);
13391
14045
  }
@@ -13399,27 +14053,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
13399
14053
  ]);
13400
14054
  async function findHookFiles(scanPath) {
13401
14055
  const found = [];
13402
- const walk8 = async (dir) => {
14056
+ const walk9 = async (dir) => {
13403
14057
  const entries = await import_node_fs30.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
13404
14058
  for (const entry2 of entries) {
13405
14059
  if (entry2.isDirectory()) {
13406
14060
  if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
13407
- await walk8(import_node_path63.default.join(dir, entry2.name));
14061
+ await walk9(import_node_path64.default.join(dir, entry2.name));
13408
14062
  } else if (entry2.isFile()) {
13409
14063
  if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
13410
- const rel = import_node_path63.default.relative(scanPath, import_node_path63.default.join(dir, entry2.name));
13411
- found.push(rel.split(import_node_path63.default.sep).join("/"));
14064
+ const rel = import_node_path64.default.relative(scanPath, import_node_path64.default.join(dir, entry2.name));
14065
+ found.push(rel.split(import_node_path64.default.sep).join("/"));
13412
14066
  }
13413
14067
  }
13414
14068
  }
13415
14069
  };
13416
- await walk8(scanPath);
14070
+ await walk9(scanPath);
13417
14071
  return found.sort();
13418
14072
  }
13419
14073
  async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
13420
14074
  let fallback = null;
13421
14075
  for (const file of hookFiles) {
13422
- const content = await import_node_fs30.promises.readFile(import_node_path63.default.join(scanPath, file), "utf8");
14076
+ const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(scanPath, file), "utf8");
13423
14077
  const patched = splicedContent(content, snippet2);
13424
14078
  if (patched !== null) return { file, content, patched };
13425
14079
  if (fallback === null) fallback = { file, content };
@@ -13427,11 +14081,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
13427
14081
  return { file: fallback.file, content: fallback.content, patched: null };
13428
14082
  }
13429
14083
  function extendLogPath() {
13430
- return process.env.NEAT_EXTEND_LOG ?? import_node_path63.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
14084
+ return process.env.NEAT_EXTEND_LOG ?? import_node_path64.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
13431
14085
  }
13432
14086
  async function appendExtendLog(entry2) {
13433
14087
  const logPath = extendLogPath();
13434
- await import_node_fs30.promises.mkdir(import_node_path63.default.dirname(logPath), { recursive: true });
14088
+ await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(logPath), { recursive: true });
13435
14089
  await import_node_fs30.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
13436
14090
  }
13437
14091
  function splicedContent(fileContent, snippet2) {
@@ -13490,7 +14144,7 @@ function lookupInstrumentation(library, installedVersion) {
13490
14144
  }
13491
14145
  async function describeProjectInstrumentation(ctx) {
13492
14146
  const hookFiles = await findHookFiles(ctx.scanPath);
13493
- const envNeat = await fileExists2(import_node_path63.default.join(ctx.scanPath, ".env.neat"));
14147
+ const envNeat = await fileExists2(import_node_path64.default.join(ctx.scanPath, ".env.neat"));
13494
14148
  const registryInstrPackages = new Set(
13495
14149
  (0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
13496
14150
  );
@@ -13512,7 +14166,7 @@ async function applyExtension(ctx, args, options) {
13512
14166
  );
13513
14167
  }
13514
14168
  for (const file of hookFiles) {
13515
- const content = await import_node_fs30.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
14169
+ const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(ctx.scanPath, file), "utf8");
13516
14170
  if (content.includes(args.registration_snippet)) {
13517
14171
  return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
13518
14172
  }
@@ -13524,10 +14178,10 @@ async function applyExtension(ctx, args, options) {
13524
14178
  );
13525
14179
  }
13526
14180
  const primaryFile = primary.file;
13527
- const primaryPath = import_node_path63.default.join(ctx.scanPath, primaryFile);
14181
+ const primaryPath = import_node_path64.default.join(ctx.scanPath, primaryFile);
13528
14182
  const filesTouched = [];
13529
14183
  const depsAdded = [];
13530
- const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
14184
+ const pkgPath = import_node_path64.default.join(ctx.scanPath, "package.json");
13531
14185
  const pkg = await readPackageJson(ctx.scanPath);
13532
14186
  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
13533
14187
  pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
@@ -13566,7 +14220,7 @@ async function dryRunExtension(ctx, args) {
13566
14220
  };
13567
14221
  }
13568
14222
  for (const file of hookFiles) {
13569
- const content = await import_node_fs30.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
14223
+ const content = await import_node_fs30.promises.readFile(import_node_path64.default.join(ctx.scanPath, file), "utf8");
13570
14224
  if (content.includes(args.registration_snippet)) {
13571
14225
  return {
13572
14226
  library: args.library,
@@ -13607,7 +14261,7 @@ async function rollbackExtension(ctx, args) {
13607
14261
  if (!match) {
13608
14262
  return { undone: false, message: "no apply found for library" };
13609
14263
  }
13610
- const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
14264
+ const pkgPath = import_node_path64.default.join(ctx.scanPath, "package.json");
13611
14265
  if (await fileExists2(pkgPath)) {
13612
14266
  const pkg = await readPackageJson(ctx.scanPath);
13613
14267
  if (pkg.dependencies?.[match.instrumentation_package]) {
@@ -13618,7 +14272,7 @@ async function rollbackExtension(ctx, args) {
13618
14272
  }
13619
14273
  const hookFiles = await findHookFiles(ctx.scanPath);
13620
14274
  for (const file of hookFiles) {
13621
- const filePath = import_node_path63.default.join(ctx.scanPath, file);
14275
+ const filePath = import_node_path64.default.join(ctx.scanPath, file);
13622
14276
  const content = await import_node_fs30.promises.readFile(filePath, "utf8");
13623
14277
  if (content.includes(match.registration_snippet)) {
13624
14278
  const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
@@ -13756,23 +14410,23 @@ function canonicalJson(value) {
13756
14410
 
13757
14411
  // src/projects.ts
13758
14412
  init_cjs_shims();
13759
- var import_node_path64 = __toESM(require("path"), 1);
14413
+ var import_node_path65 = __toESM(require("path"), 1);
13760
14414
  function pathsForProject(project, baseDir) {
13761
14415
  if (project === DEFAULT_PROJECT) {
13762
14416
  return {
13763
- snapshotPath: import_node_path64.default.join(baseDir, "graph.json"),
13764
- errorsPath: import_node_path64.default.join(baseDir, "errors.ndjson"),
13765
- staleEventsPath: import_node_path64.default.join(baseDir, "stale-events.ndjson"),
13766
- embeddingsCachePath: import_node_path64.default.join(baseDir, "embeddings.json"),
13767
- policyViolationsPath: import_node_path64.default.join(baseDir, "policy-violations.ndjson")
14417
+ snapshotPath: import_node_path65.default.join(baseDir, "graph.json"),
14418
+ errorsPath: import_node_path65.default.join(baseDir, "errors.ndjson"),
14419
+ staleEventsPath: import_node_path65.default.join(baseDir, "stale-events.ndjson"),
14420
+ embeddingsCachePath: import_node_path65.default.join(baseDir, "embeddings.json"),
14421
+ policyViolationsPath: import_node_path65.default.join(baseDir, "policy-violations.ndjson")
13768
14422
  };
13769
14423
  }
13770
14424
  return {
13771
- snapshotPath: import_node_path64.default.join(baseDir, `${project}.json`),
13772
- errorsPath: import_node_path64.default.join(baseDir, `errors.${project}.ndjson`),
13773
- staleEventsPath: import_node_path64.default.join(baseDir, `stale-events.${project}.ndjson`),
13774
- embeddingsCachePath: import_node_path64.default.join(baseDir, `embeddings.${project}.json`),
13775
- policyViolationsPath: import_node_path64.default.join(baseDir, `policy-violations.${project}.ndjson`)
14425
+ snapshotPath: import_node_path65.default.join(baseDir, `${project}.json`),
14426
+ errorsPath: import_node_path65.default.join(baseDir, `errors.${project}.ndjson`),
14427
+ staleEventsPath: import_node_path65.default.join(baseDir, `stale-events.${project}.ndjson`),
14428
+ embeddingsCachePath: import_node_path65.default.join(baseDir, `embeddings.${project}.json`),
14429
+ policyViolationsPath: import_node_path65.default.join(baseDir, `policy-violations.${project}.ndjson`)
13776
14430
  };
13777
14431
  }
13778
14432
  var Projects = class {
@@ -13810,26 +14464,26 @@ var Projects = class {
13810
14464
  init_cjs_shims();
13811
14465
  var import_node_fs32 = require("fs");
13812
14466
  var import_node_os3 = __toESM(require("os"), 1);
13813
- var import_node_path65 = __toESM(require("path"), 1);
13814
- var import_types52 = require("@neat.is/types");
14467
+ var import_node_path66 = __toESM(require("path"), 1);
14468
+ var import_types53 = require("@neat.is/types");
13815
14469
  var LOCK_TIMEOUT_MS = 5e3;
13816
14470
  var LOCK_RETRY_MS = 50;
13817
14471
  function neatHome() {
13818
14472
  const override = process.env.NEAT_HOME;
13819
- if (override && override.length > 0) return import_node_path65.default.resolve(override);
13820
- return import_node_path65.default.join(import_node_os3.default.homedir(), ".neat");
14473
+ if (override && override.length > 0) return import_node_path66.default.resolve(override);
14474
+ return import_node_path66.default.join(import_node_os3.default.homedir(), ".neat");
13821
14475
  }
13822
14476
  function registryPath() {
13823
- return import_node_path65.default.join(neatHome(), "projects.json");
14477
+ return import_node_path66.default.join(neatHome(), "projects.json");
13824
14478
  }
13825
14479
  function registryLockPath() {
13826
- return import_node_path65.default.join(neatHome(), "projects.json.lock");
14480
+ return import_node_path66.default.join(neatHome(), "projects.json.lock");
13827
14481
  }
13828
14482
  function daemonPidPath() {
13829
- return import_node_path65.default.join(neatHome(), "neatd.pid");
14483
+ return import_node_path66.default.join(neatHome(), "neatd.pid");
13830
14484
  }
13831
14485
  function daemonsDir() {
13832
- return import_node_path65.default.join(neatHome(), "daemons");
14486
+ return import_node_path66.default.join(neatHome(), "daemons");
13833
14487
  }
13834
14488
  function isFiniteInt(v) {
13835
14489
  return typeof v === "number" && Number.isFinite(v);
@@ -13870,7 +14524,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
13870
14524
  const out = [];
13871
14525
  for (const name of names) {
13872
14526
  if (!name.endsWith(".json")) continue;
13873
- const file = import_node_path65.default.join(dir, name);
14527
+ const file = import_node_path66.default.join(dir, name);
13874
14528
  let raw;
13875
14529
  try {
13876
14530
  raw = await import_node_fs32.promises.readFile(file, "utf8");
@@ -13991,7 +14645,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
13991
14645
  }
13992
14646
  }
13993
14647
  async function normalizeProjectPath(input) {
13994
- const resolved = import_node_path65.default.resolve(input);
14648
+ const resolved = import_node_path66.default.resolve(input);
13995
14649
  try {
13996
14650
  return await import_node_fs32.promises.realpath(resolved);
13997
14651
  } catch {
@@ -13999,7 +14653,7 @@ async function normalizeProjectPath(input) {
13999
14653
  }
14000
14654
  }
14001
14655
  async function writeAtomically(target, contents) {
14002
- await import_node_fs32.promises.mkdir(import_node_path65.default.dirname(target), { recursive: true });
14656
+ await import_node_fs32.promises.mkdir(import_node_path66.default.dirname(target), { recursive: true });
14003
14657
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
14004
14658
  const fd = await import_node_fs32.promises.open(tmp, "w");
14005
14659
  try {
@@ -14012,7 +14666,7 @@ async function writeAtomically(target, contents) {
14012
14666
  }
14013
14667
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
14014
14668
  const deadline = Date.now() + timeoutMs;
14015
- await import_node_fs32.promises.mkdir(import_node_path65.default.dirname(lockPath), { recursive: true });
14669
+ await import_node_fs32.promises.mkdir(import_node_path66.default.dirname(lockPath), { recursive: true });
14016
14670
  let probedHolder = false;
14017
14671
  while (true) {
14018
14672
  try {
@@ -14065,10 +14719,10 @@ async function readRegistry() {
14065
14719
  throw err;
14066
14720
  }
14067
14721
  const parsed = JSON.parse(raw);
14068
- return import_types52.RegistryFileSchema.parse(parsed);
14722
+ return import_types53.RegistryFileSchema.parse(parsed);
14069
14723
  }
14070
14724
  async function writeRegistry(reg) {
14071
- const validated = import_types52.RegistryFileSchema.parse(reg);
14725
+ const validated = import_types53.RegistryFileSchema.parse(reg);
14072
14726
  await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
14073
14727
  }
14074
14728
  var ProjectNameCollisionError = class extends Error {
@@ -14254,7 +14908,7 @@ init_auth();
14254
14908
  // src/connectors-config.ts
14255
14909
  init_cjs_shims();
14256
14910
  var import_node_os4 = __toESM(require("os"), 1);
14257
- var import_node_path66 = __toESM(require("path"), 1);
14911
+ var import_node_path67 = __toESM(require("path"), 1);
14258
14912
  var import_node_fs33 = require("fs");
14259
14913
  var CONNECTORS_CONFIG_VERSION = 1;
14260
14914
  var EnvRefUnsetError = class extends Error {
@@ -14269,11 +14923,11 @@ var EnvRefUnsetError = class extends Error {
14269
14923
  };
14270
14924
  function neatHome2() {
14271
14925
  const override = process.env.NEAT_HOME;
14272
- if (override && override.length > 0) return import_node_path66.default.resolve(override);
14273
- return import_node_path66.default.join(import_node_os4.default.homedir(), ".neat");
14926
+ if (override && override.length > 0) return import_node_path67.default.resolve(override);
14927
+ return import_node_path67.default.join(import_node_os4.default.homedir(), ".neat");
14274
14928
  }
14275
14929
  function connectorsConfigPath(home = neatHome2()) {
14276
- return import_node_path66.default.join(home, "connectors.json");
14930
+ return import_node_path67.default.join(home, "connectors.json");
14277
14931
  }
14278
14932
  var MODE_MASK_LOOSER_THAN_0600 = 63;
14279
14933
  async function warnIfModeLooserThan0600(file) {
@@ -14404,7 +15058,7 @@ function connectorMatchesProject(entry2, project) {
14404
15058
  var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
14405
15059
  var CONNECTORS_LOCK_RETRY_MS = 50;
14406
15060
  function connectorsConfigLockPath(home = neatHome2()) {
14407
- return import_node_path66.default.join(home, "connectors.json.lock");
15061
+ return import_node_path67.default.join(home, "connectors.json.lock");
14408
15062
  }
14409
15063
  function isEnvRef(value) {
14410
15064
  return value.length > 1 && value.startsWith("$");
@@ -14417,7 +15071,7 @@ function redactCredentialRef(ref) {
14417
15071
  return out;
14418
15072
  }
14419
15073
  async function writeConfigAtomically0600(file, contents) {
14420
- await import_node_fs33.promises.mkdir(import_node_path66.default.dirname(file), { recursive: true });
15074
+ await import_node_fs33.promises.mkdir(import_node_path67.default.dirname(file), { recursive: true });
14421
15075
  const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
14422
15076
  const fd = await import_node_fs33.promises.open(tmp, "w", 384);
14423
15077
  try {
@@ -14431,7 +15085,7 @@ async function writeConfigAtomically0600(file, contents) {
14431
15085
  }
14432
15086
  async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
14433
15087
  const deadline = Date.now() + timeoutMs;
14434
- await import_node_fs33.promises.mkdir(import_node_path66.default.dirname(lockPath), { recursive: true });
15088
+ await import_node_fs33.promises.mkdir(import_node_path67.default.dirname(lockPath), { recursive: true });
14435
15089
  for (; ; ) {
14436
15090
  try {
14437
15091
  const fd = await import_node_fs33.promises.open(lockPath, "wx");
@@ -14581,15 +15235,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
14581
15235
 
14582
15236
  // src/connectors/index.ts
14583
15237
  init_cjs_shims();
14584
- var import_types53 = require("@neat.is/types");
15238
+ var import_types54 = require("@neat.is/types");
14585
15239
  var NO_ENV = "unknown";
14586
15240
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
14587
15241
  if (!graph.hasNode(targetNodeId)) return void 0;
14588
15242
  const sites = [];
14589
15243
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
14590
15244
  const edge = graph.getEdgeAttributes(edgeId);
14591
- if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
14592
- const parsed = (0, import_types53.parseFileId)(edge.source);
15245
+ if (edge.provenance !== import_types54.Provenance.EXTRACTED) continue;
15246
+ const parsed = (0, import_types54.parseFileId)(edge.source);
14593
15247
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
14594
15248
  const site = { relPath: edge.evidence.file };
14595
15249
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -14600,7 +15254,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
14600
15254
  function routeCallSiteFor(graph, targetNodeId) {
14601
15255
  if (!graph.hasNode(targetNodeId)) return void 0;
14602
15256
  const attrs = graph.getNodeAttributes(targetNodeId);
14603
- if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
15257
+ if (attrs.type !== import_types54.NodeType.RouteNode || !attrs.path) return void 0;
14604
15258
  const site = { relPath: attrs.path };
14605
15259
  if (attrs.line !== void 0) site.line = attrs.line;
14606
15260
  return site;
@@ -15081,10 +15735,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
15081
15735
  // src/connectors/supabase/map.ts
15082
15736
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
15083
15737
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
15084
- function targetFromRestPath(path81) {
15085
- const rpcMatch = REST_RPC_PATH_RE.exec(path81);
15738
+ function targetFromRestPath(path82) {
15739
+ const rpcMatch = REST_RPC_PATH_RE.exec(path82);
15086
15740
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
15087
- const tableMatch = REST_TABLE_PATH_RE.exec(path81);
15741
+ const tableMatch = REST_TABLE_PATH_RE.exec(path82);
15088
15742
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
15089
15743
  return null;
15090
15744
  }
@@ -15195,23 +15849,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
15195
15849
 
15196
15850
  // src/connectors/supabase/resolve.ts
15197
15851
  init_cjs_shims();
15198
- var import_types55 = require("@neat.is/types");
15852
+ var import_types56 = require("@neat.is/types");
15199
15853
  function createSupabaseResolveTarget(graph, config) {
15200
15854
  return (signal, _ctx) => {
15201
15855
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
15202
15856
  return null;
15203
15857
  }
15204
- const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
15858
+ const subResourceId = (0, import_types56.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
15205
15859
  if (graph.hasNode(subResourceId)) {
15206
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
15860
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
15207
15861
  }
15208
- const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
15862
+ const bareResourceId = (0, import_types56.infraId)(signal.targetKind, signal.targetName);
15209
15863
  if (graph.hasNode(bareResourceId)) {
15210
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
15864
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
15211
15865
  }
15212
- const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
15866
+ const projectLevelId = (0, import_types56.infraId)("supabase", config.nodeRef);
15213
15867
  if (graph.hasNode(projectLevelId)) {
15214
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
15868
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types56.EdgeType.CALLS };
15215
15869
  }
15216
15870
  return null;
15217
15871
  };
@@ -15304,7 +15958,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
15304
15958
 
15305
15959
  // src/connectors/railway/index.ts
15306
15960
  init_cjs_shims();
15307
- var import_types59 = require("@neat.is/types");
15961
+ var import_types60 = require("@neat.is/types");
15308
15962
 
15309
15963
  // src/connectors/railway/client.ts
15310
15964
  init_cjs_shims();
@@ -15455,7 +16109,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
15455
16109
  const out = [];
15456
16110
  graph.forEachNode((_id, attrs) => {
15457
16111
  const node = attrs;
15458
- if (node.type !== import_types59.NodeType.RouteNode) return;
16112
+ if (node.type !== import_types60.NodeType.RouteNode) return;
15459
16113
  const route = attrs;
15460
16114
  if (route.service !== serviceName) return;
15461
16115
  out.push({
@@ -15559,12 +16213,12 @@ function createRailwayResolveTarget(config) {
15559
16213
  const serviceName = config.serviceNameById[config.serviceId];
15560
16214
  if (!serviceName) return null;
15561
16215
  if (signal.targetKind === ROUTE_TARGET_KIND) {
15562
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
16216
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types60.EdgeType.CALLS };
15563
16217
  }
15564
16218
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
15565
16219
  const peerName = config.serviceNameById[signal.targetName];
15566
16220
  if (!peerName) return null;
15567
- return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
16221
+ return { targetNodeId: (0, import_types60.serviceId)(peerName), serviceName, edgeType: import_types60.EdgeType.CONNECTS_TO };
15568
16222
  }
15569
16223
  return null;
15570
16224
  };
@@ -15688,9 +16342,9 @@ function parseFirebaseTargetName(targetName) {
15688
16342
  const secondSep = rest.indexOf(FIELD_SEP);
15689
16343
  if (secondSep === -1) return null;
15690
16344
  const method = rest.slice(0, secondSep);
15691
- const path81 = rest.slice(secondSep + 1);
15692
- if (!resourceName || !method || !path81) return null;
15693
- return { resourceName, method, path: path81 };
16345
+ const path82 = rest.slice(secondSep + 1);
16346
+ if (!resourceName || !method || !path82) return null;
16347
+ return { resourceName, method, path: path82 };
15694
16348
  }
15695
16349
  function resourceNameFor(type, labels) {
15696
16350
  if (!labels) return null;
@@ -15728,14 +16382,14 @@ function mapLogEntryToSignal(entry2) {
15728
16382
  if (!req) return null;
15729
16383
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
15730
16384
  const method = req.requestMethod.toUpperCase();
15731
- const path81 = pathFromRequestUrl(req.requestUrl);
15732
- if (path81 === null) return null;
16385
+ const path82 = pathFromRequestUrl(req.requestUrl);
16386
+ if (path82 === null) return null;
15733
16387
  const timestamp = entry2.timestamp;
15734
16388
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
15735
16389
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
15736
16390
  return {
15737
16391
  targetKind: resourceType,
15738
- targetName: packFirebaseTargetName({ resourceName, method, path: path81 }),
16392
+ targetName: packFirebaseTargetName({ resourceName, method, path: path82 }),
15739
16393
  callCount: 1,
15740
16394
  errorCount: isError ? 1 : 0,
15741
16395
  lastObservedIso: timestamp
@@ -15752,7 +16406,7 @@ function mapLogEntriesToSignals(entries) {
15752
16406
 
15753
16407
  // src/connectors/firebase/resolve.ts
15754
16408
  init_cjs_shims();
15755
- var import_types60 = require("@neat.is/types");
16409
+ var import_types61 = require("@neat.is/types");
15756
16410
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
15757
16411
  switch (resourceType) {
15758
16412
  case "cloud_function":
@@ -15767,7 +16421,7 @@ function routeEntriesFor(graph, serviceName) {
15767
16421
  const entries = [];
15768
16422
  graph.forEachNode((_id, attrs) => {
15769
16423
  const node = attrs;
15770
- if (node.type !== import_types60.NodeType.RouteNode) return;
16424
+ if (node.type !== import_types61.NodeType.RouteNode) return;
15771
16425
  const route = attrs;
15772
16426
  if (route.service !== serviceName) return;
15773
16427
  entries.push({
@@ -15799,7 +16453,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
15799
16453
  return {
15800
16454
  targetNodeId: match.routeNodeId,
15801
16455
  serviceName,
15802
- edgeType: import_types60.EdgeType.CALLS
16456
+ edgeType: import_types61.EdgeType.CALLS
15803
16457
  };
15804
16458
  };
15805
16459
  }
@@ -15826,7 +16480,7 @@ init_cjs_shims();
15826
16480
 
15827
16481
  // src/connectors/cloudflare/connector.ts
15828
16482
  init_cjs_shims();
15829
- var import_types62 = require("@neat.is/types");
16483
+ var import_types63 = require("@neat.is/types");
15830
16484
 
15831
16485
  // src/connectors/cloudflare/client.ts
15832
16486
  init_cjs_shims();
@@ -15942,7 +16596,7 @@ function mapEventToSignal(event) {
15942
16596
  if (Number.isNaN(observedAt.getTime())) return null;
15943
16597
  const statusCode = metadata?.statusCode;
15944
16598
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
15945
- const path81 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
16599
+ const path82 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
15946
16600
  return {
15947
16601
  targetKind: CLOUDFLARE_TARGET_KIND,
15948
16602
  targetName: scriptName,
@@ -15950,7 +16604,7 @@ function mapEventToSignal(event) {
15950
16604
  errorCount: isError ? 1 : 0,
15951
16605
  lastObservedIso: observedAt.toISOString(),
15952
16606
  method,
15953
- ...path81 ? { path: path81 } : {},
16607
+ ...path82 ? { path: path82 } : {},
15954
16608
  ...typeof statusCode === "number" ? { statusCode } : {},
15955
16609
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
15956
16610
  };
@@ -15990,19 +16644,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
15990
16644
  graph.forEachNode((id, attrs) => {
15991
16645
  if (found) return;
15992
16646
  const a = attrs;
15993
- if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
16647
+ if (a.type === import_types63.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
15994
16648
  found = id;
15995
16649
  }
15996
16650
  });
15997
16651
  return found;
15998
16652
  }
15999
- function findMatchingRouteNode(graph, serviceName, method, path81) {
16000
- const normalizedPath = normalizePathTemplate(path81);
16653
+ function findMatchingRouteNode(graph, serviceName, method, path82) {
16654
+ const normalizedPath = normalizePathTemplate(path82);
16001
16655
  let found = null;
16002
16656
  graph.forEachNode((id, attrs) => {
16003
16657
  if (found) return;
16004
16658
  const a = attrs;
16005
- if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
16659
+ if (a.type !== import_types63.NodeType.RouteNode || a.service !== serviceName) return;
16006
16660
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
16007
16661
  const routeMethod = (a.method ?? "").toUpperCase();
16008
16662
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -16014,18 +16668,18 @@ function createCloudflareResolveTarget(config, graph) {
16014
16668
  return (signal) => {
16015
16669
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
16016
16670
  const scriptName = signal.targetName;
16017
- const { method, path: path81 } = signal;
16671
+ const { method, path: path82 } = signal;
16018
16672
  const resolveRouteGrain = (serviceName, wholeFileId) => {
16019
- if (!method || !path81) return wholeFileId;
16020
- return findMatchingRouteNode(graph, serviceName, method, path81) ?? wholeFileId;
16673
+ if (!method || !path82) return wholeFileId;
16674
+ return findMatchingRouteNode(graph, serviceName, method, path82) ?? wholeFileId;
16021
16675
  };
16022
16676
  const mapping = config.workers?.[scriptName];
16023
16677
  if (mapping) {
16024
- const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
16678
+ const wholeFileId = (0, import_types63.fileId)(mapping.service, mapping.entryFile);
16025
16679
  return {
16026
16680
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
16027
16681
  serviceName: mapping.service,
16028
- edgeType: import_types62.EdgeType.CALLS
16682
+ edgeType: import_types63.EdgeType.CALLS
16029
16683
  };
16030
16684
  }
16031
16685
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -16034,13 +16688,13 @@ function createCloudflareResolveTarget(config, graph) {
16034
16688
  return {
16035
16689
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
16036
16690
  serviceName: fileNode.service,
16037
- edgeType: import_types62.EdgeType.CALLS
16691
+ edgeType: import_types63.EdgeType.CALLS
16038
16692
  };
16039
16693
  }
16040
16694
  return {
16041
- targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
16695
+ targetNodeId: (0, import_types63.infraId)("cloudflare-worker", scriptName),
16042
16696
  serviceName: scriptName,
16043
- edgeType: import_types62.EdgeType.CALLS,
16697
+ edgeType: import_types63.EdgeType.CALLS,
16044
16698
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
16045
16699
  };
16046
16700
  };
@@ -16236,14 +16890,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
16236
16890
 
16237
16891
  // src/connectors/neon/resolve.ts
16238
16892
  init_cjs_shims();
16239
- var import_types66 = require("@neat.is/types");
16893
+ var import_types67 = require("@neat.is/types");
16240
16894
  function createNeonResolveTarget(config) {
16241
16895
  return (signal) => {
16242
16896
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
16243
16897
  return {
16244
- targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
16898
+ targetNodeId: (0, import_types67.infraId)("sql-table", signal.targetName),
16245
16899
  serviceName: config.serviceName,
16246
- edgeType: import_types66.EdgeType.CALLS,
16900
+ edgeType: import_types67.EdgeType.CALLS,
16247
16901
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
16248
16902
  };
16249
16903
  };
@@ -16369,9 +17023,9 @@ function parseCloudRunTargetName(targetName) {
16369
17023
  const secondSep = rest.indexOf(FIELD_SEP2);
16370
17024
  if (secondSep === -1) return null;
16371
17025
  const method = rest.slice(0, secondSep);
16372
- const path81 = rest.slice(secondSep + 1);
16373
- if (!serviceName || !method || !path81) return null;
16374
- return { serviceName, method, path: path81 };
17026
+ const path82 = rest.slice(secondSep + 1);
17027
+ if (!serviceName || !method || !path82) return null;
17028
+ return { serviceName, method, path: path82 };
16375
17029
  }
16376
17030
 
16377
17031
  // src/connectors/cloud-run/map.ts
@@ -16400,14 +17054,14 @@ function mapLogEntryToSignal2(entry2) {
16400
17054
  if (!req) return null;
16401
17055
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
16402
17056
  const method = req.requestMethod.toUpperCase();
16403
- const path81 = pathFromRequestUrl2(req.requestUrl);
16404
- if (path81 === null) return null;
17057
+ const path82 = pathFromRequestUrl2(req.requestUrl);
17058
+ if (path82 === null) return null;
16405
17059
  const timestamp = entry2.timestamp;
16406
17060
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
16407
17061
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
16408
17062
  return {
16409
17063
  targetKind: CLOUD_RUN_TARGET_KIND,
16410
- targetName: packCloudRunTargetName({ serviceName, method, path: path81 }),
17064
+ targetName: packCloudRunTargetName({ serviceName, method, path: path82 }),
16411
17065
  callCount: 1,
16412
17066
  errorCount: isError ? 1 : 0,
16413
17067
  lastObservedIso: timestamp
@@ -16424,14 +17078,14 @@ function mapLogEntriesToSignals2(entries) {
16424
17078
 
16425
17079
  // src/connectors/cloud-run/resolve.ts
16426
17080
  init_cjs_shims();
16427
- var import_types70 = require("@neat.is/types");
17081
+ var import_types71 = require("@neat.is/types");
16428
17082
  var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
16429
17083
  function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
16430
17084
  let found = null;
16431
17085
  graph.forEachNode((_id, attrs) => {
16432
17086
  if (found) return;
16433
17087
  const node = attrs;
16434
- if (node.type !== import_types70.NodeType.RouteNode) return;
17088
+ if (node.type !== import_types71.NodeType.RouteNode) return;
16435
17089
  const route = attrs;
16436
17090
  if (route.service !== serviceName || !route.pathTemplate) return;
16437
17091
  if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
@@ -16446,23 +17100,23 @@ function createCloudRunResolveTarget(graph, config) {
16446
17100
  if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
16447
17101
  const identity = parseCloudRunTargetName(signal.targetName);
16448
17102
  if (!identity) return null;
16449
- const { serviceName: gcpServiceName, method, path: path81 } = identity;
17103
+ const { serviceName: gcpServiceName, method, path: path82 } = identity;
16450
17104
  const mappedService = config.serviceMap?.[gcpServiceName];
16451
17105
  if (mappedService) {
16452
17106
  const routeNodeId = findMatchingRouteNode2(
16453
17107
  graph,
16454
17108
  mappedService,
16455
17109
  method,
16456
- normalizePathTemplate(path81)
17110
+ normalizePathTemplate(path82)
16457
17111
  );
16458
17112
  if (routeNodeId) {
16459
- return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
17113
+ return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types71.EdgeType.CALLS };
16460
17114
  }
16461
17115
  }
16462
17116
  return {
16463
- targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
17117
+ targetNodeId: (0, import_types71.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
16464
17118
  serviceName: mappedService ?? gcpServiceName,
16465
- edgeType: import_types70.EdgeType.CALLS,
17119
+ edgeType: import_types71.EdgeType.CALLS,
16466
17120
  ensureInfraNode: {
16467
17121
  kind: CLOUD_RUN_SERVICE_INFRA_KIND,
16468
17122
  name: gcpServiceName,
@@ -16503,7 +17157,7 @@ function createCloudRunConnector(graph, config = {}) {
16503
17157
 
16504
17158
  // src/connectors/render/index.ts
16505
17159
  init_cjs_shims();
16506
- var import_types73 = require("@neat.is/types");
17160
+ var import_types74 = require("@neat.is/types");
16507
17161
 
16508
17162
  // src/connectors/render/types.ts
16509
17163
  init_cjs_shims();
@@ -16581,7 +17235,7 @@ function buildRenderRouteIndex(graph, serviceName) {
16581
17235
  const out = [];
16582
17236
  graph.forEachNode((_id, attrs) => {
16583
17237
  const node = attrs;
16584
- if (node.type !== import_types73.NodeType.RouteNode) return;
17238
+ if (node.type !== import_types74.NodeType.RouteNode) return;
16585
17239
  const route = attrs;
16586
17240
  if (route.service !== serviceName) return;
16587
17241
  out.push({
@@ -16666,7 +17320,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
16666
17320
  function createRenderResolveTarget(config) {
16667
17321
  return (signal) => {
16668
17322
  if (signal.targetKind === ROUTE_TARGET_KIND2) {
16669
- return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
17323
+ return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types74.EdgeType.CALLS };
16670
17324
  }
16671
17325
  return null;
16672
17326
  };
@@ -16804,21 +17458,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
16804
17458
 
16805
17459
  // src/connectors/planetscale/resolve.ts
16806
17460
  init_cjs_shims();
16807
- var import_types77 = require("@neat.is/types");
17461
+ var import_types78 = require("@neat.is/types");
16808
17462
  var PLANETSCALE_DATABASE_KIND = "planetscale-database";
16809
17463
  function createPlanetscaleResolveTarget(graph, config) {
16810
17464
  const databaseName = `${config.organization}/${config.database}`;
16811
17465
  return (signal, _ctx) => {
16812
17466
  if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
16813
- const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
17467
+ const tableId = (0, import_types78.infraId)("sql-table", signal.targetName);
16814
17468
  if (graph.hasNode(tableId)) {
16815
- return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
17469
+ return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types78.EdgeType.CALLS };
16816
17470
  }
16817
- const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
17471
+ const providerId = (0, import_types78.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
16818
17472
  return {
16819
17473
  targetNodeId: providerId,
16820
17474
  serviceName: config.serviceName,
16821
- edgeType: import_types77.EdgeType.CALLS,
17475
+ edgeType: import_types78.EdgeType.CALLS,
16822
17476
  ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
16823
17477
  };
16824
17478
  };
@@ -17567,11 +18221,11 @@ function registerRoutes(scope, ctx) {
17567
18221
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
17568
18222
  const parsed = [];
17569
18223
  for (const c of candidates) {
17570
- const r = import_types80.DivergenceTypeSchema.safeParse(c);
18224
+ const r = import_types81.DivergenceTypeSchema.safeParse(c);
17571
18225
  if (!r.success) {
17572
18226
  return reply.code(400).send({
17573
18227
  error: `unknown divergence type "${c}"`,
17574
- allowed: import_types80.DivergenceTypeSchema.options
18228
+ allowed: import_types81.DivergenceTypeSchema.options
17575
18229
  });
17576
18230
  }
17577
18231
  parsed.push(r.data);
@@ -17880,7 +18534,7 @@ function registerRoutes(scope, ctx) {
17880
18534
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
17881
18535
  let violations = await log.readAll();
17882
18536
  if (req.query.severity) {
17883
- const sev = import_types80.PolicySeveritySchema.safeParse(req.query.severity);
18537
+ const sev = import_types81.PolicySeveritySchema.safeParse(req.query.severity);
17884
18538
  if (!sev.success) {
17885
18539
  return reply.code(400).send({
17886
18540
  error: "invalid severity",
@@ -17919,7 +18573,7 @@ function registerRoutes(scope, ctx) {
17919
18573
  scope.post("/policies/check", async (req, reply) => {
17920
18574
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
17921
18575
  if (!proj) return;
17922
- const parsed = import_types80.PoliciesCheckBodySchema.safeParse(req.body ?? {});
18576
+ const parsed = import_types81.PoliciesCheckBodySchema.safeParse(req.body ?? {});
17923
18577
  if (!parsed.success) {
17924
18578
  return reply.code(400).send({
17925
18579
  error: "invalid /policies/check body",
@@ -18241,7 +18895,7 @@ init_otel();
18241
18895
  // src/daemon.ts
18242
18896
  init_cjs_shims();
18243
18897
  var import_node_fs35 = require("fs");
18244
- var import_node_path68 = __toESM(require("path"), 1);
18898
+ var import_node_path69 = __toESM(require("path"), 1);
18245
18899
  var import_node_module = require("module");
18246
18900
  init_otel();
18247
18901
  init_auth();
@@ -18249,28 +18903,28 @@ init_auth();
18249
18903
  // src/unrouted.ts
18250
18904
  init_cjs_shims();
18251
18905
  var import_node_fs34 = require("fs");
18252
- var import_node_path67 = __toESM(require("path"), 1);
18906
+ var import_node_path68 = __toESM(require("path"), 1);
18253
18907
 
18254
18908
  // src/daemon.ts
18255
- var import_types81 = require("@neat.is/types");
18909
+ var import_types82 = require("@neat.is/types");
18256
18910
  function daemonJsonPath(scanPath) {
18257
- return import_node_path68.default.join(scanPath, "neat-out", "daemon.json");
18911
+ return import_node_path69.default.join(scanPath, "neat-out", "daemon.json");
18258
18912
  }
18259
18913
  function daemonsDiscoveryDir(home) {
18260
18914
  const base = home && home.length > 0 ? home : neatHomeFromEnv();
18261
- return import_node_path68.default.join(base, "daemons");
18915
+ return import_node_path69.default.join(base, "daemons");
18262
18916
  }
18263
18917
  function daemonDiscoveryPath(project, home) {
18264
- return import_node_path68.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
18918
+ return import_node_path69.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
18265
18919
  }
18266
18920
  function sanitizeDiscoveryName(project) {
18267
18921
  return project.replace(/[^A-Za-z0-9._-]/g, "_");
18268
18922
  }
18269
18923
  function neatHomeFromEnv() {
18270
18924
  const env = process.env.NEAT_HOME;
18271
- if (env && env.length > 0) return import_node_path68.default.resolve(env);
18925
+ if (env && env.length > 0) return import_node_path69.default.resolve(env);
18272
18926
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
18273
- return import_node_path68.default.join(home, ".neat");
18927
+ return import_node_path69.default.join(home, ".neat");
18274
18928
  }
18275
18929
  async function readDaemonRecord(scanPath) {
18276
18930
  try {
@@ -18341,7 +18995,7 @@ init_otel_grpc();
18341
18995
  // src/search.ts
18342
18996
  init_cjs_shims();
18343
18997
  var import_node_fs36 = require("fs");
18344
- var import_node_path69 = __toESM(require("path"), 1);
18998
+ var import_node_path70 = __toESM(require("path"), 1);
18345
18999
  var import_node_crypto4 = require("crypto");
18346
19000
  var DEFAULT_LIMIT = 10;
18347
19001
  var NOMIC_DIM = 768;
@@ -18504,7 +19158,7 @@ async function readCache(cachePath) {
18504
19158
  }
18505
19159
  }
18506
19160
  async function writeCache(cachePath, cache) {
18507
- await import_node_fs36.promises.mkdir(import_node_path69.default.dirname(cachePath), { recursive: true });
19161
+ await import_node_fs36.promises.mkdir(import_node_path70.default.dirname(cachePath), { recursive: true });
18508
19162
  await import_node_fs36.promises.writeFile(cachePath, JSON.stringify(cache));
18509
19163
  }
18510
19164
  var VectorIndex = class {
@@ -18664,8 +19318,8 @@ var ALL_PHASES = [
18664
19318
  ];
18665
19319
  function classifyChange(relPath) {
18666
19320
  const phases = /* @__PURE__ */ new Set();
18667
- const base = import_node_path70.default.basename(relPath).toLowerCase();
18668
- const segments = relPath.split(import_node_path70.default.sep).map((s) => s.toLowerCase());
19321
+ const base = import_node_path71.default.basename(relPath).toLowerCase();
19322
+ const segments = relPath.split(import_node_path71.default.sep).map((s) => s.toLowerCase());
18669
19323
  if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
18670
19324
  phases.add("services");
18671
19325
  phases.add("aliases");
@@ -18805,9 +19459,9 @@ function countWatchableDirs(scanPath, limit) {
18805
19459
  for (const e of entries) {
18806
19460
  if (count >= limit) return;
18807
19461
  if (!e.isDirectory()) continue;
18808
- if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path70.default.join(dir, e.name) + import_node_path70.default.sep))) continue;
19462
+ if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path71.default.join(dir, e.name) + import_node_path71.default.sep))) continue;
18809
19463
  count++;
18810
- if (depth < 2) visit(import_node_path70.default.join(dir, e.name), depth + 1);
19464
+ if (depth < 2) visit(import_node_path71.default.join(dir, e.name), depth + 1);
18811
19465
  }
18812
19466
  };
18813
19467
  visit(scanPath, 0);
@@ -18825,8 +19479,8 @@ async function startWatch(graph, opts) {
18825
19479
  const projectName = opts.project ?? DEFAULT_PROJECT;
18826
19480
  await loadGraphFromDisk(graph, opts.outPath);
18827
19481
  const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
18828
- const policyFilePath = import_node_path70.default.join(opts.scanPath, "policy.json");
18829
- const policyViolationsPath = import_node_path70.default.join(import_node_path70.default.dirname(opts.outPath), "policy-violations.ndjson");
19482
+ const policyFilePath = import_node_path71.default.join(opts.scanPath, "policy.json");
19483
+ const policyViolationsPath = import_node_path71.default.join(import_node_path71.default.dirname(opts.outPath), "policy-violations.ndjson");
18830
19484
  let policies = [];
18831
19485
  try {
18832
19486
  policies = await loadPolicyFile(policyFilePath);
@@ -18886,7 +19540,7 @@ async function startWatch(graph, opts) {
18886
19540
  assertBindAuthority(host, auth.authToken);
18887
19541
  const port = opts.port ?? 8080;
18888
19542
  const otelPort = opts.otelPort ?? 4318;
18889
- const cachePath = opts.embeddingsCachePath ?? import_node_path70.default.join(import_node_path70.default.dirname(opts.outPath), "embeddings.json");
19543
+ const cachePath = opts.embeddingsCachePath ?? import_node_path71.default.join(import_node_path71.default.dirname(opts.outPath), "embeddings.json");
18890
19544
  let searchIndex;
18891
19545
  try {
18892
19546
  searchIndex = await buildSearchIndex(graph, { cachePath });
@@ -18904,7 +19558,7 @@ async function startWatch(graph, opts) {
18904
19558
  // Paths are derived from the explicit options the watch caller passes
18905
19559
  // — pathsForProject is only used to fill in the embeddings/snapshot
18906
19560
  // fields so the registry shape is complete.
18907
- ...pathsForProject(projectName, import_node_path70.default.dirname(opts.outPath)),
19561
+ ...pathsForProject(projectName, import_node_path71.default.dirname(opts.outPath)),
18908
19562
  snapshotPath: opts.outPath,
18909
19563
  errorsPath: opts.errorsPath,
18910
19564
  staleEventsPath: opts.staleEventsPath
@@ -19022,9 +19676,9 @@ async function startWatch(graph, opts) {
19022
19676
  };
19023
19677
  const onPath = (absPath) => {
19024
19678
  if (shouldIgnore(absPath)) return;
19025
- const rel = import_node_path70.default.relative(opts.scanPath, absPath);
19679
+ const rel = import_node_path71.default.relative(opts.scanPath, absPath);
19026
19680
  if (!rel || rel.startsWith("..")) return;
19027
- pendingPaths.add(rel.split(import_node_path70.default.sep).join("/"));
19681
+ pendingPaths.add(rel.split(import_node_path71.default.sep).join("/"));
19028
19682
  const phases = classifyChange(rel);
19029
19683
  if (phases.size === 0) {
19030
19684
  for (const p of ALL_PHASES) pending.add(p);
@@ -19082,7 +19736,7 @@ async function startWatch(graph, opts) {
19082
19736
  // src/deploy/detect.ts
19083
19737
  init_cjs_shims();
19084
19738
  var import_node_fs38 = require("fs");
19085
- var import_node_path71 = __toESM(require("path"), 1);
19739
+ var import_node_path72 = __toESM(require("path"), 1);
19086
19740
  var import_node_child_process2 = require("child_process");
19087
19741
  var import_node_crypto5 = require("crypto");
19088
19742
  function generateToken() {
@@ -19182,7 +19836,7 @@ async function runDeploy(opts = {}) {
19182
19836
  const token = generateToken();
19183
19837
  switch (substrate) {
19184
19838
  case "docker-compose": {
19185
- const artifactPath = import_node_path71.default.join(cwd, "docker-compose.neat.yml");
19839
+ const artifactPath = import_node_path72.default.join(cwd, "docker-compose.neat.yml");
19186
19840
  const contents = emitDockerCompose(cwd);
19187
19841
  await import_node_fs38.promises.writeFile(artifactPath, contents, "utf8");
19188
19842
  return {
@@ -19190,11 +19844,11 @@ async function runDeploy(opts = {}) {
19190
19844
  artifactPath,
19191
19845
  token,
19192
19846
  contents,
19193
- startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path71.default.basename(artifactPath)} up -d`
19847
+ startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path72.default.basename(artifactPath)} up -d`
19194
19848
  };
19195
19849
  }
19196
19850
  case "systemd": {
19197
- const artifactPath = import_node_path71.default.join(cwd, "neat.service");
19851
+ const artifactPath = import_node_path72.default.join(cwd, "neat.service");
19198
19852
  const contents = emitSystemdUnit(cwd);
19199
19853
  await import_node_fs38.promises.writeFile(artifactPath, contents, "utf8");
19200
19854
  return {
@@ -19230,7 +19884,7 @@ init_cjs_shims();
19230
19884
  // src/installers/javascript.ts
19231
19885
  init_cjs_shims();
19232
19886
  var import_node_fs39 = require("fs");
19233
- var import_node_path72 = __toESM(require("path"), 1);
19887
+ var import_node_path73 = __toESM(require("path"), 1);
19234
19888
  var import_semver2 = __toESM(require("semver"), 1);
19235
19889
 
19236
19890
  // src/installers/templates.ts
@@ -19897,11 +20551,11 @@ var OTEL_ENV = {
19897
20551
  value: "http://localhost:4318/projects/<project>/v1/traces"
19898
20552
  };
19899
20553
  function serviceNodeName(pkg, serviceDir) {
19900
- return pkg.name ?? import_node_path72.default.basename(serviceDir);
20554
+ return pkg.name ?? import_node_path73.default.basename(serviceDir);
19901
20555
  }
19902
20556
  function projectToken(pkg, serviceDir, project) {
19903
20557
  if (project && project.length > 0) return project;
19904
- return pkg.name ?? import_node_path72.default.basename(serviceDir);
20558
+ return pkg.name ?? import_node_path73.default.basename(serviceDir);
19905
20559
  }
19906
20560
  async function readJsonFile(p) {
19907
20561
  try {
@@ -19914,16 +20568,16 @@ async function readJsonFile(p) {
19914
20568
  async function detectRuntimeKind(pkgRoot, pkg) {
19915
20569
  const deps = allDeps(pkg);
19916
20570
  if ("react-native" in deps || "expo" in deps) return "react-native";
19917
- const appJson = await readJsonFile(import_node_path72.default.join(pkgRoot, "app.json"));
20571
+ const appJson = await readJsonFile(import_node_path73.default.join(pkgRoot, "app.json"));
19918
20572
  if (appJson && typeof appJson === "object" && "expo" in appJson) {
19919
20573
  return "react-native";
19920
20574
  }
19921
- if (await exists3(import_node_path72.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path72.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path72.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
20575
+ if (await exists3(import_node_path73.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path73.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path73.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
19922
20576
  return "browser-bundle";
19923
20577
  }
19924
- if (await exists3(import_node_path72.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
19925
- if (await exists3(import_node_path72.default.join(pkgRoot, "bun.lockb"))) return "bun";
19926
- if (await exists3(import_node_path72.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path72.default.join(pkgRoot, "deno.lock"))) {
20578
+ if (await exists3(import_node_path73.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
20579
+ if (await exists3(import_node_path73.default.join(pkgRoot, "bun.lockb"))) return "bun";
20580
+ if (await exists3(import_node_path73.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path73.default.join(pkgRoot, "deno.lock"))) {
19927
20581
  return "deno";
19928
20582
  }
19929
20583
  const engines = pkg.engines ?? {};
@@ -19932,7 +20586,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
19932
20586
  }
19933
20587
  async function readPackageJson2(serviceDir) {
19934
20588
  try {
19935
- const raw = await import_node_fs39.promises.readFile(import_node_path72.default.join(serviceDir, "package.json"), "utf8");
20589
+ const raw = await import_node_fs39.promises.readFile(import_node_path73.default.join(serviceDir, "package.json"), "utf8");
19936
20590
  return JSON.parse(raw);
19937
20591
  } catch {
19938
20592
  return null;
@@ -19976,7 +20630,7 @@ function needsVersionUpgrade(installed, expected) {
19976
20630
  var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
19977
20631
  async function findNextConfig(serviceDir) {
19978
20632
  for (const name of NEXT_CONFIG_CANDIDATES) {
19979
- const candidate = import_node_path72.default.join(serviceDir, name);
20633
+ const candidate = import_node_path73.default.join(serviceDir, name);
19980
20634
  if (await exists3(candidate)) return candidate;
19981
20635
  }
19982
20636
  return null;
@@ -20045,7 +20699,7 @@ function hasRemixDependency(pkg) {
20045
20699
  }
20046
20700
  async function findRemixEntry(serviceDir) {
20047
20701
  for (const rel of REMIX_ENTRY_CANDIDATES) {
20048
- const candidate = import_node_path72.default.join(serviceDir, rel);
20702
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20049
20703
  if (await exists3(candidate)) return candidate;
20050
20704
  }
20051
20705
  return null;
@@ -20057,14 +20711,14 @@ function hasSvelteKitDependency(pkg) {
20057
20711
  }
20058
20712
  async function findSvelteKitHooks(serviceDir) {
20059
20713
  for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
20060
- const candidate = import_node_path72.default.join(serviceDir, rel);
20714
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20061
20715
  if (await exists3(candidate)) return candidate;
20062
20716
  }
20063
20717
  return null;
20064
20718
  }
20065
20719
  async function findSvelteKitConfig(serviceDir) {
20066
20720
  for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
20067
- const candidate = import_node_path72.default.join(serviceDir, rel);
20721
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20068
20722
  if (await exists3(candidate)) return candidate;
20069
20723
  }
20070
20724
  return null;
@@ -20075,7 +20729,7 @@ function hasNuxtDependency(pkg) {
20075
20729
  }
20076
20730
  async function findNuxtConfig(serviceDir) {
20077
20731
  for (const name of NUXT_CONFIG_CANDIDATES) {
20078
- const candidate = import_node_path72.default.join(serviceDir, name);
20732
+ const candidate = import_node_path73.default.join(serviceDir, name);
20079
20733
  if (await exists3(candidate)) return candidate;
20080
20734
  }
20081
20735
  return null;
@@ -20086,7 +20740,7 @@ function hasAstroDependency(pkg) {
20086
20740
  }
20087
20741
  async function findAstroConfig(serviceDir) {
20088
20742
  for (const name of ASTRO_CONFIG_CANDIDATES) {
20089
- const candidate = import_node_path72.default.join(serviceDir, name);
20743
+ const candidate = import_node_path73.default.join(serviceDir, name);
20090
20744
  if (await exists3(candidate)) return candidate;
20091
20745
  }
20092
20746
  return null;
@@ -20100,7 +20754,7 @@ function parseNextMajor(range) {
20100
20754
  return Number.isFinite(n) ? n : null;
20101
20755
  }
20102
20756
  async function isTypeScriptProject(serviceDir) {
20103
- return exists3(import_node_path72.default.join(serviceDir, "tsconfig.json"));
20757
+ return exists3(import_node_path73.default.join(serviceDir, "tsconfig.json"));
20104
20758
  }
20105
20759
  var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
20106
20760
  var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
@@ -20149,7 +20803,7 @@ function entryFromScript(script) {
20149
20803
  }
20150
20804
  async function resolveEntry(serviceDir, pkg) {
20151
20805
  if (typeof pkg.main === "string" && pkg.main.length > 0) {
20152
- const candidate = import_node_path72.default.resolve(serviceDir, pkg.main);
20806
+ const candidate = import_node_path73.default.resolve(serviceDir, pkg.main);
20153
20807
  if (await exists3(candidate)) return candidate;
20154
20808
  }
20155
20809
  if (pkg.bin) {
@@ -20163,40 +20817,40 @@ async function resolveEntry(serviceDir, pkg) {
20163
20817
  if (typeof first === "string") binEntry = first;
20164
20818
  }
20165
20819
  if (binEntry) {
20166
- const candidate = import_node_path72.default.resolve(serviceDir, binEntry);
20820
+ const candidate = import_node_path73.default.resolve(serviceDir, binEntry);
20167
20821
  if (await exists3(candidate)) return candidate;
20168
20822
  }
20169
20823
  }
20170
20824
  const startEntry = entryFromScript(pkg.scripts?.start);
20171
20825
  if (startEntry) {
20172
- const candidate = import_node_path72.default.resolve(serviceDir, startEntry);
20826
+ const candidate = import_node_path73.default.resolve(serviceDir, startEntry);
20173
20827
  if (await exists3(candidate)) return candidate;
20174
20828
  }
20175
20829
  const devEntry = entryFromScript(pkg.scripts?.dev);
20176
20830
  if (devEntry) {
20177
- const candidate = import_node_path72.default.resolve(serviceDir, devEntry);
20831
+ const candidate = import_node_path73.default.resolve(serviceDir, devEntry);
20178
20832
  if (await exists3(candidate)) return candidate;
20179
20833
  }
20180
20834
  for (const rel of SRC_INDEX_CANDIDATES) {
20181
- const candidate = import_node_path72.default.join(serviceDir, rel);
20835
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20182
20836
  if (await exists3(candidate)) return candidate;
20183
20837
  }
20184
20838
  for (const rel of SRC_NAMED_CANDIDATES) {
20185
- const candidate = import_node_path72.default.join(serviceDir, rel);
20839
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20186
20840
  if (await exists3(candidate)) return candidate;
20187
20841
  }
20188
20842
  for (const rel of ROOT_NAMED_CANDIDATES) {
20189
- const candidate = import_node_path72.default.join(serviceDir, rel);
20843
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20190
20844
  if (await exists3(candidate)) return candidate;
20191
20845
  }
20192
20846
  for (const name of INDEX_CANDIDATES) {
20193
- const candidate = import_node_path72.default.join(serviceDir, name);
20847
+ const candidate = import_node_path73.default.join(serviceDir, name);
20194
20848
  if (await exists3(candidate)) return candidate;
20195
20849
  }
20196
20850
  return null;
20197
20851
  }
20198
20852
  function dispatchEntry(entryFile, pkg) {
20199
- const ext = import_node_path72.default.extname(entryFile).toLowerCase();
20853
+ const ext = import_node_path73.default.extname(entryFile).toLowerCase();
20200
20854
  if (ext === ".ts" || ext === ".tsx") return pkg.type === "module" ? "ts" : "ts-cjs";
20201
20855
  if (ext === ".mjs") return "esm";
20202
20856
  if (ext === ".cjs") return "cjs";
@@ -20214,9 +20868,9 @@ function otelInitContents(flavor) {
20214
20868
  return OTEL_INIT_CJS;
20215
20869
  }
20216
20870
  function injectionLine(flavor, entryFile, otelInitFile) {
20217
- let rel = import_node_path72.default.relative(import_node_path72.default.dirname(entryFile), otelInitFile);
20871
+ let rel = import_node_path73.default.relative(import_node_path73.default.dirname(entryFile), otelInitFile);
20218
20872
  if (!rel.startsWith(".")) rel = `./${rel}`;
20219
- rel = rel.split(import_node_path72.default.sep).join("/");
20873
+ rel = rel.split(import_node_path73.default.sep).join("/");
20220
20874
  if (flavor === "cjs") return `require('${rel}')`;
20221
20875
  if (flavor === "esm") return `import '${rel}'`;
20222
20876
  const tsRel = rel.replace(/\.ts$/, "");
@@ -20229,27 +20883,27 @@ function lineIsOtelInjection(line) {
20229
20883
  }
20230
20884
  async function detectsSrcLayout(serviceDir) {
20231
20885
  const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
20232
- exists3(import_node_path72.default.join(serviceDir, "src", "app")),
20233
- exists3(import_node_path72.default.join(serviceDir, "src", "pages")),
20234
- exists3(import_node_path72.default.join(serviceDir, "app")),
20235
- exists3(import_node_path72.default.join(serviceDir, "pages"))
20886
+ exists3(import_node_path73.default.join(serviceDir, "src", "app")),
20887
+ exists3(import_node_path73.default.join(serviceDir, "src", "pages")),
20888
+ exists3(import_node_path73.default.join(serviceDir, "app")),
20889
+ exists3(import_node_path73.default.join(serviceDir, "pages"))
20236
20890
  ]);
20237
20891
  return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
20238
20892
  }
20239
20893
  async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
20240
20894
  const useTs = await isTypeScriptProject(serviceDir);
20241
20895
  const srcLayout = await detectsSrcLayout(serviceDir);
20242
- const baseDir = srcLayout ? import_node_path72.default.join(serviceDir, "src") : serviceDir;
20243
- const instrumentationFile = import_node_path72.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
20244
- const instrumentationNodeFile = import_node_path72.default.join(
20896
+ const baseDir = srcLayout ? import_node_path73.default.join(serviceDir, "src") : serviceDir;
20897
+ const instrumentationFile = import_node_path73.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
20898
+ const instrumentationNodeFile = import_node_path73.default.join(
20245
20899
  baseDir,
20246
20900
  useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
20247
20901
  );
20248
- const instrumentationEdgeFile = import_node_path72.default.join(
20902
+ const instrumentationEdgeFile = import_node_path73.default.join(
20249
20903
  baseDir,
20250
20904
  useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
20251
20905
  );
20252
- const envNeatFile = import_node_path72.default.join(baseDir, ".env.neat");
20906
+ const envNeatFile = import_node_path73.default.join(baseDir, ".env.neat");
20253
20907
  const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
20254
20908
  const dependencyEdits = [];
20255
20909
  for (const sdk of SDK_PACKAGES) {
@@ -20374,7 +21028,7 @@ function buildDependencyEdits(pkg, manifestPath) {
20374
21028
  return edits;
20375
21029
  }
20376
21030
  async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
20377
- const envNeatFile = import_node_path72.default.join(serviceDir, ".env.neat");
21031
+ const envNeatFile = import_node_path73.default.join(serviceDir, ".env.neat");
20378
21032
  if (!await exists3(envNeatFile)) {
20379
21033
  generatedFiles.push({
20380
21034
  file: envNeatFile,
@@ -20409,7 +21063,7 @@ function fileImportsOtelHook(raw, specifiers) {
20409
21063
  }
20410
21064
  async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
20411
21065
  const useTs = await isTypeScriptProject(serviceDir);
20412
- const otelServerFile = import_node_path72.default.join(
21066
+ const otelServerFile = import_node_path73.default.join(
20413
21067
  serviceDir,
20414
21068
  useTs ? "app/otel.server.ts" : "app/otel.server.js"
20415
21069
  );
@@ -20466,11 +21120,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
20466
21120
  }
20467
21121
  async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
20468
21122
  const useTs = await isTypeScriptProject(serviceDir);
20469
- const otelInitFile = import_node_path72.default.join(
21123
+ const otelInitFile = import_node_path73.default.join(
20470
21124
  serviceDir,
20471
21125
  useTs ? "src/otel-init.ts" : "src/otel-init.js"
20472
21126
  );
20473
- const resolvedHooksFile = hooksFile ?? import_node_path72.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
21127
+ const resolvedHooksFile = hooksFile ?? import_node_path73.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
20474
21128
  const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
20475
21129
  const generatedFiles = [];
20476
21130
  const entrypointEdits = [];
@@ -20532,11 +21186,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
20532
21186
  }
20533
21187
  async function planNuxt(serviceDir, pkg, manifestPath, project) {
20534
21188
  const useTs = await isTypeScriptProject(serviceDir);
20535
- const otelPluginFile = import_node_path72.default.join(
21189
+ const otelPluginFile = import_node_path73.default.join(
20536
21190
  serviceDir,
20537
21191
  useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
20538
21192
  );
20539
- const otelInitFile = import_node_path72.default.join(
21193
+ const otelInitFile = import_node_path73.default.join(
20540
21194
  serviceDir,
20541
21195
  useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
20542
21196
  );
@@ -20587,19 +21241,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
20587
21241
  var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
20588
21242
  async function findAstroMiddleware(serviceDir) {
20589
21243
  for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
20590
- const candidate = import_node_path72.default.join(serviceDir, rel);
21244
+ const candidate = import_node_path73.default.join(serviceDir, rel);
20591
21245
  if (await exists3(candidate)) return candidate;
20592
21246
  }
20593
21247
  return null;
20594
21248
  }
20595
21249
  async function planAstro(serviceDir, pkg, manifestPath, project) {
20596
21250
  const useTs = await isTypeScriptProject(serviceDir);
20597
- const otelInitFile = import_node_path72.default.join(
21251
+ const otelInitFile = import_node_path73.default.join(
20598
21252
  serviceDir,
20599
21253
  useTs ? "src/otel-init.ts" : "src/otel-init.js"
20600
21254
  );
20601
21255
  const existingMiddleware = await findAstroMiddleware(serviceDir);
20602
- const middlewareFile = existingMiddleware ?? import_node_path72.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
21256
+ const middlewareFile = existingMiddleware ?? import_node_path73.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
20603
21257
  const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
20604
21258
  const generatedFiles = [];
20605
21259
  const entrypointEdits = [];
@@ -20695,7 +21349,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
20695
21349
  }
20696
21350
  async function plan(serviceDir, opts) {
20697
21351
  const pkg = await readPackageJson2(serviceDir);
20698
- const manifestPath = import_node_path72.default.join(serviceDir, "package.json");
21352
+ const manifestPath = import_node_path73.default.join(serviceDir, "package.json");
20699
21353
  const project = opts?.project;
20700
21354
  const empty = {
20701
21355
  language: "javascript",
@@ -20730,8 +21384,8 @@ async function plan(serviceDir, opts) {
20730
21384
  return { ...empty, libOnly: true };
20731
21385
  }
20732
21386
  const flavor = dispatchEntry(entryFile, pkg);
20733
- const otelInitFile = import_node_path72.default.join(import_node_path72.default.dirname(entryFile), otelInitFilename(flavor));
20734
- const envNeatFile = import_node_path72.default.join(serviceDir, ".env.neat");
21387
+ const otelInitFile = import_node_path73.default.join(import_node_path73.default.dirname(entryFile), otelInitFilename(flavor));
21388
+ const envNeatFile = import_node_path73.default.join(serviceDir, ".env.neat");
20735
21389
  const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
20736
21390
  const dependencyEdits = [];
20737
21391
  for (const sdk of SDK_PACKAGES) {
@@ -20800,13 +21454,13 @@ async function plan(serviceDir, opts) {
20800
21454
  };
20801
21455
  }
20802
21456
  function isAllowedWritePath(serviceDir, target) {
20803
- const rel = import_node_path72.default.relative(serviceDir, target);
21457
+ const rel = import_node_path73.default.relative(serviceDir, target);
20804
21458
  if (rel.startsWith("..")) return false;
20805
- const base = import_node_path72.default.basename(target);
21459
+ const base = import_node_path73.default.basename(target);
20806
21460
  if (base === "package.json") return true;
20807
21461
  if (base === ".env.neat") return true;
20808
21462
  if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
20809
- const relPosix = rel.split(import_node_path72.default.sep).join("/");
21463
+ const relPosix = rel.split(import_node_path73.default.sep).join("/");
20810
21464
  if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
20811
21465
  if (relPosix === base) return true;
20812
21466
  if (relPosix === `src/${base}`) return true;
@@ -20823,7 +21477,7 @@ function isAllowedWritePath(serviceDir, target) {
20823
21477
  return false;
20824
21478
  }
20825
21479
  async function writeAtomic(file, contents) {
20826
- await import_node_fs39.promises.mkdir(import_node_path72.default.dirname(file), { recursive: true });
21480
+ await import_node_fs39.promises.mkdir(import_node_path73.default.dirname(file), { recursive: true });
20827
21481
  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
20828
21482
  await import_node_fs39.promises.writeFile(tmp, contents, "utf8");
20829
21483
  await import_node_fs39.promises.rename(tmp, file);
@@ -21007,7 +21661,7 @@ async function rollback(installPlan, originals, createdFiles) {
21007
21661
  ...removed.map((f) => `removed: ${f}`),
21008
21662
  ""
21009
21663
  ];
21010
- const rollbackPath = import_node_path72.default.join(installPlan.serviceDir, "neat-rollback.patch");
21664
+ const rollbackPath = import_node_path73.default.join(installPlan.serviceDir, "neat-rollback.patch");
21011
21665
  await import_node_fs39.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
21012
21666
  }
21013
21667
  function injectInstrumentationHook(raw) {
@@ -21038,7 +21692,7 @@ var javascriptInstaller = {
21038
21692
  // src/installers/python.ts
21039
21693
  init_cjs_shims();
21040
21694
  var import_node_fs40 = require("fs");
21041
- var import_node_path73 = __toESM(require("path"), 1);
21695
+ var import_node_path74 = __toESM(require("path"), 1);
21042
21696
  var SDK_PACKAGES2 = [
21043
21697
  { name: "opentelemetry-distro", version: ">=0.49b0" },
21044
21698
  { name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
@@ -21136,7 +21790,7 @@ async function writeFileAtomic(file, contents) {
21136
21790
  await import_node_fs40.promises.rename(tmp, file);
21137
21791
  }
21138
21792
  async function resolvePyEntrypoint(serviceDir) {
21139
- const procfile = import_node_path73.default.join(serviceDir, "Procfile");
21793
+ const procfile = import_node_path74.default.join(serviceDir, "Procfile");
21140
21794
  if (await exists4(procfile)) {
21141
21795
  const raw = await import_node_fs40.promises.readFile(procfile, "utf8");
21142
21796
  for (const line of raw.split(/\r?\n/)) {
@@ -21146,20 +21800,20 @@ async function resolvePyEntrypoint(serviceDir) {
21146
21800
  const asgi = cmd.match(/\b(?:uvicorn|gunicorn|hypercorn|daphne)\s+([\w.]+):/);
21147
21801
  if (asgi) {
21148
21802
  const modPath = asgi[1].replace(/\./g, "/");
21149
- const asFile = import_node_path73.default.join(serviceDir, `${modPath}.py`);
21803
+ const asFile = import_node_path74.default.join(serviceDir, `${modPath}.py`);
21150
21804
  if (await exists4(asFile)) return asFile;
21151
- const asPkg = import_node_path73.default.join(serviceDir, modPath, "__init__.py");
21805
+ const asPkg = import_node_path74.default.join(serviceDir, modPath, "__init__.py");
21152
21806
  if (await exists4(asPkg)) return asPkg;
21153
21807
  }
21154
21808
  const runFile = cmd.match(/\b(?:python3?|fastapi\s+(?:run|dev))\s+([\w./-]+\.py)\b/);
21155
21809
  if (runFile) {
21156
- const p = import_node_path73.default.join(serviceDir, runFile[1]);
21810
+ const p = import_node_path74.default.join(serviceDir, runFile[1]);
21157
21811
  if (await exists4(p)) return p;
21158
21812
  }
21159
21813
  }
21160
21814
  }
21161
21815
  for (const name of ["main.py", "app.py", "asgi.py", "wsgi.py", "manage.py", "server.py"]) {
21162
- const p = import_node_path73.default.join(serviceDir, name);
21816
+ const p = import_node_path74.default.join(serviceDir, name);
21163
21817
  if (await exists4(p)) return p;
21164
21818
  }
21165
21819
  return null;
@@ -21185,7 +21839,7 @@ async function exists4(p) {
21185
21839
  async function detect2(serviceDir) {
21186
21840
  const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
21187
21841
  for (const m of markers) {
21188
- if (await exists4(import_node_path73.default.join(serviceDir, m))) return true;
21842
+ if (await exists4(import_node_path74.default.join(serviceDir, m))) return true;
21189
21843
  }
21190
21844
  return false;
21191
21845
  }
@@ -21195,7 +21849,7 @@ function reqPackageName(line) {
21195
21849
  return head.replace(/[<>=!~].*$/, "").toLowerCase();
21196
21850
  }
21197
21851
  async function planRequirementsTxtEdits(serviceDir) {
21198
- const file = import_node_path73.default.join(serviceDir, "requirements.txt");
21852
+ const file = import_node_path74.default.join(serviceDir, "requirements.txt");
21199
21853
  if (!await exists4(file)) return null;
21200
21854
  const raw = await import_node_fs40.promises.readFile(file, "utf8");
21201
21855
  const presentNames = new Set(
@@ -21205,7 +21859,7 @@ async function planRequirementsTxtEdits(serviceDir) {
21205
21859
  return { manifest: file, missing: [...missing] };
21206
21860
  }
21207
21861
  async function planProcfileEdits(serviceDir) {
21208
- const procfile = import_node_path73.default.join(serviceDir, "Procfile");
21862
+ const procfile = import_node_path74.default.join(serviceDir, "Procfile");
21209
21863
  if (!await exists4(procfile)) return [];
21210
21864
  const raw = await import_node_fs40.promises.readFile(procfile, "utf8");
21211
21865
  const edits = [];
@@ -21243,7 +21897,7 @@ async function plan2(serviceDir) {
21243
21897
  }
21244
21898
  const entrypointEdits = await planProcfileEdits(serviceDir);
21245
21899
  const entryFile = await resolvePyEntrypoint(serviceDir);
21246
- const generatedFiles = entryFile ? [{ file: import_node_path73.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
21900
+ const generatedFiles = entryFile ? [{ file: import_node_path74.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
21247
21901
  if (dependencyEdits.length === 0 && entrypointEdits.length === 0 && !entryFile) {
21248
21902
  return empty;
21249
21903
  }
@@ -21311,7 +21965,7 @@ async function apply2(installPlan) {
21311
21965
  if (raw === void 0) {
21312
21966
  throw new Error(`python installer: cannot read ${file} during apply`);
21313
21967
  }
21314
- const base = import_node_path73.default.basename(file);
21968
+ const base = import_node_path74.default.basename(file);
21315
21969
  if (base === "requirements.txt") {
21316
21970
  const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
21317
21971
  if (edits.length > 0) {
@@ -21366,7 +22020,7 @@ async function rollback2(installPlan, originals, createdFiles = []) {
21366
22020
  ...removed.map((f) => `removed: ${f}`),
21367
22021
  ""
21368
22022
  ];
21369
- const rollbackPath = import_node_path73.default.join(installPlan.serviceDir, "neat-rollback.patch");
22023
+ const rollbackPath = import_node_path74.default.join(installPlan.serviceDir, "neat-rollback.patch");
21370
22024
  await import_node_fs40.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
21371
22025
  }
21372
22026
  var pythonInstaller = {
@@ -21379,7 +22033,7 @@ var pythonInstaller = {
21379
22033
  // src/installers/go.ts
21380
22034
  init_cjs_shims();
21381
22035
  var import_node_fs41 = require("fs");
21382
- var import_node_path74 = __toESM(require("path"), 1);
22036
+ var import_node_path75 = __toESM(require("path"), 1);
21383
22037
  var GO_DEPS = [
21384
22038
  { name: "go.opentelemetry.io/otel", version: "v1.38.0" },
21385
22039
  { name: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp", version: "v1.38.0" },
@@ -21389,13 +22043,13 @@ async function exists5(file) {
21389
22043
  return import_node_fs41.promises.stat(file).then(() => true, () => false);
21390
22044
  }
21391
22045
  async function findMain(serviceDir) {
21392
- const root = import_node_path74.default.join(serviceDir, "main.go");
22046
+ const root = import_node_path75.default.join(serviceDir, "main.go");
21393
22047
  if (await exists5(root)) return root;
21394
- const cmd = import_node_path74.default.join(serviceDir, "cmd");
22048
+ const cmd = import_node_path75.default.join(serviceDir, "cmd");
21395
22049
  const entries = await import_node_fs41.promises.readdir(cmd, { withFileTypes: true }).catch(() => []);
21396
22050
  for (const entry2 of entries.sort((a, b) => a.name.localeCompare(b.name))) {
21397
22051
  if (!entry2.isDirectory()) continue;
21398
- const candidate = import_node_path74.default.join(cmd, entry2.name, "main.go");
22052
+ const candidate = import_node_path75.default.join(cmd, entry2.name, "main.go");
21399
22053
  if (await exists5(candidate)) return candidate;
21400
22054
  }
21401
22055
  return null;
@@ -21470,17 +22124,17 @@ func init() {
21470
22124
  `;
21471
22125
  }
21472
22126
  async function detect3(serviceDir) {
21473
- return exists5(import_node_path74.default.join(serviceDir, "go.mod"));
22127
+ return exists5(import_node_path75.default.join(serviceDir, "go.mod"));
21474
22128
  }
21475
22129
  async function plan3(serviceDir) {
21476
- const manifest = import_node_path74.default.join(serviceDir, "go.mod");
22130
+ const manifest = import_node_path75.default.join(serviceDir, "go.mod");
21477
22131
  const raw = await import_node_fs41.promises.readFile(manifest, "utf8");
21478
22132
  const main2 = await findMain(serviceDir);
21479
22133
  const dependencyEdits = GO_DEPS.filter((dep) => !raw.includes(dep.name)).map((dep) => ({ file: manifest, kind: "add", ...dep }));
21480
22134
  if (!main2) return { language: "go", serviceDir, dependencyEdits: [], entrypointEdits: [], envEdits: [], libOnly: true };
21481
22135
  const source = await import_node_fs41.promises.readFile(main2, "utf8");
21482
22136
  const packageName = source.match(/^\s*package\s+(\w+)\s*$/m)?.[1] ?? "main";
21483
- const generated = import_node_path74.default.join(import_node_path74.default.dirname(main2), "neat_otel.go");
22137
+ const generated = import_node_path75.default.join(import_node_path75.default.dirname(main2), "neat_otel.go");
21484
22138
  const generatedFiles = await exists5(generated) ? [] : [{ file: generated, contents: neatOtelGo(packageName) }];
21485
22139
  return { language: "go", serviceDir, dependencyEdits, entrypointEdits: [], envEdits: [], generatedFiles, entryFile: main2 };
21486
22140
  }
@@ -21622,7 +22276,7 @@ init_cjs_shims();
21622
22276
  var import_node_fs42 = require("fs");
21623
22277
  var import_node_http = __toESM(require("http"), 1);
21624
22278
  var import_node_net = __toESM(require("net"), 1);
21625
- var import_node_path75 = __toESM(require("path"), 1);
22279
+ var import_node_path76 = __toESM(require("path"), 1);
21626
22280
  var import_node_url4 = require("url");
21627
22281
  var import_node_child_process3 = require("child_process");
21628
22282
  var import_node_readline = __toESM(require("readline"), 1);
@@ -21632,7 +22286,7 @@ async function extractAndPersist(opts) {
21632
22286
  const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
21633
22287
  resetGraph(graphKey);
21634
22288
  const graph = getGraph(graphKey);
21635
- const projectPaths = pathsForProject(graphKey, import_node_path75.default.join(opts.scanPath, "neat-out"));
22289
+ const projectPaths = pathsForProject(graphKey, import_node_path76.default.join(opts.scanPath, "neat-out"));
21636
22290
  const extraction = await extractFromDirectory(graph, opts.scanPath, {
21637
22291
  errorsPath: projectPaths.errorsPath
21638
22292
  });
@@ -21684,7 +22338,7 @@ async function applyInstallersOver(services, project, options = {}) {
21684
22338
  libOnly++;
21685
22339
  const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
21686
22340
  if (appDeps.length > 0) {
21687
- const svcName = import_node_path75.default.basename(svc.dir);
22341
+ const svcName = import_node_path76.default.basename(svc.dir);
21688
22342
  const list = appDeps.join(", ");
21689
22343
  console.warn(
21690
22344
  `neat: runtime layer won't engage for ${svcName}: no entry point found.
@@ -21697,7 +22351,7 @@ async function applyInstallersOver(services, project, options = {}) {
21697
22351
  console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
21698
22352
  } else if (outcome.outcome === "react-native") {
21699
22353
  reactNative++;
21700
- const svcName = import_node_path75.default.basename(svc.dir);
22354
+ const svcName = import_node_path76.default.basename(svc.dir);
21701
22355
  console.log(
21702
22356
  `neat: ${svc.dir} detected as React Native / Expo
21703
22357
  The installer doesn't cover this runtime deterministically.
@@ -21708,7 +22362,7 @@ async function applyInstallersOver(services, project, options = {}) {
21708
22362
  );
21709
22363
  } else if (outcome.outcome === "bun") {
21710
22364
  bun++;
21711
- const svcName = import_node_path75.default.basename(svc.dir);
22365
+ const svcName = import_node_path76.default.basename(svc.dir);
21712
22366
  console.log(
21713
22367
  `neat: ${svc.dir} detected as Bun
21714
22368
  The installer doesn't cover this runtime deterministically.
@@ -21719,7 +22373,7 @@ async function applyInstallersOver(services, project, options = {}) {
21719
22373
  );
21720
22374
  } else if (outcome.outcome === "deno") {
21721
22375
  deno++;
21722
- const svcName = import_node_path75.default.basename(svc.dir);
22376
+ const svcName = import_node_path76.default.basename(svc.dir);
21723
22377
  console.log(
21724
22378
  `neat: ${svc.dir} detected as Deno
21725
22379
  The installer doesn't cover this runtime deterministically.
@@ -21730,7 +22384,7 @@ async function applyInstallersOver(services, project, options = {}) {
21730
22384
  );
21731
22385
  } else if (outcome.outcome === "cloudflare-workers") {
21732
22386
  cloudflareWorkers++;
21733
- const svcName = import_node_path75.default.basename(svc.dir);
22387
+ const svcName = import_node_path76.default.basename(svc.dir);
21734
22388
  console.log(
21735
22389
  `neat: ${svc.dir} detected as Cloudflare Workers
21736
22390
  The installer doesn't cover this runtime deterministically.
@@ -21741,7 +22395,7 @@ async function applyInstallersOver(services, project, options = {}) {
21741
22395
  );
21742
22396
  } else if (outcome.outcome === "electron") {
21743
22397
  electron++;
21744
- const svcName = import_node_path75.default.basename(svc.dir);
22398
+ const svcName = import_node_path76.default.basename(svc.dir);
21745
22399
  console.log(
21746
22400
  `neat: ${svc.dir} detected as Electron
21747
22401
  The installer doesn't cover this runtime deterministically.
@@ -21754,7 +22408,7 @@ async function applyInstallersOver(services, project, options = {}) {
21754
22408
  if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
21755
22409
  const gaps = uninstrumentedLibraries(svc.pkg);
21756
22410
  if (gaps.length > 0) {
21757
- const svcName = import_node_path75.default.basename(svc.dir);
22411
+ const svcName = import_node_path76.default.basename(svc.dir);
21758
22412
  const list = gaps.join(", ");
21759
22413
  const subject = gaps.length === 1 ? "this library" : "these libraries";
21760
22414
  const aux = gaps.length === 1 ? "isn't" : "aren't";
@@ -21960,8 +22614,8 @@ async function persistedPortsFor(scanPath) {
21960
22614
  return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
21961
22615
  }
21962
22616
  async function acquireSpawnLock(scanPath) {
21963
- const lockPath = import_node_path75.default.join(scanPath, "neat-out", "daemon.spawn.lock");
21964
- await import_node_fs42.promises.mkdir(import_node_path75.default.dirname(lockPath), { recursive: true });
22617
+ const lockPath = import_node_path76.default.join(scanPath, "neat-out", "daemon.spawn.lock");
22618
+ await import_node_fs42.promises.mkdir(import_node_path76.default.dirname(lockPath), { recursive: true });
21965
22619
  const STALE_LOCK_MS = 6e4;
21966
22620
  try {
21967
22621
  const fd = await import_node_fs42.promises.open(lockPath, "wx");
@@ -22006,13 +22660,13 @@ async function healthIsForProject(restPort, project) {
22006
22660
  return false;
22007
22661
  }
22008
22662
  function daemonLogPath(projectPath3) {
22009
- return import_node_path75.default.join(projectPath3, "neat-out", "daemon.log");
22663
+ return import_node_path76.default.join(projectPath3, "neat-out", "daemon.log");
22010
22664
  }
22011
22665
  function spawnDaemonDetached(spec) {
22012
- const here = import_node_path75.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
22666
+ const here = import_node_path76.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
22013
22667
  const candidates = [
22014
- import_node_path75.default.join(here, "neatd.cjs"),
22015
- import_node_path75.default.join(here, "neatd.js")
22668
+ import_node_path76.default.join(here, "neatd.cjs"),
22669
+ import_node_path76.default.join(here, "neatd.js")
22016
22670
  ];
22017
22671
  let entry2 = null;
22018
22672
  const fsSync = require("fs");
@@ -22042,7 +22696,7 @@ function spawnDaemonDetached(spec) {
22042
22696
  let logFd = null;
22043
22697
  if (spec) {
22044
22698
  const logPath = daemonLogPath(spec.projectPath);
22045
- fsSync.mkdirSync(import_node_path75.default.dirname(logPath), { recursive: true });
22699
+ fsSync.mkdirSync(import_node_path76.default.dirname(logPath), { recursive: true });
22046
22700
  logFd = fsSync.openSync(logPath, "a");
22047
22701
  }
22048
22702
  const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
@@ -22241,7 +22895,7 @@ async function runOrchestrator(opts) {
22241
22895
  result.steps.browser = openBrowser(dashboardUrl);
22242
22896
  }
22243
22897
  const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
22244
- const daemonLog = daemonRunning ? import_node_path75.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
22898
+ const daemonLog = daemonRunning ? import_node_path76.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
22245
22899
  printSummary(result, graph, dashboardUrl, daemonLog);
22246
22900
  return result;
22247
22901
  }
@@ -22700,7 +23354,7 @@ async function runConnectorCommand(rawArgs, deps = {}) {
22700
23354
 
22701
23355
  // src/hooks-cli.ts
22702
23356
  init_cjs_shims();
22703
- var import_node_path76 = __toESM(require("path"), 1);
23357
+ var import_node_path77 = __toESM(require("path"), 1);
22704
23358
  var import_node_os5 = __toESM(require("os"), 1);
22705
23359
  var import_node_fs43 = require("fs");
22706
23360
  var import_node_url5 = require("url");
@@ -22709,14 +23363,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
22709
23363
  var GUIDE_INSTALL_NAME = "neat-graph-first.md";
22710
23364
  var HOOK_MATCHER = "Grep|Glob|Bash";
22711
23365
  function moduleDir() {
22712
- return typeof __dirname !== "undefined" ? __dirname : import_node_path76.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
23366
+ return typeof __dirname !== "undefined" ? __dirname : import_node_path77.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
22713
23367
  }
22714
23368
  async function readSkillAsset(rel) {
22715
23369
  const here = moduleDir();
22716
23370
  const candidates = [
22717
- import_node_path76.default.resolve(here, "../../claude-skill", rel),
22718
- import_node_path76.default.resolve(here, "../../../claude-skill", rel),
22719
- import_node_path76.default.resolve(here, "../claude-skill", rel)
23371
+ import_node_path77.default.resolve(here, "../../claude-skill", rel),
23372
+ import_node_path77.default.resolve(here, "../../../claude-skill", rel),
23373
+ import_node_path77.default.resolve(here, "../claude-skill", rel)
22720
23374
  ];
22721
23375
  for (const candidate of candidates) {
22722
23376
  try {
@@ -22730,17 +23384,17 @@ async function readSkillAsset(rel) {
22730
23384
  }
22731
23385
  function neatHome3() {
22732
23386
  const override = process.env.NEAT_HOME;
22733
- if (override && override.length > 0) return import_node_path76.default.resolve(override);
22734
- return import_node_path76.default.join(import_node_os5.default.homedir(), ".neat");
23387
+ if (override && override.length > 0) return import_node_path77.default.resolve(override);
23388
+ return import_node_path77.default.join(import_node_os5.default.homedir(), ".neat");
22735
23389
  }
22736
23390
  function claudeSettingsPath() {
22737
23391
  const override = process.env.NEAT_CLAUDE_SETTINGS;
22738
- if (override && override.length > 0) return import_node_path76.default.resolve(override);
23392
+ if (override && override.length > 0) return import_node_path77.default.resolve(override);
22739
23393
  const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os5.default.homedir();
22740
- return import_node_path76.default.join(home, ".claude", "settings.json");
23394
+ return import_node_path77.default.join(home, ".claude", "settings.json");
22741
23395
  }
22742
23396
  function installedHookPath() {
22743
- return import_node_path76.default.join(neatHome3(), "hooks", HOOK_FILENAME);
23397
+ return import_node_path77.default.join(neatHome3(), "hooks", HOOK_FILENAME);
22744
23398
  }
22745
23399
  function isNeatSearchEntry(entry2) {
22746
23400
  return (entry2.hooks ?? []).some(
@@ -22773,9 +23427,9 @@ async function runHooks(opts) {
22773
23427
  const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
22774
23428
  const guide = await readSkillAsset(GUIDE_FILENAME);
22775
23429
  const scriptPath = installedHookPath();
22776
- await import_node_fs43.promises.mkdir(import_node_path76.default.dirname(scriptPath), { recursive: true });
23430
+ await import_node_fs43.promises.mkdir(import_node_path77.default.dirname(scriptPath), { recursive: true });
22777
23431
  await import_node_fs43.promises.writeFile(scriptPath, hookScript, { mode: 493 });
22778
- const guidePath = import_node_path76.default.join(neatHome3(), GUIDE_INSTALL_NAME);
23432
+ const guidePath = import_node_path77.default.join(neatHome3(), GUIDE_INSTALL_NAME);
22779
23433
  await import_node_fs43.promises.writeFile(guidePath, guide, "utf8");
22780
23434
  const settingsFile = claudeSettingsPath();
22781
23435
  let settings = {};
@@ -22802,7 +23456,7 @@ async function runHooks(opts) {
22802
23456
  ...settings,
22803
23457
  hooks: { ...hooks, PreToolUse: preToolUse }
22804
23458
  };
22805
- await import_node_fs43.promises.mkdir(import_node_path76.default.dirname(settingsFile), { recursive: true });
23459
+ await import_node_fs43.promises.mkdir(import_node_path77.default.dirname(settingsFile), { recursive: true });
22806
23460
  await import_node_fs43.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
22807
23461
  console.log(`neat hooks: installed the search-nudge hook`);
22808
23462
  console.log(` script: ${scriptPath}`);
@@ -22874,7 +23528,7 @@ async function runHooksCommand(args) {
22874
23528
 
22875
23529
  // src/codex-cli.ts
22876
23530
  init_cjs_shims();
22877
- var import_node_path77 = __toESM(require("path"), 1);
23531
+ var import_node_path78 = __toESM(require("path"), 1);
22878
23532
  var import_node_os6 = __toESM(require("os"), 1);
22879
23533
  var import_node_fs44 = require("fs");
22880
23534
  var import_node_util = require("util");
@@ -22894,14 +23548,14 @@ var NEAT_GRAPH_FIRST_START = "<!-- neat:graph-first -->";
22894
23548
  var NEAT_GRAPH_FIRST_END = "<!-- /neat:graph-first -->";
22895
23549
  function codexConfigPath() {
22896
23550
  const override = process.env.NEAT_CODEX_CONFIG;
22897
- if (override && override.length > 0) return import_node_path77.default.resolve(override);
23551
+ if (override && override.length > 0) return import_node_path78.default.resolve(override);
22898
23552
  const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os6.default.homedir();
22899
- return import_node_path77.default.join(home, ".codex", "config.toml");
23553
+ return import_node_path78.default.join(home, ".codex", "config.toml");
22900
23554
  }
22901
23555
  function agentsFilePath() {
22902
23556
  const override = process.env.NEAT_CODEX_AGENTS;
22903
- if (override && override.length > 0) return import_node_path77.default.resolve(override);
22904
- return import_node_path77.default.join(process.cwd(), "AGENTS.md");
23557
+ if (override && override.length > 0) return import_node_path78.default.resolve(override);
23558
+ return import_node_path78.default.join(process.cwd(), "AGENTS.md");
22905
23559
  }
22906
23560
  function isTableHeader(line) {
22907
23561
  return /^\s*\[\[?[^\]]+\]\]?\s*$/.test(line);
@@ -23084,14 +23738,14 @@ async function runCodex(opts) {
23084
23738
  return { exitCode: 0 };
23085
23739
  }
23086
23740
  if (config.changed) {
23087
- await import_node_fs44.promises.mkdir(import_node_path77.default.dirname(configPath), { recursive: true });
23741
+ await import_node_fs44.promises.mkdir(import_node_path78.default.dirname(configPath), { recursive: true });
23088
23742
  await import_node_fs44.promises.writeFile(configPath, config.text, "utf8");
23089
23743
  console.log(`neat codex: wrote [mcp_servers.neat] to ${configPath}`);
23090
23744
  } else {
23091
23745
  console.log(`neat codex: ${configPath} already has NEAT's MCP server`);
23092
23746
  }
23093
23747
  if (agents.changed) {
23094
- await import_node_fs44.promises.mkdir(import_node_path77.default.dirname(agentsPath), { recursive: true });
23748
+ await import_node_fs44.promises.mkdir(import_node_path78.default.dirname(agentsPath), { recursive: true });
23095
23749
  await import_node_fs44.promises.writeFile(agentsPath, agents.text, "utf8");
23096
23750
  console.log(`neat codex: wrote the graph-first block to ${agentsPath}`);
23097
23751
  } else {
@@ -23149,7 +23803,7 @@ async function runCodexCommand(args) {
23149
23803
 
23150
23804
  // src/editors-cli.ts
23151
23805
  init_cjs_shims();
23152
- var import_node_path78 = __toESM(require("path"), 1);
23806
+ var import_node_path79 = __toESM(require("path"), 1);
23153
23807
  var import_node_os7 = __toESM(require("os"), 1);
23154
23808
  var import_node_fs45 = require("fs");
23155
23809
  var import_node_util2 = require("util");
@@ -23175,17 +23829,17 @@ function homeDir() {
23175
23829
  }
23176
23830
  function xdgConfigDir() {
23177
23831
  const xdg = process.env.XDG_CONFIG_HOME;
23178
- return xdg && xdg.length > 0 ? import_node_path78.default.resolve(xdg) : import_node_path78.default.join(homeDir(), ".config");
23832
+ return xdg && xdg.length > 0 ? import_node_path79.default.resolve(xdg) : import_node_path79.default.join(homeDir(), ".config");
23179
23833
  }
23180
23834
  function envOverride(name) {
23181
23835
  const v = process.env[name];
23182
- return v && v.length > 0 ? import_node_path78.default.resolve(v) : void 0;
23836
+ return v && v.length > 0 ? import_node_path79.default.resolve(v) : void 0;
23183
23837
  }
23184
23838
  var CURSOR_CLIENT = {
23185
23839
  id: "cursor",
23186
23840
  label: "Cursor",
23187
23841
  docsUrl: "https://docs.cursor.com/context/mcp",
23188
- mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? import_node_path78.default.join(homeDir(), ".cursor", "mcp.json"),
23842
+ mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? import_node_path79.default.join(homeDir(), ".cursor", "mcp.json"),
23189
23843
  mcpContainerKey: "mcpServers",
23190
23844
  format: "json",
23191
23845
  // Cursor still reads a single `.cursorrules` at the project root (the modern
@@ -23197,7 +23851,7 @@ var DEVIN_CLIENT = {
23197
23851
  id: "devin",
23198
23852
  label: "Devin Desktop (Cascade)",
23199
23853
  docsUrl: "https://docs.devin.ai/desktop/cascade/mcp",
23200
- mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? import_node_path78.default.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
23854
+ mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? import_node_path79.default.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
23201
23855
  mcpContainerKey: "mcpServers",
23202
23856
  format: "json",
23203
23857
  rulesFileName: ".windsurfrules"
@@ -23206,7 +23860,7 @@ var GEMINI_CLIENT = {
23206
23860
  id: "gemini",
23207
23861
  label: "Gemini CLI",
23208
23862
  docsUrl: "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
23209
- mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? import_node_path78.default.join(homeDir(), ".gemini", "settings.json"),
23863
+ mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? import_node_path79.default.join(homeDir(), ".gemini", "settings.json"),
23210
23864
  mcpContainerKey: "mcpServers",
23211
23865
  format: "json",
23212
23866
  rulesFileName: "GEMINI.md"
@@ -23215,7 +23869,7 @@ var QWEN_CLIENT = {
23215
23869
  id: "qwen",
23216
23870
  label: "Qwen Code",
23217
23871
  docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/",
23218
- mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? import_node_path78.default.join(homeDir(), ".qwen", "settings.json"),
23872
+ mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? import_node_path79.default.join(homeDir(), ".qwen", "settings.json"),
23219
23873
  mcpContainerKey: "mcpServers",
23220
23874
  format: "json",
23221
23875
  rulesFileName: "QWEN.md"
@@ -23224,7 +23878,7 @@ var AMAZONQ_CLIENT = {
23224
23878
  id: "amazonq",
23225
23879
  label: "Amazon Q Developer CLI",
23226
23880
  docsUrl: "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html",
23227
- mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? import_node_path78.default.join(homeDir(), ".aws", "amazonq", "mcp.json"),
23881
+ mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? import_node_path79.default.join(homeDir(), ".aws", "amazonq", "mcp.json"),
23228
23882
  mcpContainerKey: "mcpServers",
23229
23883
  format: "json"
23230
23884
  };
@@ -23232,7 +23886,7 @@ var ROOCODE_CLIENT = {
23232
23886
  id: "roocode",
23233
23887
  label: "Roo Code",
23234
23888
  docsUrl: "https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo",
23235
- mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? import_node_path78.default.join(process.cwd(), ".roo", "mcp.json"),
23889
+ mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? import_node_path79.default.join(process.cwd(), ".roo", "mcp.json"),
23236
23890
  mcpContainerKey: "mcpServers",
23237
23891
  format: "json"
23238
23892
  };
@@ -23245,9 +23899,9 @@ var ZED_CLIENT = {
23245
23899
  if (override) return override;
23246
23900
  if (process.platform === "win32") {
23247
23901
  const appData = process.env.APPDATA;
23248
- if (appData && appData.length > 0) return import_node_path78.default.join(appData, "Zed", "settings.json");
23902
+ if (appData && appData.length > 0) return import_node_path79.default.join(appData, "Zed", "settings.json");
23249
23903
  }
23250
- return import_node_path78.default.join(homeDir(), ".config", "zed", "settings.json");
23904
+ return import_node_path79.default.join(homeDir(), ".config", "zed", "settings.json");
23251
23905
  },
23252
23906
  mcpContainerKey: "context_servers",
23253
23907
  format: "jsonc",
@@ -23257,7 +23911,7 @@ var OPENCODE_CLIENT = {
23257
23911
  id: "opencode",
23258
23912
  label: "OpenCode",
23259
23913
  docsUrl: "https://opencode.ai/docs/mcp-servers/",
23260
- mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? import_node_path78.default.join(xdgConfigDir(), "opencode", "opencode.json"),
23914
+ mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? import_node_path79.default.join(xdgConfigDir(), "opencode", "opencode.json"),
23261
23915
  mcpContainerKey: "mcp",
23262
23916
  format: "json",
23263
23917
  serverEntry: NEAT_OPENCODE_SERVER,
@@ -23267,7 +23921,7 @@ var CRUSH_CLIENT = {
23267
23921
  id: "crush",
23268
23922
  label: "Crush",
23269
23923
  docsUrl: "https://charmbracelet-crush.mintlify.app/configuration/mcp",
23270
- mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? import_node_path78.default.join(xdgConfigDir(), "crush", "crush.json"),
23924
+ mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? import_node_path79.default.join(xdgConfigDir(), "crush", "crush.json"),
23271
23925
  mcpContainerKey: "mcp",
23272
23926
  format: "json",
23273
23927
  serverEntry: NEAT_CRUSH_SERVER,
@@ -23372,7 +24026,7 @@ async function runEditorInstall(client, opts) {
23372
24026
  const mcpPath = client.mcpConfigPath();
23373
24027
  const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER;
23374
24028
  const hasRules = typeof client.rulesFileName === "string";
23375
- const rulesPath = hasRules ? import_node_path78.default.join(opts.projectDir, client.rulesFileName) : "";
24029
+ const rulesPath = hasRules ? import_node_path79.default.join(opts.projectDir, client.rulesFileName) : "";
23376
24030
  const mcp = await planMcp(client, mcpPath);
23377
24031
  if (mcp === null) return { exitCode: 1 };
23378
24032
  let existingRules = "";
@@ -23415,10 +24069,10 @@ async function runEditorInstall(client, opts) {
23415
24069
  );
23416
24070
  return { exitCode: 0 };
23417
24071
  }
23418
- await import_node_fs45.promises.mkdir(import_node_path78.default.dirname(mcpPath), { recursive: true });
24072
+ await import_node_fs45.promises.mkdir(import_node_path79.default.dirname(mcpPath), { recursive: true });
23419
24073
  await import_node_fs45.promises.writeFile(mcpPath, mcp.text, "utf8");
23420
24074
  if (hasRules) {
23421
- await import_node_fs45.promises.mkdir(import_node_path78.default.dirname(rulesPath), { recursive: true });
24075
+ await import_node_fs45.promises.mkdir(import_node_path79.default.dirname(rulesPath), { recursive: true });
23422
24076
  await import_node_fs45.promises.writeFile(rulesPath, newRules, "utf8");
23423
24077
  }
23424
24078
  console.log(`neat ${client.id}: wired NEAT into ${client.label}`);
@@ -23482,11 +24136,11 @@ async function runEditorCommand(clientId, args, projectDir = process.cwd()) {
23482
24136
 
23483
24137
  // src/monitor.ts
23484
24138
  init_cjs_shims();
23485
- var import_types83 = require("@neat.is/types");
24139
+ var import_types84 = require("@neat.is/types");
23486
24140
 
23487
24141
  // src/cli-client.ts
23488
24142
  init_cjs_shims();
23489
- var import_types82 = require("@neat.is/types");
24143
+ var import_types83 = require("@neat.is/types");
23490
24144
  var HttpError = class extends Error {
23491
24145
  constructor(status2, message, responseBody = "") {
23492
24146
  super(message);
@@ -23511,10 +24165,10 @@ function createHttpClient(baseUrl, bearerToken) {
23511
24165
  const root = baseUrl.replace(/\/$/, "");
23512
24166
  const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
23513
24167
  return {
23514
- async get(path81) {
24168
+ async get(path82) {
23515
24169
  let res;
23516
24170
  try {
23517
- res = await fetch(`${root}${path81}`, {
24171
+ res = await fetch(`${root}${path82}`, {
23518
24172
  headers: { ...authHeader }
23519
24173
  });
23520
24174
  } catch (err) {
@@ -23526,16 +24180,16 @@ function createHttpClient(baseUrl, bearerToken) {
23526
24180
  const body = await res.text().catch(() => "");
23527
24181
  throw new HttpError(
23528
24182
  res.status,
23529
- `${res.status} ${res.statusText} on GET ${path81}: ${body}`,
24183
+ `${res.status} ${res.statusText} on GET ${path82}: ${body}`,
23530
24184
  body
23531
24185
  );
23532
24186
  }
23533
24187
  return await res.json();
23534
24188
  },
23535
- async post(path81, body) {
24189
+ async post(path82, body) {
23536
24190
  let res;
23537
24191
  try {
23538
- res = await fetch(`${root}${path81}`, {
24192
+ res = await fetch(`${root}${path82}`, {
23539
24193
  method: "POST",
23540
24194
  headers: { "content-type": "application/json", ...authHeader },
23541
24195
  body: JSON.stringify(body)
@@ -23549,7 +24203,7 @@ function createHttpClient(baseUrl, bearerToken) {
23549
24203
  const text = await res.text().catch(() => "");
23550
24204
  throw new HttpError(
23551
24205
  res.status,
23552
- `${res.status} ${res.statusText} on POST ${path81}: ${text}`,
24206
+ `${res.status} ${res.statusText} on POST ${path82}: ${text}`,
23553
24207
  text
23554
24208
  );
23555
24209
  }
@@ -23563,12 +24217,12 @@ function projectPath(project, suffix) {
23563
24217
  }
23564
24218
  async function runRootCause(client, input) {
23565
24219
  const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
23566
- const path81 = projectPath(
24220
+ const path82 = projectPath(
23567
24221
  input.project,
23568
24222
  `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
23569
24223
  );
23570
24224
  try {
23571
- const result = await client.get(path81);
24225
+ const result = await client.get(path82);
23572
24226
  const arrowPath = result.traversalPath.join(" \u2190 ");
23573
24227
  const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
23574
24228
  const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
@@ -23594,12 +24248,12 @@ async function runRootCause(client, input) {
23594
24248
  }
23595
24249
  async function runBlastRadius(client, input) {
23596
24250
  const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
23597
- const path81 = projectPath(
24251
+ const path82 = projectPath(
23598
24252
  input.project,
23599
24253
  `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
23600
24254
  );
23601
24255
  try {
23602
- const result = await client.get(path81);
24256
+ const result = await client.get(path82);
23603
24257
  if (result.totalAffected === 0) {
23604
24258
  return {
23605
24259
  summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
@@ -23628,17 +24282,17 @@ async function runBlastRadius(client, input) {
23628
24282
  }
23629
24283
  }
23630
24284
  function formatBlastEntry(n) {
23631
- const tag = n.edgeProvenance === import_types82.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
24285
+ const tag = n.edgeProvenance === import_types83.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
23632
24286
  return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
23633
24287
  }
23634
24288
  async function runDependencies(client, input) {
23635
24289
  const depth = input.depth ?? 3;
23636
- const path81 = projectPath(
24290
+ const path82 = projectPath(
23637
24291
  input.project,
23638
24292
  `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
23639
24293
  );
23640
24294
  try {
23641
- const result = await client.get(path81);
24295
+ const result = await client.get(path82);
23642
24296
  if (result.total === 0) {
23643
24297
  return {
23644
24298
  summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
@@ -23685,7 +24339,7 @@ async function runObservedDependencies(client, input) {
23685
24339
  if (result.observed) {
23686
24340
  return {
23687
24341
  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.`,
23688
- provenance: import_types82.Provenance.OBSERVED
24342
+ provenance: import_types83.Provenance.OBSERVED
23689
24343
  };
23690
24344
  }
23691
24345
  const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
@@ -23695,7 +24349,7 @@ async function runObservedDependencies(client, input) {
23695
24349
  return {
23696
24350
  summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
23697
24351
  block: blockLines.join("\n"),
23698
- provenance: import_types82.Provenance.OBSERVED
24352
+ provenance: import_types83.Provenance.OBSERVED
23699
24353
  };
23700
24354
  } catch (err) {
23701
24355
  if (err instanceof HttpError && err.status === 404) {
@@ -23730,9 +24384,9 @@ function formatDuration(ms) {
23730
24384
  return `${Math.round(h / 24)}d`;
23731
24385
  }
23732
24386
  async function runIncidents(client, input) {
23733
- const path81 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
24387
+ const path82 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
23734
24388
  try {
23735
- const body = await client.get(path81);
24389
+ const body = await client.get(path82);
23736
24390
  const events = body.events;
23737
24391
  if (events.length === 0) {
23738
24392
  return {
@@ -23749,7 +24403,7 @@ async function runIncidents(client, input) {
23749
24403
  return {
23750
24404
  summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
23751
24405
  block: blockLines.join("\n"),
23752
- provenance: import_types82.Provenance.OBSERVED
24406
+ provenance: import_types83.Provenance.OBSERVED
23753
24407
  };
23754
24408
  } catch (err) {
23755
24409
  if (err instanceof HttpError && err.status === 404) {
@@ -23858,7 +24512,7 @@ async function runStaleEdges(client, input) {
23858
24512
  return {
23859
24513
  summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
23860
24514
  block: blockLines.join("\n"),
23861
- provenance: import_types82.Provenance.STALE
24515
+ provenance: import_types83.Provenance.STALE
23862
24516
  };
23863
24517
  }
23864
24518
  async function runPolicies(client, input) {
@@ -24017,10 +24671,10 @@ async function pushSnapshotToRemote(input) {
24017
24671
 
24018
24672
  // src/monitor.ts
24019
24673
  var OBSERVED_DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
24020
- import_types83.EdgeType.CALLS,
24021
- import_types83.EdgeType.CONNECTS_TO,
24022
- import_types83.EdgeType.PUBLISHES_TO,
24023
- import_types83.EdgeType.CONSUMES_FROM
24674
+ import_types84.EdgeType.CALLS,
24675
+ import_types84.EdgeType.CONNECTS_TO,
24676
+ import_types84.EdgeType.PUBLISHES_TO,
24677
+ import_types84.EdgeType.CONSUMES_FROM
24024
24678
  ]);
24025
24679
  function divergenceKey(d) {
24026
24680
  const column = "column" in d && d.column ? d.column : "";
@@ -24065,7 +24719,7 @@ function formatDivergenceLine2(d) {
24065
24719
  }
24066
24720
  }
24067
24721
  function formatStaleLine(edgeId) {
24068
- const parsed = (0, import_types83.parseEdgeId)(edgeId);
24722
+ const parsed = (0, import_types84.parseEdgeId)(edgeId);
24069
24723
  if (parsed) {
24070
24724
  return `\u22EF stale ${parsed.source} \u2192 ${parsed.target} (observed edge went quiet)`;
24071
24725
  }
@@ -24078,7 +24732,7 @@ function divergenceJson(d) {
24078
24732
  return JSON.stringify({ kind: "divergence", ...d });
24079
24733
  }
24080
24734
  function staleJson(edgeId) {
24081
- const parsed = (0, import_types83.parseEdgeId)(edgeId);
24735
+ const parsed = (0, import_types84.parseEdgeId)(edgeId);
24082
24736
  return JSON.stringify({
24083
24737
  kind: "stale",
24084
24738
  edgeId,
@@ -24148,7 +24802,7 @@ var MonitorEmitter = class {
24148
24802
  // ignores non-OBSERVED edges and non-dependency edge types (structural
24149
24803
  // ownership), so only real runtime dependencies reach stdout.
24150
24804
  emitObservedEdge(edge) {
24151
- if (edge.provenance !== import_types83.Provenance.OBSERVED) return false;
24805
+ if (edge.provenance !== import_types84.Provenance.OBSERVED) return false;
24152
24806
  if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false;
24153
24807
  const key = `edge|${edge.id}`;
24154
24808
  if (this.seen.has(key)) return false;
@@ -24306,7 +24960,7 @@ async function runMonitor(opts) {
24306
24960
  case "edge-added": {
24307
24961
  const payload = safeParse(frame.data);
24308
24962
  const edge = payload?.edge;
24309
- if (edge && edge.provenance === import_types83.Provenance.OBSERVED) {
24963
+ if (edge && edge.provenance === import_types84.Provenance.OBSERVED) {
24310
24964
  emitter.emitObservedEdge(edge);
24311
24965
  divergences.schedule();
24312
24966
  }
@@ -24386,7 +25040,7 @@ function sleep(ms, signal) {
24386
25040
 
24387
25041
  // src/cli-verbs.ts
24388
25042
  init_cjs_shims();
24389
- var import_node_path79 = __toESM(require("path"), 1);
25043
+ var import_node_path80 = __toESM(require("path"), 1);
24390
25044
  async function resolveProjectEntry(opts) {
24391
25045
  const entries = await listProjects();
24392
25046
  if (opts.project) {
@@ -24396,7 +25050,7 @@ async function resolveProjectEntry(opts) {
24396
25050
  const cwd = opts.cwd ?? process.cwd();
24397
25051
  const resolvedCwd = await normalizeProjectPath(cwd);
24398
25052
  for (const entry2 of entries) {
24399
- if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path79.default.sep}`)) {
25053
+ if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path80.default.sep}`)) {
24400
25054
  return entry2;
24401
25055
  }
24402
25056
  }
@@ -24549,7 +25203,7 @@ async function runSync(opts) {
24549
25203
  }
24550
25204
 
24551
25205
  // src/cli.ts
24552
- var import_types84 = require("@neat.is/types");
25206
+ var import_types85 = require("@neat.is/types");
24553
25207
  function isNpxInvocation() {
24554
25208
  if (process.env.npm_command === "exec") return true;
24555
25209
  const execpath = process.env.npm_execpath ?? "";
@@ -24920,12 +25574,12 @@ async function runInit(opts) {
24920
25574
  printDiscoveryReport(opts, services);
24921
25575
  const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
24922
25576
  const patch = renderPatch(sections);
24923
- const patchPath = import_node_path80.default.join(opts.scanPath, "neat.patch");
25577
+ const patchPath = import_node_path81.default.join(opts.scanPath, "neat.patch");
24924
25578
  if (opts.dryRun) {
24925
25579
  await import_node_fs46.promises.writeFile(patchPath, patch, "utf8");
24926
25580
  written.push(patchPath);
24927
25581
  console.log(`dry-run: patch written to ${patchPath}`);
24928
- const gitignorePath = import_node_path80.default.join(opts.scanPath, ".gitignore");
25582
+ const gitignorePath = import_node_path81.default.join(opts.scanPath, ".gitignore");
24929
25583
  const gitignoreExists = await import_node_fs46.promises.stat(gitignorePath).then(() => true).catch(() => false);
24930
25584
  const verb = gitignoreExists ? "append" : "create";
24931
25585
  console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
@@ -24937,9 +25591,9 @@ async function runInit(opts) {
24937
25591
  const graph = getGraph(graphKey);
24938
25592
  const projectPaths = pathsForProject(
24939
25593
  graphKey,
24940
- import_node_path80.default.join(opts.scanPath, "neat-out")
25594
+ import_node_path81.default.join(opts.scanPath, "neat-out")
24941
25595
  );
24942
- const errorsPath = import_node_path80.default.join(import_node_path80.default.dirname(opts.outPath), import_node_path80.default.basename(projectPaths.errorsPath));
25596
+ const errorsPath = import_node_path81.default.join(import_node_path81.default.dirname(opts.outPath), import_node_path81.default.basename(projectPaths.errorsPath));
24943
25597
  const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
24944
25598
  await saveGraphToDisk(graph, opts.outPath);
24945
25599
  written.push(opts.outPath);
@@ -25058,9 +25712,9 @@ var CLAUDE_SKILL_CONFIG = {
25058
25712
  };
25059
25713
  function claudeConfigPath() {
25060
25714
  const override = process.env.NEAT_CLAUDE_CONFIG;
25061
- if (override && override.length > 0) return import_node_path80.default.resolve(override);
25715
+ if (override && override.length > 0) return import_node_path81.default.resolve(override);
25062
25716
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
25063
- return import_node_path80.default.join(home, ".claude.json");
25717
+ return import_node_path81.default.join(home, ".claude.json");
25064
25718
  }
25065
25719
  async function runSkill(opts) {
25066
25720
  const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
@@ -25084,7 +25738,7 @@ async function runSkill(opts) {
25084
25738
  ...existing,
25085
25739
  mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
25086
25740
  };
25087
- await import_node_fs46.promises.mkdir(import_node_path80.default.dirname(target), { recursive: true });
25741
+ await import_node_fs46.promises.mkdir(import_node_path81.default.dirname(target), { recursive: true });
25088
25742
  await import_node_fs46.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
25089
25743
  console.log(`neat skill: wrote mcpServers.neat to ${target}`);
25090
25744
  console.log("restart Claude Code to pick up the new MCP server.");
@@ -25171,12 +25825,12 @@ async function main() {
25171
25825
  console.error("neat init: --apply and --dry-run are mutually exclusive");
25172
25826
  process.exit(2);
25173
25827
  }
25174
- const scanPath = import_node_path80.default.resolve(target);
25828
+ const scanPath = import_node_path81.default.resolve(target);
25175
25829
  const projectExplicit = parsed.project !== null;
25176
- const projectName = projectExplicit ? project : import_node_path80.default.basename(scanPath);
25830
+ const projectName = projectExplicit ? project : import_node_path81.default.basename(scanPath);
25177
25831
  const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
25178
- const fallback = pathsForProject(projectKey, import_node_path80.default.join(scanPath, "neat-out")).snapshotPath;
25179
- const outPath = import_node_path80.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
25832
+ const fallback = pathsForProject(projectKey, import_node_path81.default.join(scanPath, "neat-out")).snapshotPath;
25833
+ const outPath = import_node_path81.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
25180
25834
  const result = await runInit({
25181
25835
  scanPath,
25182
25836
  outPath,
@@ -25197,21 +25851,21 @@ async function main() {
25197
25851
  usage4();
25198
25852
  process.exit(2);
25199
25853
  }
25200
- const scanPath = import_node_path80.default.resolve(target);
25854
+ const scanPath = import_node_path81.default.resolve(target);
25201
25855
  const stat = await import_node_fs46.promises.stat(scanPath).catch(() => null);
25202
25856
  if (!stat || !stat.isDirectory()) {
25203
25857
  console.error(`neat watch: ${scanPath} is not a directory`);
25204
25858
  process.exit(2);
25205
25859
  }
25206
- const projectPaths = pathsForProject(project, import_node_path80.default.join(scanPath, "neat-out"));
25207
- const outPath = import_node_path80.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
25208
- const errorsPath = import_node_path80.default.resolve(
25209
- process.env.NEAT_ERRORS_PATH ?? import_node_path80.default.join(import_node_path80.default.dirname(outPath), import_node_path80.default.basename(projectPaths.errorsPath))
25860
+ const projectPaths = pathsForProject(project, import_node_path81.default.join(scanPath, "neat-out"));
25861
+ const outPath = import_node_path81.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
25862
+ const errorsPath = import_node_path81.default.resolve(
25863
+ process.env.NEAT_ERRORS_PATH ?? import_node_path81.default.join(import_node_path81.default.dirname(outPath), import_node_path81.default.basename(projectPaths.errorsPath))
25210
25864
  );
25211
- const staleEventsPath = import_node_path80.default.resolve(
25212
- process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path80.default.join(import_node_path80.default.dirname(outPath), import_node_path80.default.basename(projectPaths.staleEventsPath))
25865
+ const staleEventsPath = import_node_path81.default.resolve(
25866
+ process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path81.default.join(import_node_path81.default.dirname(outPath), import_node_path81.default.basename(projectPaths.staleEventsPath))
25213
25867
  );
25214
- const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path80.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
25868
+ const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path81.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
25215
25869
  const handle = await startWatch(getGraph(project), {
25216
25870
  scanPath,
25217
25871
  outPath,
@@ -25220,7 +25874,7 @@ async function main() {
25220
25874
  project,
25221
25875
  // Resolve NEAT_HOME so a `neat watch` picks up connectors added to
25222
25876
  // ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
25223
- neatHome: process.env.NEAT_HOME ? import_node_path80.default.resolve(process.env.NEAT_HOME) : import_node_path80.default.join(import_node_os8.default.homedir(), ".neat"),
25877
+ neatHome: process.env.NEAT_HOME ? import_node_path81.default.resolve(process.env.NEAT_HOME) : import_node_path81.default.join(import_node_os8.default.homedir(), ".neat"),
25224
25878
  ...embeddingsCachePath ? { embeddingsCachePath } : {},
25225
25879
  host: process.env.HOST ?? "0.0.0.0",
25226
25880
  port: Number(process.env.PORT ?? 8080),
@@ -25402,11 +26056,11 @@ async function main() {
25402
26056
  process.exit(1);
25403
26057
  }
25404
26058
  async function tryOrchestrator(cmd, parsed) {
25405
- const scanPath = import_node_path80.default.resolve(cmd);
26059
+ const scanPath = import_node_path81.default.resolve(cmd);
25406
26060
  const stat = await import_node_fs46.promises.stat(scanPath).catch(() => null);
25407
26061
  if (!stat || !stat.isDirectory()) return null;
25408
26062
  const projectExplicit = parsed.project !== null;
25409
- const projectName = projectExplicit ? parsed.project : import_node_path80.default.basename(scanPath);
26063
+ const projectName = projectExplicit ? parsed.project : import_node_path81.default.basename(scanPath);
25410
26064
  const result = await runOrchestrator({
25411
26065
  scanPath,
25412
26066
  project: projectName,
@@ -25595,10 +26249,10 @@ async function runQueryVerb(cmd, parsed) {
25595
26249
  const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
25596
26250
  const out = [];
25597
26251
  for (const p of parts) {
25598
- const r = import_types84.DivergenceTypeSchema.safeParse(p);
26252
+ const r = import_types85.DivergenceTypeSchema.safeParse(p);
25599
26253
  if (!r.success) {
25600
26254
  console.error(
25601
- `neat divergences: unknown --type "${p}". allowed: ${import_types84.DivergenceTypeSchema.options.join(", ")}`
26255
+ `neat divergences: unknown --type "${p}". allowed: ${import_types85.DivergenceTypeSchema.options.join(", ")}`
25602
26256
  );
25603
26257
  return 2;
25604
26258
  }