@neat.is/core 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OJHI33LD.js → chunk-5W7H35JJ.js} +1111 -343
- package/dist/chunk-5W7H35JJ.js.map +1 -0
- package/dist/{chunk-W4RNPPB5.js → chunk-TWNJX26R.js} +2 -2
- package/dist/cli.cjs +1471 -682
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +197 -169
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1145 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +1133 -368
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +1267 -502
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-OJHI33LD.js.map +0 -1
- /package/dist/{chunk-W4RNPPB5.js.map → chunk-TWNJX26R.js.map} +0 -0
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/tsup/assets/cjs_shims.js","../src/auth.ts","../src/otel-grpc.ts","../src/otel.ts","../src/cli.ts","../src/graph.ts","../src/extract.ts","../src/extract/index.ts","../src/ingest.ts","../src/policy.ts","../src/compat.ts","../compat.json","../src/events.ts","../src/traverse.ts","../src/extract/services.ts","../src/extract/shared.ts","../src/extract/python.ts","../src/extract/owners.ts","../src/extract/errors.ts","../src/extract/aliases.ts","../src/extract/databases/index.ts","../src/extract/databases/db-config-yaml.ts","../src/extract/databases/dotenv.ts","../src/extract/databases/shared.ts","../src/extract/databases/prisma.ts","../src/extract/databases/drizzle.ts","../src/extract/databases/knex.ts","../src/extract/databases/ormconfig.ts","../src/extract/databases/typeorm.ts","../src/extract/databases/sequelize.ts","../src/extract/databases/docker-compose.ts","../src/extract/configs.ts","../src/extract/calls/index.ts","../src/extract/calls/http.ts","../src/extract/calls/shared.ts","../src/extract/calls/kafka.ts","../src/extract/calls/redis.ts","../src/extract/calls/aws.ts","../src/extract/calls/grpc.ts","../src/extract/infra/index.ts","../src/extract/infra/docker-compose.ts","../src/extract/infra/shared.ts","../src/extract/infra/dockerfile.ts","../src/extract/infra/terraform.ts","../src/extract/infra/k8s.ts","../src/extract/retire.ts","../src/divergences.ts","../src/persist.ts","../src/gitignore.ts","../src/summary.ts","../src/watch.ts","../src/api.ts","../src/diff.ts","../src/projects.ts","../src/registry.ts","../src/streaming.ts","../src/search.ts","../src/deploy/detect.ts","../src/installers/index.ts","../src/installers/javascript.ts","../src/installers/templates.ts","../src/installers/python.ts","../src/installers/shared.ts","../src/orchestrator.ts","../src/installers/package-manager.ts","../src/cli-verbs.ts","../src/cli-client.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\n * Delegated auth at the daemon boundary (ADR-073 §3 + §4).\n *\n * NEAT does not issue, rotate, or distribute the token — that is the deploy\n * platform's job. This module provides the two surfaces the daemon needs:\n *\n * - `assertBindAuthority(host, token)` — fail-loud pre-bind check. When no\n * token is set, the daemon refuses to bind on any non-loopback address.\n * Loopback-only without a token stays unauthenticated (laptop dev path).\n *\n * - `mountBearerAuth(app, opts)` — Fastify `preHandler` that requires\n * `Authorization: Bearer <token>` on every request other than the\n * unauthenticated health/readiness probes. Constant-time comparison.\n *\n * The same shape covers both the REST host and the OTLP receivers; the OTLP\n * side passes a different token (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) so the\n * two surfaces rotate independently.\n */\n\nimport { timingSafeEqual } from 'node:crypto'\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\n\n// Hosts that count as loopback for the bind-authority gate. `0.0.0.0` is\n// explicitly not loopback — it binds on every interface, including any\n// public one the operator's box happens to have.\nconst LOOPBACK_HOSTS: ReadonlySet<string> = new Set([\n '127.0.0.1',\n 'localhost',\n '::1',\n '::ffff:127.0.0.1',\n])\n\nexport function isLoopbackHost(host: string | undefined | null): boolean {\n if (!host) return false\n return LOOPBACK_HOSTS.has(host)\n}\n\nexport class BindAuthorityError extends Error {\n constructor(host: string) {\n super(\n `NEAT refuses to bind on a public interface without \\`NEAT_AUTH_TOKEN\\` set (host=\"${host}\"). Set the token or bind to loopback only.`,\n )\n this.name = 'BindAuthorityError'\n }\n}\n\nexport function assertBindAuthority(host: string, token: string | undefined): void {\n if (token && token.length > 0) return\n if (isLoopbackHost(host)) return\n throw new BindAuthorityError(host)\n}\n\nexport interface AuthOptions {\n // Bearer token required on every protected route. Undefined / empty → the\n // middleware is not mounted and the route stays unauthenticated. The\n // loopback-only gate above is what keeps that case from being public.\n token?: string\n // When `true`, trust an upstream reverse proxy and skip the request-side\n // check. The fail-loud bind-authority gate still applies upstream. Wired\n // to `NEAT_AUTH_PROXY=true` in production.\n trustProxy?: boolean\n // ADR-073 §3 amendment — public-read mode for reference deployments.\n // When `true`, GET / HEAD / OPTIONS pass through without a bearer; every\n // other verb still requires the token. OTLP ingest is excluded — that\n // surface stays gated unconditionally (the receiver mounts its own\n // middleware without this flag).\n publicRead?: boolean\n // Extra paths (or path suffixes) to leave unauthenticated. Used by tests\n // and by ad-hoc callers that mount their own probes.\n extraUnauthenticatedSuffixes?: ReadonlyArray<string>\n}\n\n// Verbs the public-read split treats as reads. Everything else is a write\n// and keeps the bearer requirement.\nconst PUBLIC_READ_METHODS: ReadonlySet<string> = new Set(['GET', 'HEAD', 'OPTIONS'])\n\n// Probes that always stay open. Dual-mounted under `/projects/:project/` too,\n// so the check is a suffix match — `/projects/foo/health` is skipped along\n// with the top-level `/health`. ADR-073 §3 names `/healthz` and `/readyz`\n// explicitly; `/health` is the existing endpoint the web shell and CI smoke\n// already lean on, so it keeps the unauthenticated treatment. `/api/config`\n// is the public-read negotiation endpoint — the web shell hits it before any\n// authed call to learn which mode the daemon is running in.\nconst DEFAULT_UNAUTH_SUFFIXES: ReadonlyArray<string> = [\n '/health',\n '/healthz',\n '/readyz',\n '/api/config',\n]\n\nexport function mountBearerAuth(app: FastifyInstance, opts: AuthOptions): void {\n if (!opts.token || opts.token.length === 0) return\n if (opts.trustProxy) return\n\n const expected = Buffer.from(opts.token, 'utf8')\n const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...(opts.extraUnauthenticatedSuffixes ?? [])]\n const publicRead = opts.publicRead === true\n\n app.addHook('preHandler', (req: FastifyRequest, reply: FastifyReply, done: (err?: Error) => void) => {\n const path = (req.url.split('?')[0] ?? '').replace(/\\/+$/, '')\n for (const suffix of suffixes) {\n if (path === suffix || path.endsWith(suffix)) {\n done()\n return\n }\n }\n\n // Public-read split: GET / HEAD / OPTIONS pass through anonymously, every\n // other verb keeps the bearer check. The token still authorizes writes,\n // and the bind-authority gate above still demands a token for non-loopback\n // binds — public-read enables anonymous reads on top of that, it doesn't\n // replace either invariant.\n if (publicRead && PUBLIC_READ_METHODS.has(req.method)) {\n done()\n return\n }\n\n const header = req.headers.authorization\n if (typeof header !== 'string' || !header.startsWith('Bearer ')) {\n void reply.code(401).send({ error: 'unauthorized' })\n return\n }\n const provided = Buffer.from(header.slice('Bearer '.length).trim(), 'utf8')\n if (provided.length !== expected.length || !timingSafeEqual(provided, expected)) {\n void reply.code(401).send({ error: 'unauthorized' })\n return\n }\n done()\n })\n}\n\n// Read both tokens from the environment in one place so server.ts, daemon.ts,\n// and the OTel receivers all agree on precedence (ADR-073 §4). `publicRead`\n// rides the same shape so callers don't need a second env read.\nexport interface AuthEnv {\n authToken: string | undefined\n otelToken: string | undefined\n trustProxy: boolean\n publicRead: boolean\n}\n\nfunction parseBoolEnv(v: string | undefined): boolean {\n if (!v) return false\n return v === 'true' || v === '1'\n}\n\nexport function readAuthEnv(env: NodeJS.ProcessEnv = process.env): AuthEnv {\n const t = env.NEAT_AUTH_TOKEN\n const ot = env.NEAT_OTEL_TOKEN\n return {\n authToken: t && t.length > 0 ? t : undefined,\n otelToken: ot && ot.length > 0 ? ot : t && t.length > 0 ? t : undefined,\n trustProxy: env.NEAT_AUTH_PROXY === 'true',\n publicRead: parseBoolEnv(env.NEAT_PUBLIC_READ),\n }\n}\n","import { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport { timingSafeEqual } from 'node:crypto'\nimport * as grpc from '@grpc/grpc-js'\nimport * as protoLoader from '@grpc/proto-loader'\nimport {\n parseOtlpRequest,\n type OtlpTracesRequest,\n type ParsedSpan,\n type SpanHandler,\n} from './otel.js'\n\n// OTLP/gRPC receiver. Sits next to buildOtelReceiver (HTTP/JSON) in otel.ts;\n// shares the same parseOtlpRequest decoder so a span looks identical to the\n// downstream onSpan handler whether it came in over JSON or protobuf.\n//\n// Default OFF — opts.enabled (typically NEAT_OTLP_GRPC=true) decides whether\n// server.ts wires this up. We keep gRPC behind a flag so existing HTTP-only\n// deployments don't get a surprise port binding on upgrade.\n\nexport interface BuildOtelGrpcReceiverOptions {\n onSpan: SpanHandler\n // ADR-073 §4 — bearer required in the gRPC call's `authorization` metadata\n // when set. Same precedence as the HTTP receiver: NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN.\n authToken?: string\n // Skip the request-side check when an upstream proxy already authenticated.\n trustProxy?: boolean\n}\n\n// proto-loader output for the trace service has fields like resource_spans,\n// scope_spans, span_id, etc. (snake_case keys, since we leave keepCase: true\n// when loading). The HTTP path uses camelCase JSON, so we shape-shift the\n// gRPC payload onto the HTTP shape and let parseOtlpRequest do the rest.\n//\n// All `bytes` fields arrive as Buffers; the HTTP wire format encodes them as\n// hex strings, so we hex-encode for consistency.\n\ninterface GrpcAnyValue {\n string_value?: string\n bool_value?: boolean\n int_value?: string | number\n double_value?: number\n array_value?: { values?: GrpcAnyValue[] }\n // bytes/kvlist fields exist in the proto but the demo doesn't use them.\n}\n\ninterface GrpcKeyValue {\n key?: string\n value?: GrpcAnyValue\n}\n\ninterface GrpcStatus {\n code?: number\n message?: string\n}\n\ninterface GrpcEvent {\n name?: string\n time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n}\n\ninterface GrpcSpan {\n trace_id?: Buffer\n span_id?: Buffer\n parent_span_id?: Buffer\n name?: string\n kind?: number\n start_time_unix_nano?: string | number\n end_time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n events?: GrpcEvent[]\n status?: GrpcStatus\n}\n\ninterface GrpcScopeSpans {\n spans?: GrpcSpan[]\n}\n\ninterface GrpcResourceSpans {\n resource?: { attributes?: GrpcKeyValue[] }\n scope_spans?: GrpcScopeSpans[]\n}\n\ninterface GrpcExportRequest {\n resource_spans?: GrpcResourceSpans[]\n}\n\nfunction bytesToHex(buf: Buffer | undefined): string {\n if (!buf) return ''\n return Buffer.isBuffer(buf) ? buf.toString('hex') : ''\n}\n\nfunction nanosToString(n: string | number | undefined): string {\n if (n === undefined || n === null) return '0'\n return typeof n === 'string' ? n : String(n)\n}\n\nfunction reshapeAttributes(\n attrs: GrpcKeyValue[] | undefined,\n): OtlpTracesRequest['resourceSpans'] extends Array<infer R>\n ? R extends { resource?: { attributes?: infer A } }\n ? A\n : never\n : never {\n // Map snake_case oneof fields to the camelCase the JSON path expects.\n const out = (attrs ?? []).map((kv) => ({\n key: kv.key ?? '',\n value: kv.value\n ? {\n stringValue: kv.value.string_value,\n boolValue: kv.value.bool_value,\n intValue: kv.value.int_value,\n doubleValue: kv.value.double_value,\n arrayValue: kv.value.array_value\n ? {\n values: (kv.value.array_value.values ?? []).map((v) => ({\n stringValue: v.string_value,\n boolValue: v.bool_value,\n intValue: v.int_value,\n doubleValue: v.double_value,\n })),\n }\n : undefined,\n }\n : undefined,\n }))\n return out as never\n}\n\nexport function reshapeGrpcRequest(req: GrpcExportRequest): OtlpTracesRequest {\n return {\n resourceSpans: (req.resource_spans ?? []).map((rs) => ({\n resource: rs.resource ? { attributes: reshapeAttributes(rs.resource.attributes) } : undefined,\n scopeSpans: (rs.scope_spans ?? []).map((ss) => ({\n spans: (ss.spans ?? []).map((s) => ({\n traceId: bytesToHex(s.trace_id),\n spanId: bytesToHex(s.span_id),\n parentSpanId: s.parent_span_id ? bytesToHex(s.parent_span_id) : undefined,\n name: s.name,\n kind: s.kind,\n startTimeUnixNano: nanosToString(s.start_time_unix_nano),\n endTimeUnixNano: nanosToString(s.end_time_unix_nano),\n attributes: reshapeAttributes(s.attributes),\n events: (s.events ?? []).map((e) => ({\n name: e.name,\n timeUnixNano: nanosToString(e.time_unix_nano),\n attributes: reshapeAttributes(e.attributes),\n })),\n status: s.status ? { code: s.status.code, message: s.status.message } : undefined,\n })),\n })),\n })),\n }\n}\n\n// Find the bundled .proto tree at packages/core/proto/. The dev server runs\n// from the source tree (tsx); the built bundles run from dist/. tsup keeps\n// source layout, so __dirname-relative resolution works for both — we look two\n// levels up from this file.\nfunction resolveProtoRoot(): string {\n // Built output (CJS) sets __dirname natively; ESM build is bundled by tsup\n // and keeps a dirname injection. import.meta.url is the safe bet.\n const here = path.dirname(fileURLToPath(import.meta.url))\n // src/ → packages/core/proto/, dist/ → packages/core/proto/.\n return path.resolve(here, '..', 'proto')\n}\n\nfunction loadTraceService(): grpc.ServiceDefinition {\n const protoRoot = resolveProtoRoot()\n const def = protoLoader.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n {\n keepCase: true,\n longs: String,\n enums: Number,\n defaults: true,\n oneofs: true,\n includeDirs: [protoRoot],\n },\n )\n const pkg = grpc.loadPackageDefinition(def) as unknown as {\n opentelemetry: {\n proto: {\n collector: {\n trace: {\n v1: {\n TraceService: { service: grpc.ServiceDefinition }\n }\n }\n }\n }\n }\n }\n return pkg.opentelemetry.proto.collector.trace.v1.TraceService.service\n}\n\nexport interface OtelGrpcReceiver {\n // Bound address (host:port) once .start() has resolved. Useful for tests.\n address: string\n // Stop accepting new requests, shut down the server.\n stop: () => Promise<void>\n}\n\nexport async function startOtelGrpcReceiver(\n opts: BuildOtelGrpcReceiverOptions & { host?: string; port?: number },\n): Promise<OtelGrpcReceiver> {\n const server = new grpc.Server()\n const service = loadTraceService()\n\n const requiresAuth = !opts.trustProxy && !!opts.authToken && opts.authToken.length > 0\n const expectedHeader = requiresAuth ? `Bearer ${opts.authToken}` : ''\n\n server.addService(service, {\n Export: (\n call: grpc.ServerUnaryCall<GrpcExportRequest, unknown>,\n callback: grpc.sendUnaryData<{ partial_success: object }>,\n ) => {\n // ADR-073 §4 — same bearer shape as the HTTP receiver, carried in the\n // `authorization` gRPC metadata header. Constant-time comparison.\n if (requiresAuth) {\n const meta = call.metadata.get('authorization')\n const got = meta.length > 0 ? String(meta[0]) : ''\n const a = Buffer.from(got, 'utf8')\n const b = Buffer.from(expectedHeader, 'utf8')\n const ok = a.length === b.length && timingSafeEqual(a, b)\n if (!ok) {\n callback({ code: grpc.status.UNAUTHENTICATED, message: 'unauthorized' })\n return\n }\n }\n void (async () => {\n try {\n const reshaped = reshapeGrpcRequest(call.request ?? {})\n const spans: ParsedSpan[] = parseOtlpRequest(reshaped)\n for (const span of spans) {\n await opts.onSpan(span)\n }\n callback(null, { partial_success: {} })\n } catch (err) {\n callback({\n code: grpc.status.INTERNAL,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n })()\n },\n })\n\n const host = opts.host ?? '0.0.0.0'\n const port = opts.port ?? 4317\n\n const boundPort = await new Promise<number>((resolve, reject) => {\n server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, p) => {\n if (err) return reject(err)\n resolve(p)\n })\n })\n\n return {\n address: `${host}:${boundPort}`,\n stop: () =>\n new Promise<void>((resolve) => {\n server.tryShutdown(() => resolve())\n }),\n }\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport Fastify, { type FastifyInstance } from 'fastify'\nimport protobuf from 'protobufjs'\nimport { mountBearerAuth } from './auth.js'\n\n// OTLP/HTTP receiver. Listens on /v1/traces and decodes the JSON wire format\n// (collector's `otlphttp` exporter with `encoding: json`). Each span is\n// flattened into a ParsedSpan and handed to the configured handler. The\n// handler is the seam #8 wires its edge mapper into; #7 itself stays decoupled\n// from graph mutation.\n\nexport interface ParsedSpan {\n service: string\n // True when the resource carried a `service.name` attribute. False (or\n // omitted, for legacy producers) routes the span to `service:unidentified`\n // in the resolved project and trips a once-per-session-per-project warning\n // on the ingest side (issue #374). OTel spec requires SDKs to set\n // `service.name`, but customised exporters can omit it — diagnostic\n // visibility beats silent drop. Field is optional so test fixtures that\n // hand-construct ParsedSpan with a known service.name don't need to set\n // a flag they don't care about; the receiver always sets it.\n // See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n // is missing.\n resourceServiceNamePresent?: boolean\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n // ISO8601 derived from startTimeUnixNano. Production paths (lastObserved on\n // OBSERVED edges) read this so the recorded time reflects when the span fired,\n // not when the receiver received it. Undefined only when startTimeUnixNano is\n // missing or unparseable — handler falls back to wall-clock in that case.\n // See docs/contracts/otel-ingest.md §lastObserved-from-span-time.\n startTimeIso?: string\n // bigint so the 9-digit-nanos arithmetic doesn't lose precision on long traces.\n durationNanos: bigint\n // Deployment environment from `deployment.environment(.name)`. Span attrs\n // win over resource attrs (per-span overrides a resource-wide declaration);\n // the canonical `deployment.environment.name` (OTel SC v1.27+) wins over\n // the compat form `deployment.environment`. Literal `'unknown'` is the\n // honest fallback when no env signal is present anywhere on the span or\n // its resource. See ADR-074 §2 / docs/contracts/env-dimension.md.\n env: string\n attributes: Record<string, AttributeValue>\n // Convenience accessors for the attributes #8 cares about.\n dbSystem?: string\n dbName?: string\n // 0 = UNSET, 1 = OK, 2 = ERROR per OTLP. We only care that 2 means error.\n statusCode?: number\n errorMessage?: string\n // Pre-extracted from a span event with name=\"exception\". OTLP SDKs record\n // exceptions this way (richer than status.message). handleSpan reads these\n // first, falling back to status.message and span.name. See\n // docs/contracts/otel-ingest.md §exception-data-from-span-events.\n exception?: {\n type?: string\n message?: string\n stacktrace?: string\n }\n}\n\nexport type AttributeValue =\n | string\n | number\n | boolean\n | bigint\n | string[]\n | number[]\n | boolean[]\n | null\n\nexport type SpanHandler = (span: ParsedSpan) => void | Promise<void>\n// Variant that receives the project the URL already resolved to. Used by the\n// project-scoped route mounted at `/projects/:project/v1/traces` (issue #367):\n// the receiver hands the URL-path project to the daemon directly so the\n// daemon never has to guess via `service.name`-against-registry matching.\nexport type ProjectSpanHandler = (project: string, span: ParsedSpan) => void | Promise<void>\n\nexport interface BuildOtelReceiverOptions {\n onSpan: SpanHandler\n // Synchronous handler for spans with statusCode === 2. The receiver awaits\n // it before replying, so a write failure can return 500 → OTel SDK retries.\n // Optional — wiring is expected to plumb appendErrorEvent here when error\n // durability matters; ad-hoc receivers leave it undefined.\n // See docs/contracts/otel-ingest.md §Error events.\n onErrorSpanSync?: (span: ParsedSpan) => Promise<void>\n // Project-scoped variants — used by the `/projects/:project/v1/traces`\n // route. When unset the route is still mounted but falls through to the\n // legacy `onSpan` / `onErrorSpanSync` handlers (the project name is then\n // available to the consumer via the `OTEL_PROJECT_OVERRIDE` attribute on\n // each parsed span; ad-hoc receivers commonly leave both unset).\n onProjectSpan?: ProjectSpanHandler\n onProjectErrorSpanSync?: (project: string, span: ParsedSpan) => Promise<void>\n // Fastify body limit. OTLP batches can be large; default is 16 MB.\n bodyLimit?: number\n // ADR-073 §4 — bearer required on `/v1/traces`. Defaults to `NEAT_AUTH_TOKEN`\n // when unset; `NEAT_OTEL_TOKEN` overrides at the call site so the REST and\n // OTLP surfaces rotate on independent schedules.\n authToken?: string\n // Same shape as the REST middleware: skip the request-side check when an\n // upstream reverse proxy already authenticated.\n trustProxy?: boolean\n}\n\ninterface OtlpKeyValue {\n key: string\n value?: OtlpAnyValue\n}\n\ninterface OtlpAnyValue {\n stringValue?: string\n intValue?: string | number\n doubleValue?: number\n boolValue?: boolean\n arrayValue?: { values?: OtlpAnyValue[] }\n // kvlistValue / bytesValue are skipped — neither is on the demo path.\n}\n\ninterface OtlpStatus {\n code?: number\n message?: string\n}\n\ninterface OtlpEvent {\n name?: string\n timeUnixNano?: string\n attributes?: OtlpKeyValue[]\n}\n\ninterface OtlpSpan {\n traceId?: string\n spanId?: string\n parentSpanId?: string\n name?: string\n kind?: number\n startTimeUnixNano?: string\n endTimeUnixNano?: string\n attributes?: OtlpKeyValue[]\n events?: OtlpEvent[]\n status?: OtlpStatus\n}\n\nfunction extractExceptionFromEvents(events: OtlpEvent[] | undefined): ParsedSpan['exception'] {\n if (!events) return undefined\n for (const ev of events) {\n if (ev.name !== 'exception') continue\n const attrs = attrsToRecord(ev.attributes)\n const out: ParsedSpan['exception'] = {}\n const t = attrs['exception.type']\n const m = attrs['exception.message']\n const s = attrs['exception.stacktrace']\n if (typeof t === 'string') out.type = t\n if (typeof m === 'string') out.message = m\n if (typeof s === 'string') out.stacktrace = s\n if (out.type || out.message || out.stacktrace) return out\n }\n return undefined\n}\n\ninterface OtlpScopeSpans {\n spans?: OtlpSpan[]\n}\n\ninterface OtlpResourceSpans {\n resource?: { attributes?: OtlpKeyValue[] }\n scopeSpans?: OtlpScopeSpans[]\n}\n\nexport interface OtlpTracesRequest {\n resourceSpans?: OtlpResourceSpans[]\n}\n\nfunction flattenAttribute(v: OtlpAnyValue | undefined): AttributeValue {\n if (!v) return null\n if (v.stringValue !== undefined) return v.stringValue\n if (v.boolValue !== undefined) return v.boolValue\n if (v.intValue !== undefined) {\n return typeof v.intValue === 'string' ? Number(v.intValue) : v.intValue\n }\n if (v.doubleValue !== undefined) return v.doubleValue\n if (v.arrayValue?.values) {\n return v.arrayValue.values.map((x) => flattenAttribute(x)) as AttributeValue\n }\n return null\n}\n\nfunction attrsToRecord(attrs: OtlpKeyValue[] | undefined): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {}\n if (!attrs) return out\n for (const kv of attrs) {\n if (kv.key) out[kv.key] = flattenAttribute(kv.value)\n }\n return out\n}\n\nfunction durationNanos(start?: string, end?: string): bigint {\n if (!start || !end) return 0n\n try {\n return BigInt(end) - BigInt(start)\n } catch {\n return 0n\n }\n}\n\n// Convert OTLP's startTimeUnixNano (a base-10 string of nanoseconds since the\n// Unix epoch) to ISO8601. Returns undefined when the input is missing, zero,\n// or unparseable, so the caller can fall back to wall-clock without surfacing\n// a fake timestamp on the edge.\nexport function isoFromUnixNano(nanos: string | undefined): string | undefined {\n if (!nanos || nanos === '0') return undefined\n try {\n const ms = Number(BigInt(nanos) / 1_000_000n)\n if (!Number.isFinite(ms)) return undefined\n return new Date(ms).toISOString()\n } catch {\n return undefined\n }\n}\n\n// Resolve `deployment.environment` per ADR-074 §2. The four-step fallback\n// is: span-attr canonical form → span-attr compat form → resource-attr\n// canonical form → resource-attr compat form → literal `'unknown'`. The\n// literal `'unknown'` is the honest sentinel; defaulting to `'production'`\n// or `'development'` would bake an incorrect assumption into every span\n// from a workload that hasn't yet wired its env signal.\nconst ENV_ATTR_CANONICAL = 'deployment.environment.name'\nconst ENV_ATTR_COMPAT = 'deployment.environment'\nconst ENV_FALLBACK = 'unknown'\n\nfunction pickEnv(\n spanAttrs: Record<string, AttributeValue>,\n resourceAttrs: Record<string, AttributeValue>,\n): string {\n for (const attrs of [spanAttrs, resourceAttrs]) {\n for (const key of [ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT]) {\n const v = attrs[key]\n if (typeof v === 'string' && v.length > 0) return v\n }\n }\n return ENV_FALLBACK\n}\n\nexport function parseOtlpRequest(body: OtlpTracesRequest): ParsedSpan[] {\n const out: ParsedSpan[] = []\n for (const rs of body.resourceSpans ?? []) {\n const resourceAttrs = attrsToRecord(rs.resource?.attributes)\n // OTel spec requires SDKs to set `service.name`, but customised exporters\n // can omit it. Missing `service.name` routes to `service:unidentified`\n // in handleSpan + emits a once-per-session-per-project warning so the\n // diagnostic stays visible (issue #374). Silent drop is not an option.\n const rawServiceName = resourceAttrs['service.name']\n const resourceServiceNamePresent =\n typeof rawServiceName === 'string' && rawServiceName.length > 0\n const service = resourceServiceNamePresent\n ? (rawServiceName as string)\n : 'unidentified'\n\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = attrsToRecord(span.attributes)\n const parsed: ParsedSpan = {\n service,\n resourceServiceNamePresent,\n traceId: span.traceId ?? '',\n spanId: span.spanId ?? '',\n parentSpanId: span.parentSpanId || undefined,\n name: span.name ?? '',\n kind: span.kind,\n startTimeUnixNano: span.startTimeUnixNano ?? '0',\n endTimeUnixNano: span.endTimeUnixNano ?? '0',\n startTimeIso: isoFromUnixNano(span.startTimeUnixNano),\n durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),\n env: pickEnv(attrs, resourceAttrs),\n attributes: attrs,\n dbSystem: typeof attrs['db.system'] === 'string' ? (attrs['db.system'] as string) : undefined,\n dbName: typeof attrs['db.name'] === 'string' ? (attrs['db.name'] as string) : undefined,\n statusCode: span.status?.code,\n errorMessage: span.status?.message,\n exception: extractExceptionFromEvents(span.events),\n }\n out.push(parsed)\n }\n }\n }\n return out\n}\n\nexport interface OtelReceiver {\n app: FastifyInstance\n // Resolves once every span enqueued so far has been handed to opts.onSpan.\n // Test seam — production code never awaits this.\n flushPending: () => Promise<void>\n}\n\n// Lazy-loaded protobuf decoder for ExportTraceServiceRequest. The bundled\n// .proto tree at packages/core/proto/ is shared with the gRPC receiver\n// (ADR-020). Cached after first load so successive receiver builds reuse it.\nlet exportTraceServiceRequestType: protobuf.Type | null = null\nlet exportTraceServiceResponseType: protobuf.Type | null = null\n\nfunction loadProtoRoot(): protobuf.Root {\n const here = path.dirname(fileURLToPath(import.meta.url))\n const protoRoot = path.resolve(here, '..', 'proto')\n const root = new protobuf.Root()\n root.resolvePath = (_origin, target) => path.resolve(protoRoot, target)\n root.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n { keepCase: true },\n )\n return root\n}\n\nfunction loadProtobufDecoder(): protobuf.Type {\n if (exportTraceServiceRequestType) return exportTraceServiceRequestType\n const root = loadProtoRoot()\n exportTraceServiceRequestType = root.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n )\n return exportTraceServiceRequestType\n}\n\nfunction loadProtobufResponseEncoder(): protobuf.Type {\n if (exportTraceServiceResponseType) return exportTraceServiceResponseType\n const root = loadProtoRoot()\n exportTraceServiceResponseType = root.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse',\n )\n return exportTraceServiceResponseType\n}\n\n// Empty-partial-success response, encoded once and cached. Per ADR-033 the\n// receiver always reports \"all accepted\" today — there's no per-span reject\n// path. Caching the bytes avoids re-running the protobuf encoder per request.\nlet cachedProtobufResponseBody: Buffer | null = null\n\nfunction encodeProtobufResponseBody(): Buffer {\n if (cachedProtobufResponseBody) return cachedProtobufResponseBody\n const Type = loadProtobufResponseEncoder()\n // `partial_success` left unset = empty submessage = \"everything accepted\".\n // verify() returns null on success; the empty payload is always valid.\n const msg = Type.create({})\n const encoded = Type.encode(msg).finish()\n cachedProtobufResponseBody = Buffer.from(encoded)\n return cachedProtobufResponseBody\n}\n\nasync function decodeProtobufBody(buf: Buffer): Promise<OtlpTracesRequest> {\n const Type = loadProtobufDecoder()\n // Decode keeps the proto field names verbatim (keepCase: true), matching the\n // GrpcExportRequest shape that reshapeGrpcRequest already understands.\n // Dynamic import sidesteps the circular module dep with otel-grpc.ts.\n const decoded = Type.decode(buf).toJSON() as Record<string, unknown>\n const { reshapeGrpcRequest } = await import('./otel-grpc.js')\n return reshapeGrpcRequest(decoded as never)\n}\n\nexport async function buildOtelReceiver(\n opts: BuildOtelReceiverOptions,\n): Promise<FastifyInstance & { flushPending: () => Promise<void> }> {\n const app = Fastify({\n logger: false,\n bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024,\n })\n\n // ADR-073 §4 — bearer on `/v1/traces`. `/health` stays unauthenticated via\n // the default suffix list (the CI smoke and supervisors lean on it for\n // liveness probes).\n mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy })\n\n // Non-blocking ingest (ADR-033). The receiver replies 200 OK as soon as the\n // body is parsed; mutation runs through this queue, drained on the next tick.\n // OTel SDK exporters retry on timeout, so blocking ingest produces observable\n // backpressure on the system being observed — ambient observation requires no\n // observable effect.\n const queue: ParsedSpan[] = []\n let draining = false\n let drainPromise: Promise<void> = Promise.resolve()\n\n const drain = async (): Promise<void> => {\n if (draining) return\n draining = true\n try {\n while (queue.length > 0) {\n const span = queue.shift()!\n try {\n await opts.onSpan(span)\n } catch (err) {\n console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n }\n }\n } finally {\n draining = false\n }\n }\n\n const enqueue = (spans: ParsedSpan[]): void => {\n if (spans.length === 0) return\n for (const s of spans) queue.push(s)\n // Schedule on the next tick so the 200 response is on the wire before any\n // mutation runs. Each call gets its own promise so flushPending() can wait\n // on the latest drain cycle.\n drainPromise = drainPromise.then(() => drain())\n }\n\n // Per-project queue is reusable across the project-scoped route — the\n // project name rides in the URL, not on the span. Drain semantics mirror\n // the global queue so flushPending() captures both.\n const projectQueue: Array<{ project: string; span: ParsedSpan }> = []\n let projectDraining = false\n let projectDrainPromise: Promise<void> = Promise.resolve()\n const drainProject = async (): Promise<void> => {\n if (projectDraining) return\n projectDraining = true\n try {\n while (projectQueue.length > 0) {\n const { project, span } = projectQueue.shift()!\n try {\n if (opts.onProjectSpan) {\n await opts.onProjectSpan(project, span)\n } else {\n await opts.onSpan(span)\n }\n } catch (err) {\n console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n }\n }\n } finally {\n projectDraining = false\n }\n }\n const enqueueProject = (project: string, spans: ParsedSpan[]): void => {\n if (spans.length === 0) return\n for (const s of spans) projectQueue.push({ project, span: s })\n projectDrainPromise = projectDrainPromise.then(() => drainProject())\n }\n\n // One-time-per-service-name deprecation warning for spans landing on the\n // legacy global endpoint. The replacement is the project-scoped URL\n // (`/projects/<project>/v1/traces`) the installer writes into `.env.neat`\n // from v0.4.4. The warning is once-per-name so a long-running daemon\n // doesn't flood stderr while an operator is migrating.\n const legacyEndpointWarned = new Set<string>()\n function warnLegacyEndpoint(serviceName: string): void {\n if (legacyEndpointWarned.has(serviceName)) return\n legacyEndpointWarned.add(serviceName)\n console.warn(\n `[neatd] received span on the global endpoint; migrate OTEL_EXPORTER_OTLP_TRACES_ENDPOINT to /projects/<name>/v1/traces (service.name=\"${serviceName}\").`,\n )\n }\n\n // Shared body-decode + content-negotiation. Both `/v1/traces` and\n // `/projects/:project/v1/traces` go through this so the protobuf/JSON\n // dispatch stays in one place.\n async function readOtlpBody(req: import('fastify').FastifyRequest): Promise<\n | { ok: true; body: OtlpTracesRequest; flavor: 'json' | 'protobuf' }\n | { ok: false; code: 400 | 415; error: string }\n > {\n const ct = (req.headers['content-type'] ?? '').toString().split(';')[0]!.trim().toLowerCase()\n if (ct === 'application/x-protobuf') {\n try {\n const body = await decodeProtobufBody(req.body as Buffer)\n return { ok: true, body, flavor: 'protobuf' }\n } catch (err) {\n return { ok: false, code: 400, error: `protobuf decode failed: ${(err as Error).message}` }\n }\n }\n if (!ct || ct === 'application/json') {\n return { ok: true, body: (req.body ?? {}) as OtlpTracesRequest, flavor: 'json' }\n }\n return { ok: false, code: 415, error: `unsupported content-type: ${ct}` }\n }\n\n function sendOtlpSuccess(reply: import('fastify').FastifyReply, flavor: 'json' | 'protobuf'): unknown {\n if (flavor === 'protobuf') {\n const buf = encodeProtobufResponseBody()\n return reply\n .code(200)\n .header('content-type', 'application/x-protobuf')\n .send(buf)\n }\n return reply\n .code(200)\n .header('content-type', 'application/json')\n .send({ partialSuccess: {} })\n }\n\n // Buffer application/x-protobuf bodies as raw bytes; the route handler\n // decodes them via the bundled .proto tree (ADR-020).\n app.addContentTypeParser(\n 'application/x-protobuf',\n { parseAs: 'buffer', bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },\n (_req, body, done) => {\n done(null, body)\n },\n )\n\n app.get('/health', async () => ({ ok: true }))\n\n app.post('/v1/traces', async (req, reply) => {\n // Legacy global endpoint. Spans land here when an OTel exporter hasn't\n // migrated to the project-scoped URL yet (issue #367); the daemon still\n // routes by `service.name` against the registry. Per-service-name\n // deprecation warning fires once so an operator notices without their\n // stderr flooding.\n const result = await readOtlpBody(req)\n if (!result.ok) {\n return reply.code(result.code).send({ error: result.error })\n }\n const spans = parseOtlpRequest(result.body)\n for (const s of spans) warnLegacyEndpoint(s.service)\n if (opts.onErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n }\n enqueue(spans)\n return sendOtlpSuccess(reply, result.flavor)\n })\n\n // Project-scoped route (issue #367). The URL `:project` carries the routing\n // key, sidestepping the `service.name`-against-registry heuristic the legacy\n // path uses. Spans get dispatched into the named project's ingest path\n // directly; `OTEL_SERVICE_NAME` regains its proper semantic role of naming\n // the ServiceNode inside the one project the URL already picked.\n app.post<{ Params: { project: string } }>('/projects/:project/v1/traces', async (req, reply) => {\n const project = req.params.project\n const result = await readOtlpBody(req)\n if (!result.ok) {\n return reply.code(result.code).send({ error: result.error })\n }\n const spans = parseOtlpRequest(result.body)\n if (opts.onProjectErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onProjectErrorSpanSync(project, span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n } else if (opts.onErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n }\n enqueueProject(project, spans)\n return sendOtlpSuccess(reply, result.flavor)\n })\n\n // Attach flushPending so tests can wait for the queue without exporting a\n // separate handle. The cast goes through `unknown` because Fastify's typing\n // is parameterised over the raw server type and the simple intersection\n // confuses TS's structural narrowing.\n const decorated = app as unknown as FastifyInstance & { flushPending: () => Promise<void> }\n decorated.flushPending = async () => {\n // Settle both drain chains, then loop until both queues are fully empty\n // (a span enqueued mid-flush would otherwise be missed).\n while (queue.length > 0 || draining || projectQueue.length > 0 || projectDraining) {\n await Promise.all([drainPromise, projectDrainPromise])\n }\n }\n return decorated\n}\n\nexport function logSpanHandler(span: ParsedSpan): void {\n const parent = span.parentSpanId ? span.parentSpanId.slice(0, 8) : '<root>'\n const status = span.statusCode === 2 ? 'ERROR' : 'OK'\n const db = span.dbSystem ? ` db=${span.dbSystem}/${span.dbName ?? '?'}` : ''\n console.log(\n `otel: ${span.service} ${span.name} parent=${parent} status=${status}${db}`,\n )\n}\n","#!/usr/bin/env node\n\nimport path from 'node:path'\nimport { promises as fs, readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport {\n formatExtractionBanner,\n formatPrecisionFloorBanner,\n isStrictExtractionEnabled,\n} from './extract/errors.js'\nimport { discoverServices } from './extract/services.js'\nimport type { DiscoveredService } from './extract/shared.js'\nimport { computeDivergences } from './divergences.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { renderValueForwardSummary } from './summary.js'\nimport { startWatch, type WatchHandle } from './watch.js'\nimport { runDeploy, renderOtelEnvBlock } from './deploy/detect.js'\nimport { pathsForProject } from './projects.js'\nimport {\n addProject,\n listProjects,\n ProjectNameCollisionError,\n removeProject,\n setStatus,\n} from './registry.js'\nimport {\n INSTALLERS,\n isEmptyPlan,\n pickInstaller,\n renderPatch,\n type InstallPlan,\n type PatchSection,\n} from './installers/index.js'\nimport { runOrchestrator } from './orchestrator.js'\nimport { runSync } from './cli-verbs.js'\nimport { DivergenceTypeSchema, type DivergenceType } from '@neat.is/types'\nimport {\n createHttpClient,\n exitCodeForError,\n formatHuman,\n formatJson,\n HttpError,\n resolveAuthToken,\n runBlastRadius,\n runDependencies,\n runDiff,\n runDivergences,\n runIncidents,\n runObservedDependencies,\n runPolicies,\n runRootCause,\n runSearch,\n runStaleEdges,\n TransportError,\n type VerbResult,\n} from './cli-client.js'\n\nexport interface InitOptions {\n scanPath: string\n outPath: string\n // The project's registry name. Defaults to the basename of the scan path\n // when the user didn't pass `--project` (ADR-046 — project naming).\n project: string\n // Whether `project` was set explicitly via `--project`. The flag affects\n // which in-memory graph slot we use: explicit names get isolated slots\n // per ADR-026, the default basename keeps using DEFAULT_PROJECT for\n // back-compat with `neat watch`.\n projectExplicit: boolean\n apply: boolean\n dryRun: boolean\n noInstall: boolean\n // ADR-073 §5 — when true, append the per-type node/edge breakdown after\n // the value-forward findings block. Default false.\n verbose: boolean\n}\n\nexport interface InitResult {\n // Process exit code. 0 on success, 1 on collision / runtime failure,\n // 2 on misuse (handled before we get here, but documented for completeness).\n exitCode: number\n // Paths the run actually wrote to. Empty in `--dry-run` except for\n // `neat.patch`. Useful for tests asserting \"init only wrote X\".\n writtenFiles: string[]\n}\n\nfunction usage(): void {\n console.log('usage: neat <command> [args] [--project <name>]')\n console.log('')\n console.log('lifecycle commands:')\n console.log(' init <path> One-time install: discover, extract, register, plan SDK install.')\n console.log(' Snapshot lands in <path>/neat-out/graph.json by default')\n console.log(' (or <path>/neat-out/<project>.json for non-default).')\n console.log(' Flags:')\n console.log(' --apply run the SDK install patch in place')\n console.log(' --dry-run write only neat.patch; do not register or snapshot')\n console.log(' --no-install skip SDK install planning entirely')\n console.log(' watch <path> Start neat-core, watch <path>, re-extract on changes.')\n console.log(' PORT (default 8080), OTEL_PORT (4318), HOST (0.0.0.0)')\n console.log(' control listeners. NEAT_OTLP_GRPC=true also opens 4317.')\n console.log(' list List every project registered in the machine-level registry.')\n console.log(' pause <name> Mark a project paused — daemon stops watching until resumed.')\n console.log(' resume <name> Mark a project active again.')\n console.log(' uninstall <name>')\n console.log(' Remove a project from the registry. Does not touch')\n console.log(' neat-out/, policy.json, or any user file.')\n console.log(' version Print the installed @neat.is/core version and exit.')\n console.log(' Aliases: --version, -v.')\n console.log(' skill Install or print the Claude Code MCP drop-in.')\n console.log(' Flags:')\n console.log(' --print-config print the JSON snippet to stdout')\n console.log(' --apply merge mcpServers.neat into ~/.claude.json')\n console.log(' deploy Detect the deploy substrate, generate NEAT_AUTH_TOKEN,')\n console.log(' emit a docker-compose / systemd / docker run artifact, and')\n console.log(' print the OTel env-vars block to paste into your platform.')\n console.log(' sync Re-run discovery, extraction, and SDK apply against the')\n console.log(' registered project, then notify the running daemon.')\n console.log(' Flags:')\n console.log(' --project <name> target a registered project by name')\n console.log(' --to <url> push the snapshot to a remote daemon')\n console.log(' --token <token> bearer token for --to (or $NEAT_REMOTE_TOKEN)')\n console.log(' --dry-run run extraction in-memory; do not write')\n console.log(' --no-instrument skip the SDK install apply step')\n console.log(' --json emit the delta summary as JSON')\n console.log('')\n console.log('query commands (mirror the MCP tools, ADR-050):')\n console.log(' root-cause <node-id> Walk inbound edges to find what broke first.')\n console.log(' example: neat root-cause service:<name>')\n console.log(' blast-radius <node-id> BFS outbound — what would break if this dies.')\n console.log(' example: neat blast-radius database:<host>')\n console.log(' dependencies <node-id> Transitive outbound dependencies.')\n console.log(' Flags: --depth N (default 3, max 10)')\n console.log(' example: neat dependencies service:<name> --depth 2')\n console.log(' observed-dependencies <node-id> OBSERVED-only outbound edges (runtime traffic).')\n console.log(' example: neat observed-dependencies service:<name>')\n console.log(' incidents [<node-id>] Recent error events; per-node when an id is given.')\n console.log(' Flags: --limit N (default 20)')\n console.log(' example: neat incidents service:<name> --limit 5')\n console.log(' search <query> Semantic (or substring) match on node names/ids.')\n console.log(' example: neat search \"checkout\"')\n console.log(' diff --against <snapshot> Compare the live graph to a saved snapshot.')\n console.log(' example: neat diff --against ./snapshots/baseline.json')\n console.log(' stale-edges Recent OBSERVED → STALE transitions.')\n console.log(' Flags: --limit N, --edge-type CALLS|CONNECTS_TO|...')\n console.log(' example: neat stale-edges --edge-type CALLS')\n console.log(' policies Current policy violations.')\n console.log(' Flags: --node <id>, --hypothetical-action <json>')\n console.log(' example: neat policies --node service:<name> --json')\n console.log(' divergences Where code (EXTRACTED) and production (OBSERVED) disagree.')\n console.log(' Flags: --type <list>, --min-confidence <0..1>, --node <id>')\n console.log(' example: neat divergences --min-confidence 0.7')\n console.log('')\n console.log('flags:')\n console.log(' --project <name> Name the project this command targets. Default: \"default\".')\n console.log(' --json Emit machine-readable JSON instead of human text. Query verbs only.')\n console.log('')\n console.log('exit codes:')\n console.log(' 0 success')\n console.log(' 1 server error (4xx/5xx body printed to stderr)')\n console.log(' 2 misuse (missing args, bad flags) — handled before any network call')\n console.log(' 3 environmental — daemon unreachable, or one of ports 8080 / 4318 / 6328')\n console.log(' is held by another process when `neat <path>` tries to spawn the daemon')\n console.log('')\n console.log('environment:')\n console.log(' NEAT_API_URL base URL for the core REST API (default http://localhost:8080)')\n console.log(' NEAT_PROJECT project name when --project isn\\'t passed')\n}\n\n// Tiny argv parser — pulls `--project <name>`, the v0.2.5 init flags, and\n// the v0.2.8 verb flags out of `rest`. Boolean / value flags are surfaced\n// unconditionally; per-command validation lives in `main`.\ninterface ParsedArgs {\n project: string | null\n apply: boolean\n dryRun: boolean\n noInstall: boolean\n noInstrument: boolean\n noOpen: boolean\n yes: boolean\n verbose: boolean\n printConfig: boolean\n json: boolean\n depth: number | null\n limit: number | null\n edgeType: string | null\n node: string | null\n since: string | null\n against: string | null\n errorId: string | null\n hypotheticalAction: string | null\n type: string | null\n minConfidence: number | null\n // `neat sync` (ADR-074 §1) — remote daemon URL + bearer token.\n to: string | null\n token: string | null\n positional: string[]\n}\n\n// String-valued flags supported across the verb surface. Each entry maps the\n// canonical `--flag` name (and its `--flag=` equivalent) to the parsed-args\n// field that receives it. Centralising the table keeps misuse diagnostics\n// (exit code 2) consistent across verbs.\nconst STRING_FLAGS = [\n ['--project', 'project'],\n ['--depth', 'depth'],\n ['--limit', 'limit'],\n ['--edge-type', 'edgeType'],\n ['--node', 'node'],\n ['--since', 'since'],\n ['--against', 'against'],\n ['--error-id', 'errorId'],\n ['--hypothetical-action', 'hypotheticalAction'],\n ['--type', 'type'],\n ['--min-confidence', 'minConfidence'],\n ['--to', 'to'],\n ['--token', 'token'],\n] as const\n\nfunction parseArgs(rest: string[]): ParsedArgs {\n const positional: string[] = []\n const out: ParsedArgs = {\n project: null,\n apply: false,\n dryRun: false,\n noInstall: false,\n noInstrument: false,\n noOpen: false,\n yes: false,\n verbose: false,\n printConfig: false,\n json: false,\n depth: null,\n limit: null,\n edgeType: null,\n node: null,\n since: null,\n against: null,\n errorId: null,\n hypotheticalAction: null,\n type: null,\n minConfidence: null,\n to: null,\n token: null,\n positional: [],\n }\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i] as string\n\n // Boolean flags first.\n if (arg === '--apply') { out.apply = true; continue }\n if (arg === '--dry-run') { out.dryRun = true; continue }\n if (arg === '--no-install') { out.noInstall = true; continue }\n if (arg === '--no-instrument') { out.noInstrument = true; continue }\n if (arg === '--no-open') { out.noOpen = true; continue }\n if (arg === '--yes' || arg === '-y') { out.yes = true; continue }\n if (arg === '--verbose') { out.verbose = true; continue }\n if (arg === '--print-config') { out.printConfig = true; continue }\n if (arg === '--json') { out.json = true; continue }\n\n // String/number flags via the shared table.\n let matched = false\n for (const [flag, field] of STRING_FLAGS) {\n if (arg === flag) {\n const next = rest[i + 1]\n if (next === undefined) {\n console.error(`neat: ${flag} requires a value`)\n process.exit(2)\n }\n assignFlag(out, field, next)\n i++\n matched = true\n break\n }\n if (arg.startsWith(`${flag}=`)) {\n assignFlag(out, field, arg.slice(flag.length + 1))\n matched = true\n break\n }\n }\n if (matched) continue\n positional.push(arg)\n }\n out.positional = positional\n return out\n}\n\nexport { parseArgs }\n\n// Number flags get parsed at assignment time so misuse (`--depth foo`)\n// surfaces with exit code 2 before any network call.\nfunction assignFlag(out: ParsedArgs, field: (typeof STRING_FLAGS)[number][1], value: string): void {\n if (field === 'depth' || field === 'limit') {\n const n = Number(value)\n if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n console.error(`neat: --${field === 'depth' ? 'depth' : 'limit'} must be a positive integer`)\n process.exit(2)\n }\n out[field] = n\n return\n }\n if (field === 'minConfidence') {\n const n = Number(value)\n if (!Number.isFinite(n) || n < 0 || n > 1) {\n console.error('neat: --min-confidence must be a number in [0, 1]')\n process.exit(2)\n }\n out.minConfidence = n\n return\n }\n // String fields.\n ;(out as unknown as Record<string, unknown>)[field] = value\n}\n\n// Per-type node/edge counts + compat formatting moved into summary.ts as\n// part of the value-forward findings block (issue #305 / ADR-073 §5).\n\n// The `neat --version` family reads its answer from the bundled package's\n// own package.json. Reading at run time keeps the published bin in lockstep\n// with whatever version `tsup` shipped without a build-time substitution.\n// `dist/cli.cjs` sits one level below the package root.\nexport function readPackageVersion(): string {\n const here =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url))\n // dist/ → package root. tsup writes both cjs and mjs to dist/, so the\n // parent-of-parent walk is the same in either format.\n const candidates = [\n path.resolve(here, '../package.json'),\n path.resolve(here, '../../package.json'),\n ]\n for (const candidate of candidates) {\n try {\n const raw = readFileSync(candidate, 'utf8')\n const parsed = JSON.parse(raw) as { name?: string; version?: string }\n if (parsed.name === '@neat.is/core' && typeof parsed.version === 'string') {\n return parsed.version\n }\n } catch {\n // try the next candidate\n }\n }\n return 'unknown'\n}\n\nfunction printVersion(): void {\n process.stdout.write(`${readPackageVersion()}\\n`)\n}\n\nexport function printBanner(): void {\n console.log('███╗ ██╗███████╗ █████╗ ████████╗')\n console.log('████╗ ██║██╔════╝██╔══██╗╚══██╔══╝')\n console.log('██╔██╗ ██║█████╗ ███████║ ██║ ')\n console.log('██║╚██╗██║██╔══╝ ██╔══██║ ██║ ')\n console.log('██║ ╚████║███████╗██║ ██║ ██║ ')\n console.log('╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═╝ ')\n console.log('')\n console.log(' Network Expressive Architecting Tool')\n console.log(` neat.is · v${readPackageVersion()} · Apache 2.0`)\n console.log('')\n}\n\nfunction printDiscoveryReport(opts: InitOptions, services: DiscoveredService[]): void {\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n const mode = opts.dryRun ? 'dry-run' : opts.apply ? 'apply' : 'patch-only'\n printBanner()\n console.log('=== neat init: discovery ===')\n console.log(`scan path: ${opts.scanPath}`)\n console.log(`project: ${opts.project}`)\n console.log(`mode: ${mode}`)\n console.log(`services: ${services.length}`)\n for (const s of services) {\n const where = s.node.repoPath && s.node.repoPath.length > 0 ? s.node.repoPath : '.'\n console.log(` - ${s.node.name} (${s.node.language}) — ${where}`)\n }\n console.log(`languages: ${languages.length > 0 ? languages.join(', ') : '(none)'}`)\n if (opts.noInstall) {\n console.log('install: skipped (--no-install)')\n } else if (opts.dryRun) {\n console.log('install: patch will be written to neat.patch; nothing else.')\n } else if (opts.apply) {\n console.log('install: patch will be applied in place. Run `npm install` afterwards.')\n } else {\n console.log('install: patch will be written to neat.patch for review.')\n }\n console.log('')\n}\n\nasync function buildPatchSections(\n services: DiscoveredService[],\n project: string,\n): Promise<PatchSection[]> {\n const sections: PatchSection[] = []\n for (const svc of services) {\n const installer = await pickInstaller(svc.dir)\n if (!installer) continue\n // v0.4.1 / refs #339 — pass the registered project name so the per-\n // package `.env.neat` carries `OTEL_SERVICE_NAME=<project>`. The daemon\n // routes spans by registered project name; matching keys end-to-end\n // is what keeps OBSERVED edges landing.\n const plan: InstallPlan = await installer.plan(svc.dir, { project })\n // Lib-only + runtime-kind-skipped packages keep a section so the dry-run\n // patch documents the skip and the apply summary counts them (ADR-069 §2,\n // v0.4.4 / #370). Empty plans without either flag are already-instrumented\n // end-to-end and drop out.\n if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) continue\n sections.push({ installer: installer.name, plan })\n }\n return sections\n}\n\nexport async function runInit(opts: InitOptions): Promise<InitResult> {\n const written: string[] = []\n\n // ── Step 1: validate path ────────────────────────────────────────────\n const stat = await fs.stat(opts.scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat init: ${opts.scanPath} is not a directory`)\n return { exitCode: 2, writtenFiles: written }\n }\n\n // ── Step 2: discovery (ADR-046 #2 — before any mutation) ─────────────\n const services = await discoverServices(opts.scanPath)\n printDiscoveryReport(opts, services)\n\n // ── Step 3: plan SDK install (pure data, no fs writes) ───────────────\n const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project)\n const patch = renderPatch(sections)\n const patchPath = path.join(opts.scanPath, 'neat.patch')\n\n // ── Step 4: dry-run shortcut — only neat.patch is allowed to land ────\n if (opts.dryRun) {\n await fs.writeFile(patchPath, patch, 'utf8')\n written.push(patchPath)\n console.log(`dry-run: patch written to ${patchPath}`)\n // ADR-073 §6 — list the planned `.gitignore` write alongside the other\n // planned writes. No file mutation in dry-run; only the announcement.\n const gitignorePath = path.join(opts.scanPath, '.gitignore')\n const gitignoreExists = await fs.stat(gitignorePath).then(() => true).catch(() => false)\n const verb = gitignoreExists ? 'append' : 'create'\n console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`)\n console.log('rerun without --dry-run to register and snapshot.')\n return { exitCode: 0, writtenFiles: written }\n }\n\n // ── Step 5: extraction + snapshot ────────────────────────────────────\n // Use DEFAULT_PROJECT for the in-memory graph slot when --project wasn't\n // explicitly passed; named projects get isolated slots per ADR-026.\n const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n resetGraph(graphKey)\n const graph = getGraph(graphKey)\n // ADR-065 — per-file extraction failures land alongside the snapshot in\n // <projectDir>/neat-out/errors.ndjson. Same file as OTel error events\n // (ADR-033) with a `source: 'extract'` discriminator.\n const projectPaths = pathsForProject(\n graphKey,\n path.join(opts.scanPath, 'neat-out'),\n )\n const errorsPath = path.join(path.dirname(opts.outPath), path.basename(projectPaths.errorsPath))\n const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath })\n await saveGraphToDisk(graph, opts.outPath)\n written.push(opts.outPath)\n\n // ADR-073 §6 — ensure `neat-out/` is git-ignored. Snapshot just landed on\n // disk; an un-ignored neat-out/ would leak into git history on the next\n // commit. Idempotent: the helper no-ops when the line is already present.\n const gitignoreResult = await ensureNeatOutIgnored(opts.scanPath)\n if (gitignoreResult.action !== 'unchanged') {\n written.push(gitignoreResult.file)\n }\n\n // ── Step 6: register in the machine-level registry ───────────────────\n // Idempotent re-init of the same path under the same name refreshes the\n // entry; collision against a different path exits non-zero (ADR-046 #7).\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n let currentProjectName = opts.project\n try {\n const entry = await addProject({\n name: opts.project,\n path: opts.scanPath,\n languages,\n status: 'active',\n })\n currentProjectName = entry.name\n } catch (err) {\n if (err instanceof ProjectNameCollisionError) {\n console.error(`neat init: ${err.message}`)\n console.error('pass --project <other-name> to register under a different name.')\n return { exitCode: 1, writtenFiles: written }\n }\n throw err\n }\n\n // Narrow the active-project surface to the project the operator just\n // registered. Mirrors the bare-orchestrator behaviour so `neat init` and\n // `neat <path>` agree on the activation contract.\n const siblings = await listProjects()\n const paused: string[] = []\n for (const p of siblings) {\n if (p.name !== currentProjectName && p.status === 'active') {\n await setStatus(p.name, 'paused')\n paused.push(p.name)\n }\n }\n if (paused.length > 0) {\n const plural = paused.length === 1 ? '' : 's'\n console.log(\n `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n )\n }\n\n // ── Step 7: write or apply patch ─────────────────────────────────────\n if (!opts.noInstall) {\n if (opts.apply) {\n let instrumented = 0\n let alreadyInstrumented = 0\n let libOnly = 0\n let browserBundle = 0\n let reactNative = 0\n for (const section of sections) {\n const installer = INSTALLERS.find((i) => i.name === section.installer)\n if (!installer) continue\n const outcome = await installer.apply(section.plan)\n if (outcome.outcome === 'instrumented') {\n instrumented++\n for (const f of outcome.writtenFiles) written.push(f)\n } else if (outcome.outcome === 'already-instrumented') {\n alreadyInstrumented++\n } else if (outcome.outcome === 'lib-only') {\n libOnly++\n } else if (outcome.outcome === 'browser-bundle') {\n browserBundle++\n console.log(`skipping ${section.plan.serviceDir}: browser bundle; browser-OTel support lands in a future release.`)\n } else if (outcome.outcome === 'react-native') {\n reactNative++\n console.log(`skipping ${section.plan.serviceDir}: React Native target; browser-OTel support lands in a future release.`)\n }\n }\n if (sections.length > 0) {\n console.log('')\n const parts = [\n `instrumented ${instrumented}`,\n `already-instrumented ${alreadyInstrumented}`,\n `lib-only ${libOnly}`,\n ]\n if (browserBundle > 0) parts.push(`browser-bundle ${browserBundle}`)\n if (reactNative > 0) parts.push(`react-native ${reactNative}`)\n console.log(`apply: ${parts.join(', ')}`)\n console.log('Run `npm install` (or your language equivalent) to refresh lockfiles.')\n }\n } else {\n await fs.writeFile(patchPath, patch, 'utf8')\n written.push(patchPath)\n }\n }\n\n // ── Step 8: summary + incompatibilities ──────────────────────────────\n // ADR-073 §5 / issue #305 — findings-first: compat violations, top\n // divergences, services without OBSERVED coverage, then the OTel env-vars\n // block. Per-type counts ride behind `--verbose`.\n console.log('')\n console.log(`snapshot: ${opts.outPath}`)\n console.log(`added: ${result.nodesAdded} nodes, ${result.edgesAdded} edges`)\n console.log('')\n const divergenceResult = computeDivergences(graph)\n console.log(\n renderValueForwardSummary({\n graph,\n divergences: divergenceResult.divergences,\n verbose: opts.verbose,\n }),\n )\n // ADR-065 — loud failure mode banner. Unconditional; 0 is a positive\n // signal. When errors > 0, also surface the sidecar path so the operator\n // can read per-file detail.\n console.log(formatExtractionBanner(result.extractionErrors))\n if (result.extractionErrors > 0) {\n console.log(`errors: ${errorsPath}`)\n }\n // ADR-066 — precision-floor drop banner. Always emitted; 0 is observable\n // as a positive signal that no cross-service heuristic edges grew the\n // graph this pass.\n console.log(formatPrecisionFloorBanner(result.extractedDropped))\n\n // ADR-065 — NEAT_STRICT_EXTRACTION=1 makes any per-file failure exit\n // non-zero. Default is forgiving (banner only). Exit code 4 keeps\n // misuse (2) and daemon-down (3) distinguishable per the CLI contract.\n if (result.extractionErrors > 0 && isStrictExtractionEnabled()) {\n return { exitCode: 4, writtenFiles: written }\n }\n\n return { exitCode: 0, writtenFiles: written }\n}\n\n// ── Claude Code skill (ADR-049 / v0.2.5 step 6) ────────────────────────\n//\n// The skill is a one-shot MCP-config drop-in. Source of truth for the\n// snippet lives here (the @neat.is/claude-skill package's\n// claude_code_config.json holds an identical copy for documentation; a\n// contract test keeps the two byte-aligned).\nexport const CLAUDE_SKILL_CONFIG = {\n mcpServers: {\n neat: {\n type: 'stdio' as const,\n command: 'npx',\n args: ['-y', '@neat.is/mcp'],\n env: {\n NEAT_API_URL: 'http://localhost:8080',\n },\n },\n },\n}\n\nfunction claudeConfigPath(): string {\n // ~/.claude.json is Claude Code's user-level MCP config. Tests override\n // via NEAT_CLAUDE_CONFIG so they don't touch the real file.\n const override = process.env.NEAT_CLAUDE_CONFIG\n if (override && override.length > 0) return path.resolve(override)\n const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n return path.join(home, '.claude.json')\n}\n\nexport interface SkillOptions {\n apply: boolean\n printConfig: boolean\n}\n\nexport async function runSkill(opts: SkillOptions): Promise<{ exitCode: number }> {\n const snippet = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + '\\n'\n\n if (opts.printConfig) {\n process.stdout.write(snippet)\n return { exitCode: 0 }\n }\n\n if (opts.apply) {\n const target = claudeConfigPath()\n let existing: Record<string, unknown> = {}\n try {\n existing = JSON.parse(await fs.readFile(target, 'utf8'))\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.error(`neat skill: failed to read ${target} — ${(err as Error).message}`)\n return { exitCode: 1 }\n }\n }\n // Merge mcpServers.neat without disturbing other entries the user\n // might have wired up by hand.\n const mcp =\n (existing as { mcpServers?: Record<string, unknown> }).mcpServers ?? {}\n const merged = {\n ...existing,\n mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat },\n }\n await fs.mkdir(path.dirname(target), { recursive: true })\n await fs.writeFile(target, JSON.stringify(merged, null, 2) + '\\n', 'utf8')\n console.log(`neat skill: wrote mcpServers.neat to ${target}`)\n console.log('restart Claude Code to pick up the new MCP server.')\n return { exitCode: 0 }\n }\n\n console.log('neat skill — Claude Code MCP drop-in for NEAT')\n console.log('')\n console.log(' --print-config print the JSON snippet to stdout')\n console.log(' --apply merge mcpServers.neat into ~/.claude.json')\n console.log('')\n console.log('Manual install: copy mcpServers.neat from --print-config into ~/.claude.json,')\n console.log('then restart Claude Code. See packages/claude-skill/SKILL.md for the tool list.')\n return { exitCode: 0 }\n}\n\nasync function main(): Promise<void> {\n const [, , cmd, ...rest] = process.argv\n\n if (!cmd || cmd === '-h' || cmd === '--help') {\n usage()\n process.exit(0)\n }\n\n if (cmd === '--version' || cmd === '-v' || cmd === 'version') {\n printVersion()\n process.exit(0)\n }\n\n const parsed = parseArgs(rest)\n const { positional, apply, dryRun, noInstall } = parsed\n const project = parsed.project ?? DEFAULT_PROJECT\n\n if (cmd === 'init') {\n const target = positional[0]\n if (!target) {\n console.error('neat init: missing <path>')\n usage()\n process.exit(2)\n }\n if (apply && dryRun) {\n console.error('neat init: --apply and --dry-run are mutually exclusive')\n process.exit(2)\n }\n const scanPath = path.resolve(target)\n // ADR-046 — when --project isn't passed, the registry name defaults to\n // the basename of the scan path. The in-memory graph slot stays on\n // DEFAULT_PROJECT (back-compat with existing `neat watch` invocations).\n const projectExplicit = parsed.project !== null\n const projectName = projectExplicit ? project : path.basename(scanPath)\n // Default project keeps writing to graph.json (ADR-026 back-compat);\n // named projects use <project>.json under the same neat-out directory.\n const projectKey = projectExplicit ? project : DEFAULT_PROJECT\n const fallback = pathsForProject(projectKey, path.join(scanPath, 'neat-out')).snapshotPath\n const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? fallback)\n const result = await runInit({\n scanPath,\n outPath,\n project: projectName,\n projectExplicit,\n apply,\n dryRun,\n noInstall,\n verbose: parsed.verbose,\n })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n if (cmd === 'watch') {\n const target = positional[0]\n if (!target) {\n console.error('neat watch: missing <path>')\n usage()\n process.exit(2)\n }\n const scanPath = path.resolve(target)\n const stat = await fs.stat(scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat watch: ${scanPath} is not a directory`)\n process.exit(2)\n }\n const projectPaths = pathsForProject(project, path.join(scanPath, 'neat-out'))\n const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath)\n const errorsPath = path.resolve(\n process.env.NEAT_ERRORS_PATH ??\n path.join(path.dirname(outPath), path.basename(projectPaths.errorsPath)),\n )\n const staleEventsPath = path.resolve(\n process.env.NEAT_STALE_EVENTS_PATH ??\n path.join(path.dirname(outPath), path.basename(projectPaths.staleEventsPath)),\n )\n\n const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH\n ? path.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH)\n : undefined\n\n const handle: WatchHandle = await startWatch(getGraph(project), {\n scanPath,\n outPath,\n errorsPath,\n staleEventsPath,\n project,\n ...(embeddingsCachePath ? { embeddingsCachePath } : {}),\n host: process.env.HOST ?? '0.0.0.0',\n port: Number(process.env.PORT ?? 8080),\n otelPort: Number(process.env.OTEL_PORT ?? 4318),\n otelGrpc: process.env.NEAT_OTLP_GRPC === 'true',\n otelGrpcPort: process.env.NEAT_OTLP_GRPC_PORT\n ? Number(process.env.NEAT_OTLP_GRPC_PORT)\n : undefined,\n })\n\n // startPersistLoop already wires SIGTERM/SIGINT to flush + exit. Hook in\n // ahead of it so the watcher closes cleanly first; the persist handler's\n // `process.exit(0)` will still run after our stop() resolves.\n let shuttingDown = false\n const shutdown = (signal: NodeJS.Signals): void => {\n if (shuttingDown) return\n shuttingDown = true\n console.log(`neat watch: ${signal} received, stopping…`)\n void handle.stop().catch((err) => {\n console.error('neat watch: shutdown error', err)\n })\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n return\n }\n\n if (cmd === 'list') {\n const projects = await listProjects()\n if (projects.length === 0) {\n console.log('no projects registered. run `neat init <path>` to register one.')\n return\n }\n for (const p of projects) {\n const seen = p.lastSeenAt ? p.lastSeenAt : 'never'\n const langs = p.languages.length > 0 ? p.languages.join(',') : '-'\n console.log(`${p.name}\\t${p.status}\\t${langs}\\t${p.path}\\tlast-seen=${seen}`)\n }\n return\n }\n\n if (cmd === 'pause') {\n const name = positional[0]\n if (!name) {\n console.error('neat pause: missing <name>')\n usage()\n process.exit(2)\n }\n try {\n const entry = await setStatus(name, 'paused')\n console.log(`paused: ${entry.name} (${entry.path})`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return\n }\n\n if (cmd === 'resume') {\n const name = positional[0]\n if (!name) {\n console.error('neat resume: missing <name>')\n usage()\n process.exit(2)\n }\n try {\n const entry = await setStatus(name, 'active')\n console.log(`resumed: ${entry.name} (${entry.path})`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return\n }\n\n if (cmd === 'skill') {\n const result = await runSkill({ apply: parsed.apply, printConfig: parsed.printConfig })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n if (cmd === 'uninstall') {\n const name = positional[0]\n if (!name) {\n console.error('neat uninstall: missing <name>')\n usage()\n process.exit(2)\n }\n const removed = await removeProject(name)\n if (!removed) {\n console.error(`neat uninstall: no project named \"${name}\"`)\n process.exit(1)\n }\n console.log(`unregistered: ${removed.name} (${removed.path})`)\n console.log('note: neat-out/, policy.json, and other files at the project path were left in place.')\n return\n }\n\n if (cmd === 'deploy') {\n // ADR-073 §2 — detect substrate, generate token, emit artifact, print\n // the OTel env-vars block. Token is the only secret printed to stdout;\n // the artifact written to disk names the env-var by reference only.\n const artifact = await runDeploy()\n const block = renderOtelEnvBlock(artifact.token)\n\n console.log()\n console.log(`Substrate detected: ${artifact.substrate}`)\n if (artifact.artifactPath) {\n console.log(`Artifact written: ${artifact.artifactPath}`)\n } else {\n console.log('No on-disk artifact — copy the snippet below into your substrate.')\n console.log()\n console.log(artifact.contents)\n }\n console.log()\n console.log('NEAT_AUTH_TOKEN (store this — it will not be printed again):')\n console.log(` ${artifact.token}`)\n console.log()\n console.log(\"For your application's deploy platform, set these env vars:\")\n console.log(block.split('\\n').map((l) => ` ${l}`).join('\\n'))\n console.log()\n console.log('Once NEAT is running, your dashboard will be at:')\n console.log(' https://<host>:6328')\n console.log()\n console.log('To start NEAT, run:')\n console.log(` ${artifact.startCommand}`)\n return\n }\n\n if (cmd === 'sync') {\n // ADR-074 §1 — re-runs discovery + extract + SDK apply + daemon notify\n // against the registered project. Skips registry registration, browser\n // open, daemon spawn, and the first-run summary block.\n const result = await runSync({\n ...(parsed.project ? { project: parsed.project } : {}),\n ...(parsed.to ? { to: parsed.to } : {}),\n ...(parsed.token ? { token: parsed.token } : {}),\n dryRun: parsed.dryRun,\n noInstrument: parsed.noInstrument,\n json: parsed.json,\n })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n // ── Query verbs (ADR-050) ────────────────────────────────────────────\n // The nine verbs mirror the MCP tool allowlist. Same multi-project\n // routing, same three-part response shape (summary + block + footer),\n // exit codes branch on misuse vs server error vs daemon-down.\n if (QUERY_VERBS.has(cmd)) {\n const code = await runQueryVerb(cmd, parsed)\n if (code !== 0) process.exit(code)\n return\n }\n\n // ── Bare-path orchestrator (ADR-073 §1) ──────────────────────────────\n // `neat <path>` — when the first positional doesn't match any verb but\n // resolves to a directory, hand the run off to the orchestrator. This is\n // the `npx neat.is <path>` shape from ADR-073: one command, end-to-end.\n const orchestratorCode = await tryOrchestrator(cmd, parsed)\n if (orchestratorCode !== null) {\n if (orchestratorCode !== 0) process.exit(orchestratorCode)\n return\n }\n\n console.error(`neat: unknown command \"${cmd}\"`)\n usage()\n process.exit(1)\n}\n\n// Returns null when the first positional doesn't resolve to a directory\n// (so the caller can fall through to the unknown-command error). Returns\n// an exit code when the orchestrator ran.\nasync function tryOrchestrator(cmd: string, parsed: ParsedArgs): Promise<number | null> {\n const scanPath = path.resolve(cmd)\n const stat = await fs.stat(scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) return null\n\n const projectExplicit = parsed.project !== null\n const projectName = projectExplicit ? (parsed.project as string) : path.basename(scanPath)\n const result = await runOrchestrator({\n scanPath,\n project: projectName,\n projectExplicit,\n noInstrument: parsed.noInstrument,\n noOpen: parsed.noOpen,\n yes: parsed.yes,\n })\n return result.exitCode\n}\n\n// ── Query verb dispatcher ──────────────────────────────────────────────\n\nexport const QUERY_VERBS: Set<string> = new Set([\n 'root-cause',\n 'blast-radius',\n 'dependencies',\n 'observed-dependencies',\n 'incidents',\n 'search',\n 'diff',\n 'stale-edges',\n 'policies',\n // Tenth verb (ADR-060) — amends ADR-050's locked allowlist of nine.\n 'divergences',\n])\n\n// ADR-050 #2: --project flag → NEAT_PROJECT env → undefined (server's\n// `default` slot). undefined keeps legacy unprefixed routes; explicit names\n// route through /projects/:project/...\nfunction resolveProjectFlag(parsed: ParsedArgs): string | undefined {\n if (parsed.project) return parsed.project\n const env = process.env.NEAT_PROJECT\n if (env && env.length > 0 && env !== DEFAULT_PROJECT) return env\n return undefined\n}\n\nexport async function runQueryVerb(cmd: string, parsed: ParsedArgs): Promise<number> {\n const baseUrl = process.env.NEAT_API_URL ?? 'http://localhost:8080'\n // ADR-073 §3 — read the bearer once and thread it into the single client\n // every verb shares, so no verb path can reach a secured daemon without it.\n const client = createHttpClient(baseUrl, resolveAuthToken())\n const project = resolveProjectFlag(parsed)\n const positional = parsed.positional\n\n // Per-verb arg/flag validation. Misuse exits 2 before any network call.\n let work: Promise<VerbResult>\n switch (cmd) {\n case 'root-cause': {\n const node = positional[0]\n if (!node) {\n console.error('neat root-cause: missing <node-id>')\n return 2\n }\n work = runRootCause(client, {\n errorNode: node,\n ...(parsed.errorId ? { errorId: parsed.errorId } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'blast-radius': {\n const node = positional[0]\n if (!node) {\n console.error('neat blast-radius: missing <node-id>')\n return 2\n }\n work = runBlastRadius(client, {\n nodeId: node,\n ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'dependencies': {\n const node = positional[0]\n if (!node) {\n console.error('neat dependencies: missing <node-id>')\n return 2\n }\n work = runDependencies(client, {\n nodeId: node,\n ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'observed-dependencies': {\n const node = positional[0]\n if (!node) {\n console.error('neat observed-dependencies: missing <node-id>')\n return 2\n }\n work = runObservedDependencies(client, {\n nodeId: node,\n ...(project ? { project } : {}),\n })\n break\n }\n case 'incidents': {\n // node-id is optional — bare `neat incidents` returns the global log.\n work = runIncidents(client, {\n ...(positional[0] ? { nodeId: positional[0] } : {}),\n ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'search': {\n const q = positional.join(' ').trim()\n if (!q) {\n console.error('neat search: missing <query>')\n return 2\n }\n work = runSearch(client, { query: q, ...(project ? { project } : {}) })\n break\n }\n case 'diff': {\n // --against names a snapshot file the core can resolve via\n // loadSnapshotForDiff. --since is reserved for a future date-range\n // mode (the contract lists it as `[--since <date>]`); for MVP, the\n // diff verb requires --against.\n const against = parsed.against ?? parsed.since\n if (!against) {\n console.error('neat diff: --against <snapshot-path> is required')\n return 2\n }\n work = runDiff(client, {\n againstSnapshot: against,\n ...(project ? { project } : {}),\n })\n break\n }\n case 'stale-edges': {\n work = runStaleEdges(client, {\n ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n ...(parsed.edgeType ? { edgeType: parsed.edgeType } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'policies': {\n let hypothetical: ReturnType<typeof JSON.parse> | undefined\n if (parsed.hypotheticalAction) {\n try {\n hypothetical = JSON.parse(parsed.hypotheticalAction)\n } catch (err) {\n console.error(\n `neat policies: --hypothetical-action must be valid JSON: ${(err as Error).message}`,\n )\n return 2\n }\n }\n work = runPolicies(client, {\n ...(parsed.node ? { nodeId: parsed.node } : {}),\n ...(hypothetical ? { hypotheticalAction: hypothetical } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'divergences': {\n let typeFilter: DivergenceType[] | undefined\n if (parsed.type) {\n const parts = parsed.type\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0)\n const out: DivergenceType[] = []\n for (const p of parts) {\n const r = DivergenceTypeSchema.safeParse(p)\n if (!r.success) {\n console.error(\n `neat divergences: unknown --type \"${p}\". allowed: ${DivergenceTypeSchema.options.join(', ')}`,\n )\n return 2\n }\n out.push(r.data)\n }\n typeFilter = out\n }\n work = runDivergences(client, {\n ...(typeFilter ? { type: typeFilter } : {}),\n ...(parsed.minConfidence !== null ? { minConfidence: parsed.minConfidence } : {}),\n ...(parsed.node ? { node: parsed.node } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n default:\n // Unreachable — QUERY_VERBS gates the dispatch.\n console.error(`neat: unknown query verb \"${cmd}\"`)\n return 2\n }\n\n try {\n const result = await work\n if (parsed.json) process.stdout.write(formatJson(result) + '\\n')\n else process.stdout.write(formatHuman(result) + '\\n')\n return 0\n } catch (err) {\n // Server / transport errors land on stderr per ADR-050 #3 (stderr for\n // diagnostics, stdout for results — never mix). Exit code branches per\n // ADR-050 #4: 1 for HttpError, 3 for TransportError.\n if (err instanceof HttpError) {\n const detail = err.responseBody.length > 0 ? err.responseBody : err.message\n console.error(`neat ${cmd}: ${detail.trim()}`)\n } else if (err instanceof TransportError) {\n console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (NEAT_API_URL=${process.env.NEAT_API_URL ?? 'http://localhost:8080'})`)\n } else {\n console.error(`neat ${cmd}: ${(err as Error).message}`)\n }\n return exitCodeForError(err)\n }\n}\n\n// Only auto-run when invoked as the CLI entry point. Importing this module\n// from tests must not start the parser; otherwise vitest sees a stray\n// `process.exit` from `main()` running with no argv.\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/]cli\\.(?:cjs|js)$/.test(entry) || entry.endsWith('/cli') || entry.endsWith('/neat') || entry.endsWith('/neat.is')) {\n main().catch((err) => {\n console.error(err)\n process.exit(1)\n })\n}\n","import GraphDefault from 'graphology'\nimport type { MultiDirectedGraph as MDGType } from 'graphology'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\n\n// graphology ships as a CJS bundle that does `module.exports = Graph` with\n// the other constructors attached as properties (`Graph.MultiDirectedGraph =\n// ...`). cjs-module-lexer can't see through that attachment, so a named\n// import like `import { MultiDirectedGraph } from 'graphology'` fails under\n// strict Node ESM (Node 22+ via tsx in particular). Pull the constructor off\n// the default export instead — same shape under tsx and tsup-bundled output.\ntype MultiDirectedGraphCtor = typeof MDGType\nconst MultiDirectedGraph: MultiDirectedGraphCtor = (\n GraphDefault as unknown as { MultiDirectedGraph: MultiDirectedGraphCtor }\n).MultiDirectedGraph\n\n// Multi because two nodes can have edges of different types simultaneously\n// (e.g. CALLS and DEPENDS_ON between the same pair of services).\nexport type NeatGraph = MDGType<GraphNode, GraphEdge>\n\nexport const DEFAULT_PROJECT = 'default'\n\n// One graph per project. The map is the source of truth; getGraph() with no\n// arg or with 'default' hits the legacy single-project path so existing\n// callers keep working byte-for-byte (ADR-026).\nconst graphs = new Map<string, NeatGraph>()\n\nfunction makeGraph(): NeatGraph {\n return new MultiDirectedGraph<GraphNode, GraphEdge>({ allowSelfLoops: false })\n}\n\nexport function getGraph(project: string = DEFAULT_PROJECT): NeatGraph {\n let g = graphs.get(project)\n if (!g) {\n g = makeGraph()\n graphs.set(project, g)\n }\n return g\n}\n\nexport function hasProject(project: string): boolean {\n return graphs.has(project)\n}\n\nexport function listProjects(): string[] {\n return [...graphs.keys()].sort()\n}\n\n// Reset a single project, or all of them when the arg is omitted. Tests use\n// the no-arg form between cases; runtime never calls it.\nexport function resetGraph(project?: string): void {\n if (project === undefined) {\n graphs.clear()\n return\n }\n graphs.delete(project)\n}\n","export { extractFromDirectory, type ExtractResult } from './extract/index.js'\n","// Static-extraction pipeline. Phase order is load-bearing:\n// services → aliases → databases (+ compat) → configs → calls → infra → frontier promotion.\n//\n// Contract anchors (see /docs/contracts.md):\n// * Rule 1 — Every emitted edge carries Provenance.EXTRACTED from @neat.is/types.\n// * Rule 2 — EXTRACTED edges use the plain `${type}:src->tgt` id pattern.\n// Never write under the OBSERVED id pattern; that's ingest.ts's territory.\n// * Rule 5 — Nodes/edges constructed against schemas in @neat.is/types; no\n// local interface redefinitions in this tree.\n// * Rule 8 — No demo-name hardcoding. Driver names come from package.json\n// dependencies; engine names from compat.json via compatPairs().\n// * Rule 14 — ConfigNodes record file existence only; never the contents.\nimport type { NeatGraph } from '../graph.js'\nimport { DEFAULT_PROJECT } from '../graph.js'\nimport { promoteFrontierNodes } from '../ingest.js'\nimport { ensureCompatLoaded } from '../compat.js'\nimport { emitNeatEvent } from '../events.js'\nimport { addServiceNodes, discoverServices } from './services.js'\nimport { addServiceAliases } from './aliases.js'\nimport { addDatabasesAndCompat } from './databases/index.js'\nimport { addConfigNodes } from './configs.js'\nimport { addCallEdges } from './calls/index.js'\nimport { addInfra } from './infra/index.js'\nimport {\n drainExtractionErrors,\n writeExtractionErrors,\n drainDroppedExtracted,\n isRejectedLogEnabled,\n writeRejectedExtracted,\n type ExtractionError,\n type DroppedExtractedEdge,\n} from './errors.js'\nimport path from 'node:path'\nimport { retireExtractedEdgesByMissingFile } from './retire.js'\n\nexport interface ExtractResult {\n nodesAdded: number\n edgesAdded: number\n frontiersPromoted: number\n // ADR-065 — per-file extraction failures collected during the pass.\n // `extractionErrors` is the count; `errorEntries` is the drained list,\n // available for callers that want to surface per-file context. Both are\n // present on every pass (zero is observable as a positive signal).\n extractionErrors: number\n errorEntries: ExtractionError[]\n // #140 — count of EXTRACTED edges retired this pass because their\n // evidence.file no longer exists on disk. Zero on a clean pass; non-zero\n // means the snapshot was carrying ghosts from deleted source.\n ghostsRetired: number\n // ADR-066 — count of EXTRACTED candidates dropped at emit time because\n // their graded confidence fell below NEAT_EXTRACTED_PRECISION_FLOOR.\n // Always reported (zero is observable). Detail entries surface in\n // `droppedEntries` and route to rejected.ndjson when\n // NEAT_EXTRACTED_REJECTED_LOG=1.\n extractedDropped: number\n droppedEntries: DroppedExtractedEdge[]\n}\n\nexport interface ExtractOptions {\n // Post-extract policy trigger (ADR-043). Awaited after frontier promotion\n // so policies see the final post-pass graph state. Daemons wire this to\n // evaluateAllPolicies + PolicyViolationsLog.append.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n // Project tag for the extraction-complete event (ADR-051). Defaults to\n // DEFAULT_PROJECT when omitted.\n project?: string\n // ADR-065 — when set, drained extraction errors are appended to this\n // path as ndjson with `source: 'extract'`. Daemons / `neat init` /\n // `neat watch` wire this to `<projectDir>/neat-out/errors.ndjson`. When\n // omitted, errors are still drained and returned in the result, just\n // not persisted.\n errorsPath?: string\n}\n\nexport async function extractFromDirectory(\n graph: NeatGraph,\n scanPath: string,\n opts: ExtractOptions = {},\n): Promise<ExtractResult> {\n await ensureCompatLoaded()\n // Clear any stale entries from a prior pass (the producer-side sink is\n // process-local). Per ADR-065, every pass collects its own errors; we drain\n // again at the end to capture this pass's failures.\n drainExtractionErrors()\n\n const services = await discoverServices(scanPath)\n\n const phase1Nodes = addServiceNodes(graph, services)\n await addServiceAliases(graph, scanPath, services)\n const phase2 = await addDatabasesAndCompat(graph, services, scanPath)\n const phase3 = await addConfigNodes(graph, services, scanPath)\n const phase4 = await addCallEdges(graph, services)\n const phase5 = await addInfra(graph, scanPath, services)\n // #140 — drop EXTRACTED edges whose evidence.file no longer exists on disk.\n // Catches the deleted-file ghost case for the full-pass entry point\n // (init / daemon bootstrap). The edited-file case is handled per-mtime by\n // watch.ts's `retireEdgesByFile`. Service dirs are passed alongside scanPath\n // because CALLS-family producers store service-dir-relative paths while\n // configs / databases / infra store scanPath-relative.\n const ghostsRetired = retireExtractedEdgesByMissingFile(\n graph,\n scanPath,\n services.map((s) => s.dir),\n )\n const frontiersPromoted = promoteFrontierNodes(graph)\n\n // Post-extract policy trigger (ADR-043). Fires after frontier promotion so\n // policies see the post-pass graph (including any FRONTIER → OBSERVED edge\n // upgrades that just landed).\n if (opts.onPolicyTrigger) await opts.onPolicyTrigger(graph)\n\n // ADR-065 — drain the per-file extraction errors collected during the pass.\n // If a sidecar path was supplied, append the entries; otherwise return them\n // for the caller to surface.\n const errorEntries = drainExtractionErrors()\n if (opts.errorsPath && errorEntries.length > 0) {\n try {\n await writeExtractionErrors(errorEntries, opts.errorsPath)\n } catch (err) {\n console.warn(\n `[neat] failed to write extraction errors to ${opts.errorsPath}: ${(err as Error).message}`,\n )\n }\n }\n\n // ADR-066 — drain the precision-floor drops. Always returned; only\n // persisted when NEAT_EXTRACTED_REJECTED_LOG=1 (opt-in to keep the\n // default sidecar surface quiet).\n const droppedEntries = drainDroppedExtracted()\n if (\n isRejectedLogEnabled() &&\n opts.errorsPath &&\n droppedEntries.length > 0\n ) {\n // rejected.ndjson lives alongside errors.ndjson under neat-out/. Derive\n // from errorsPath rather than re-plumbing a new option.\n const rejectedPath = path.join(path.dirname(opts.errorsPath), 'rejected.ndjson')\n try {\n await writeRejectedExtracted(droppedEntries, rejectedPath)\n } catch (err) {\n console.warn(\n `[neat] failed to write rejected extracted edges to ${rejectedPath}: ${(err as Error).message}`,\n )\n }\n }\n\n const result: ExtractResult = {\n nodesAdded:\n phase1Nodes +\n phase2.nodesAdded +\n phase3.nodesAdded +\n phase4.nodesAdded +\n phase5.nodesAdded,\n edgesAdded:\n phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,\n frontiersPromoted,\n extractionErrors: errorEntries.length,\n errorEntries,\n ghostsRetired,\n extractedDropped: droppedEntries.length,\n droppedEntries,\n }\n\n // extraction-complete (ADR-051). fileCount is the number of services\n // discovered — the closest proxy we have for \"how much source did this\n // pass touch\" without a per-phase file accountant.\n emitNeatEvent({\n type: 'extraction-complete',\n project: opts.project ?? DEFAULT_PROJECT,\n payload: {\n project: opts.project ?? DEFAULT_PROJECT,\n fileCount: services.length,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n },\n })\n\n return result\n}\n","import { promises as fs, existsSync, readFileSync } from 'node:fs'\nimport path from 'node:path'\nimport * as sourceMapJs from 'source-map-js'\nimport type {\n DatabaseNode,\n ErrorEvent,\n FileNode,\n FrontierNode,\n GraphEdge,\n GraphNode,\n Policy,\n ServiceNode,\n StaleEvent,\n} from '@neat.is/types'\nimport type { PersistedGraph } from './persist.js'\nimport type { EvaluationContext as PolicyEvaluationContext } from './policy.js'\nimport { canPromoteFrontier } from './policy.js'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForObservedSignal,\n databaseId,\n extractedEdgeId,\n fileId,\n frontierId,\n inferredEdgeId,\n observedEdgeId,\n serviceId,\n type EdgeTypeValue,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport type { ParsedSpan } from './otel.js'\nimport { emitNeatEvent } from './events.js'\n\n// Maps OTel spans to graph signal:\n// * Cross-service span → upsert CALLS edge.\n// * Database span (db.system attr present) → upsert CONNECTS_TO edge to a\n// DatabaseNode resolved by host.\n// * Span with status.code === 2 → ErrorEvent appended to errors.ndjson.\n//\n// Contract anchors (see /docs/contracts.md):\n// * Rule 1 — Provenance: every edge here carries Provenance.X from @neat.is/types.\n// * Rule 2 — Coexistence: OBSERVED edges live alongside EXTRACTED ones with a\n// distinct id pattern (`${type}:OBSERVED:src->tgt`). Never write OBSERVED\n// under the EXTRACTED id; that erases the gap NEAT exists to surface.\n// * Rule 4 — Per-edge-type staleness (ADR-024): STALE_THRESHOLDS_BY_EDGE_TYPE\n// governs decay; never hardcode a flat 24h threshold.\n// * Rule 8 — No demo names: derive driver/engine identifiers from node\n// properties, not literals.\n\nexport interface IngestContext {\n graph: NeatGraph\n errorsPath: string\n // Absolute scan root the daemon is watching for this project. When set, a\n // runtime `code.filepath` is made service-root-relative against it before the\n // FileNode is keyed (file-awareness.md §4) — the service's absolute root is\n // `scanPath/<repoPath>`, which recovers `dist/foo.js` even for a single-\n // package service whose `repoPath` is empty (issue #430). Omitted by ad-hoc\n // callers and most tests, which rely on the repoPath-segment anchor instead.\n scanPath?: string\n // Project name for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT\n // when omitted — keeps single-project tests / scripts wire-compatible.\n project?: string\n now?: () => number\n // Set to false when the receiver already wrote the ErrorEvent synchronously\n // (production daemons via watch.ts wire this). When true or omitted, handleSpan\n // appends the ErrorEvent itself — the path used by ad-hoc scripts and tests\n // that don't go through buildOtelReceiver. ADR-033 §Error events.\n writeErrorEventInline?: boolean\n // Post-mutation policy trigger (ADR-043). Fires after handleSpan finishes\n // and the queue is drained. Daemons wire this to evaluateAllPolicies +\n // PolicyViolationsLog.append. Ad-hoc callers leave it undefined; their tests\n // don't need policy side effects.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n}\n\nconst HOUR_MS = 60 * 60 * 1000\nconst DAY_MS = 24 * HOUR_MS\n\n// Per-edge-type stale thresholds. HTTP CALLS at 24h is meaningless because\n// healthy traffic recurs in seconds; infra DEPENDS_ON is the opposite — a\n// docker-compose service can sit idle overnight without anything being wrong.\n// Override via NEAT_STALE_THRESHOLDS (JSON, ms-per-edge-type).\nconst DEFAULT_STALE_THRESHOLDS: Record<string, number> = {\n CALLS: HOUR_MS,\n CONNECTS_TO: 4 * HOUR_MS,\n PUBLISHES_TO: 4 * HOUR_MS,\n CONSUMES_FROM: 4 * HOUR_MS,\n DEPENDS_ON: DAY_MS,\n CONFIGURED_BY: DAY_MS,\n RUNS_ON: DAY_MS,\n}\n// Fallback for any edge type not in the map (forward compat — adding a new\n// EdgeType shouldn't break staleness sweeps).\nconst FALLBACK_STALE_THRESHOLD_MS = DAY_MS\n\nfunction loadStaleThresholdsFromEnv(): Record<string, number> {\n const raw = process.env.NEAT_STALE_THRESHOLDS\n if (!raw) return DEFAULT_STALE_THRESHOLDS\n try {\n const overrides = JSON.parse(raw) as Record<string, unknown>\n const merged = { ...DEFAULT_STALE_THRESHOLDS }\n for (const [k, v] of Object.entries(overrides)) {\n if (typeof v === 'number' && Number.isFinite(v) && v >= 0) merged[k] = v\n }\n return merged\n } catch (err) {\n console.warn(\n `[neat] NEAT_STALE_THRESHOLDS could not be parsed (${(err as Error).message}); using defaults`,\n )\n return DEFAULT_STALE_THRESHOLDS\n }\n}\n\nexport function thresholdForEdgeType(\n edgeType: string,\n overrides?: Record<string, number>,\n): number {\n const map = overrides ?? loadStaleThresholdsFromEnv()\n return map[edgeType] ?? FALLBACK_STALE_THRESHOLD_MS\n}\n\nfunction nowIso(ctx: IngestContext): string {\n return new Date(ctx.now ? ctx.now() : Date.now()).toISOString()\n}\n\n// One-time-per-session-per-project warning for spans whose resource omits\n// `service.name`. The OTel spec requires SDKs to set it; customised exporters\n// occasionally don't. Routing the span to `service:unidentified` keeps\n// diagnostic visibility intact (silent drop hides a real SDK misconfiguration);\n// the warning gives an operator one line of stderr per project to act on.\n// See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n// is missing.\nconst unidentifiedWarnedProjects = new Set<string>()\nfunction warnUnidentifiedSpan(project: string): void {\n if (unidentifiedWarnedProjects.has(project)) return\n unidentifiedWarnedProjects.add(project)\n console.warn(\n `[neatd] span lacked service.name; routed to 'unidentified' in project ${project}; check your OTel SDK config.`,\n )\n}\n\n// Test seam — production code never calls this. Tests that exercise the\n// once-per-session contract reset between cases so each assertion sees a\n// fresh warned-set.\nexport function resetUnidentifiedSpanWarnings(): void {\n unidentifiedWarnedProjects.clear()\n}\n\n// One-time-per-session-per-service audit for a compiled `dist/...js` call site\n// that carried no adjacent source map (file-awareness.md §4 + §6). Without a\n// map, ingest can't reconcile the observed dist file to the static `src/...ts`\n// the extractor parsed — the dist path is the honest answer, never a fabricated\n// src path. The leak this surfaces (issue #430) was hiding behind an absolute\n// path prefix; once the path is service-root-relative the mismatch is legible,\n// and this line tells the operator how to close it.\nconst noSourceMapWarnedServices = new Set<string>()\nfunction warnNoSourceMaps(serviceName: string): void {\n if (noSourceMapWarnedServices.has(serviceName)) return\n noSourceMapWarnedServices.add(serviceName)\n console.warn(\n `[neat] ${serviceName}: no .map files found under dist/; observed file edges will land on dist paths, not src. Set sourceMap: true in tsconfig to enable file-level reconciliation.`,\n )\n}\n\n// Test seam — mirrors resetUnidentifiedSpanWarnings for the once-per-service\n// audit above.\nexport function resetNoSourceMapWarnings(): void {\n noSourceMapWarnedServices.clear()\n}\n\nfunction pickAttr(span: ParsedSpan, ...keys: string[]): string | undefined {\n for (const k of keys) {\n const v = span.attributes[k]\n if (typeof v === 'string' && v.length > 0) return v\n }\n return undefined\n}\n\nfunction hostFromUrl(u: string | undefined): string | undefined {\n if (!u) return undefined\n try {\n return new URL(u).hostname\n } catch {\n return undefined\n }\n}\n\n// OTel HTTP/db semconv has gone through several names for \"the host on the\n// other end of this call.\" Try the modern ones first, fall back to the legacy\n// ones, then last resort parse out of a full URL.\nfunction pickAddress(span: ParsedSpan): string | undefined {\n return (\n pickAttr(span, 'server.address', 'net.peer.name', 'net.host.name') ??\n hostFromUrl(pickAttr(span, 'url.full', 'http.url'))\n )\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Call-site capture (file-awareness.md §4)\n//\n// The injected SpanProcessor sets `code.filepath` / `code.lineno` /\n// `code.function` on CLIENT/PRODUCER spans — the exact OTel attribute names,\n// written by the emit template (installers/templates.ts) and read here. The\n// two sites are cross-referenced so the names can't drift. When present, an\n// OBSERVED relationship originates from the file rather than the service.\n// SERVER spans and the callee side carry no call site and stay service-level;\n// evidence is never fabricated (§6).\nconst CODE_FILEPATH_ATTR = 'code.filepath'\nconst CODE_LINENO_ATTR = 'code.lineno'\nconst CODE_FUNCTION_ATTR = 'code.function'\n\nfunction toPosix(p: string): string {\n return p.split('\\\\').join('/')\n}\n\nfunction languageForExt(relPath: string): string | undefined {\n const dot = relPath.lastIndexOf('.')\n if (dot === -1) return undefined\n switch (relPath.slice(dot).toLowerCase()) {\n case '.py':\n return 'python'\n case '.ts':\n case '.tsx':\n return 'typescript'\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return 'javascript'\n default:\n return undefined\n }\n}\n\n// Join the runtime `code.filepath` against the service root so the OBSERVED\n// relPath lines up with the EXTRACTED service-relative path (file-awareness.md\n// §4 + §7). ServiceNode.repoPath is the scanPath-relative package dir; its\n// segments appear inside the absolute runtime path, so anchoring on it recovers\n// the package-relative tail. With no usable anchor, the real runtime path is\n// returned in a relative-looking form — honest, even if it doesn't align with a\n// static src path. Never fabricated.\nfunction relPathForRuntimeFile(\n filepath: string,\n serviceNode?: ServiceNode,\n scanPath?: string,\n): string | null {\n let p = toPosix(filepath).replace(/^file:\\/\\//, '')\n // When ingest knows the absolute scan root, the service's absolute root is\n // `scanPath/<repoPath>`. Stripping it directly recovers the service-relative\n // tail (`dist/foo.js`) even for a single-package service whose `repoPath` is\n // empty — the segment anchor below has nothing to grab in that case, so the\n // absolute path used to leak into the FileNode key (issue #430).\n if (scanPath && scanPath.length > 0) {\n const absRoot = toPosix(path.resolve(scanPath, serviceNode?.repoPath ?? ''))\n const anchor = absRoot.endsWith('/') ? absRoot : `${absRoot}/`\n if (p.startsWith(anchor)) return p.slice(anchor.length)\n }\n const root = serviceNode?.repoPath\n if (root && root !== '.' && root.length > 0) {\n const rootPosix = toPosix(root)\n const anchor = `/${rootPosix}/`\n const idx = p.lastIndexOf(anchor)\n if (idx !== -1) return p.slice(idx + anchor.length)\n const base = rootPosix.split('/').filter(Boolean).pop()\n if (base) {\n const baseAnchor = `/${base}/`\n const bidx = p.lastIndexOf(baseAnchor)\n if (bidx !== -1) return p.slice(bidx + baseAnchor.length)\n }\n }\n p = p.replace(/^[A-Za-z]:/, '').replace(/^\\/+/, '')\n return p.length > 0 ? p : null\n}\n\ninterface CallSite {\n relPath: string\n line?: number\n fn?: string\n // The service-relative dist path the call site was captured on, when ingest\n // resolved it through a source map to a different (source) `relPath`\n // (file-awareness.md §4). Surfaces as FileNode.originalPath. Absent when the\n // captured frame was already source-grained.\n originalRelPath?: string\n}\n\n// dist→src source-map resolution (file-awareness.md §4). A runtime call site in\n// a compiled `dist/...js` is resolved through a disk-adjacent `.map` to the\n// original `src/...ts`, so an OBSERVED edge lands on the source file an agent\n// can open. Same-host only — when the daemon's filesystem doesn't carry the map\n// (a service that ran on a different machine) the dist frame is kept, honestly,\n// never fabricated (§6). Each dist file is read from disk once: a present map\n// caches its consumer, an absent one caches `null`. Synchronous reads keep\n// callSiteFromSpan synchronous; the cost is amortised across a file's spans.\nconst sourceMapCache = new Map<\n string,\n { consumer: sourceMapJs.SourceMapConsumer; dir: string } | null\n>()\n\ninterface ResolvedSrc {\n filepath: string\n line?: number\n}\n\nfunction resolveDistToSrc(absFilepath: string, line?: number): ResolvedSrc | null {\n if (!absFilepath.endsWith('.js')) return null\n let entry = sourceMapCache.get(absFilepath)\n if (entry === undefined) {\n entry = null\n const mapPath = `${absFilepath}.map`\n try {\n if (existsSync(mapPath)) {\n const raw = JSON.parse(readFileSync(mapPath, 'utf8')) as unknown\n const consumer = new sourceMapJs.SourceMapConsumer(raw as never)\n entry = { consumer, dir: path.dirname(mapPath) }\n }\n } catch {\n entry = null\n }\n sourceMapCache.set(absFilepath, entry)\n }\n if (!entry) return null\n try {\n const pos = entry.consumer.originalPositionFor({\n line: line !== undefined && Number.isFinite(line) ? line : 1,\n column: 0,\n })\n if (!pos || !pos.source) return null\n const root = entry.consumer.sourceRoot ?? ''\n const resolved = path.resolve(entry.dir, root, pos.source)\n return { filepath: resolved, ...(pos.line ? { line: pos.line } : {}) }\n } catch {\n return null\n }\n}\n\n// Read the call-site attributes off a span. Returns null when the span carries\n// no `code.filepath` (SERVER spans, un-instrumented peers, callee side) so the\n// caller falls back to a service-level edge.\nfunction callSiteFromSpan(\n span: ParsedSpan,\n serviceNode?: ServiceNode,\n scanPath?: string,\n): CallSite | null {\n const filepath = span.attributes[CODE_FILEPATH_ATTR]\n if (typeof filepath !== 'string' || filepath.length === 0) return null\n const linenoRaw = span.attributes[CODE_LINENO_ATTR]\n let line =\n typeof linenoRaw === 'number' && Number.isFinite(linenoRaw) ? linenoRaw : undefined\n // Resolve a compiled dist frame to its source before computing the service-\n // relative path, so the FileNode lands on the original `src/...ts`.\n const abs = toPosix(filepath).replace(/^file:\\/\\//, '')\n const resolved = resolveDistToSrc(abs, line)\n let effectivePath = filepath\n let originalRelPath: string | undefined\n if (resolved) {\n originalRelPath = relPathForRuntimeFile(filepath, serviceNode, scanPath) ?? undefined\n effectivePath = resolved.filepath\n if (resolved.line !== undefined) line = resolved.line\n }\n const relPath = relPathForRuntimeFile(effectivePath, serviceNode, scanPath)\n if (!relPath) return null\n // A compiled `dist/...js` call site that didn't resolve through a map keeps\n // the (honest) dist path. Surface the absence once per service so the\n // operator can enable source maps and recover src-level reconciliation\n // (file-awareness.md §4 + §6, issue #430).\n if (!resolved && abs.endsWith('.js') && relPath.startsWith('dist/') && serviceNode?.name) {\n warnNoSourceMaps(serviceNode.name)\n }\n const fnRaw = span.attributes[CODE_FUNCTION_ATTR]\n const fn = typeof fnRaw === 'string' && fnRaw.length > 0 ? fnRaw : undefined\n return {\n relPath,\n ...(line !== undefined ? { line } : {}),\n ...(fn ? { fn } : {}),\n ...(originalRelPath && originalRelPath !== relPath ? { originalRelPath } : {}),\n }\n}\n\n// Ensure the FileNode for an observed call site and the owning service's\n// OBSERVED `CONTAINS` edge both exist, returning the FileNode id so the caller\n// can originate the relationship from it (file-awareness.md §1–2 + §4). The\n// CONTAINS edge carries no `lastObserved` — structural ownership doesn't go\n// STALE when traffic quiets (markStaleEdges skips edges without lastObserved),\n// and divergence detection skips CONTAINS so an OTel-only file node doesn't\n// surface as a missing-extracted finding.\nfunction ensureObservedFileNode(\n graph: NeatGraph,\n serviceName: string,\n serviceNodeId: string,\n callSite: CallSite,\n): string {\n const fileNodeId = fileId(serviceName, callSite.relPath)\n if (!graph.hasNode(fileNodeId)) {\n const language = languageForExt(callSite.relPath)\n const node: FileNode = {\n id: fileNodeId,\n type: NodeType.FileNode,\n service: serviceName,\n path: callSite.relPath,\n ...(language ? { language } : {}),\n ...(callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {}),\n discoveredVia: 'otel',\n }\n graph.addNode(fileNodeId, node)\n }\n const containsId = makeObservedEdgeId(EdgeType.CONTAINS, serviceNodeId, fileNodeId)\n if (!graph.hasEdge(containsId)) {\n const edge: GraphEdge = {\n id: containsId,\n source: serviceNodeId,\n target: fileNodeId,\n type: EdgeType.CONTAINS,\n provenance: Provenance.OBSERVED,\n }\n graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n }\n return fileNodeId\n}\n\n// Edge id helpers live in @neat.is/types/identity.ts (ADR-029). The local\n// signatures below preserve the (type, source, target) argument order ingest.ts\n// has used historically while delegating to the canonical wire-format helpers.\nfunction makeObservedEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n return observedEdgeId(source, target, type)\n}\n\nfunction makeInferredEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n return inferredEdgeId(source, target, type)\n}\n\nconst INFERRED_CONFIDENCE = 0.6\nconst STITCH_MAX_DEPTH = 2\n\n// OTLP-wire SpanKind values. The receiver decodes the raw wire integer onto\n// `ParsedSpan.kind` (otel.ts), and the wire enum is offset by one from the\n// `@opentelemetry/api` SpanKind the SDK uses in-process — UNSPECIFIED 0,\n// INTERNAL 1, SERVER 2, CLIENT 3, PRODUCER 4, CONSUMER 5. So we must NOT import\n// `@opentelemetry/api` here: its CLIENT is 2 (= wire SERVER) and PRODUCER is 3\n// (= wire CLIENT), which would gate the wrong kinds. Cross-referenced with the\n// wire fixtures in otel.test.ts (kind 2 = SERVER, kind 3 = CLIENT) and the\n// CLIENT call-site spans in ingest.test.ts (kind 3).\nconst WIRE_SPAN_KIND_CLIENT = 3\nconst WIRE_SPAN_KIND_PRODUCER = 4\n\n// An OBSERVED edge originates from the caller/producer side of a call. CLIENT\n// and PRODUCER spans are that side; INTERNAL / SERVER / CONSUMER are not — a\n// SERVER span is the callee, and its edge is minted from its parent CLIENT via\n// the parent-span fallback (the mirror image of CLIENT+SERVER, and of\n// PRODUCER+CONSUMER for queues). Without this gate every INTERNAL span that\n// happens to carry a peer address — e.g. a `tcp.connect` / `tls.connect` to an\n// AWS endpoint — mints a spurious service-level edge (issue #429), because no\n// §4 capture layer stamps `code.*` on INTERNAL spans.\n//\n// A span that reports no kind (undefined) or UNSPECIFIED (0) carries no\n// caller/callee signal, so it falls back to the historical unconditional\n// behavior — hand-built and legacy producers keep minting. The leak this gates\n// is always an explicitly-kinded INTERNAL span.\nfunction spanMintsObservedEdge(kind: number | undefined): boolean {\n if (kind === undefined || kind === 0) return true\n return kind === WIRE_SPAN_KIND_CLIENT || kind === WIRE_SPAN_KIND_PRODUCER\n}\n\n// Parent-span TTL cache (ADR-033). Address-based peer resolution (server.address /\n// net.peer.name / url.full) misses non-HTTP RPCs and any span with an opaque\n// peer. The cache stores each span's service keyed by `${traceId}:${spanId}` so\n// a child span whose address resolution fails can fall back to its parent's\n// service, identifying a cross-service CALLS edge from parent → current.\n//\n// Bounded size + TTL — out-of-order arrival (child before parent) drops the\n// child rather than buffering. We accept that loss because the cache is best-\n// effort: for every cross-service call, the CLIENT span on the caller side\n// covers the same edge via address-based resolution, so missing one direction\n// is recoverable.\nconst PARENT_SPAN_CACHE_SIZE = 10_000\nconst PARENT_SPAN_CACHE_TTL_MS = 5 * 60 * 1000\n\ninterface ParentSpanCacheEntry {\n service: string\n // Env discriminator from the parent span (ADR-074 §2). The parent-span\n // fallback in handleSpan uses this so the auto-created parent ServiceNode\n // lands on the same env-tagged id the OTel emitter advertised.\n env: string\n expiresAt: number\n}\n\nconst parentSpanCache = new Map<string, ParentSpanCacheEntry>()\n\nfunction parentSpanKey(traceId: string, spanId: string): string {\n return `${traceId}:${spanId}`\n}\n\nfunction cacheSpanService(span: ParsedSpan, now: number): void {\n if (!span.traceId || !span.spanId) return\n const key = parentSpanKey(span.traceId, span.spanId)\n // Map preserves insertion order, so deleting + re-inserting bumps an entry to\n // the back. Eviction is \"drop oldest\" once size exceeds the cap.\n parentSpanCache.delete(key)\n parentSpanCache.set(key, {\n service: span.service,\n env: span.env ?? 'unknown',\n expiresAt: now + PARENT_SPAN_CACHE_TTL_MS,\n })\n while (parentSpanCache.size > PARENT_SPAN_CACHE_SIZE) {\n const oldest = parentSpanCache.keys().next().value\n if (!oldest) break\n parentSpanCache.delete(oldest)\n }\n}\n\nfunction lookupParentSpan(\n traceId: string,\n parentSpanId: string,\n now: number,\n): { service: string; env: string } | null {\n const entry = parentSpanCache.get(parentSpanKey(traceId, parentSpanId))\n if (!entry) return null\n if (entry.expiresAt <= now) {\n parentSpanCache.delete(parentSpanKey(traceId, parentSpanId))\n return null\n }\n return { service: entry.service, env: entry.env }\n}\n\n// Test seam: lets unit tests start from a clean slate.\nexport function resetParentSpanCache(): void {\n parentSpanCache.clear()\n}\n\n// Peer host → ServiceNode id resolution. With env-dimension (ADR-074 §2),\n// the same `name` may live across multiple ServiceNodes — one per env, plus\n// the env-less form from static extraction. When `env` is known (the source\n// span's env), prefer a same-env match; fall back to the env-less node so\n// EXTRACTED edges from static analysis remain reachable until OBSERVED\n// traffic from the same env promotes them.\n//\n// Match passes:\n// 1. Exact id lookup for `(host, env)` — `serviceId(host, env)`.\n// 2. Exact id lookup for env-less `serviceId(host)`.\n// 3. Name/alias scan across every ServiceNode, preferring same-env then\n// env-less then any other env.\nfunction resolveServiceId(\n graph: NeatGraph,\n host: string,\n env: string,\n): string | null {\n const envTagged = serviceId(host, env)\n if (graph.hasNode(envTagged)) return envTagged\n const envLess = serviceId(host)\n if (envLess !== envTagged && graph.hasNode(envLess)) return envLess\n\n let sameEnv: string | null = null\n let envLessMatch: string | null = null\n let anyMatch: string | null = null\n graph.forEachNode((id, attrs) => {\n if (sameEnv) return\n const a = attrs as ServiceNode & { type?: string }\n if (a.type !== NodeType.ServiceNode) return\n const matchesByName = a.name === host\n const matchesByAlias = a.aliases ? a.aliases.includes(host) : false\n if (!matchesByName && !matchesByAlias) return\n const nodeEnv = a.env ?? 'unknown'\n if (nodeEnv === env) {\n sameEnv = id\n return\n }\n if (nodeEnv === 'unknown' && !envLessMatch) envLessMatch = id\n else if (!anyMatch) anyMatch = id\n })\n return sameEnv ?? envLessMatch ?? anyMatch\n}\n\nexport function frontierIdFor(host: string): string {\n return frontierId(host)\n}\n\n// Auto-create a minimal ServiceNode for span.service when no such node exists.\n// Used at the top of handleSpan so subsequent edge upserts always have endpoints\n// — without it, OBSERVED edges silently drop for any service the static\n// extractor hasn't reached yet (and never reaches at all in OTel-only setups).\n// `language: 'unknown'` is the contract's specified placeholder (ADR-033). When\n// static extraction later produces a ServiceNode at the same id, addServiceNodes\n// merges and flips discoveredVia to 'merged' rather than overwriting.\nfunction ensureServiceNode(\n graph: NeatGraph,\n serviceName: string,\n env: string,\n): string {\n const id = serviceId(serviceName, env)\n if (graph.hasNode(id)) return id\n const node: ServiceNode = {\n id,\n type: NodeType.ServiceNode,\n name: serviceName,\n language: 'unknown',\n discoveredVia: 'otel',\n ...(env !== 'unknown' ? { env } : {}),\n }\n graph.addNode(id, node)\n return id\n}\n\n// Same shape for unseen db.system + host pairs. Engine comes off the OTel\n// attribute as a string per Rule 8 — no hardcoded engine list. compatibleDrivers\n// is empty until static extraction merges in the matrix-derived drivers.\nfunction ensureDatabaseNode(graph: NeatGraph, host: string, engine: string): string {\n const id = databaseId(host)\n if (graph.hasNode(id)) return id\n const node: DatabaseNode = {\n id,\n type: NodeType.DatabaseNode,\n name: host,\n engine,\n engineVersion: 'unknown',\n compatibleDrivers: [],\n host,\n discoveredVia: 'otel',\n }\n graph.addNode(id, node)\n return id\n}\n\nfunction ensureFrontierNode(graph: NeatGraph, host: string, ts: string): string {\n const id = frontierIdFor(host)\n if (graph.hasNode(id)) {\n const existing = graph.getNodeAttributes(id) as FrontierNode\n graph.replaceNodeAttributes(id, { ...existing, lastObserved: ts })\n return id\n }\n const node: FrontierNode = {\n id,\n type: NodeType.FrontierNode,\n name: host,\n host,\n firstObserved: ts,\n lastObserved: ts,\n }\n graph.addNode(id, node)\n return id\n}\n\ninterface UpsertResult {\n edge: GraphEdge\n created: boolean\n}\n\nfunction upsertObservedEdge(\n graph: NeatGraph,\n type: EdgeTypeValue,\n source: string,\n target: string,\n ts: string,\n isError = false,\n): UpsertResult | null {\n if (!graph.hasNode(source) || !graph.hasNode(target)) return null\n\n const id = makeObservedEdgeId(type, source, target)\n if (graph.hasEdge(id)) {\n const existing = graph.getEdgeAttributes(id) as GraphEdge\n const newSpanCount = (existing.signal?.spanCount ?? existing.callCount ?? 0) + 1\n const newErrorCount = (existing.signal?.errorCount ?? 0) + (isError ? 1 : 0)\n const newSignal = {\n spanCount: newSpanCount,\n errorCount: newErrorCount,\n lastObservedAgeMs: 0,\n }\n // ADR-066 §2 — confidence grades from the signal block. PROV_RANK stays;\n // the grade reflects volume + recency + error ratio within the OBSERVED\n // tier.\n const updated: GraphEdge = {\n ...existing,\n provenance: Provenance.OBSERVED,\n lastObserved: ts,\n callCount: newSpanCount,\n signal: newSignal,\n confidence: confidenceForObservedSignal(newSignal),\n }\n graph.replaceEdgeAttributes(id, updated)\n return { edge: updated, created: false }\n }\n\n const signal = {\n spanCount: 1,\n errorCount: isError ? 1 : 0,\n lastObservedAgeMs: 0,\n }\n const edge: GraphEdge = {\n id,\n source,\n target,\n type,\n provenance: Provenance.OBSERVED,\n confidence: confidenceForObservedSignal(signal),\n lastObserved: ts,\n callCount: 1,\n signal,\n }\n graph.addEdgeWithKey(id, source, target, edge)\n return { edge, created: true }\n}\n\n// When a span errors, the system is exercising its dependencies right now even\n// if some of them aren't auto-instrumented (pg 7.4.0 in the demo, see ADR-014).\n// Walk EXTRACTED edges out from the erroring service for a couple of hops and\n// promote them to INFERRED twins so traversal can prefer them over the bare\n// static edges without claiming OBSERVED-grade certainty.\nfunction stitchTrace(graph: NeatGraph, sourceServiceId: string, ts: string): void {\n if (!graph.hasNode(sourceServiceId)) return\n\n const visited = new Set<string>([sourceServiceId])\n const queue: { nodeId: string; depth: number }[] = [{ nodeId: sourceServiceId, depth: 0 }]\n\n while (queue.length > 0) {\n const { nodeId, depth } = queue.shift()!\n if (depth >= STITCH_MAX_DEPTH) continue\n\n const outbound = graph.outboundEdges(nodeId)\n for (const edgeId of outbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) continue\n\n // OBSERVED twin already covers this hop with ground truth — no inference\n // needed (ADR-034). Stomping it with INFERRED erases the gap NEAT exists\n // to surface; skipping it keeps the OBSERVED edge as the authoritative\n // record and avoids cluttering the graph with a redundant INFERRED twin.\n if (graph.hasEdge(observedEdgeId(edge.source, edge.target, edge.type))) continue\n\n upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts)\n\n if (!visited.has(edge.target)) {\n visited.add(edge.target)\n queue.push({ nodeId: edge.target, depth: depth + 1 })\n }\n }\n }\n}\n\nfunction upsertInferredEdge(\n graph: NeatGraph,\n type: EdgeTypeValue,\n source: string,\n target: string,\n ts: string,\n): void {\n const id = makeInferredEdgeId(type, source, target)\n if (graph.hasEdge(id)) {\n const existing = graph.getEdgeAttributes(id) as GraphEdge\n const updated: GraphEdge = { ...existing, lastObserved: ts }\n graph.replaceEdgeAttributes(id, updated)\n return\n }\n\n const edge: GraphEdge = {\n id,\n source,\n target,\n type,\n provenance: Provenance.INFERRED,\n confidence: INFERRED_CONFIDENCE,\n lastObserved: ts,\n }\n graph.addEdgeWithKey(id, source, target, edge)\n}\n\nasync function appendErrorEvent(ctx: IngestContext, ev: ErrorEvent): Promise<void> {\n await fs.mkdir(path.dirname(ctx.errorsPath), { recursive: true })\n await fs.appendFile(ctx.errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\n}\n\n// Build the minimal ErrorEvent the receiver writes synchronously before\n// replying (ADR-033 §Error events, amended). affectedNode resolves to the\n// originating service because graph state isn't available at this point —\n// the queued handleSpan path may reach a more precise target later, but the\n// durable record is what the receiver writes here.\n//\n// errorMessage reads from the exception event's `exception.message` (OTel\n// semconv) so the incident surface shows the actual thrown error string.\n// When the span carries no exception event the field falls back to the\n// literal 'unknown error' rather than `span.name` — OTel HTTP server\n// instrumentation routinely populates `span.name` with the HTTP method,\n// which produces incidents that read 'GET' or 'POST' instead of the\n// underlying failure. `span.status.message` is intentionally out of the\n// chain for the same reason.\n// Span attributes pass through verbatim so consumers can read source\n// attribution (`code.filepath`, `code.lineno`, `code.function`) and other\n// SDK-emitted context without ingest enumerating every key it cares about.\n// Coerce span attributes to a JSON-safe shape — bigint values from the\n// parsed span (long ids, high-cardinality counters) become strings so the\n// passthrough record can be serialised to the ErrorEvent shape and round-\n// tripped through ErrorEventSchema. All other types pass through verbatim.\nfunction sanitizeAttributes(\n attrs: ParsedSpan['attributes'],\n): Record<string, string | number | boolean | null | string[] | number[] | boolean[]> {\n const out: Record<string, string | number | boolean | null | string[] | number[] | boolean[]> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v === 'bigint') out[k] = v.toString()\n else out[k] = v as string | number | boolean | null | string[] | number[] | boolean[]\n }\n return out\n}\n\nexport function buildErrorEventForReceiver(span: ParsedSpan): ErrorEvent | null {\n if (span.statusCode !== 2) return null\n const ts = span.startTimeIso ?? new Date().toISOString()\n const attrs = sanitizeAttributes(span.attributes)\n return {\n id: `${span.traceId}:${span.spanId}`,\n timestamp: ts,\n service: span.service,\n traceId: span.traceId,\n spanId: span.spanId,\n errorMessage: span.exception?.message ?? 'unknown error',\n ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n ...(span.exception?.stacktrace\n ? { exceptionStacktrace: span.exception.stacktrace }\n : {}),\n ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n affectedNode: serviceId(span.service, span.env),\n }\n}\n\n// Synchronous file-write helper bound to a receiver. The receiver awaits this\n// before replying, so a write failure surfaces as 500 → OTel SDK retries.\nexport function makeErrorSpanWriter(\n errorsPath: string,\n): (span: ParsedSpan) => Promise<void> {\n return async (span) => {\n const ev = buildErrorEventForReceiver(span)\n if (!ev) return\n await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n await fs.appendFile(errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\n }\n}\n\nexport async function handleSpan(ctx: IngestContext, span: ParsedSpan): Promise<void> {\n // lastObserved derives from the span's own startTime per ADR-033 — replayed\n // traces and out-of-order spans get a timestamp that reflects when the call\n // actually fired, not when the receiver received it. Wall-clock is only the\n // fallback for spans whose startTimeUnixNano is missing or unparseable.\n const ts = span.startTimeIso ?? nowIso(ctx)\n const nowMs = ctx.now ? ctx.now() : Date.now()\n // Env discriminator from `deployment.environment(.name)` (ADR-074 §2).\n // Older ParsedSpan producers may omit it — fall back to the literal\n // `'unknown'` so the env-less wire format is preserved on auto-creation.\n const env = span.env ?? 'unknown'\n // Issue #374 — spans whose resource omits `service.name` route to\n // `service:unidentified` in the URL-resolved project (the parser already\n // substitutes the fallback). One warning per project per session names\n // the project so an operator can fix the SDK config without grepping.\n if (span.resourceServiceNamePresent === false) {\n warnUnidentifiedSpan(ctx.project ?? DEFAULT_PROJECT)\n }\n // Auto-create a minimal ServiceNode for unseen span.service so OBSERVED\n // edges land instead of silently dropping. Static extraction merges richer\n // fields when it later finds the same id (ADR-033). The node is env-tagged\n // when the span carries an env signal.\n const sourceId = ensureServiceNode(ctx.graph, span.service, env)\n const isError = span.statusCode === 2\n // Stash this span in the parent-span cache so any later child whose address\n // resolution misses can still resolve the cross-service edge via parentSpanId.\n cacheSpanService(span, nowMs)\n\n // File-first OBSERVED origin (file-awareness.md §4). When the injected\n // SpanProcessor captured a call site on this outbound (CLIENT/PRODUCER) span,\n // the relationship originates from the file; without one it stays\n // service-level. `observedSource()` creates the FileNode + CONTAINS lazily so\n // they only land when an edge actually does — and never for the inbound\n // (SERVER) parent-fallback side, which carries no call site.\n const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId) as ServiceNode\n const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath)\n const observedSource = (): string =>\n callSite ? ensureObservedFileNode(ctx.graph, span.service, sourceId, callSite) : sourceId\n\n let affectedNode = sourceId\n\n // Only the caller/producer side of a call mints an OBSERVED edge directly\n // (issue #429). INTERNAL / SERVER / CONSUMER spans don't: a SERVER/CONSUMER\n // span is the callee, and its edge is minted from its parent via the\n // parent-span fallback below (left ungated). Gating here keeps INTERNAL\n // connection spans (`tcp.connect` / `tls.connect` with a peer address) from\n // minting spurious service-level edges.\n const mintsFromCallerSide = spanMintsObservedEdge(span.kind)\n\n if (span.dbSystem) {\n // Database span — try to resolve the DatabaseNode by host.\n const host = pickAddress(span)\n if (mintsFromCallerSide && host) {\n // Auto-create a minimal DatabaseNode when this host hasn't been seen.\n // Engine comes off the OTel attribute as a string per Rule 8.\n ensureDatabaseNode(ctx.graph, host, span.dbSystem)\n const targetId = databaseId(host)\n const result = upsertObservedEdge(\n ctx.graph,\n EdgeType.CONNECTS_TO,\n observedSource(),\n targetId,\n ts,\n isError,\n )\n if (result) affectedNode = targetId\n }\n } else {\n // Possibly a cross-service call. Resolve the peer; if it matches a known\n // ServiceNode, record an OBSERVED CALLS edge to the typed target. If it\n // matches nothing — pod IP, ingress hostname, AWS PrivateLink endpoint —\n // create a FrontierNode placeholder and record an OBSERVED edge to that\n // FrontierNode so the call carries the same provenance + signal-block +\n // graded confidence as any other OBSERVED edge (ADR-068). The target ref\n // identifies the node-type; provenance describes how the edge was learned.\n // promoteFrontierNodes (run by the extract orchestrator) rewrites the\n // target ref once a later round resolves the host; the edge's provenance\n // stays OBSERVED across promotion.\n const host = pickAddress(span)\n let resolvedViaAddress = false\n if (mintsFromCallerSide && host && host !== span.service) {\n const targetId = resolveServiceId(ctx.graph, host, env)\n if (targetId && targetId !== sourceId) {\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n observedSource(),\n targetId,\n ts,\n isError,\n )\n affectedNode = targetId\n resolvedViaAddress = true\n } else if (!targetId) {\n const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts)\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n observedSource(),\n frontierNodeId,\n ts,\n isError,\n )\n affectedNode = frontierNodeId\n resolvedViaAddress = true\n }\n }\n\n // Parent-span fallback (ADR-033): when address-based resolution didn't\n // produce an edge and the span has a parentSpanId we've cached, the\n // parent's service identifies the caller. The current span is the server\n // side of the call, so the edge direction is parent.service → current.\n // The cached entry carries the parent span's env, so the auto-created\n // parent ServiceNode lands on the env-tagged id the parent advertised.\n if (!resolvedViaAddress && span.parentSpanId) {\n const parent = lookupParentSpan(span.traceId, span.parentSpanId, nowMs)\n if (parent && parent.service !== span.service) {\n const parentId = ensureServiceNode(ctx.graph, parent.service, parent.env)\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n parentId,\n sourceId,\n ts,\n isError,\n )\n }\n }\n }\n\n if (span.statusCode === 2) {\n stitchTrace(ctx.graph, sourceId, ts)\n // The durable ErrorEvent write moved to the receiver so the file write\n // happens synchronously before the 200 reply (ADR-033 §Error events,\n // amended). watch.ts wires makeErrorSpanWriter into onErrorSpanSync.\n // handleSpan still runs the in-graph error effects (stitchTrace above);\n // it just doesn't append to errors.ndjson anymore. ctx.errorsPath stays\n // for the optional opt-in path below — daemon-less callers (CLI tests,\n // ad-hoc scripts) that skip the receiver hook still get a write here.\n if (ctx.writeErrorEventInline !== false) {\n const attrs = sanitizeAttributes(span.attributes)\n const ev: ErrorEvent = {\n id: `${span.traceId}:${span.spanId}`,\n timestamp: ts,\n service: span.service,\n traceId: span.traceId,\n spanId: span.spanId,\n errorMessage: span.exception?.message ?? 'unknown error',\n ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n ...(span.exception?.stacktrace\n ? { exceptionStacktrace: span.exception.stacktrace }\n : {}),\n ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n affectedNode,\n }\n await appendErrorEvent(ctx, ev)\n }\n }\n void affectedNode\n\n // Post-ingest policy trigger (ADR-043). The hook is awaited so failures\n // surface; daemons wrap it in a try/catch that logs without throwing.\n if (ctx.onPolicyTrigger) await ctx.onPolicyTrigger(ctx.graph)\n}\n\nexport { stitchTrace }\n\n// Promote any frontier:<host> placeholder whose host matches an alias on a\n// real ServiceNode: re-link inbound/outbound edges to the service, then drop\n// the placeholder. Returns the count of nodes promoted, for tests + logs.\n//\n// Called at the end of every extraction round. Static rounds are when new\n// aliases land (compose names, k8s metadata.name, Dockerfile labels), so\n// running it there picks up the case the issue describes: ingest fills in a\n// frontier when traffic arrives for an unknown host, and the next extraction\n// round resolves it.\n// Optional gate for block-action policies (ADR-044). When `policies` is\n// non-empty, each candidate FrontierNode runs through `canPromoteFrontier`\n// before its incident edges are rewired. Block-action policies that fire on\n// the frontier veto the promotion — the FrontierNode persists; the next\n// extract pass tries again.\nexport interface PromoteFrontierOptions {\n policies?: Policy[]\n policyCtx?: PolicyEvaluationContext\n}\n\nexport function promoteFrontierNodes(\n graph: NeatGraph,\n opts: PromoteFrontierOptions = {},\n): number {\n const aliasIndex = new Map<string, string>()\n graph.forEachNode((id, attrs) => {\n const a = attrs as ServiceNode & { type?: string }\n if (a.type !== NodeType.ServiceNode) return\n aliasIndex.set(a.name, id)\n if (a.aliases) {\n for (const alias of a.aliases) aliasIndex.set(alias, id)\n }\n })\n\n const toPromote: { frontierId: string; serviceId: string }[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as FrontierNode & { type?: string }\n if (a.type !== NodeType.FrontierNode) return\n const target = aliasIndex.get(a.host)\n if (!target) return\n if (target === id) return\n toPromote.push({ frontierId: id, serviceId: target })\n })\n\n let promoted = 0\n for (const { frontierId, serviceId } of toPromote) {\n if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {\n const gate = canPromoteFrontier(graph, frontierId, opts.policies, opts.policyCtx)\n if (!gate.allowed) {\n // Block-action policy fired on this frontier — skip the rewire and\n // leave the FrontierNode in place. Violations already surfaced via\n // the policy log on the same evaluation pass.\n continue\n }\n }\n rewireFrontierEdges(graph, frontierId, serviceId)\n graph.dropNode(frontierId)\n promoted++\n }\n return promoted\n}\n\nfunction rewireFrontierEdges(graph: NeatGraph, frontierId: string, serviceId: string): void {\n const inbound = [...graph.inboundEdges(frontierId)]\n const outbound = [...graph.outboundEdges(frontierId)]\n\n for (const edgeId of inbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n rebuildEdge(graph, edge, edge.source, serviceId, edgeId)\n }\n for (const edgeId of outbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n rebuildEdge(graph, edge, serviceId, edge.target, edgeId)\n }\n}\n\nfunction rebuildEdge(\n graph: NeatGraph,\n edge: GraphEdge,\n newSource: string,\n newTarget: string,\n oldEdgeId: string,\n): void {\n graph.dropEdge(oldEdgeId)\n // ADR-068 — promotion rewrites the target ref; provenance carries forward.\n // An OBSERVED edge to a FrontierNode promotes to an OBSERVED edge to the\n // matched typed node; an INFERRED edge stays INFERRED; etc.\n const newId =\n edge.provenance === Provenance.OBSERVED\n ? observedEdgeId(newSource, newTarget, edge.type)\n : edge.provenance === Provenance.INFERRED\n ? inferredEdgeId(newSource, newTarget, edge.type)\n : extractedEdgeId(newSource, newTarget, edge.type)\n\n if (graph.hasEdge(newId)) {\n const existing = graph.getEdgeAttributes(newId) as GraphEdge\n const merged: GraphEdge = {\n ...existing,\n callCount: (existing.callCount ?? 0) + (edge.callCount ?? 0),\n lastObserved: pickLater(existing.lastObserved, edge.lastObserved),\n }\n graph.replaceEdgeAttributes(newId, merged)\n return\n }\n\n const rebuilt: GraphEdge = {\n ...edge,\n id: newId,\n source: newSource,\n target: newTarget,\n }\n graph.addEdgeWithKey(newId, newSource, newTarget, rebuilt)\n}\n\nfunction pickLater(a: string | undefined, b: string | undefined): string | undefined {\n if (!a) return b\n if (!b) return a\n return new Date(a).getTime() >= new Date(b).getTime() ? a : b\n}\n\nexport function makeSpanHandler(ctx: IngestContext): (span: ParsedSpan) => Promise<void> {\n return (span) => handleSpan(ctx, span)\n}\n\nexport type { StaleEvent }\n\nexport interface MarkStaleOptions {\n // Per-edge-type override map. Defaults to DEFAULT_STALE_THRESHOLDS, merged\n // with NEAT_STALE_THRESHOLDS if the env var is set.\n thresholds?: Record<string, number>\n now?: number\n // ndjson path. When set, every OBSERVED → STALE transition appends one\n // line. Skipped if undefined — tests and embedded use cases don't need a\n // log.\n staleEventsPath?: string\n // Project tag for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT.\n project?: string\n}\n\n// Demote OBSERVED edges that haven't been seen in a while. Per-edge-type\n// thresholds: HTTP CALLS go stale fast; infra DEPENDS_ON is patient. Returns\n// the count of demotions and the events appended to the log.\nexport async function markStaleEdges(\n graph: NeatGraph,\n options: MarkStaleOptions = {},\n): Promise<{ count: number; events: StaleEvent[] }> {\n const thresholds = options.thresholds ?? loadStaleThresholdsFromEnv()\n const now = options.now ?? Date.now()\n const events: StaleEvent[] = []\n\n const project = options.project ?? DEFAULT_PROJECT\n graph.forEachEdge((id, attrs) => {\n const e = attrs as GraphEdge\n if (e.provenance !== Provenance.OBSERVED) return\n if (!e.lastObserved) return\n const threshold = thresholdForEdgeType(e.type, thresholds)\n const age = now - new Date(e.lastObserved).getTime()\n if (age > threshold) {\n const updated: GraphEdge = { ...e, provenance: Provenance.STALE, confidence: 0.3 }\n graph.replaceEdgeAttributes(id, updated)\n events.push({\n edgeId: id,\n source: e.source,\n target: e.target,\n edgeType: e.type,\n thresholdMs: threshold,\n ageMs: age,\n lastObserved: e.lastObserved,\n transitionedAt: new Date(now).toISOString(),\n })\n // Stale-transition fires through the bus (ADR-051). The graph\n // subscription in events.ts can't see the OBSERVED→STALE semantic on\n // its own — a provenance flip is just an attribute update from\n // graphology's view.\n emitNeatEvent({\n type: 'stale-transition',\n project,\n payload: {\n edgeId: id,\n from: Provenance.OBSERVED,\n to: Provenance.STALE,\n },\n })\n }\n })\n\n if (options.staleEventsPath && events.length > 0) {\n await appendStaleEvents(options.staleEventsPath, events)\n }\n\n return { count: events.length, events }\n}\n\nasync function appendStaleEvents(staleEventsPath: string, events: StaleEvent[]): Promise<void> {\n await fs.mkdir(path.dirname(staleEventsPath), { recursive: true })\n const lines = events.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n await fs.appendFile(staleEventsPath, lines, 'utf8')\n}\n\nexport async function readStaleEvents(staleEventsPath: string): Promise<StaleEvent[]> {\n try {\n const raw = await fs.readFile(staleEventsPath, 'utf8')\n return raw\n .split('\\n')\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as StaleEvent)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n}\n\nexport interface StalenessLoopOptions {\n thresholds?: Record<string, number>\n intervalMs?: number\n staleEventsPath?: string\n // Project tag for event-bus routing (ADR-051).\n project?: string\n // Post-stale-transition policy trigger (ADR-043). Fires after each tick of\n // markStaleEdges so policies see the new STALE state. Daemons wire this to\n // evaluateAllPolicies + PolicyViolationsLog.append.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n}\n\nexport function startStalenessLoop(\n graph: NeatGraph,\n options: StalenessLoopOptions = {},\n): () => void {\n let stopped = false\n const intervalMs = options.intervalMs ?? 60_000\n const tick = (): void => {\n if (stopped) return\n void (async () => {\n try {\n await markStaleEdges(graph, {\n thresholds: options.thresholds,\n staleEventsPath: options.staleEventsPath,\n project: options.project,\n })\n if (options.onPolicyTrigger) await options.onPolicyTrigger(graph)\n } catch (err) {\n console.error('staleness tick failed', err)\n }\n })()\n }\n const interval = setInterval(tick, intervalMs)\n if (typeof interval.unref === 'function') interval.unref()\n return () => {\n stopped = true\n clearInterval(interval)\n }\n}\n\nexport async function readErrorEvents(errorsPath: string): Promise<ErrorEvent[]> {\n try {\n const raw = await fs.readFile(errorsPath, 'utf8')\n return raw\n .split('\\n')\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as ErrorEvent)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot merge (ADR-074 §1)\n//\n// `neat sync` (local) and `neat sync --to <url>` (remote) feed snapshots into\n// a live graph through this helper. It lives in ingest.ts because mutation\n// authority sits with ingest + extract per the lifecycle contract (ADR-030);\n// the merge is ingestion of an external snapshot, no different in shape from\n// the way handleSpan ingests an OTel span.\n//\n// The merge preserves EXTRACTED + OBSERVED coexistence per Rule 2 — each\n// provenance variant has its own edge id, so the incoming EXTRACTED edges\n// can't stomp the daemon's accumulated OBSERVED edges and vice versa. Rule of\n// thumb: incoming wins for nodes/edges the live graph hasn't seen yet;\n// everything already present keeps its current attributes.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface MergeSnapshotResult {\n nodesAdded: number\n edgesAdded: number\n}\n\nexport function mergeSnapshot(\n graph: NeatGraph,\n snapshot: PersistedGraph,\n): MergeSnapshotResult {\n const exported = snapshot.graph as {\n nodes?: Array<{ key: string; attributes?: GraphNode }>\n edges?: Array<{ key?: string; source: string; target: string; attributes?: GraphEdge }>\n }\n\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const node of exported.nodes ?? []) {\n if (graph.hasNode(node.key)) continue\n if (!node.attributes) continue\n graph.addNode(node.key, node.attributes)\n nodesAdded++\n }\n\n for (const edge of exported.edges ?? []) {\n const attrs = edge.attributes\n if (!attrs) continue\n const id = edge.key ?? attrs.id\n if (!id) continue\n if (graph.hasEdge(id)) continue\n // Skip when either endpoint is missing — can happen if the snapshot\n // names a node the live graph already evicted and the incoming nodes\n // array didn't include.\n if (!graph.hasNode(edge.source) || !graph.hasNode(edge.target)) continue\n graph.addEdgeWithKey(id, edge.source, edge.target, attrs)\n edgesAdded++\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n GraphEdge,\n GraphNode,\n Policy,\n PolicyAction,\n PolicyFile,\n PolicyRule,\n PolicySeverity,\n PolicyViolation,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n PolicyFileSchema,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n deprecatedApis,\n nodeEngineConstraints,\n packageConflicts,\n} from './compat.js'\nimport { emitNeatEvent } from './events.js'\nimport { getBlastRadius } from './traverse.js'\n\n// Policy evaluation engine (ADR-043). The entry point evaluateAllPolicies is\n// pure: same graph + same policies → same violations. Per-rule-type dispatch\n// via the policyEvaluators table. Adding a new rule type means one new\n// evaluator entry plus the schema entry in @neat.is/types/policy.ts.\n//\n// Deterministic violation ids per ADR-043: ${policy.id}:${context}. The\n// context is shape-specific (nodeId, edgeId, or composite). The\n// policy-violations.ndjson writer skips on duplicate ids.\n\nexport interface EvaluationContext {\n // Wall-clock provider. Tests pin this; production uses Date.now.\n now: () => number\n}\n\ninterface RuleEvaluatorArgs<T extends PolicyRule = PolicyRule> {\n graph: NeatGraph\n policy: Policy\n rule: T\n ctx: EvaluationContext\n}\n\ntype RuleEvaluator<T extends PolicyRule = PolicyRule> = (\n args: RuleEvaluatorArgs<T>,\n) => PolicyViolation[]\n\n// Severity-driven default action per ADR-044.\nconst DEFAULT_ACTION_BY_SEVERITY: Record<PolicySeverity, PolicyAction> = {\n info: 'log',\n warning: 'alert',\n error: 'alert',\n critical: 'block',\n}\n\nexport function resolveOnViolation(policy: Policy): PolicyAction {\n return policy.onViolation ?? DEFAULT_ACTION_BY_SEVERITY[policy.severity]\n}\n\nfunction makeViolation(\n policy: Policy,\n rule: PolicyRule,\n contextSuffix: string,\n message: string,\n subject: PolicyViolation['subject'],\n ctx: EvaluationContext,\n): PolicyViolation {\n return {\n id: `${policy.id}:${contextSuffix}`,\n policyId: policy.id,\n policyName: policy.name,\n severity: policy.severity,\n onViolation: resolveOnViolation(policy),\n ruleType: rule.type,\n subject,\n message,\n observedAt: new Date(ctx.now()).toISOString(),\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Per-rule-type evaluators\n// ──────────────────────────────────────────────────────────────────────────\n\nconst evaluateStructural: RuleEvaluator<Extract<PolicyRule, { type: 'structural' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== rule.fromNodeType) return\n let satisfied = false\n for (const edgeId of graph.outboundEdges(id)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== rule.edgeType) continue\n const target = graph.getNodeAttributes(e.target) as GraphNode\n // FrontierNodes are unresolved peers (ADR-068) — skip; the rule\n // counts edges that resolve to a real typed node only.\n if (target.type === NodeType.FrontierNode) continue\n if (target.type === rule.toNodeType) {\n satisfied = true\n break\n }\n }\n if (!satisfied) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.fromNodeType} ${id} has no ${rule.edgeType} edge to a ${rule.toNodeType}`,\n { nodeId: id },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateOwnership: RuleEvaluator<Extract<PolicyRule, { type: 'ownership' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode & Record<string, unknown>\n if (a.type !== rule.nodeType) return\n const value = a[rule.field]\n if (typeof value !== 'string' || value.length === 0) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.nodeType} ${id} is missing required field \"${rule.field}\"`,\n { nodeId: id },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateProvenance: RuleEvaluator<Extract<PolicyRule, { type: 'provenance' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const required = Array.isArray(rule.required) ? new Set(rule.required) : new Set([rule.required])\n const violations: PolicyViolation[] = []\n graph.forEachEdge((edgeId, attrs) => {\n const e = attrs as GraphEdge\n if (e.type !== rule.edgeType) return\n if (rule.targetNodeId && e.target !== rule.targetNodeId) return\n if (!required.has(e.provenance)) {\n const requiredList = [...required].join(' | ')\n violations.push(\n makeViolation(\n policy,\n rule,\n edgeId,\n `${rule.edgeType} edge ${edgeId} has provenance ${e.provenance}; required ${requiredList}`,\n { edgeId },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateBlastRadius: RuleEvaluator<Extract<PolicyRule, { type: 'blast-radius' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n const depth = rule.depth\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== rule.nodeType) return\n const result = depth !== undefined ? getBlastRadius(graph, id, depth) : getBlastRadius(graph, id)\n if (result.totalAffected > rule.maxAffected) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.nodeType} ${id} has blast radius ${result.totalAffected} > ${rule.maxAffected}`,\n { nodeId: id, path: [id] },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateCompatibility: RuleEvaluator<Extract<PolicyRule, { type: 'compatibility' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n // Iterate every ServiceNode and re-run the compat shapes the static\n // extractor runs at extract time. Catches OBSERVED-vs-EXTRACTED divergence:\n // a service whose dep manifest changed since the last extract gets re-flagged\n // here on every evaluation cycle.\n const wantsKind = (kind: NonNullable<typeof rule.kind>): boolean =>\n rule.kind === undefined || rule.kind === kind\n\n graph.forEachNode((svcId, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== NodeType.ServiceNode) return\n const svc = a as ServiceNode\n const deps = svc.dependencies ?? {}\n\n if (wantsKind('driver-engine')) {\n // Walk every CONNECTS_TO edge from this service to a DatabaseNode,\n // then run the driver-engine compat for each (driver, declared, engine,\n // engineVersion) tuple.\n for (const edgeId of graph.outboundEdges(svcId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== EdgeType.CONNECTS_TO) continue\n const dbAttrs = graph.getNodeAttributes(e.target) as GraphNode\n // FrontierNodes are unresolved peers (ADR-068) — skip; compat\n // checking needs a typed DatabaseNode.\n if (dbAttrs.type === NodeType.FrontierNode) continue\n if (dbAttrs.type !== NodeType.DatabaseNode) continue\n const db = dbAttrs as { engine: string; engineVersion: string }\n for (const pair of compatPairs()) {\n if (pair.engine !== db.engine) continue\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(pair.driver, declared, db.engine, db.engineVersion)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:driver-engine:${pair.driver}@${declared}:${db.engine}@${db.engineVersion}`,\n result.reason,\n { nodeId: svcId, edgeId },\n ctx,\n ),\n )\n }\n }\n }\n }\n\n if (wantsKind('node-engine')) {\n const serviceNodeRange = svc.nodeEngine\n for (const constraint of nodeEngineConstraints()) {\n const declared = deps[constraint.package]\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeRange)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:node-engine:${constraint.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n\n if (wantsKind('package-conflict')) {\n for (const conflict of packageConflicts()) {\n const declared = deps[conflict.package]\n if (!declared) continue\n const requiredDeclared = deps[conflict.requires.name]\n const result = checkPackageConflict(conflict, declared, requiredDeclared)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:package-conflict:${conflict.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n\n if (wantsKind('deprecated-api')) {\n for (const dep of deprecatedApis()) {\n const declared = deps[dep.package]\n if (!declared) continue\n const result = checkDeprecatedApi(dep, declared)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:deprecated-api:${dep.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n })\n\n return violations\n}\n\nconst policyEvaluators: { [K in PolicyRule['type']]: RuleEvaluator<Extract<PolicyRule, { type: K }>> } = {\n structural: evaluateStructural,\n ownership: evaluateOwnership,\n provenance: evaluateProvenance,\n 'blast-radius': evaluateBlastRadius,\n compatibility: evaluateCompatibility,\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public entry point\n// ──────────────────────────────────────────────────────────────────────────\n\n// Block-action gating for FrontierNode promotion (ADR-044 §block, MVP scope).\n// Runs the policy evaluator and returns the subset of block-action violations\n// that mention the candidate FrontierNode. Callers (ingest.ts\n// promoteFrontierNodes) check `allowed` before rewiring; when false, the\n// promotion is skipped and the violations surface through the standard\n// policy-violations.ndjson channel.\n//\n// Block scope is tightly bounded per the contract: FrontierNode promotion\n// only. Other gating points (deploy, codemod, OTel auto-create) need their\n// own ADRs before this function expands.\nexport function canPromoteFrontier(\n graph: NeatGraph,\n frontierId: string,\n policies: Policy[],\n ctx: EvaluationContext,\n): { allowed: boolean; violations: PolicyViolation[] } {\n if (policies.length === 0) return { allowed: true, violations: [] }\n const all = evaluateAllPolicies(graph, policies, ctx)\n const blocking = all.filter((v) => {\n if (v.onViolation !== 'block') return false\n return (\n v.subject.nodeId === frontierId ||\n v.subject.path?.includes(frontierId) === true\n )\n })\n return { allowed: blocking.length === 0, violations: blocking }\n}\n\nexport function evaluateAllPolicies(\n graph: NeatGraph,\n policies: Policy[],\n ctx: EvaluationContext,\n): PolicyViolation[] {\n const out: PolicyViolation[] = []\n for (const policy of policies) {\n const evaluator = policyEvaluators[policy.rule.type] as RuleEvaluator\n const violations = evaluator({ graph, policy, rule: policy.rule, ctx })\n for (const v of violations) out.push(v)\n }\n return out\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Loader\n// ──────────────────────────────────────────────────────────────────────────\n\n// Reads <projectRoot>/policy.json. Returns [] when the file doesn't exist —\n// a project without policies is a perfectly fine state. Failures to parse\n// throw with the Zod error so the daemon surfaces malformed files loudly\n// instead of silently dropping rules.\nexport async function loadPolicyFile(policyPath: string): Promise<Policy[]> {\n let raw: string\n try {\n raw = await fs.readFile(policyPath, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n const json = JSON.parse(raw) as unknown\n const file: PolicyFile = PolicyFileSchema.parse(json)\n return file.policies\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Append-only ndjson writer with id-based dedup\n// ──────────────────────────────────────────────────────────────────────────\n\n// Keeps an in-memory Set of seen violation ids so re-evaluation cycles don't\n// produce duplicate ndjson lines. The set hydrates from disk on first append\n// — startups that load an existing log don't lose dedup state.\nexport class PolicyViolationsLog {\n private readonly path: string\n private readonly project: string\n private seen: Set<string> | null = null\n\n constructor(logPath: string, project: string = DEFAULT_PROJECT) {\n this.path = logPath\n this.project = project\n }\n\n async append(v: PolicyViolation): Promise<boolean> {\n if (!this.seen) await this.hydrate()\n if (this.seen!.has(v.id)) return false\n this.seen!.add(v.id)\n await fs.mkdir(path.dirname(this.path), { recursive: true })\n await fs.appendFile(this.path, JSON.stringify(v) + '\\n', 'utf8')\n // Emit policy-violation only on first sighting (post-dedup) so SSE\n // consumers don't see the same violation again on every evaluation\n // cycle (ADR-051 #2).\n emitNeatEvent({\n type: 'policy-violation',\n project: this.project,\n payload: { violation: v },\n })\n return true\n }\n\n async readAll(): Promise<PolicyViolation[]> {\n try {\n const raw = await fs.readFile(this.path, 'utf8')\n return raw\n .split('\\n')\n .filter(Boolean)\n .map((line) => JSON.parse(line) as PolicyViolation)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n }\n\n private async hydrate(): Promise<void> {\n this.seen = new Set()\n const existing = await this.readAll()\n for (const v of existing) this.seen.add(v.id)\n }\n}\n","import { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport semver from 'semver'\nimport compatData from '../compat.json' with { type: 'json' }\n\nexport interface CompatibilityResult {\n compatible: boolean\n reason?: string\n minDriverVersion?: string\n}\n\nexport interface CompatPair {\n kind?: 'driver-engine'\n driver: string\n engine: string\n minDriverVersion: string\n // The driver constraint only kicks in once the engine is at this major or higher.\n // Older engines (e.g. PostgreSQL 13) accept the older driver fine.\n minEngineVersion?: string\n reason: string\n}\n\nexport interface NodeEngineConstraint {\n kind?: 'node-engine'\n package: string\n packageMinVersion?: string\n minNodeVersion: string\n reason: string\n}\n\nexport interface PackageConflict {\n kind?: 'package-conflict'\n package: string\n packageMinVersion?: string\n requires: { name: string; minVersion: string }\n reason: string\n}\n\nexport interface DeprecatedApi {\n kind?: 'deprecated-api'\n package: string\n packageMaxVersion?: string\n reason: string\n}\n\nexport interface CompatMatrix {\n pairs: CompatPair[]\n nodeEngineConstraints?: NodeEngineConstraint[]\n packageConflicts?: PackageConflict[]\n deprecatedApis?: DeprecatedApi[]\n}\n\nconst bundledMatrix = compatData as CompatMatrix\nlet mergedMatrix: CompatMatrix | null = null\nlet remoteLoadAttempted = false\n\nconst REMOTE_CACHE_DIR = path.join(os.homedir(), '.neat')\nconst REMOTE_CACHE_PATH = path.join(REMOTE_CACHE_DIR, 'compat-cache.json')\nconst REMOTE_TTL_MS = 24 * 60 * 60 * 1000\n\ninterface RemoteCacheFile {\n fetchedAt: string\n url: string\n matrix: CompatMatrix\n}\n\n// Engines like Postgres/MySQL only carry a major in the version field, so semver\n// won't always parse them cleanly. Compare as integers when both sides look like\n// majors; otherwise fall back to semver.coerce.\nfunction engineMeetsThreshold(engineVersion: string, threshold: string): boolean {\n const e = parseInt(engineVersion, 10)\n const t = parseInt(threshold, 10)\n if (Number.isFinite(e) && Number.isFinite(t)) return e >= t\n\n const ec = semver.coerce(engineVersion)\n const tc = semver.coerce(threshold)\n if (ec && tc) return semver.gte(ec, tc)\n\n return false\n}\n\nexport function checkCompatibility(\n driver: string,\n driverVersion: string,\n engine: string,\n engineVersion: string,\n): CompatibilityResult {\n const matrix = currentMatrix()\n const pair = matrix.pairs.find((p) => p.driver === driver && p.engine === engine)\n if (!pair) return { compatible: true }\n\n if (pair.minEngineVersion && !engineMeetsThreshold(engineVersion, pair.minEngineVersion)) {\n return { compatible: true }\n }\n\n const driverCoerced = semver.coerce(driverVersion)\n if (!driverCoerced) return { compatible: true }\n\n if (semver.lt(driverCoerced, pair.minDriverVersion)) {\n return {\n compatible: false,\n reason: pair.reason,\n minDriverVersion: pair.minDriverVersion,\n }\n }\n\n return { compatible: true }\n}\n\nexport interface NodeEngineCheck {\n compatible: boolean\n reason?: string\n requiredNodeVersion?: string\n}\n\n// True when `serviceNodeRange` (a service's `engines.node`) is guaranteed to\n// admit `requiredNodeVersion`. We use a permissive semver compare via `coerce`\n// — exact ranges like \">=20\" parse fine, exotic ones like \"^20 || ^22\" pass as\n// long as semver can resolve them. If the range can't be parsed at all, we\n// don't claim a conflict — under-flag rather than over-flag.\nfunction rangeAdmitsVersion(serviceNodeRange: string, requiredNodeVersion: string): boolean {\n try {\n const required = semver.coerce(requiredNodeVersion)\n if (!required) return true\n // Is every version that satisfies the service's range >= required? If yes,\n // the service guarantees the requirement; if not, there's at least one\n // admissible Node version that won't satisfy the dep — that's the\n // conflict.\n return semver.subset(serviceNodeRange, `>=${required.version}`, {\n includePrerelease: false,\n })\n } catch {\n return true\n }\n}\n\nexport function checkNodeEngineConstraint(\n constraint: NodeEngineConstraint,\n declaredPackageVersion: string | undefined,\n serviceNodeRange: string | undefined,\n): NodeEngineCheck {\n if (constraint.packageMinVersion && declaredPackageVersion) {\n const v = semver.coerce(declaredPackageVersion)\n if (v && semver.lt(v, constraint.packageMinVersion)) {\n return { compatible: true }\n }\n }\n if (!serviceNodeRange) {\n return { compatible: true }\n }\n if (rangeAdmitsVersion(serviceNodeRange, constraint.minNodeVersion)) {\n return { compatible: true }\n }\n return {\n compatible: false,\n reason: constraint.reason,\n requiredNodeVersion: constraint.minNodeVersion,\n }\n}\n\nexport interface PackageConflictCheck {\n compatible: boolean\n reason?: string\n requires?: { name: string; minVersion: string }\n foundVersion?: string\n}\n\nexport function checkPackageConflict(\n conflict: PackageConflict,\n declaredPackageVersion: string | undefined,\n declaredRequiredVersion: string | undefined,\n): PackageConflictCheck {\n if (!declaredPackageVersion) return { compatible: true }\n if (conflict.packageMinVersion) {\n const v = semver.coerce(declaredPackageVersion)\n if (v && semver.lt(v, conflict.packageMinVersion)) {\n return { compatible: true }\n }\n }\n if (!declaredRequiredVersion) {\n return {\n compatible: false,\n reason: conflict.reason,\n requires: conflict.requires,\n }\n }\n const requiredCoerced = semver.coerce(declaredRequiredVersion)\n if (!requiredCoerced) return { compatible: true }\n if (semver.lt(requiredCoerced, conflict.requires.minVersion)) {\n return {\n compatible: false,\n reason: conflict.reason,\n requires: conflict.requires,\n foundVersion: declaredRequiredVersion,\n }\n }\n return { compatible: true }\n}\n\nexport function checkDeprecatedApi(\n rule: DeprecatedApi,\n declaredVersion: string | undefined,\n): { compatible: boolean; reason?: string } {\n if (declaredVersion === undefined) return { compatible: true }\n if (rule.packageMaxVersion) {\n const v = semver.coerce(declaredVersion)\n const max = semver.coerce(rule.packageMaxVersion)\n if (v && max && semver.gt(v, max)) return { compatible: true }\n }\n return { compatible: false, reason: rule.reason }\n}\n\nfunction currentMatrix(): CompatMatrix {\n return mergedMatrix ?? bundledMatrix\n}\n\nfunction mergeMatrices(a: CompatMatrix, b: CompatMatrix): CompatMatrix {\n return {\n pairs: [...a.pairs, ...(b.pairs ?? [])],\n nodeEngineConstraints: [\n ...(a.nodeEngineConstraints ?? []),\n ...(b.nodeEngineConstraints ?? []),\n ],\n packageConflicts: [...(a.packageConflicts ?? []), ...(b.packageConflicts ?? [])],\n deprecatedApis: [...(a.deprecatedApis ?? []), ...(b.deprecatedApis ?? [])],\n }\n}\n\nasync function readRemoteCache(url: string): Promise<CompatMatrix | null> {\n try {\n const raw = await fs.readFile(REMOTE_CACHE_PATH, 'utf8')\n const parsed = JSON.parse(raw) as RemoteCacheFile\n if (parsed.url !== url) return null\n const age = Date.now() - new Date(parsed.fetchedAt).getTime()\n if (age > REMOTE_TTL_MS) return null\n return parsed.matrix\n } catch {\n return null\n }\n}\n\nasync function writeRemoteCache(url: string, matrix: CompatMatrix): Promise<void> {\n const file: RemoteCacheFile = {\n fetchedAt: new Date().toISOString(),\n url,\n matrix,\n }\n try {\n await fs.mkdir(REMOTE_CACHE_DIR, { recursive: true })\n await fs.writeFile(REMOTE_CACHE_PATH, JSON.stringify(file), 'utf8')\n } catch (err) {\n console.warn(`[neat] failed to cache compat matrix: ${(err as Error).message}`)\n }\n}\n\n// Loads the bundled matrix and, if `NEAT_COMPAT_URL` is set, merges in a\n// remote extension. Falls back to a fresh fetch when the on-disk cache is\n// stale (24h TTL) or missing. Returns the merged matrix; subsequent calls are\n// memoised.\n//\n// Async because the fetch happens lazily on first use. Extract phase 2 awaits\n// this before iterating pairs; everything else goes through the sync\n// `currentMatrix()` view, which is fine because by the time CLI / traversal\n// runs, extraction has already loaded.\nexport async function ensureCompatLoaded(): Promise<CompatMatrix> {\n if (mergedMatrix) return mergedMatrix\n if (remoteLoadAttempted) {\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n remoteLoadAttempted = true\n\n const url = process.env.NEAT_COMPAT_URL\n if (!url) {\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n\n const cached = await readRemoteCache(url)\n if (cached) {\n mergedMatrix = mergeMatrices(bundledMatrix, cached)\n return mergedMatrix\n }\n\n try {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)\n const remote = (await res.json()) as CompatMatrix\n await writeRemoteCache(url, remote)\n mergedMatrix = mergeMatrices(bundledMatrix, remote)\n return mergedMatrix\n } catch (err) {\n console.warn(\n `[neat] NEAT_COMPAT_URL fetch failed (${(err as Error).message}); using bundled matrix only`,\n )\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n}\n\n// Reset the merged-matrix memo. Intended for tests so each test starts with a\n// freshly loaded matrix.\nexport function resetCompatMatrix(): void {\n mergedMatrix = null\n remoteLoadAttempted = false\n}\n\nexport function compatPairs(): readonly CompatPair[] {\n return currentMatrix().pairs\n}\n\nexport function nodeEngineConstraints(): readonly NodeEngineConstraint[] {\n return currentMatrix().nodeEngineConstraints ?? []\n}\n\nexport function packageConflicts(): readonly PackageConflict[] {\n return currentMatrix().packageConflicts ?? []\n}\n\nexport function deprecatedApis(): readonly DeprecatedApi[] {\n return currentMatrix().deprecatedApis ?? []\n}\n","{\n \"pairs\": [\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"pg\",\n \"engine\": \"postgresql\",\n \"minDriverVersion\": \"8.0.0\",\n \"minEngineVersion\": \"14\",\n \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; pg < 8.0.0 only speaks md5.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mysql2\",\n \"engine\": \"mysql\",\n \"minDriverVersion\": \"3.0.0\",\n \"minEngineVersion\": \"8\",\n \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql2 < 3.0.0 doesn't negotiate it.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mongoose\",\n \"engine\": \"mongodb\",\n \"minDriverVersion\": \"7.0.0\",\n \"minEngineVersion\": \"7\",\n \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that mongoose < 7.0.0 still emits.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"psycopg2\",\n \"engine\": \"postgresql\",\n \"minDriverVersion\": \"2.9.0\",\n \"minEngineVersion\": \"14\",\n \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; psycopg2 < 2.9.0 only speaks md5.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"pymongo\",\n \"engine\": \"mongodb\",\n \"minDriverVersion\": \"4.0.0\",\n \"minEngineVersion\": \"7\",\n \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that pymongo < 4.0.0 still emits.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mysql-connector-python\",\n \"engine\": \"mysql\",\n \"minDriverVersion\": \"8.0.0\",\n \"minEngineVersion\": \"8\",\n \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql-connector-python < 8.0.0 doesn't negotiate it.\"\n }\n ],\n \"nodeEngineConstraints\": [\n {\n \"kind\": \"node-engine\",\n \"package\": \"vitest\",\n \"packageMinVersion\": \"2.0.0\",\n \"minNodeVersion\": \"18.0.0\",\n \"reason\": \"vitest >= 2.0 drops Node 16 support; requires Node 18+.\"\n },\n {\n \"kind\": \"node-engine\",\n \"package\": \"next\",\n \"packageMinVersion\": \"14.0.0\",\n \"minNodeVersion\": \"18.17.0\",\n \"reason\": \"Next 14+ requires Node 18.17+ (uses APIs introduced in that minor).\"\n },\n {\n \"kind\": \"node-engine\",\n \"package\": \"@modelcontextprotocol/sdk\",\n \"packageMinVersion\": \"1.0.0\",\n \"minNodeVersion\": \"18.0.0\",\n \"reason\": \"@modelcontextprotocol/sdk >= 1 requires Node 18+ (web-streams polyfill removed).\"\n }\n ],\n \"packageConflicts\": [\n {\n \"kind\": \"package-conflict\",\n \"package\": \"@tanstack/react-query\",\n \"packageMinVersion\": \"5.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.0.0\"\n },\n \"reason\": \"@tanstack/react-query 5+ uses useSyncExternalStore — only available in React 18+.\"\n },\n {\n \"kind\": \"package-conflict\",\n \"package\": \"react-router-dom\",\n \"packageMinVersion\": \"7.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.0.0\"\n },\n \"reason\": \"react-router-dom 7+ requires React 18+.\"\n },\n {\n \"kind\": \"package-conflict\",\n \"package\": \"next\",\n \"packageMinVersion\": \"14.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.2.0\"\n },\n \"reason\": \"Next.js 14+ requires React 18.2+.\"\n }\n ],\n \"deprecatedApis\": [\n {\n \"kind\": \"deprecated-api\",\n \"package\": \"request\",\n \"packageMaxVersion\": \"2.88.2\",\n \"reason\": \"request is deprecated; use undici, node-fetch, or axios instead.\"\n },\n {\n \"kind\": \"deprecated-api\",\n \"package\": \"node-uuid\",\n \"reason\": \"node-uuid is deprecated; use the `uuid` package.\"\n }\n ]\n}\n","// Frontend-facing event bus (ADR-051). The single in-process EventEmitter\n// every producer (ingest / extract / watch / policy) emits through and the\n// only thing the SSE handler in streaming.ts subscribes to.\n//\n// Direct producer-to-handler coupling is a contract violation — every event\n// goes through `eventBus.emit('event', envelope)` so the SSE layer is the\n// only consumer that has to know the wire taxonomy.\n//\n// The taxonomy is locked at eight types (ADR-051 #2). Adding a ninth type\n// requires a successor ADR.\n\nimport { EventEmitter } from 'node:events'\nimport type { GraphEdge, GraphNode, PolicyViolation, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Locked event taxonomy. Eight values. Tests assert the array shape\n// directly, so adding here without updating the contract is a regression.\nexport const NEAT_EVENT_TYPES = [\n 'node-added',\n 'node-updated',\n 'node-removed',\n 'edge-added',\n 'edge-removed',\n 'extraction-complete',\n 'policy-violation',\n 'stale-transition',\n] as const\n\nexport type NeatEventType = (typeof NEAT_EVENT_TYPES)[number]\n\n// Per-type payload shapes. The wire layer (SSE) writes the payload as the\n// `data` field; producers use `emit*` helpers below for type safety.\nexport interface NodeAddedPayload {\n node: GraphNode\n}\nexport interface NodeUpdatedPayload {\n id: string\n changes: Partial<GraphNode>\n}\nexport interface NodeRemovedPayload {\n id: string\n}\nexport interface EdgeAddedPayload {\n edge: GraphEdge\n}\nexport interface EdgeRemovedPayload {\n id: string\n}\nexport interface ExtractionCompletePayload {\n project: string\n fileCount: number\n nodesAdded: number\n edgesAdded: number\n}\nexport interface PolicyViolationPayload {\n violation: PolicyViolation\n}\nexport interface StaleTransitionPayload {\n edgeId: string\n from: typeof Provenance.OBSERVED\n to: typeof Provenance.STALE\n}\n\nexport type NeatEventPayload = {\n 'node-added': NodeAddedPayload\n 'node-updated': NodeUpdatedPayload\n 'node-removed': NodeRemovedPayload\n 'edge-added': EdgeAddedPayload\n 'edge-removed': EdgeRemovedPayload\n 'extraction-complete': ExtractionCompletePayload\n 'policy-violation': PolicyViolationPayload\n 'stale-transition': StaleTransitionPayload\n}\n\n// What the bus carries internally. Project is metadata used by the SSE\n// handler to route between /events and /projects/:project/events; it never\n// lands in the wire payload.\nexport interface NeatEventEnvelope<T extends NeatEventType = NeatEventType> {\n type: T\n project: string\n payload: NeatEventPayload[T]\n}\n\n// Single event channel — listeners filter by `envelope.type` and\n// `envelope.project`. Using one channel keeps the contract surface narrow\n// and matches the SSE handler's needs (one subscription, fan out).\nexport const EVENT_BUS_CHANNEL = 'event'\n\nclass NeatEventBus extends EventEmitter {}\n\n// Singleton. Process-wide so producers in ingest / extract / watch / policy\n// can emit without threading a bus instance through every call site.\nexport const eventBus: NeatEventBus = new NeatEventBus()\n\n// EventEmitter defaults to 10 listeners; SSE clients add up quickly under a\n// browser refresh storm, so lift the cap.\neventBus.setMaxListeners(0)\n\nexport function emitNeatEvent<T extends NeatEventType>(envelope: NeatEventEnvelope<T>): void {\n eventBus.emit(EVENT_BUS_CHANNEL, envelope)\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Graph subscription — one place to wire graphology mutation events into\n// the bus so producers don't have to instrument every addNode/addEdge.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface AttachOptions {\n project: string\n}\n\n// Subscribes to a NeatGraph and re-emits node/edge add/remove + node/edge\n// attribute updates as bus envelopes scoped to `project`. Returns a detach\n// fn that removes every listener it installed.\n//\n// Stale-transition is NOT routed through here — a provenance flip is just an\n// attribute update from graphology's view, and we'd lose the OBSERVED→STALE\n// semantic. ingest.ts emits stale-transition itself.\nexport function attachGraphToEventBus(graph: NeatGraph, opts: AttachOptions): () => void {\n const { project } = opts\n\n const onNodeAdded = (payload: { key: string; attributes: GraphNode }): void => {\n emitNeatEvent({\n type: 'node-added',\n project,\n payload: { node: payload.attributes },\n })\n }\n const onNodeDropped = (payload: { key: string }): void => {\n emitNeatEvent({\n type: 'node-removed',\n project,\n payload: { id: payload.key },\n })\n }\n const onEdgeAdded = (payload: { key: string; attributes: GraphEdge }): void => {\n emitNeatEvent({\n type: 'edge-added',\n project,\n payload: { edge: payload.attributes },\n })\n }\n const onEdgeDropped = (payload: { key: string }): void => {\n emitNeatEvent({\n type: 'edge-removed',\n project,\n payload: { id: payload.key },\n })\n }\n const onNodeAttrsUpdated = (payload: { key: string; attributes: GraphNode }): void => {\n emitNeatEvent({\n type: 'node-updated',\n project,\n payload: { id: payload.key, changes: payload.attributes },\n })\n }\n\n graph.on('nodeAdded', onNodeAdded)\n graph.on('nodeDropped', onNodeDropped)\n graph.on('edgeAdded', onEdgeAdded)\n graph.on('edgeDropped', onEdgeDropped)\n graph.on('nodeAttributesUpdated', onNodeAttrsUpdated)\n\n return () => {\n graph.off('nodeAdded', onNodeAdded)\n graph.off('nodeDropped', onNodeDropped)\n graph.off('edgeAdded', onEdgeAdded)\n graph.off('edgeDropped', onEdgeDropped)\n graph.off('nodeAttributesUpdated', onNodeAttrsUpdated)\n }\n}\n","import type {\n BlastRadiusAffectedNode,\n BlastRadiusResult,\n DatabaseNode,\n ErrorEvent,\n GraphEdge,\n GraphNode,\n RootCauseResult,\n ServiceNode,\n TransitiveDependenciesResult,\n TransitiveDependency,\n} from '@neat.is/types'\nimport {\n BlastRadiusResultSchema,\n EdgeType,\n NodeType,\n PROV_RANK,\n RootCauseResultSchema,\n TransitiveDependenciesResultSchema,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n checkCompatibility,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n nodeEngineConstraints,\n packageConflicts,\n} from './compat.js'\n\n// Contract anchors (see /docs/contracts.md + docs/contracts/provenance.md):\n// * Rule 2 — Coexistence: walk by provenance priority, never collapse edges.\n// * Rule 3 — FrontierNodes terminate traversal — edges to/from FrontierNodes\n// are skipped, not merely deprioritized. If a node's only neighbour is a\n// FrontierNode, traversal stops there. ADR-068 makes node-type the gating\n// property, independent of edge provenance.\n// * Rule 5 — Validate results against RootCauseResultSchema /\n// BlastRadiusResultSchema before returning.\n// * Rule 8 — No demo-name hardcoding: driver/engine identifiers come from\n// node properties + compatPairs(), never literals.\n// * ADR-029 — PROV_RANK is the canonical provenance ranking, imported\n// from @neat.is/types so consumers (traversal, MCP, policies) all agree.\n\nconst ROOT_CAUSE_MAX_DEPTH = 5\nconst BLAST_RADIUS_DEFAULT_DEPTH = 10\n\nfunction isFrontierNode(graph: NeatGraph, nodeId: string): boolean {\n if (!graph.hasNode(nodeId)) return false\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n return attrs.type === NodeType.FrontierNode\n}\n\n// Resolve a node on the walk path to the ServiceNode that carries the compat\n// evidence (declared dependencies + node engine). A ServiceNode resolves to\n// itself; a FileNode resolves to its owning service via the inbound\n// `service ──CONTAINS──▶ file` edge (file-awareness.md §2) — in a file-first\n// graph the caller on the path is a FileNode, but the dependency declaration\n// lives on the service that owns it. Anything else has no service to resolve\n// to. Returns the resolved ServiceNode's id + attributes, or null.\nfunction resolveOwningService(\n graph: NeatGraph,\n nodeId: string,\n): { id: string; svc: ServiceNode } | null {\n if (!graph.hasNode(nodeId)) return null\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n if (attrs.type === NodeType.ServiceNode) {\n return { id: nodeId, svc: attrs as ServiceNode }\n }\n if (attrs.type === NodeType.FileNode) {\n for (const edgeId of graph.inboundEdges(nodeId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== EdgeType.CONTAINS) continue\n const owner = graph.getNodeAttributes(e.source) as GraphNode\n if (owner.type === NodeType.ServiceNode) {\n return { id: e.source, svc: owner as ServiceNode }\n }\n }\n }\n return null\n}\n\n// Multiple edges between the same pair coexist by provenance (EXTRACTED next to\n// OBSERVED next to INFERRED). Traversal walks the system as the graph \"sees it\n// best\", so for any neighbour pair we pick the highest-provenance edge.\n// Edges connecting to FrontierNodes are skipped at the node level (ADR-068):\n// FrontierNodes are unresolved peers, traversal terminates at them rather than\n// pretending the path continues into unknown territory.\nfunction bestEdgeBySource(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n const best = new Map<string, GraphEdge>()\n for (const id of edgeIds) {\n const e = graph.getEdgeAttributes(id) as GraphEdge\n if (isFrontierNode(graph, e.source)) continue\n const cur = best.get(e.source)\n if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {\n best.set(e.source, e)\n }\n }\n return best\n}\n\nfunction bestEdgeByTarget(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n const best = new Map<string, GraphEdge>()\n for (const id of edgeIds) {\n const e = graph.getEdgeAttributes(id) as GraphEdge\n if (isFrontierNode(graph, e.target)) continue\n const cur = best.get(e.target)\n if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {\n best.set(e.target, e)\n }\n }\n return best\n}\n\n// Per-edge confidence is provenance × volume × recency × cleanliness.\n// * provenance gives a ceiling: OBSERVED 1.0, INFERRED 0.7, EXTRACTED 0.5,\n// STALE 0.3.\n// * volume: log-scaled span count, saturating quickly so 1 span ≈ 0.55 and\n// ~1k spans ≈ 1.0.\n// * recency: 1.0 within an hour; decays toward 0.5 by 24h, toward 0.3 past.\n// * cleanliness: error rate above ~10% pulls the score down — a flapping\n// edge with thousands of spans shouldn't outrank a clean low-traffic one.\n// Bounded to [0, 1]. Walks of multiple edges multiply per-edge confidences.\nconst PROVENANCE_CEILING: Record<string, number> = {\n OBSERVED: 1.0,\n INFERRED: 0.7,\n EXTRACTED: 0.5,\n STALE: 0.3,\n}\n\nfunction volumeWeight(spanCount: number | undefined): number {\n if (!spanCount || spanCount <= 0) return 0.5\n // log10 saturating around ~1000 spans → ~1.0.\n const w = 0.5 + Math.log10(spanCount + 1) / 3\n return Math.min(1, w)\n}\n\nfunction recencyWeight(ageMs: number | undefined): number {\n if (ageMs === undefined) return 0.8\n const hour = 60 * 60 * 1000\n if (ageMs <= hour) return 1.0\n if (ageMs <= 24 * hour) {\n const t = (ageMs - hour) / (23 * hour)\n return 1.0 - 0.5 * t\n }\n return 0.3\n}\n\nfunction cleanlinessWeight(spanCount: number | undefined, errorCount: number | undefined): number {\n if (!spanCount || spanCount <= 0) return 1\n const rate = (errorCount ?? 0) / spanCount\n if (rate <= 0.01) return 1\n if (rate >= 0.5) return 0.3\n return 1 - rate * 1.4\n}\n\nexport function confidenceForEdge(edge: GraphEdge, now = Date.now()): number {\n const ceiling = PROVENANCE_CEILING[edge.provenance] ?? 0.5\n\n // No runtime signal yet → the provenance ceiling is all we have. This keeps\n // EXTRACTED-only graphs returning the same coarse 0.3/0.5/0.7/1.0 ladder\n // they always have, while letting OBSERVED edges with real OTel data move\n // off the ceiling once ingest starts populating signal counters.\n const spanCount = edge.signal?.spanCount ?? edge.callCount\n const ageMs = edge.signal?.lastObservedAgeMs ?? lastObservedAge(edge, now)\n if (spanCount === undefined && ageMs === undefined && edge.signal === undefined) {\n return ceiling\n }\n\n const v = volumeWeight(spanCount)\n const r = recencyWeight(ageMs)\n const c = cleanlinessWeight(spanCount, edge.signal?.errorCount)\n return Math.max(0, Math.min(1, ceiling * v * r * c))\n}\n\nfunction lastObservedAge(edge: GraphEdge, now: number): number | undefined {\n if (!edge.lastObserved) return undefined\n const t = Date.parse(edge.lastObserved)\n if (!Number.isFinite(t)) return undefined\n return Math.max(0, now - t)\n}\n\n// Path-level confidence is the *product* of per-edge confidences (ADR-036).\n// Each hop is independent evidence and uncertainty compounds — a 3-hop path\n// of edges at confidence 0.8 each gives 0.512, not 0.8. Multiplying punishes\n// long walks accordingly, which is the contract's intent: traversal should\n// surface the cumulative trust the graph actually has, not the weakest link\n// alone.\nfunction confidenceFromMix(edges: GraphEdge[], now = Date.now()): number {\n if (edges.length === 0) return 1.0\n let product = 1\n for (const e of edges) {\n product *= confidenceForEdge(e, now)\n }\n return Math.max(0, Math.min(1, product))\n}\n\ninterface Walk {\n path: string[]\n edges: GraphEdge[]\n}\n\n// DFS along incoming edges from start, depth-bounded. Returns the longest path\n// reachable, picking best-provenance edges per neighbour pair so the walk\n// reflects the system as the graph knows it most reliably.\nfunction longestIncomingWalk(graph: NeatGraph, start: string, maxDepth: number): Walk {\n let best: Walk = { path: [start], edges: [] }\n const visited = new Set<string>([start])\n\n function step(node: string, path: string[], edges: GraphEdge[]): void {\n if (path.length > best.path.length) {\n best = { path: [...path], edges: [...edges] }\n }\n if (path.length - 1 >= maxDepth) return\n\n const incoming = bestEdgeBySource(graph, graph.inboundEdges(node))\n for (const [srcId, edge] of incoming) {\n if (visited.has(srcId)) continue\n visited.add(srcId)\n path.push(srcId)\n edges.push(edge)\n step(srcId, path, edges)\n path.pop()\n edges.pop()\n visited.delete(srcId)\n }\n }\n\n step(start, [start], [])\n return best\n}\n\n// Per-shape match result. Each shape walks the same incoming `walk.path` but\n// looks for a different class of incompatibility. Adding a new shape (e.g. a\n// future ConfigNode \"missing required env var\" rule) is one entry in\n// `rootCauseShapes` plus its match function — no restructure to getRootCause.\ninterface RootCauseMatch {\n rootCauseNode: string\n rootCauseReason: string\n fixRecommendation?: string\n}\n\ntype RootCauseShape = (\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n) => RootCauseMatch | null\n\n// DatabaseNode origin → driver/engine compat (the original v0.1.x behavior,\n// preserved verbatim). The walk ignores non-ServiceNodes; the first upstream\n// service whose declared driver fails compat against the origin DB's\n// (engine, engineVersion) wins.\nfunction databaseRootCauseShape(\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n const targetDb = origin as DatabaseNode\n // Pairs that could possibly hit on this engine — narrowed once outside the\n // walk so we don't re-scan the matrix for every service we visit.\n const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine)\n if (candidatePairs.length === 0) return null\n\n for (const id of walk.path) {\n // The compat carrier is a service: a ServiceNode resolves to itself, a\n // FileNode on the path resolves to its owning service via CONTAINS\n // (file-awareness.md §2). In a file-first graph the caller on the walk is\n // the FileNode that holds the CALLS edge, but the declared driver lives on\n // the service that owns it.\n const owner = resolveOwningService(graph, id)\n if (!owner) continue\n const { id: serviceId, svc } = owner\n const deps = svc.dependencies ?? {}\n for (const pair of candidatePairs) {\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(\n pair.driver,\n declared,\n targetDb.engine,\n targetDb.engineVersion,\n )\n if (!result.compatible) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason ?? 'incompatible driver',\n ...(result.minDriverVersion\n ? {\n fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`,\n }\n : {}),\n }\n }\n }\n }\n return null\n}\n\n// ServiceNode origin → node-engine + package-conflict shapes from compat.ts.\n// The check is over each ServiceNode along the incoming walk (the origin\n// itself + any upstream callers): a node-engine constraint failing against\n// the service's `engines.node`, or a package-conflict where a declared dep\n// requires a peer at a higher version than the service has.\nfunction serviceRootCauseShape(\n graph: NeatGraph,\n _origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n for (const id of walk.path) {\n // ServiceNode → itself; FileNode → owning service via CONTAINS\n // (file-awareness.md §2). The compat evidence (declared deps, node engine)\n // lives on the service, even when the caller on the walk is a file.\n const owner = resolveOwningService(graph, id)\n if (!owner) continue\n const { id: serviceId, svc } = owner\n const deps = svc.dependencies ?? {}\n const serviceNodeEngine = svc.nodeEngine\n\n for (const constraint of nodeEngineConstraints()) {\n const declared = deps[constraint.package]\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n if (!result.compatible && result.reason) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason,\n ...(result.requiredNodeVersion\n ? {\n fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`,\n }\n : {}),\n }\n }\n }\n\n for (const conflict of packageConflicts()) {\n const declared = deps[conflict.package]\n if (!declared) continue\n const requiredDeclared = deps[conflict.requires.name]\n const result = checkPackageConflict(conflict, declared, requiredDeclared)\n if (!result.compatible && result.reason) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason,\n fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`,\n }\n }\n }\n }\n return null\n}\n\n// FileNode origin → resolve the file to its owning service (file-awareness.md\n// §2) and run the service shape. In a file-first graph an error can land on a\n// FileNode (the file that holds the failing CALLS edge); the incompatibility,\n// if any, is still a property of the service that owns the file's declared\n// dependencies. The owning service is folded into the origin's position so the\n// service shape scans it alongside the upstream walk.\nfunction fileRootCauseShape(\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n const owner = resolveOwningService(graph, origin.id)\n if (!owner) return null\n return serviceRootCauseShape(graph, owner.svc, walk)\n}\n\n// Dispatch by origin node type per ADR-037. Origin types not present here\n// (InfraNode, ConfigNode, FrontierNode) cleanly return null — getRootCause\n// needs an explicit shape to know what an \"incompatibility\" looks like for\n// that origin, and those types don't have one yet.\nconst rootCauseShapes: Partial<Record<GraphNode['type'], RootCauseShape>> = {\n [NodeType.DatabaseNode]: databaseRootCauseShape,\n [NodeType.ServiceNode]: serviceRootCauseShape,\n [NodeType.FileNode]: fileRootCauseShape,\n}\n\nexport function getRootCause(\n graph: NeatGraph,\n errorNodeId: string,\n errorEvent?: ErrorEvent,\n): RootCauseResult | null {\n if (!graph.hasNode(errorNodeId)) return null\n const origin = graph.getNodeAttributes(errorNodeId) as GraphNode\n const shape = rootCauseShapes[origin.type]\n if (!shape) return null\n\n const walk = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH)\n const match = shape(graph, origin, walk)\n if (!match) return null\n\n const reason = errorEvent\n ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})`\n : match.rootCauseReason\n\n // Schema-validate before return (ADR-036, #139). A drift in the result\n // shape becomes a runtime throw at the call site rather than a silently\n // malformed payload reaching MCP / REST consumers.\n return RootCauseResultSchema.parse({\n rootCauseNode: match.rootCauseNode,\n rootCauseReason: reason,\n traversalPath: walk.path,\n edgeProvenances: walk.edges.map((e) => e.provenance),\n confidence: confidenceFromMix(walk.edges),\n fixRecommendation: match.fixRecommendation,\n })\n}\n\n// BFS along outgoing edges from origin. Records each reachable node with the\n// shortest distance back to origin and the provenance of the edge that brought\n// us to it. Best-provenance edge selection per pair mirrors getRootCause.\nexport function getBlastRadius(\n graph: NeatGraph,\n nodeId: string,\n maxDepth = BLAST_RADIUS_DEFAULT_DEPTH,\n): BlastRadiusResult {\n if (!graph.hasNode(nodeId)) {\n return BlastRadiusResultSchema.parse({ origin: nodeId, affectedNodes: [], totalAffected: 0 })\n }\n\n // Each frame carries its full predecessor chain so the affected-node payload\n // can surface `path` (origin → ... → nodeId) and `confidence` (cascaded over\n // every edge along that path). The BFS visits each reachable node once on\n // its shortest-distance path; later frames at greater distance are dropped.\n interface Frame {\n nodeId: string\n distance: number\n path: string[]\n pathEdges: GraphEdge[]\n }\n\n const seen = new Map<string, BlastRadiusAffectedNode>()\n const queue: Frame[] = [{ nodeId, distance: 0, path: [nodeId], pathEdges: [] }]\n const enqueued = new Set<string>([nodeId])\n\n while (queue.length > 0) {\n const frame = queue.shift()!\n if (frame.distance > 0 && frame.pathEdges.length > 0) {\n const lastEdge = frame.pathEdges[frame.pathEdges.length - 1]!\n seen.set(frame.nodeId, {\n nodeId: frame.nodeId,\n distance: frame.distance,\n edgeProvenance: lastEdge.provenance,\n path: frame.path,\n confidence: confidenceFromMix(frame.pathEdges),\n })\n }\n if (frame.distance >= maxDepth) continue\n\n const outgoing = bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n for (const [tgtId, edge] of outgoing) {\n if (enqueued.has(tgtId)) continue\n enqueued.add(tgtId)\n queue.push({\n nodeId: tgtId,\n distance: frame.distance + 1,\n path: [...frame.path, tgtId],\n pathEdges: [...frame.pathEdges, edge],\n })\n }\n }\n\n const affectedNodes = [...seen.values()].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n return BlastRadiusResultSchema.parse({\n origin: nodeId,\n affectedNodes,\n totalAffected: affectedNodes.length,\n })\n}\n\n// Default + max depth for transitive get_dependencies (issue #144). Default\n// 3 keeps the output legible at the agent layer; the contract caps the\n// caller-supplied value at 10 to prevent BFS blow-up on dense graphs.\nexport const TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH = 3\nexport const TRANSITIVE_DEPENDENCIES_MAX_DEPTH = 10\n\n// Transitive get_dependencies (ADR-039 / #144). BFS outbound from origin to\n// `depth` hops, returning a flat list with distance, edgeType, and provenance\n// per dependency. Origin is never in the list. Direct-only consumers pass\n// depth=1; the MCP get_dependencies tool defaults to 3.\n//\n// Reuses bestEdgeByTarget (FRONTIER filtered, PROV_RANK-best per pair) so\n// dedup behavior matches the rest of traversal. Result is schema-validated\n// before return per ADR-036 §Result schema validation.\nexport function getTransitiveDependencies(\n graph: NeatGraph,\n nodeId: string,\n depth: number = TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n): TransitiveDependenciesResult {\n if (!graph.hasNode(nodeId)) {\n return TransitiveDependenciesResultSchema.parse({\n origin: nodeId,\n depth,\n dependencies: [],\n total: 0,\n })\n }\n\n interface Frame {\n nodeId: string\n distance: number\n edge: GraphEdge | null\n }\n\n const seen = new Map<string, TransitiveDependency>()\n const queue: Frame[] = [{ nodeId, distance: 0, edge: null }]\n const enqueued = new Set<string>([nodeId])\n\n while (queue.length > 0) {\n const frame = queue.shift()!\n if (frame.distance > 0 && frame.edge) {\n seen.set(frame.nodeId, {\n nodeId: frame.nodeId,\n distance: frame.distance,\n edgeType: frame.edge.type,\n provenance: frame.edge.provenance,\n })\n }\n if (frame.distance >= depth) continue\n\n const outgoing = bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n for (const [tgtId, edge] of outgoing) {\n if (enqueued.has(tgtId)) continue\n enqueued.add(tgtId)\n queue.push({ nodeId: tgtId, distance: frame.distance + 1, edge })\n }\n }\n\n const dependencies = [...seen.values()].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n return TransitiveDependenciesResultSchema.parse({\n origin: nodeId,\n depth,\n dependencies,\n total: dependencies.length,\n })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport ignore, { type Ignore } from 'ignore'\nimport { minimatch } from 'minimatch'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n IGNORED_DIRS,\n exists,\n isPythonVenvDir,\n readJson,\n type DiscoveredService,\n type PackageJson,\n} from './shared.js'\nimport { discoverPythonService, pythonToPackage } from './python.js'\nimport { computeServiceOwner, loadCodeowners } from './owners.js'\nimport { recordExtractionError } from './errors.js'\n\nconst DEFAULT_SCAN_DEPTH = 5\n\ninterface RootPackageJson extends PackageJson {\n workspaces?: string[] | { packages?: string[] }\n}\n\nfunction parseScanDepth(): number {\n const raw = process.env.NEAT_SCAN_DEPTH\n if (!raw) return DEFAULT_SCAN_DEPTH\n const n = Number.parseInt(raw, 10)\n return Number.isFinite(n) && n >= 0 ? n : DEFAULT_SCAN_DEPTH\n}\n\nfunction workspaceGlobs(pkg: RootPackageJson): string[] | null {\n const ws = pkg.workspaces\n if (!ws) return null\n if (Array.isArray(ws)) return ws.length > 0 ? ws : null\n if (Array.isArray(ws.packages)) return ws.packages.length > 0 ? ws.packages : null\n return null\n}\n\nasync function loadGitignore(scanPath: string): Promise<Ignore | null> {\n const gitignorePath = path.join(scanPath, '.gitignore')\n if (!(await exists(gitignorePath))) return null\n const raw = await fs.readFile(gitignorePath, 'utf8')\n return ignore().add(raw)\n}\n\ninterface WalkOptions {\n maxDepth: number\n ig: Ignore | null\n}\n\nasync function walkDirs(\n start: string,\n scanPath: string,\n options: WalkOptions,\n visit: (dir: string) => Promise<void> | void,\n): Promise<void> {\n async function recurse(current: string, depth: number): Promise<void> {\n if (depth > options.maxDepth) return\n const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(current, entry.name)\n if (options.ig) {\n const rel = path.relative(scanPath, child).split(path.sep).join('/')\n // Trailing slash so `ignore` evaluates the entry as a directory; without\n // it, gitignore patterns like `dist/` won't match because the lib\n // distinguishes file vs. directory tests.\n if (rel && options.ig.ignores(rel + '/')) continue\n }\n // Issue #344 — `pyvenv.cfg` marks every directory that `python -m venv`\n // or `virtualenv` creates, regardless of what the wrapper dir is called.\n // The `IGNORED_DIRS` name list catches the common shapes (`.venv`,\n // `venv`, `.tox`); this catches the long-tail ones (`env-3.11`,\n // `.direnv`, ad-hoc names).\n if (await isPythonVenvDir(child)) continue\n await visit(child)\n await recurse(child, depth + 1)\n }\n }\n await recurse(start, 0)\n}\n\nasync function expandWorkspaceGlobs(\n scanPath: string,\n globs: string[],\n): Promise<string[]> {\n const found = new Set<string>()\n const scanDepth = parseScanDepth()\n\n for (const raw of globs) {\n const pattern = raw.replace(/^\\.\\//, '')\n\n if (!pattern.includes('*')) {\n const candidate = path.join(scanPath, pattern)\n if (await exists(path.join(candidate, 'package.json'))) found.add(candidate)\n continue\n }\n\n const segments = pattern.split('/')\n const staticSegments: string[] = []\n for (const seg of segments) {\n if (seg.includes('*')) break\n staticSegments.push(seg)\n }\n const start = path.join(scanPath, ...staticSegments)\n if (!(await exists(start))) continue\n\n const hasDoubleStar = pattern.includes('**')\n const walkDepth = hasDoubleStar\n ? scanDepth\n : Math.max(0, segments.length - staticSegments.length - 1)\n\n await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {\n const rel = path.relative(scanPath, dir).split(path.sep).join('/')\n if (minimatch(rel, pattern) && (await exists(path.join(dir, 'package.json')))) {\n found.add(dir)\n }\n })\n }\n\n return [...found]\n}\n\n// Framework detection from package.json deps (ADR-074 §3). Mirrors the\n// installer dispatch precedence so a project the installer recognises as\n// Remix records `framework: 'remix'` on its ServiceNode. The static\n// extractor sees only manifest data, so detection is dep-presence based —\n// it doesn't crack open config files. Detection precedence: Next → Remix\n// → SvelteKit → Nuxt → Astro → vanilla Node.\nfunction detectJsFramework(pkg: PackageJson): string | undefined {\n const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n if (deps['next'] !== undefined) return 'next'\n if (deps['remix'] !== undefined) return 'remix'\n for (const k of Object.keys(deps)) {\n if (k.startsWith('@remix-run/')) return 'remix'\n }\n if (deps['@sveltejs/kit'] !== undefined) return 'sveltekit'\n if (deps['nuxt'] !== undefined) return 'nuxt'\n if (deps['astro'] !== undefined) return 'astro'\n return undefined\n}\n\nasync function discoverNodeService(\n scanPath: string,\n dir: string,\n): Promise<DiscoveredService | null> {\n const pkgPath = path.join(dir, 'package.json')\n if (!(await exists(pkgPath))) return null\n let pkg: PackageJson\n try {\n pkg = await readJson<PackageJson>(pkgPath)\n } catch (err) {\n recordExtractionError('services', path.relative(scanPath, pkgPath), err)\n return null\n }\n if (!pkg.name) return null\n const framework = detectJsFramework(pkg)\n const node: ServiceNode = {\n id: serviceId(pkg.name),\n type: NodeType.ServiceNode,\n name: pkg.name,\n language: 'javascript',\n version: pkg.version,\n dependencies: pkg.dependencies ?? {},\n repoPath: path.relative(scanPath, dir),\n ...(pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {}),\n ...(framework ? { framework } : {}),\n }\n return { pkg, dir, node }\n}\n\nasync function discoverPyService(\n scanPath: string,\n dir: string,\n): Promise<DiscoveredService | null> {\n const py = await discoverPythonService(dir)\n if (!py) return null\n const pkg = pythonToPackage(py)\n const node: ServiceNode = {\n id: serviceId(py.name),\n type: NodeType.ServiceNode,\n name: py.name,\n language: 'python',\n version: py.version,\n dependencies: py.dependencies,\n repoPath: path.relative(scanPath, dir),\n }\n return { pkg, dir, node }\n}\n\n// Phase 1 — discover service directories under scanPath. A service is any\n// directory containing a JS/TS manifest (`package.json`) or a Python manifest\n// (`pyproject.toml` / `requirements.txt` / `setup.py`). JS wins on tie.\n//\n// If the root `package.json` declares `workspaces`, those globs are\n// authoritative — we don't fall back to a free recursive walk. Otherwise we\n// walk recursively, depth-bounded by `NEAT_SCAN_DEPTH` (default 5), skipping\n// `IGNORED_DIRS` and anything matched by the root `.gitignore`.\n//\n// Two manifests sharing a `name` collapse to one node per ADR-010; the\n// duplicate logs a warning naming both paths.\nexport async function discoverServices(scanPath: string): Promise<DiscoveredService[]> {\n const rootPkgPath = path.join(scanPath, 'package.json')\n let rootPkg: RootPackageJson | null = null\n if (await exists(rootPkgPath)) {\n try {\n rootPkg = await readJson<RootPackageJson>(rootPkgPath)\n } catch (err) {\n recordExtractionError(\n 'services workspaces',\n path.relative(scanPath, rootPkgPath),\n err,\n )\n }\n }\n const wsGlobs = rootPkg ? workspaceGlobs(rootPkg) : null\n\n const candidateDirs: string[] = []\n if (wsGlobs) {\n candidateDirs.push(...(await expandWorkspaceGlobs(scanPath, wsGlobs)))\n } else {\n if (rootPkg && rootPkg.name) candidateDirs.push(scanPath)\n const ig = await loadGitignore(scanPath)\n await walkDirs(\n scanPath,\n scanPath,\n { maxDepth: parseScanDepth(), ig },\n async (dir) => {\n if (await exists(path.join(dir, 'package.json'))) {\n candidateDirs.push(dir)\n } else if (\n (await exists(path.join(dir, 'pyproject.toml'))) ||\n (await exists(path.join(dir, 'requirements.txt'))) ||\n (await exists(path.join(dir, 'setup.py')))\n ) {\n candidateDirs.push(dir)\n }\n },\n )\n }\n\n candidateDirs.sort()\n\n const seen = new Map<string, string>()\n const out: DiscoveredService[] = []\n for (const dir of candidateDirs) {\n const service =\n (await discoverNodeService(scanPath, dir)) ??\n (await discoverPyService(scanPath, dir))\n if (!service) continue\n\n const existingDir = seen.get(service.node.name)\n if (existingDir !== undefined) {\n const a = path.relative(scanPath, existingDir) || '.'\n const b = path.relative(scanPath, dir) || '.'\n console.warn(\n `[neat] duplicate package name \"${service.node.name}\" — keeping ${a}, ignoring ${b}`,\n )\n continue\n }\n seen.set(service.node.name, dir)\n out.push(service)\n }\n\n // Owner extraction (ADR-054). CODEOWNERS first, package.json `author`\n // fallback, undefined otherwise. Read once per discovery pass; the file\n // is small and parsing it per-service would be wasteful.\n const codeowners = await loadCodeowners(scanPath)\n for (const service of out) {\n const owner = await computeServiceOwner(codeowners, service.node.repoPath, service.dir)\n if (owner !== undefined) service.node.owner = owner\n }\n\n return out\n}\n\nexport function addServiceNodes(graph: NeatGraph, services: DiscoveredService[]): number {\n let nodesAdded = 0\n for (const service of services) {\n if (!graph.hasNode(service.node.id)) {\n graph.addNode(service.node.id, { ...service.node, discoveredVia: 'static' })\n nodesAdded++\n continue\n }\n // OTel ingest may have auto-created a minimal node at this id. Merge per\n // ADR-033 / identity contract: static fields override OTel-derived fields,\n // and discoveredVia flips to 'merged' when both layers contributed.\n const existing = graph.getNodeAttributes(service.node.id) as ServiceNode\n const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n existing.discoveredVia === 'otel' ? 'merged' : 'static'\n graph.replaceNodeAttributes(service.node.id, {\n ...existing,\n ...service.node,\n discoveredVia: mergedDiscoveredVia,\n })\n }\n return nodesAdded\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\n\nexport interface PackageJson {\n name: string\n version?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n engines?: { node?: string }\n}\n\nexport interface DiscoveredService {\n pkg: PackageJson\n dir: string\n node: ServiceNode\n}\n\nexport const SERVICE_FILE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.py'])\nexport const CONFIG_FILE_EXTENSIONS = new Set(['.yaml', '.yml'])\nexport const IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.turbo',\n 'dist',\n 'build',\n '.next',\n // Python virtualenv shapes (issue #344). Walking into a venv pulls in the\n // entire CPython stdlib + every installed package as if it were first-party\n // service code — 20k+ files, none of which the user wrote. The shape names\n // cover the three common venv tools (`venv` / `python -m venv`,\n // `virtualenv`) and the tox + PEP 582 conventions.\n '.venv',\n 'venv',\n '__pypackages__',\n '.tox',\n // `site-packages` shows up nested inside venvs that don't carry one of the\n // outer names (system Python on macOS, in-place pyenv layouts). Listing it\n // here means we stop the walk at the boundary even when the wrapper dir\n // wasn't recognisable.\n 'site-packages',\n])\n\n// Marker file `python -m venv` and `virtualenv` both drop at the venv root.\n// Used by the walkers to recognise venvs whose top-level directory doesn't\n// happen to match one of the canonical `IGNORED_DIRS` names (issue #344).\n// Cached per process to keep the recursion hot path off the fs after the\n// first walk; venv contents don't change inside one extract pass.\nconst PYVENV_MARKER_CACHE = new Map<string, boolean>()\n\nexport async function isPythonVenvDir(dir: string): Promise<boolean> {\n const cached = PYVENV_MARKER_CACHE.get(dir)\n if (cached !== undefined) return cached\n try {\n const stat = await fs.stat(path.join(dir, 'pyvenv.cfg'))\n const ok = stat.isFile()\n PYVENV_MARKER_CACHE.set(dir, ok)\n return ok\n } catch {\n PYVENV_MARKER_CACHE.set(dir, false)\n return false\n }\n}\n\nexport function isConfigFile(name: string): { match: boolean; fileType: string } {\n const ext = path.extname(name)\n if (CONFIG_FILE_EXTENSIONS.has(ext)) return { match: true, fileType: ext.slice(1) }\n // .env, .env.local, .env.production. Bare filename or any dotted-suffix\n // variant; folder names get filtered upstream by walking files only.\n // ADR-065 #4 filters .env.template / .env.example / .env.sample (and the\n // dotted-suffix variants) at the producer level — those are documentation,\n // not runtime config.\n if (name === '.env' || name.startsWith('.env.')) {\n if (isEnvTemplateFile(name)) return { match: false, fileType: '' }\n return { match: true, fileType: 'env' }\n }\n return { match: false, fileType: '' }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-065 precision-filter helpers. Pre-emit gates inside the producer pass.\n// Filtered candidates are never written to the graph (idempotency intact).\n// ─────────────────────────────────────────────────────────────────────────\n\n// ADR-065 #1 — test-scope exclusion. Returns true when the file path matches\n// any test-scope pattern. Path is normalised to forward slashes before\n// matching so callers can pass either form.\n//\n// Patterns:\n// - any segment named __tests__, __fixtures__, or integration-tests\n// - basename matches *.spec.{ts,tsx,js,jsx,mjs,cjs,py}\n// - basename matches *.test.{ts,tsx,js,jsx,mjs,cjs,py}\nexport function isTestPath(filePath: string): boolean {\n const normalised = filePath.replace(/\\\\/g, '/')\n const segments = normalised.split('/')\n for (const seg of segments) {\n if (seg === '__tests__' || seg === '__fixtures__' || seg === 'integration-tests') {\n return true\n }\n }\n const base = segments[segments.length - 1] ?? ''\n return /\\.(spec|test)\\.(?:tsx?|jsx?|mjs|cjs|py)$/i.test(base)\n}\n\n// ADR-065 #4 — `.env.template` exclusion. Matches:\n// .env.template / .env.example / .env.sample\n// .env.*.template / .env.*.example / .env.*.sample\n// These are docs/onboarding artifacts, not runtime config. ConfigNodes are\n// bound to runtime existence (ADR-016); templates fail that test.\nexport function isEnvTemplateFile(name: string): boolean {\n if (\n name === '.env.template' ||\n name === '.env.example' ||\n name === '.env.sample'\n ) {\n return true\n }\n // `.env.*.template` / `.env.*.example` / `.env.*.sample`\n return /^\\.env\\.[^.]+\\.(?:template|example|sample)$/i.test(name)\n}\n\n// ADR-065 #2 — comment-body exclusion. Replaces every JS/TS comment span in\n// the source with an equal-length run of spaces, preserving line/column for\n// downstream line-mapping. Strings that contain `//` sequences (URLs) are\n// preserved by tracking the string context as we scan.\n//\n// Not a full parser — good enough for the medusa-shape failures. The HTTP\n// extractor's AST walk already gets comment-awareness for free; this helper\n// is for the regex-based extractors (redis, kafka, aws, grpc).\nexport function maskCommentsInSource(src: string): string {\n const len = src.length\n const out: string[] = new Array(len)\n let i = 0\n // String context: ' \" ` (template) — open-quote char, 0 when not in a string.\n let inString: string | 0 = 0\n let escaped = false\n while (i < len) {\n const c = src[i]!\n if (inString !== 0) {\n out[i] = c\n if (escaped) {\n escaped = false\n } else if (c === '\\\\') {\n escaped = true\n } else if (c === inString) {\n inString = 0\n }\n i++\n continue\n }\n if (c === '/' && i + 1 < len) {\n const next = src[i + 1]!\n if (next === '/') {\n out[i] = ' '\n out[i + 1] = ' '\n let j = i + 2\n while (j < len && src[j] !== '\\n') {\n out[j] = ' '\n j++\n }\n i = j\n continue\n }\n if (next === '*') {\n out[i] = ' '\n out[i + 1] = ' '\n let j = i + 2\n while (j < len) {\n if (src[j] === '\\n') {\n out[j] = '\\n'\n j++\n continue\n }\n if (src[j] === '*' && j + 1 < len && src[j + 1] === '/') {\n out[j] = ' '\n out[j + 1] = ' '\n j += 2\n break\n }\n out[j] = ' '\n j++\n }\n i = j\n continue\n }\n }\n out[i] = c\n if (c === \"'\" || c === '\"' || c === '`') inString = c\n i++\n }\n return out.join('')\n}\n\n// ADR-065 #5 — exact hostname match for cross-service URL inference. Returns\n// true if `urlString` looks like an actual URL — has an explicit `scheme://`\n// or starts with a scheme-relative `//` — and its hostname matches `host`\n// exactly (case-insensitive). No `.includes()` containment, and no bare-string\n// matching: a literal like `'admin-bundler'` would otherwise parse as\n// `http://admin-bundler` and match the basename of every service directory,\n// which is how the v0.3.3 medusa pre-check produced 279 false positives.\n//\n// Accepts a `host` that may include a port (`api.example.com:8080`); in that\n// case the URL's hostname AND port must both match.\nconst URL_LIKE = /^(?:[a-z][a-z0-9+.-]*:)?\\/\\//i\n\nexport function urlMatchesHost(urlString: string, host: string): boolean {\n if (typeof urlString !== 'string' || urlString.length === 0) return false\n // Require the literal to look like a URL — scheme + `://` or scheme-relative\n // `//host`. Bare hostnames are rejected; they're the load-bearing source of\n // false positives.\n if (!URL_LIKE.test(urlString)) return false\n const [wantedHost, wantedPort] = host.split(':')\n let parsed: URL\n try {\n // For scheme-relative `//host/path`, prepend `http:` so URL accepts it.\n const candidate = urlString.startsWith('//') ? `http:${urlString}` : urlString\n parsed = new URL(candidate)\n } catch {\n return false\n }\n if (parsed.hostname.toLowerCase() !== (wantedHost ?? '').toLowerCase()) return false\n if (wantedPort && parsed.port !== wantedPort) return false\n return true\n}\n\n// Strip semver range prefixes (^, ~, >=, etc.) and bare \"v\" so the extracted\n// version is usable for compat checks. We don't try to resolve ranges to actual\n// installed versions — that's a published-lockfile concern, not extraction's job.\nexport function cleanVersion(raw: string | undefined): string | undefined {\n if (!raw) return undefined\n return raw.replace(/^[\\^~><=v\\s]+/, '').trim() || undefined\n}\n\nexport async function readJson<T>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8')\n return JSON.parse(raw) as T\n}\n\nexport async function readYaml<T>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8')\n return parseYaml(raw) as T\n}\n\nexport async function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// Thin re-export so existing callers (calls/, configs.ts, databases/, infra/)\n// keep their import path. Wire format lives in @neat.is/types/identity.ts per\n// ADR-029.\nexport { extractedEdgeId as makeEdgeId } from '@neat.is/types'\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport { exists, type PackageJson } from './shared.js'\n\n// Lines like `psycopg2==2.7.0`, `psycopg2 == 2.7.0`, `psycopg2[extras]==2.7`,\n// or `psycopg2~=2.7,<3`. We capture the package name and the first version\n// that follows an `==` operator. Anything else (range, no pin, no version) is\n// recorded with an empty version — the compat matrix's semver coercer treats\n// those as \"can't reason\" and under-flags rather than over-flags.\nconst REQUIREMENT_LINE = /^\\s*([A-Za-z0-9_.-]+)(?:\\[[^\\]]*\\])?\\s*(?:(==)\\s*([A-Za-z0-9_.+-]+))?/\n\nfunction parseRequirementsTxt(content: string): Record<string, string> {\n const out: Record<string, string> = {}\n for (const rawLine of content.split('\\n')) {\n const line = rawLine.split('#')[0]?.trim()\n if (!line) continue\n if (line.startsWith('-')) continue // -r requirements-dev.txt etc.\n const match = REQUIREMENT_LINE.exec(line)\n if (!match) continue\n const name = match[1]!.toLowerCase()\n const version = match[3] ?? ''\n out[name] = version\n }\n return out\n}\n\ninterface PyProjectFile {\n project?: {\n name?: string\n version?: string\n dependencies?: string[]\n }\n tool?: {\n poetry?: {\n name?: string\n version?: string\n dependencies?: Record<string, string | { version?: string }>\n }\n }\n}\n\nfunction depsFromPyProject(pyproject: PyProjectFile): Record<string, string> {\n const out: Record<string, string> = {}\n\n // PEP 621 — [project] dependencies = [\"psycopg2==2.7.0\", \"requests\"]\n for (const entry of pyproject.project?.dependencies ?? []) {\n const match = REQUIREMENT_LINE.exec(entry)\n if (!match) continue\n out[match[1]!.toLowerCase()] = match[3] ?? ''\n }\n\n // Poetry — [tool.poetry.dependencies] psycopg2 = \"2.7.0\"\n const poetryDeps = pyproject.tool?.poetry?.dependencies ?? {}\n for (const [name, value] of Object.entries(poetryDeps)) {\n if (name.toLowerCase() === 'python') continue\n const raw = typeof value === 'string' ? value : (value?.version ?? '')\n out[name.toLowerCase()] = raw.replace(/^[\\^~><=v\\s]+/, '')\n }\n return out\n}\n\nexport interface PythonService {\n name: string\n version?: string\n dependencies: Record<string, string>\n}\n\n// Detect a Python service by the conventional manifest files. We try\n// pyproject.toml first because it can name the package; fallback to the\n// directory name when only requirements.txt or setup.py is present.\nexport async function discoverPythonService(serviceDir: string): Promise<PythonService | null> {\n const pyprojectPath = path.join(serviceDir, 'pyproject.toml')\n const requirementsPath = path.join(serviceDir, 'requirements.txt')\n const setupPath = path.join(serviceDir, 'setup.py')\n\n const hasPyproject = await exists(pyprojectPath)\n const hasRequirements = await exists(requirementsPath)\n const hasSetup = await exists(setupPath)\n if (!hasPyproject && !hasRequirements && !hasSetup) return null\n\n let name = path.basename(serviceDir)\n let version: string | undefined\n const dependencies: Record<string, string> = {}\n\n if (hasPyproject) {\n const raw = await fs.readFile(pyprojectPath, 'utf8')\n const pyproject = parseToml(raw) as PyProjectFile\n name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name\n version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? undefined\n Object.assign(dependencies, depsFromPyProject(pyproject))\n }\n\n if (hasRequirements) {\n const raw = await fs.readFile(requirementsPath, 'utf8')\n Object.assign(dependencies, parseRequirementsTxt(raw))\n }\n\n return { name, version, dependencies }\n}\n\n// Build the same `pkg`-shaped shim the JS path uses so downstream phases\n// (databases, calls, etc.) can keep reading service.pkg.dependencies and\n// service.pkg.name without caring which language produced the service.\nexport function pythonToPackage(service: PythonService): PackageJson {\n return {\n name: service.name,\n version: service.version,\n dependencies: service.dependencies,\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { minimatch } from 'minimatch'\nimport { exists, readJson } from './shared.js'\n\nexport interface CodeownersRule {\n pattern: string\n owners: string\n}\n\nexport interface CodeownersFile {\n rules: CodeownersRule[]\n}\n\ninterface PackageJsonAuthor {\n author?: string | { name?: string }\n}\n\n// Read CODEOWNERS at <scanPath>/CODEOWNERS first, then <scanPath>/.github/CODEOWNERS.\n// Returns null when neither exists. ADR-054 #2.1.\nexport async function loadCodeowners(scanPath: string): Promise<CodeownersFile | null> {\n const candidates = [\n path.join(scanPath, 'CODEOWNERS'),\n path.join(scanPath, '.github', 'CODEOWNERS'),\n ]\n for (const file of candidates) {\n if (await exists(file)) {\n const raw = await fs.readFile(file, 'utf8')\n return parseCodeowners(raw)\n }\n }\n return null\n}\n\nfunction parseCodeowners(raw: string): CodeownersFile {\n const rules: CodeownersRule[] = []\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const match = /^(\\S+)\\s+(.+)$/.exec(trimmed)\n if (!match) continue\n rules.push({ pattern: match[1]!, owners: match[2]!.trim() })\n }\n return { rules }\n}\n\n// First matching pattern wins; returns the literal RHS or null. ADR-054 #2.1.\n// Pattern matcher is minimal per ADR-054 #6 — handles `*`, `**`, and exact\n// paths; not a full gitignore-style parser.\nexport function matchOwner(file: CodeownersFile, repoPath: string): string | null {\n const normalized = repoPath.split(path.sep).join('/')\n for (const rule of file.rules) {\n if (matchesPattern(rule.pattern, normalized)) return rule.owners\n }\n return null\n}\n\nfunction matchesPattern(rawPattern: string, repoPath: string): boolean {\n let pattern = rawPattern.startsWith('/') ? rawPattern.slice(1) : rawPattern\n if (pattern === '*') return !repoPath.includes('/')\n if (pattern === '**' || pattern === '') return true\n // Trailing slash means \"everything in this directory\".\n if (pattern.endsWith('/')) pattern = pattern + '**'\n if (minimatch(repoPath, pattern, { dot: true })) return true\n // A pattern that names a directory should match files beneath it too.\n if (!pattern.includes('*') && minimatch(repoPath, pattern + '/**', { dot: true })) return true\n return false\n}\n\n// Read <serviceDir>/package.json and return the `author` field as a literal\n// string. Accepts either string form (\"Cem D <cem@example.com>\") or object\n// form ({ name: 'Cem D' }). Returns null when missing or unparseable.\n// ADR-054 #2.2.\nexport async function readPackageJsonAuthor(serviceDir: string): Promise<string | null> {\n const pkgPath = path.join(serviceDir, 'package.json')\n if (!(await exists(pkgPath))) return null\n try {\n const pkg = await readJson<PackageJsonAuthor>(pkgPath)\n if (!pkg.author) return null\n if (typeof pkg.author === 'string') return pkg.author\n if (typeof pkg.author === 'object' && typeof pkg.author.name === 'string') return pkg.author.name\n return null\n } catch {\n return null\n }\n}\n\n// Compute owner per ADR-054 priority: CODEOWNERS first, package.json `author`\n// fallback, undefined otherwise. Literal source value, no normalization (#3).\nexport async function computeServiceOwner(\n codeowners: CodeownersFile | null,\n repoPath: string | undefined,\n serviceDir: string,\n): Promise<string | undefined> {\n if (codeowners && repoPath !== undefined) {\n const owner = matchOwner(codeowners, repoPath)\n if (owner) return owner\n }\n const author = await readPackageJsonAuthor(serviceDir)\n return author ?? undefined\n}\n","// ADR-065 — loud failure mode for static extraction.\n//\n// Per-file extraction failures used to land as a single `console.warn` line\n// with no aggregate count and no on-disk record. The 2026-05-12 medusa\n// experiment ran `neat init` against ~90 files that all silently failed\n// extraction with \"Invalid argument\"; the snapshot shipped with those files\n// missing, the user had no signal it had happened, and the divergence query\n// couldn't surface gaps it didn't know it had.\n//\n// This module is the failure-mode plumbing: a process-local sink that every\n// producer appends to when a per-file parse fails, with helpers to drain the\n// sink to `<projectDir>/neat-out/errors.ndjson` and to surface the aggregate\n// count in init / watch banners.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface ExtractionError {\n // Producer name (e.g. \"http\", \"services\", \"infra docker-compose\"). Stable\n // human-readable identifier for logs and contract assertions.\n producer: string\n // Absolute or relative path of the file that failed. Stored verbatim from\n // the call site; no normalisation here.\n file: string\n // The error's `.message`. Stringified if the throw value wasn't an Error.\n error: string\n // Optional stack trace (captured at the call site). Useful for diagnosing\n // tree-sitter \"Invalid argument\" cases where the message alone is generic.\n stack?: string\n // ISO timestamp of when the error was recorded.\n ts: string\n // Discriminator for `errors.ndjson` consumers — separates extract failures\n // from OTel error events that share the same file (ADR-033).\n source: 'extract'\n}\n\nconst sink: ExtractionError[] = []\n\n// Record a per-file extraction failure. Preserves the visible warn line so\n// existing scripts/CI consumers still see a per-file message; appends to the\n// process-local sink so the aggregate count + sidecar write can fire later.\nexport function recordExtractionError(\n producer: string,\n file: string,\n err: unknown,\n): void {\n const e = err instanceof Error ? err : new Error(String(err))\n sink.push({\n producer,\n file,\n error: e.message,\n stack: e.stack,\n ts: new Date().toISOString(),\n source: 'extract',\n })\n // Visible warn preserved (pre-ADR-065 callers logged this). Banners\n // aggregate, but per-file context still useful for tail -f sessions.\n console.warn(`[neat] ${producer} skipped ${file}: ${e.message}`)\n}\n\n// Drain all queued errors. Idempotent — subsequent calls return an empty\n// array until new errors land. Callers (extractFromDirectory) drain at start\n// to clear stale state from prior runs, then drain again at end to collect\n// the pass's failures.\nexport function drainExtractionErrors(): ExtractionError[] {\n return sink.splice(0, sink.length)\n}\n\n// Read-only count of currently-queued errors. Used by callers that want the\n// count without consuming the sink (the banner case — we want the count for\n// display and the entries for `errors.ndjson`).\nexport function pendingExtractionErrors(): number {\n return sink.length\n}\n\n// Append the drained entries to `<projectDir>/neat-out/errors.ndjson`. The\n// file is shared with OTel error events (per ADR-033); the `source: 'extract'`\n// discriminator separates them for consumers. Creates the directory if\n// missing. Append-only — never rewritten.\nexport async function writeExtractionErrors(\n errors: ExtractionError[],\n errorsPath: string,\n): Promise<void> {\n if (errors.length === 0) return\n await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n const lines = errors.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n await fs.appendFile(errorsPath, lines, 'utf8')\n}\n\n// ADR-065 — `NEAT_STRICT_EXTRACTION=1` makes any per-file extraction failure\n// cause the calling command to exit non-zero. Default is forgiving (banner\n// only). The check is at the caller (cli.ts / server.ts / watch.ts) so the\n// extraction phase itself stays library-shaped.\nexport function isStrictExtractionEnabled(): boolean {\n const raw = process.env.NEAT_STRICT_EXTRACTION\n return raw === '1' || raw === 'true'\n}\n\n// Format the unconditional summary banner. Zero errors is a positive signal\n// (\"0 files skipped\") so callers print this even on clean runs.\nexport function formatExtractionBanner(count: number): string {\n if (count === 1) return `[neat] 1 file skipped due to parse errors`\n return `[neat] ${count} files skipped due to parse errors`\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-066 — precision-floor drop accounting.\n//\n// EXTRACTED candidates whose graded confidence falls below\n// NEAT_EXTRACTED_PRECISION_FLOOR (default 0.7) are computed but never added\n// to the graph. The drop count surfaces on the extraction banner;\n// NEAT_EXTRACTED_REJECTED_LOG=1 routes the per-candidate detail to\n// `<projectDir>/neat-out/rejected.ndjson`. The default keeps the sidecar\n// surface quiet.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface DroppedExtractedEdge {\n source: string\n target: string\n type: string\n confidence: number\n confidenceKind: string\n evidence: { file: string; line?: number; snippet?: string }\n}\n\nconst droppedSink: DroppedExtractedEdge[] = []\n\nexport function noteExtractedDropped(edge: DroppedExtractedEdge): void {\n droppedSink.push(edge)\n}\n\nexport function drainDroppedExtracted(): DroppedExtractedEdge[] {\n return droppedSink.splice(0, droppedSink.length)\n}\n\nexport function pendingDroppedExtracted(): number {\n return droppedSink.length\n}\n\nexport function isRejectedLogEnabled(): boolean {\n const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG\n return raw === '1' || raw === 'true'\n}\n\nexport async function writeRejectedExtracted(\n drops: DroppedExtractedEdge[],\n rejectedPath: string,\n): Promise<void> {\n if (drops.length === 0) return\n await fs.mkdir(path.dirname(rejectedPath), { recursive: true })\n const lines = drops.map((d) => JSON.stringify({ ...d, ts: new Date().toISOString() })).join('\\n') + '\\n'\n await fs.appendFile(rejectedPath, lines, 'utf8')\n}\n\nexport function formatPrecisionFloorBanner(count: number): string {\n if (count === 1) return `[neat] 1 extracted edge dropped below precision floor`\n return `[neat] ${count} extracted edges dropped below precision floor`\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport { parseAllDocuments } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { recordExtractionError } from './errors.js'\nimport {\n CONFIG_FILE_EXTENSIONS,\n IGNORED_DIRS,\n exists,\n isPythonVenvDir,\n readYaml,\n type DiscoveredService,\n} from './shared.js'\n\n// Populate ServiceNode.aliases from sources that the OTel layer is likely to\n// see in span attributes:\n//\n// - docker-compose service names (compose-DNS).\n// - Dockerfile LABEL values that name the service.\n// - k8s metadata.name (and the cluster-DNS variants) for Service /\n// Deployment / StatefulSet whose name matches a known service.\n//\n// resolveServiceId in ingest.ts checks aliases before falling back to a\n// FRONTIER placeholder; promoteFrontierNodes uses them to retire stale\n// placeholders once they map to a real service.\n\ninterface ComposeService {\n container_name?: string\n hostname?: string\n networks?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\ninterface K8sDoc {\n kind?: string\n metadata?: {\n name?: string\n namespace?: string\n labels?: Record<string, string>\n }\n spec?: {\n selector?: {\n app?: string\n matchLabels?: Record<string, string>\n }\n }\n}\n\nconst K8S_KINDS_WITH_HOSTNAMES = new Set([\n 'Service',\n 'Deployment',\n 'StatefulSet',\n 'DaemonSet',\n])\n\nfunction addAliases(graph: NeatGraph, serviceId: string, candidates: Iterable<string>): void {\n if (!graph.hasNode(serviceId)) return\n const node = graph.getNodeAttributes(serviceId) as ServiceNode & { type?: string }\n if (node.type !== NodeType.ServiceNode) return\n const set = new Set(node.aliases ?? [])\n for (const c of candidates) {\n if (!c) continue\n if (c === node.name) continue\n set.add(c)\n }\n if (set.size === 0) return\n const updated: ServiceNode = { ...node, aliases: [...set].sort() }\n graph.replaceNodeAttributes(serviceId, updated)\n}\n\nfunction indexServicesByName(services: DiscoveredService[]): Map<string, string> {\n const map = new Map<string, string>()\n for (const s of services) {\n map.set(s.node.name, s.node.id)\n map.set(path.basename(s.dir), s.node.id)\n }\n return map\n}\n\nasync function collectComposeAliases(\n graph: NeatGraph,\n scanPath: string,\n serviceIndex: Map<string, string>,\n): Promise<void> {\n let composePath: string | null = null\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(scanPath, name)\n if (await exists(abs)) {\n composePath = abs\n break\n }\n }\n if (!composePath) return\n\n let compose: ComposeFile\n try {\n compose = await readYaml<ComposeFile>(composePath)\n } catch (err) {\n recordExtractionError(\n 'aliases compose',\n path.relative(scanPath, composePath),\n err,\n )\n return\n }\n if (!compose?.services) return\n\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const serviceId = serviceIndex.get(composeName)\n if (!serviceId) continue\n const aliases = new Set<string>([composeName])\n if (svc.container_name) aliases.add(svc.container_name)\n if (svc.hostname) aliases.add(svc.hostname)\n addAliases(graph, serviceId, aliases)\n }\n}\n\nconst LABEL_KEYS = new Set([\n 'service',\n 'service.name',\n 'app',\n 'app.name',\n 'com.docker.compose.service',\n 'org.opencontainers.image.title',\n])\n\nfunction parseDockerfileLabels(content: string): string[] {\n const out: string[] = []\n // Support `LABEL key=value`, `LABEL key=\"value with spaces\"`, and the\n // multi-pair form `LABEL k1=v1 k2=v2`. We don't try to honour line\n // continuations — the common single-line form is enough.\n const lineRegex = /^\\s*label\\s+(.+)$/i\n for (const raw of content.split('\\n')) {\n const m = lineRegex.exec(raw)\n if (!m) continue\n const rest = m[1]!\n const pairRegex = /([\\w.-]+)\\s*=\\s*(\"([^\"]*)\"|'([^']*)'|([^\\s]+))/g\n let pair: RegExpExecArray | null\n while ((pair = pairRegex.exec(rest)) !== null) {\n const key = pair[1]!.toLowerCase()\n if (!LABEL_KEYS.has(key)) continue\n const value = pair[3] ?? pair[4] ?? pair[5] ?? ''\n if (value) out.push(value)\n }\n }\n return out\n}\n\nasync function collectDockerfileAliases(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<void> {\n for (const service of services) {\n const dockerfilePath = path.join(service.dir, 'Dockerfile')\n if (!(await exists(dockerfilePath))) continue\n let content: string\n try {\n content = await fs.readFile(dockerfilePath, 'utf8')\n } catch (err) {\n recordExtractionError('aliases dockerfile', dockerfilePath, err)\n continue\n }\n const aliases = parseDockerfileLabels(content)\n if (aliases.length > 0) addAliases(graph, service.node.id, aliases)\n }\n}\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkYamlFiles(child, depth + 1, max)))\n } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\nfunction k8sHostnames(name: string, namespace: string | undefined): string[] {\n const ns = namespace ?? 'default'\n return [\n name,\n `${name}.${ns}`,\n `${name}.${ns}.svc`,\n `${name}.${ns}.svc.cluster.local`,\n ]\n}\n\nfunction k8sServiceTarget(\n doc: K8sDoc,\n byName: Map<string, string>,\n): string | null {\n // For `Service` resources, the target is whatever app the spec selects, not\n // necessarily the Service's own metadata.name. We prefer that mapping; if no\n // selector, fall back to the metadata.name match.\n const selector = doc.spec?.selector\n const selectorApp = selector?.app ?? selector?.matchLabels?.app\n if (selectorApp && byName.has(selectorApp)) return byName.get(selectorApp)!\n\n const labelApp = doc.metadata?.labels?.app\n if (labelApp && byName.has(labelApp)) return byName.get(labelApp)!\n\n const metaName = doc.metadata?.name\n if (metaName && byName.has(metaName)) return byName.get(metaName)!\n\n return null\n}\n\nasync function collectK8sAliases(\n graph: NeatGraph,\n scanPath: string,\n serviceIndex: Map<string, string>,\n): Promise<void> {\n const files = await walkYamlFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n let docs: K8sDoc[]\n try {\n docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n } catch {\n continue\n }\n for (const doc of docs) {\n if (!doc?.kind || !doc.metadata?.name) continue\n if (!K8S_KINDS_WITH_HOSTNAMES.has(doc.kind)) continue\n const target = k8sServiceTarget(doc, serviceIndex)\n if (!target) continue\n addAliases(graph, target, k8sHostnames(doc.metadata.name, doc.metadata.namespace))\n }\n }\n}\n\nexport async function addServiceAliases(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<void> {\n const byName = indexServicesByName(services)\n await collectComposeAliases(graph, scanPath, byName)\n await collectDockerfileAliases(graph, services)\n await collectK8sAliases(graph, scanPath, byName)\n}\n","import path from 'node:path'\nimport type {\n CompatibleDriver,\n DatabaseNode,\n GraphEdge,\n GraphNode,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n databaseId,\n confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n deprecatedApis,\n nodeEngineConstraints,\n packageConflicts,\n} from '../../compat.js'\nimport { cleanVersion, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { dbConfigYamlParser } from './db-config-yaml.js'\nimport { dotenvParser } from './dotenv.js'\nimport { prismaParser } from './prisma.js'\nimport { drizzleParser } from './drizzle.js'\nimport { knexParser } from './knex.js'\nimport { ormconfigParser } from './ormconfig.js'\nimport { typeormParser } from './typeorm.js'\nimport { sequelizeParser } from './sequelize.js'\nimport { dockerComposeParser } from './docker-compose.js'\nimport type { DbConfig } from './shared.js'\n\nexport type { DbConfig } from './shared.js'\n\nexport interface DbParser {\n name: string\n parse(serviceDir: string): Promise<DbConfig[]>\n}\n\n// Registry — order is for tie-breaking only (first wins on identical host).\n// db-config.yaml stays first so the canonical demo behaviour matches today's\n// extraction byte-for-byte.\nexport const DB_PARSERS: DbParser[] = [\n dbConfigYamlParser,\n dotenvParser,\n prismaParser,\n drizzleParser,\n knexParser,\n ormconfigParser,\n typeormParser,\n sequelizeParser,\n dockerComposeParser,\n]\n\nfunction compatibleDriversFor(engine: string): CompatibleDriver[] {\n return compatPairs()\n .filter((p) => p.engine === engine)\n .map((p) => ({ name: p.driver, minVersion: p.minDriverVersion }))\n}\n\nfunction toDatabaseNode(config: DbConfig): DatabaseNode {\n return {\n id: databaseId(config.host),\n type: NodeType.DatabaseNode,\n name: config.database || config.host,\n engine: config.engine,\n engineVersion: config.engineVersion,\n compatibleDrivers: compatibleDriversFor(config.engine),\n host: config.host,\n port: config.port,\n }\n}\n\nexport function attachIncompatibilities(\n service: DiscoveredService,\n configs: DbConfig[],\n): void {\n const deps = { ...(service.pkg.dependencies ?? {}), ...(service.pkg.devDependencies ?? {}) }\n const incompatibilities: NonNullable<ServiceNode['incompatibilities']> = []\n const seen = new Set<string>()\n\n // 1. driver-engine — original behaviour. Per (db config, configured driver\n // pair) check that the declared driver version meets the engine threshold.\n for (const config of configs) {\n for (const pair of compatPairs()) {\n if (pair.engine !== config.engine) continue\n const declaredVersion = cleanVersion(deps[pair.driver])\n if (!declaredVersion) continue\n const result = checkCompatibility(\n pair.driver,\n declaredVersion,\n config.engine,\n config.engineVersion,\n )\n if (!result.compatible && result.reason) {\n const key = `driver-engine|${pair.driver}@${declaredVersion}|${config.engine}@${config.engineVersion}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'driver-engine',\n driver: pair.driver,\n driverVersion: declaredVersion,\n engine: config.engine,\n engineVersion: config.engineVersion,\n reason: result.reason,\n })\n }\n }\n }\n\n // 2. node-engine — service's `engines.node` vs each declared dep that has a\n // matrix-recorded minimum.\n const serviceNodeEngine = service.node.nodeEngine ?? service.pkg.engines?.node\n for (const constraint of nodeEngineConstraints()) {\n const declared = cleanVersion(deps[constraint.package])\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n if (!result.compatible && result.reason) {\n const key = `node-engine|${constraint.package}@${declared}|${serviceNodeEngine ?? ''}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'node-engine',\n package: constraint.package,\n packageVersion: declared,\n requiredNodeVersion: result.requiredNodeVersion ?? constraint.minNodeVersion,\n ...(serviceNodeEngine ? { declaredNodeEngine: serviceNodeEngine } : {}),\n reason: result.reason,\n })\n }\n }\n\n // 3. package-conflict — pair like react-query 5+ requiring react 18+.\n for (const conflict of packageConflicts()) {\n const declared = cleanVersion(deps[conflict.package])\n if (!declared) continue\n const requiredVersion = cleanVersion(deps[conflict.requires.name])\n const result = checkPackageConflict(conflict, declared, requiredVersion)\n if (!result.compatible && result.reason) {\n const key = `package-conflict|${conflict.package}@${declared}|${conflict.requires.name}@${requiredVersion ?? 'missing'}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'package-conflict',\n package: conflict.package,\n packageVersion: declared,\n requires: conflict.requires,\n ...(requiredVersion ? { foundVersion: requiredVersion } : {}),\n reason: result.reason,\n })\n }\n }\n\n // 4. deprecated-api — flag presence of a known-deprecated package.\n for (const rule of deprecatedApis()) {\n const declared = cleanVersion(deps[rule.package])\n if (declared === undefined) continue\n const result = checkDeprecatedApi(rule, declared)\n if (!result.compatible && result.reason) {\n const key = `deprecated-api|${rule.package}@${declared}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'deprecated-api',\n package: rule.package,\n packageVersion: declared,\n reason: result.reason,\n })\n }\n }\n\n if (incompatibilities.length > 0) service.node.incompatibilities = incompatibilities\n}\n\n// Phase 2 — for each service, run every parser and merge their DbConfigs by\n// host. Each unique host produces one DatabaseNode + CONNECTS_TO edge from the\n// service. The parser registry decides priority on tie; the demo's\n// db-config.yaml stays first so its `engineVersion: 15` continues to win.\nexport async function addDatabasesAndCompat(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const merged = new Map<string, DbConfig>()\n for (const parser of DB_PARSERS) {\n let configs: DbConfig[]\n try {\n configs = await parser.parse(service.dir)\n } catch (err) {\n console.warn(\n `[neat] ${parser.name} parser failed on ${service.node.name}: ${(err as Error).message}`,\n )\n continue\n }\n for (const config of configs) {\n if (!config.host) continue\n if (!merged.has(config.host)) merged.set(config.host, config)\n }\n }\n\n const allConfigs = [...merged.values()]\n for (const config of allConfigs) {\n const dbNode = toDatabaseNode(config)\n if (!graph.hasNode(dbNode.id)) {\n graph.addNode(dbNode.id, { ...dbNode, discoveredVia: 'static' })\n nodesAdded++\n } else {\n // OTel ingest may have auto-created a minimal node at this id. Merge\n // per ADR-033: static fields override OTel-derived fields, discoveredVia\n // flips to 'merged' when both layers contributed.\n const existing = graph.getNodeAttributes(dbNode.id) as DatabaseNode\n const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n existing.discoveredVia === 'otel' ? 'merged' : 'static'\n graph.replaceNodeAttributes(dbNode.id, {\n ...existing,\n ...dbNode,\n discoveredVia: mergedDiscoveredVia,\n })\n }\n // DB connection from a parsed config file is a direct AST/file fact —\n // structural tier per ADR-066.\n const edge: GraphEdge = {\n id: makeEdgeId(service.node.id, dbNode.id, EdgeType.CONNECTS_TO),\n source: service.node.id,\n target: dbNode.id,\n type: EdgeType.CONNECTS_TO,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n // ADR-032 / #140 — every EXTRACTED edge carries evidence.file.\n // Ghost-edge cleanup keys retirement on this; the conditional\n // sourceFile spread that used to live here was a v0.1.x leftover.\n evidence: {\n file: path.relative(scanPath, config.sourceFile).split(path.sep).join('/'),\n },\n }\n if (!graph.hasEdge(edge.id)) {\n graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n // Run all kinds of incompat checks even for services with no db connection\n // — node-engine / package-conflict / deprecated-api don't depend on db.\n attachIncompatibilities(service, allConfigs)\n if (graph.hasNode(service.node.id)) {\n // Merge with whatever's on the node already (aliases from γ #75 land\n // before this phase), so the writeback doesn't drop fields populated by\n // earlier passes.\n const current = graph.getNodeAttributes(service.node.id) as ServiceNode\n const updated: ServiceNode = {\n ...current,\n ...(service.node as ServiceNode),\n ...(current.aliases ? { aliases: current.aliases } : {}),\n }\n // attachIncompatibilities only sets the field when there's something to\n // flag. On a re-extract (`neat watch`, `POST /graph/scan`), a stale\n // entry on `current` would otherwise survive the spread and leave the\n // graph reporting a problem the new manifest no longer has.\n if (!service.node.incompatibilities || service.node.incompatibilities.length === 0) {\n delete (updated as { incompatibilities?: unknown }).incompatibilities\n }\n graph.replaceNodeAttributes(service.node.id, updated as unknown as GraphNode)\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport type { DbConfig } from './shared.js'\n\ninterface DbConfigYaml {\n host: string\n port?: number\n database: string\n engine: string\n engineVersion?: string | number\n}\n\n// The original db-config.yaml format, kept as a parser so the demo continues\n// to work. Engine + version are explicit here, so this is the one source that\n// can produce a real engineVersion without inference.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const yamlPath = path.join(serviceDir, 'db-config.yaml')\n if (!(await exists(yamlPath))) return []\n const raw = await readYaml<DbConfigYaml>(yamlPath)\n return [\n {\n host: raw.host,\n port: raw.port,\n database: raw.database,\n engine: raw.engine,\n engineVersion: raw.engineVersion !== undefined ? String(raw.engineVersion) : 'unknown',\n sourceFile: yamlPath,\n },\n ]\n}\n\nexport const dbConfigYamlParser = { name: 'db-config.yaml', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { isConfigFile } from '../shared.js'\nimport { parseConnectionString, type DbConfig } from './shared.js'\n\nconst CONNECTION_KEYS = new Set([\n 'DATABASE_URL',\n 'DB_URL',\n 'POSTGRES_URL',\n 'POSTGRESQL_URL',\n 'MYSQL_URL',\n 'MONGODB_URI',\n 'MONGO_URL',\n 'MONGO_URI',\n 'REDIS_URL',\n])\n\n// Per ADR-016, .env contents do not land in any snapshot. We read them here\n// only to derive a transient DbConfig — the value never reaches a ConfigNode.\nfunction parseDotenvLine(line: string): { key: string; value: string } | null {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) return null\n const eq = trimmed.indexOf('=')\n if (eq < 0) return null\n const key = trimmed.slice(0, eq).trim()\n let value = trimmed.slice(eq + 1).trim()\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1)\n }\n return { key, value }\n}\n\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const entries = await fs.readdir(serviceDir, { withFileTypes: true }).catch(() => [])\n const configs: DbConfig[] = []\n const seen = new Set<string>()\n\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const match = isConfigFile(entry.name)\n if (!match.match || match.fileType !== 'env') continue\n\n const filePath = path.join(serviceDir, entry.name)\n const content = await fs.readFile(filePath, 'utf8')\n for (const line of content.split('\\n')) {\n const parsed = parseDotenvLine(line)\n if (!parsed) continue\n if (!CONNECTION_KEYS.has(parsed.key.toUpperCase())) continue\n const config = parseConnectionString(parsed.value)\n if (!config) continue\n const key = `${config.engine}://${config.host}:${config.port ?? ''}/${config.database}`\n if (seen.has(key)) continue\n seen.add(key)\n configs.push({ ...config, sourceFile: filePath })\n }\n }\n return configs\n}\n\nexport const dotenvParser = { name: '.env', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface DbConfig {\n host: string\n port?: number\n database: string\n engine: string\n engineVersion: string // \"unknown\" when not statically determinable\n // Absolute path to the file the parser read this config from. Required —\n // ghost-edge cleanup keys CONNECTS_TO retirement on `evidence.file` per\n // ADR-032 / #140. Parsers that synthesize a DbConfig from a partial\n // source still set this to the file the partial came from.\n sourceFile: string\n}\n\n// Map a connection-string scheme to the engine name our compat matrix uses.\n// Schemes like \"postgres+asyncpg\" are normalised by stripping the dialect\n// suffix; anything we don't recognise returns null so the parser can decline.\nexport function schemeToEngine(scheme: string): string | null {\n const s = scheme.toLowerCase().split('+')[0]\n switch (s) {\n case 'postgres':\n case 'postgresql':\n return 'postgresql'\n case 'mysql':\n case 'mariadb':\n return 'mysql'\n case 'mongodb':\n case 'mongodb+srv':\n return 'mongodb'\n case 'redis':\n case 'rediss':\n return 'redis'\n case 'sqlite':\n return 'sqlite'\n default:\n return null\n }\n}\n\n// Returns the inner DbConfig fields without sourceFile — every caller spreads\n// the parser's own file path on top. Type makes that contract explicit.\nexport type ParsedConnectionConfig = Omit<DbConfig, 'sourceFile'>\n\nexport function parseConnectionString(url: string): ParsedConnectionConfig | null {\n const m = url.match(\n /^(?<scheme>[a-z][a-z+]*):\\/\\/(?:[^@/]+(?::[^@]*)?@)?(?<host>[^:/?]+)(?::(?<port>\\d+))?(?:\\/(?<db>[^?#]*))?/i,\n )\n if (!m || !m.groups) return null\n const engine = schemeToEngine(m.groups.scheme!)\n if (!engine) return null\n return {\n host: m.groups.host!,\n port: m.groups.port ? Number(m.groups.port) : undefined,\n database: m.groups.db ?? '',\n engine,\n engineVersion: 'unknown',\n }\n}\n\nexport async function readIfExists(filePath: string): Promise<string | null> {\n try {\n return await fs.readFile(filePath, 'utf8')\n } catch {\n return null\n }\n}\n\nexport async function findFirst(\n serviceDir: string,\n candidates: string[],\n): Promise<string | null> {\n for (const rel of candidates) {\n const abs = path.join(serviceDir, rel)\n const content = await readIfExists(abs)\n if (content !== null) return abs\n }\n return null\n}\n\n// Engine name from a docker-compose `image:` value like \"postgres:15-alpine\"\n// or \"mysql/mysql-server:8.0\". Returns the engine + version when both are\n// resolvable, or null if the image isn't one we recognise.\nexport function engineFromImage(\n image: string,\n): { engine: string; engineVersion: string } | null {\n const lower = image.toLowerCase()\n const colon = lower.lastIndexOf(':')\n const repo = colon >= 0 ? lower.slice(0, colon) : lower\n const tag = colon >= 0 ? lower.slice(colon + 1) : 'latest'\n const last = repo.split('/').pop() ?? repo\n let engine: string | null = null\n if (last.startsWith('postgres')) engine = 'postgresql'\n else if (last.startsWith('mysql') || last.startsWith('mariadb')) engine = 'mysql'\n else if (last.startsWith('mongo')) engine = 'mongodb'\n else if (last.startsWith('redis')) engine = 'redis'\n else if (last.startsWith('sqlite')) engine = 'sqlite'\n if (!engine) return null\n // Strip everything after the major version digit run; \"15-alpine\" -> \"15\".\n const versionMatch = tag.match(/^(\\d+(?:\\.\\d+){0,2})/)\n return {\n engine,\n engineVersion: versionMatch ? versionMatch[1]! : 'unknown',\n }\n}\n","import path from 'node:path'\nimport { readIfExists, parseConnectionString, schemeToEngine, type DbConfig } from './shared.js'\n\n// Prisma's schema file declares datasources of the form:\n//\n// datasource db {\n// provider = \"postgresql\"\n// url = env(\"DATABASE_URL\")\n// }\n//\n// We match the provider directly. URLs come in via env() so we can't resolve\n// them statically; host/database fall back to placeholders so the DatabaseNode\n// id remains deterministic per service.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const schemaPath = path.join(serviceDir, 'prisma', 'schema.prisma')\n const content = await readIfExists(schemaPath)\n if (!content) return []\n\n const block = content.match(/datasource\\s+\\w+\\s*\\{([^}]*)\\}/s)\n if (!block) return []\n const body = block[1] ?? ''\n\n const providerMatch = body.match(/provider\\s*=\\s*\"([^\"]+)\"/)\n if (!providerMatch) return []\n const engine = schemeToEngine(providerMatch[1]!)\n if (!engine) return []\n\n const urlMatch = body.match(/url\\s*=\\s*\"([^\"]+)\"/)\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: schemaPath }]\n }\n\n return [\n {\n host: `${engine}-prisma`,\n database: '',\n engine,\n engineVersion: 'unknown',\n sourceFile: schemaPath,\n },\n ]\n}\n\nexport const prismaParser = { name: 'prisma', parse }\n","import { findFirst, readIfExists, parseConnectionString, schemeToEngine, type DbConfig } from './shared.js'\n\nconst DIALECT_TO_ENGINE: Record<string, string> = {\n postgresql: 'postgresql',\n postgres: 'postgresql',\n pg: 'postgresql',\n mysql: 'mysql',\n mysql2: 'mysql',\n sqlite: 'sqlite',\n 'better-sqlite': 'sqlite',\n}\n\n// Drizzle's drizzle.config.{ts,js,mjs} declares a `dialect` plus credentials.\n// We can't safely eval the file, but the relevant bits are simple key/value\n// expressions — regex-extracted to stay sandbox-clean and dep-free.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'drizzle.config.ts',\n 'drizzle.config.js',\n 'drizzle.config.mjs',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const dialectMatch = content.match(/dialect\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (!dialectMatch) return []\n const engine =\n DIALECT_TO_ENGINE[dialectMatch[1]!.toLowerCase()] ?? schemeToEngine(dialectMatch[1]!)\n if (!engine) return []\n\n const urlMatch = content.match(\n /(?:url|connectionString)\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n )\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: filePath }]\n }\n const hostMatch = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (hostMatch) {\n const portMatch = content.match(/port\\s*:\\s*(\\d+)/)\n const dbMatch = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n return [\n {\n host: hostMatch[1]!,\n port: portMatch ? Number(portMatch[1]) : undefined,\n database: dbMatch?.[1] ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n }\n return [\n { host: `${engine}-drizzle`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath },\n ]\n}\n\nexport const drizzleParser = { name: 'drizzle', parse }\n","import { findFirst, readIfExists, parseConnectionString, type DbConfig } from './shared.js'\n\nconst CLIENT_TO_ENGINE: Record<string, string> = {\n pg: 'postgresql',\n postgres: 'postgresql',\n postgresql: 'postgresql',\n mysql: 'mysql',\n mysql2: 'mysql',\n sqlite3: 'sqlite',\n 'better-sqlite3': 'sqlite',\n}\n\n// knexfile.{js,ts} declares a client (one of pg/mysql/sqlite/...) plus a\n// connection string or host/port object. We pick whichever shape is in the\n// file and ignore environment-driven values we can't resolve statically.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'knexfile.js',\n 'knexfile.ts',\n 'knexfile.cjs',\n 'knexfile.mjs',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const clientMatch = content.match(/client\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (!clientMatch) return []\n const engine = CLIENT_TO_ENGINE[clientMatch[1]!.toLowerCase()]\n if (!engine) return []\n\n const urlMatch = content.match(\n /connection\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n )\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: filePath }]\n }\n\n const host = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n if (host) {\n const port = content.match(/port\\s*:\\s*(\\d+)/)?.[1]\n const database = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n return [\n {\n host,\n port: port ? Number(port) : undefined,\n database,\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n }\n\n return [{ host: `${engine}-knex`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath }]\n}\n\nexport const knexParser = { name: 'knex', parse }\n","import path from 'node:path'\nimport { exists, readJson, readYaml } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface OrmConfigEntry {\n type?: string\n host?: string\n port?: number\n database?: string\n}\n\n// ormconfig.{json,yaml,yml} — TypeORM's legacy config file. Single object or\n// an array of named connections; we walk both.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n for (const candidate of ['ormconfig.json', 'ormconfig.yaml', 'ormconfig.yml']) {\n const abs = path.join(serviceDir, candidate)\n if (!(await exists(abs))) continue\n const raw = candidate.endsWith('.json')\n ? await readJson<OrmConfigEntry | OrmConfigEntry[]>(abs)\n : await readYaml<OrmConfigEntry | OrmConfigEntry[]>(abs)\n const entries = Array.isArray(raw) ? raw : [raw]\n\n const out: DbConfig[] = []\n for (const entry of entries) {\n if (!entry?.type || !entry.host) continue\n const engine = schemeToEngine(entry.type)\n if (!engine) continue\n out.push({\n host: entry.host,\n port: entry.port,\n database: entry.database ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: abs,\n })\n }\n if (out.length > 0) return out\n }\n return []\n}\n\nexport const ormconfigParser = { name: 'ormconfig', parse }\n","import { findFirst, readIfExists, schemeToEngine, type DbConfig } from './shared.js'\n\n// TypeORM's modern shape: `new DataSource({ type: 'postgres', host, port, ... })`\n// in a data-source.ts (or .js). We regex for the type/host/port/database keys\n// in the first DataSource literal we find.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'data-source.ts',\n 'data-source.js',\n 'src/data-source.ts',\n 'src/data-source.js',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const block = content.match(/new\\s+DataSource\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)/)\n const body = block ? block[1]! : content\n\n const typeMatch = body.match(/type\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n const host = body.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n if (!typeMatch || !host) return []\n\n const engine = schemeToEngine(typeMatch[1]!)\n if (!engine) return []\n\n const port = body.match(/port\\s*:\\s*(\\d+)/)?.[1]\n const database = body.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n\n return [\n {\n host,\n port: port ? Number(port) : undefined,\n database,\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n}\n\nexport const typeormParser = { name: 'typeorm', parse }\n","import path from 'node:path'\nimport { exists, readJson } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface SequelizeConfigEntry {\n dialect?: string\n host?: string\n port?: number\n database?: string\n}\n\ntype SequelizeConfig = Record<string, SequelizeConfigEntry>\n\n// Sequelize stores per-environment configs under config/config.json. We read\n// every named environment so a service that declares production + staging\n// surfaces both DB targets.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const configPath = path.join(serviceDir, 'config', 'config.json')\n if (!(await exists(configPath))) return []\n const raw = await readJson<SequelizeConfig>(configPath)\n\n const out: DbConfig[] = []\n const seen = new Set<string>()\n for (const entry of Object.values(raw)) {\n if (!entry?.dialect || !entry.host) continue\n const engine = schemeToEngine(entry.dialect)\n if (!engine) continue\n const key = `${engine}://${entry.host}:${entry.port ?? ''}/${entry.database ?? ''}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push({\n host: entry.host,\n port: entry.port,\n database: entry.database ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: configPath,\n })\n }\n return out\n}\n\nexport const sequelizeParser = { name: 'sequelize', parse }\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport { engineFromImage, type DbConfig } from './shared.js'\n\ninterface ComposeService {\n image?: string\n ports?: (string | number)[]\n environment?: Record<string, string> | string[]\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\nfunction portFromService(svc: ComposeService): number | undefined {\n for (const raw of svc.ports ?? []) {\n const str = String(raw)\n // \"5432:5432\", \"5432\", or \"host:5432\" → take the trailing port.\n const last = str.split(':').pop()\n const n = Number(last)\n if (Number.isFinite(n) && n > 0) return n\n }\n return undefined\n}\n\nfunction databaseFromEnv(svc: ComposeService): string {\n const env = svc.environment\n const get = (key: string): string | undefined => {\n if (!env) return undefined\n if (Array.isArray(env)) {\n for (const line of env) {\n const [k, v] = line.split('=')\n if (k === key) return v\n }\n return undefined\n }\n return env[key]\n }\n return get('POSTGRES_DB') ?? get('MYSQL_DATABASE') ?? get('MONGO_INITDB_DATABASE') ?? ''\n}\n\n// Service-local docker-compose.yml — every service whose image we recognise\n// becomes a candidate DB. The compose service name doubles as the host since\n// that's how peer services on the same compose network reach it.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(serviceDir, name)\n if (!(await exists(abs))) continue\n const raw = await readYaml<ComposeFile>(abs)\n if (!raw?.services) return []\n\n const out: DbConfig[] = []\n for (const [serviceName, svc] of Object.entries(raw.services)) {\n if (!svc.image) continue\n const meta = engineFromImage(svc.image)\n if (!meta) continue\n out.push({\n host: serviceName,\n port: portFromService(svc),\n database: databaseFromEnv(svc),\n engine: meta.engine,\n engineVersion: meta.engineVersion,\n sourceFile: abs,\n })\n }\n return out\n }\n return []\n}\n\nexport const dockerComposeParser = { name: 'docker-compose', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ConfigNode, GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n configId,\n confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n IGNORED_DIRS,\n isConfigFile,\n isPythonVenvDir,\n makeEdgeId,\n type DiscoveredService,\n} from './shared.js'\n\n// Walk a service directory and collect every config file path\n// (yaml/yml + .env-shaped). We deliberately stop at file paths here so nothing\n// in this module reads file contents — .env files routinely carry secrets\n// (ADR-016).\nexport async function walkConfigFiles(dir: string): Promise<string[]> {\n const out: string[] = []\n async function walk(current: string): Promise<void> {\n const entries = await fs.readdir(current, { withFileTypes: true })\n for (const entry of entries) {\n const full = path.join(current, entry.name)\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n if (await isPythonVenvDir(full)) continue\n await walk(full)\n } else if (entry.isFile() && isConfigFile(entry.name).match) {\n out.push(full)\n }\n }\n }\n await walk(dir)\n return out\n}\n\n// Phase 3 — turn each config file into a ConfigNode with a CONFIGURED_BY edge\n// from its owning service.\nexport async function addConfigNodes(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n for (const service of services) {\n const configFiles = await walkConfigFiles(service.dir)\n for (const file of configFiles) {\n const relPath = path.relative(scanPath, file)\n const node: ConfigNode = {\n id: configId(relPath),\n type: NodeType.ConfigNode,\n name: path.basename(file),\n path: relPath,\n fileType: isConfigFile(path.basename(file)).fileType,\n }\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n // ConfigNode existence is a direct file fact (ADR-016) — graded at the\n // structural tier per ADR-066.\n const edge: GraphEdge = {\n id: makeEdgeId(service.node.id, node.id, EdgeType.CONFIGURED_BY),\n source: service.node.id,\n target: node.id,\n type: EdgeType.CONFIGURED_BY,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: relPath.split(path.sep).join('/') },\n }\n if (!graph.hasEdge(edge.id)) {\n graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n","import type { GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForExtracted,\n passesExtractedFloor,\n} from '@neat.is/types'\nimport { noteExtractedDropped } from '../errors.js'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n isTestPath,\n makeEdgeId,\n maskCommentsInSource,\n type DiscoveredService,\n} from '../shared.js'\nimport { addHttpCallEdges } from './http.js'\nimport { ensureFileNode, loadSourceFiles, toPosix, type ExternalEndpoint } from './shared.js'\nimport { kafkaEndpointsFromFile } from './kafka.js'\nimport { redisEndpointsFromFile } from './redis.js'\nimport { awsEndpointsFromFile } from './aws.js'\nimport { grpcEndpointsFromFile } from './grpc.js'\n\nexport interface CallExtractResult {\n nodesAdded: number\n edgesAdded: number\n}\n\nfunction edgeTypeFromEndpoint(ep: ExternalEndpoint): (typeof EdgeType)[keyof typeof EdgeType] {\n switch (ep.edgeType) {\n case 'PUBLISHES_TO':\n return EdgeType.PUBLISHES_TO\n case 'CONSUMES_FROM':\n return EdgeType.CONSUMES_FROM\n default:\n return EdgeType.CALLS\n }\n}\n\nfunction isAwsKind(kind: string): boolean {\n return (\n kind.startsWith('aws-') ||\n kind.startsWith('s3') ||\n kind.startsWith('dynamodb')\n )\n}\n\nasync function addExternalEndpointEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<CallExtractResult> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const files = await loadSourceFiles(service.dir)\n const endpoints: ExternalEndpoint[] = []\n for (const file of files) {\n // ADR-065 #1 — test-scope exclusion. Tests stay registered as\n // service-internal (via the file walk earlier); only outbound\n // endpoint inference from them is filtered.\n if (isTestPath(file.path)) continue\n // ADR-065 #2 — comment-body exclusion. The regex-based extractors\n // (redis / kafka / aws / grpc) scan raw file.content; URLs inside\n // JSDoc / line / block comments leaked through to the graph in the\n // v0.3.0 medusa run. Mask comments while preserving line/column for\n // evidence line-mapping.\n const masked = maskCommentsInSource(file.content)\n const maskedFile = { path: file.path, content: masked }\n endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir))\n }\n if (endpoints.length === 0) continue\n\n const seenEdges = new Set<string>()\n for (const ep of endpoints) {\n if (!graph.hasNode(ep.infraId)) {\n const node: InfraNode = {\n id: ep.infraId,\n type: NodeType.InfraNode,\n name: ep.name,\n // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,\n // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the\n // bucket / table kinds from aws.ts.\n provider: isAwsKind(ep.kind) ? 'aws' : 'self',\n kind: ep.kind,\n }\n graph.addNode(node.id, node)\n nodesAdded++\n }\n\n const edgeType = edgeTypeFromEndpoint(ep)\n const confidence = confidenceForExtracted(ep.confidenceKind)\n // File-first (file-awareness.md §1): the endpoint relationship originates\n // from the file the call site lives in, with the owning service\n // ──CONTAINS──▶ file edge alongside it (§2). File-node existence is\n // independent of edge-target precision (ADR-089 amendment) — a matched\n // call site is a parsed fact, so the FileNode + CONTAINS materialize\n // regardless of how confident we are about the resolved target.\n const relFile = toPosix(ep.evidence.file)\n const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relFile,\n )\n nodesAdded += n\n edgesAdded += e\n // Precision floor (ADR-066 §3). Only the file→target edge is gated:\n // sub-threshold candidates are recorded as drops (banner accounting) and\n // never added to the graph; the file and its call site still surface.\n if (!passesExtractedFloor(confidence)) {\n noteExtractedDropped({\n source: fileNodeId,\n target: ep.infraId,\n type: edgeType,\n confidence,\n confidenceKind: ep.confidenceKind,\n evidence: ep.evidence,\n })\n continue\n }\n const edgeId = makeEdgeId(fileNodeId, ep.infraId, edgeType)\n if (seenEdges.has(edgeId)) continue\n seenEdges.add(edgeId)\n if (!graph.hasEdge(edgeId)) {\n const edge: GraphEdge = {\n id: edgeId,\n source: fileNodeId,\n target: ep.infraId,\n type: edgeType,\n provenance: Provenance.EXTRACTED,\n confidence,\n evidence: ep.evidence,\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n\nexport async function addCallEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<CallExtractResult> {\n const http = await addHttpCallEdges(graph, services)\n const ext = await addExternalEndpointEdges(graph, services)\n return {\n nodesAdded: http.nodesAdded + ext.nodesAdded,\n edgesAdded: http.edgesAdded + ext.edgesAdded,\n }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport Python from 'tree-sitter-python'\nimport type { GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n Provenance,\n confidenceForExtracted,\n passesExtractedFloor,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n isTestPath,\n makeEdgeId,\n urlMatchesHost,\n type DiscoveredService,\n} from '../shared.js'\nimport { recordExtractionError, noteExtractedDropped } from '../errors.js'\nimport { ensureFileNode, loadSourceFiles, snippet, toPosix } from './shared.js'\n\n// JS uses `string_fragment` for the textual interior of a template/string;\n// Python uses `string_content` inside a `string` node. Either way we want the\n// raw textual content (no quotes), so we accept both.\nconst STRING_LITERAL_NODE_TYPES = new Set(['string_fragment', 'string_content'])\n\n// ADR-065 #3 — JSX external-link exclusion. Tags whose URL-attr strings are\n// user-clickable hyperlinks, not service-to-service calls.\nconst JSX_EXTERNAL_LINK_TAGS = new Set(['a', 'Link', 'NavLink', 'ExternalLink', 'Anchor'])\n\n// Walk upward from a string-literal node to detect whether it sits inside a\n// JSX attribute on an external-link element. Returns true if the literal\n// should be filtered.\nfunction isInsideJsxExternalLink(node: Parser.SyntaxNode): boolean {\n let cursor: Parser.SyntaxNode | null = node.parent\n // Step out of the string wrapper if needed (parent is `string` /\n // `template_string`).\n while (cursor) {\n if (cursor.type === 'jsx_attribute') {\n // The element that owns this attribute. jsx_attribute lives inside\n // jsx_opening_element / jsx_self_closing_element.\n let owner: Parser.SyntaxNode | null = cursor.parent\n while (owner && owner.type !== 'jsx_opening_element' && owner.type !== 'jsx_self_closing_element') {\n owner = owner.parent\n }\n if (!owner) return false\n // First named child of an opening/self-closing element is the tag name\n // (`identifier` or `member_expression`).\n const tagNode = owner.namedChild(0)\n const tagName = tagNode?.text ?? ''\n // For `<Foo.Bar>` we just want the rightmost ident; pick after the\n // last dot.\n const right = tagName.includes('.') ? tagName.split('.').pop()! : tagName\n return JSX_EXTERNAL_LINK_TAGS.has(right)\n }\n cursor = cursor.parent\n }\n return false\n}\n\n// Collect (literal text, ast-node) pairs so the JSX-context check has the\n// node available. Comment tokens have no string_fragment / string_content\n// children in tree-sitter — JSDoc text lives inside `comment` nodes — so\n// comment-body exclusion comes for free with this AST walk (ADR-065 #2).\nfunction collectStringLiterals(\n node: Parser.SyntaxNode,\n out: { text: string; node: Parser.SyntaxNode }[],\n): void {\n if (STRING_LITERAL_NODE_TYPES.has(node.type)) out.push({ text: node.text, node })\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i)\n if (child) collectStringLiterals(child, out)\n }\n}\n\n// A matched outbound call: the host the URL literal names and the 1-indexed\n// line it sits on. File-first extraction (file-awareness.md §1) originates a\n// CALLS edge from the file the call site lives in, so the position travels with\n// the host rather than being recovered after the fact.\nexport interface HttpCallSite {\n host: string\n line: number\n}\n\n// tree-sitter's node binding copies a string handed to `parser.parse` into a\n// fixed scratch buffer of ~32K code units and throws a bare \"Invalid argument\"\n// once the source is larger — it never names the size as the cause. NEAT's own\n// `cli.ts`, `ingest.ts`, and `installers/javascript.ts` all clear 40K, so the\n// http-call extractor was quietly skipping the three most interesting files in\n// the repo while dogfooding NEAT-on-NEAT. The callback form sidesteps the\n// buffer entirely: tree-sitter pulls the text in chunks we keep well under the\n// limit, so a file of any length parses. Chunking is by `.length` (UTF-16 code\n// units), which is exactly what the buffer counts.\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n return parser.parse((index: number) =>\n index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n )\n}\n\nexport function callsFromSource(\n source: string,\n parser: Parser,\n knownHosts: Set<string>,\n): HttpCallSite[] {\n const tree = parseSource(parser, source)\n const literals: { text: string; node: Parser.SyntaxNode }[] = []\n collectStringLiterals(tree.rootNode, literals)\n const out: HttpCallSite[] = []\n for (const lit of literals) {\n // ADR-065 #3 — JSX external-link exclusion. URL strings on <a>, <Link>,\n // <NavLink>, <ExternalLink>, <Anchor> are user-clickable hyperlinks, not\n // service calls.\n if (isInsideJsxExternalLink(lit.node)) continue\n for (const host of knownHosts) {\n // ADR-065 #5 — exact hostname match (not substring containment).\n // `medusa.cloud` no longer matches `@medusajs/medusa`.\n if (urlMatchesHost(lit.text, host)) {\n out.push({ host, line: lit.node.startPosition.row + 1 })\n }\n }\n }\n return out\n}\n\nfunction makeJsParser(): Parser {\n const p = new Parser()\n p.setLanguage(JavaScript)\n return p\n}\n\nfunction makePyParser(): Parser {\n const p = new Parser()\n p.setLanguage(Python)\n return p\n}\n\n// HTTP CALLS via URL hostname match. Parser is picked per file extension:\n// .py uses tree-sitter-python; everything else uses tree-sitter-javascript.\n//\n// File-first (file-awareness.md §1): each matched call site originates a\n// `file:<svc>:<relPath> ──CALLS──▶ target` edge plus the owning service's\n// CONTAINS edge, rather than collapsing every call in a service to one\n// service-level edge.\n//\n// File-node existence is independent of edge-target precision (file-awareness.md\n// §1, ADR-089 amendment). A matched call site is a parsed fact — the file and\n// its `service ──CONTAINS──▶ file` edge are certain regardless of how confident\n// we are about *what* it calls. So the FileNode + CONTAINS materialize for every\n// matched site; only the file→target CALLS edge is subject to the precision\n// floor. A hostname-shape match (0.2) below the floor surfaces the file and its\n// call site without claiming the resolved target, rather than vanishing whole.\nexport async function addHttpCallEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n const jsParser = makeJsParser()\n const pyParser = makePyParser()\n\n const knownHosts = new Set<string>()\n const hostToNodeId = new Map<string, string>()\n for (const service of services) {\n knownHosts.add(path.basename(service.dir))\n knownHosts.add(service.pkg.name)\n hostToNodeId.set(path.basename(service.dir), service.node.id)\n hostToNodeId.set(service.pkg.name, service.node.id)\n }\n\n let nodesAdded = 0\n let edgesAdded = 0\n for (const service of services) {\n const files = await loadSourceFiles(service.dir)\n // File grain: one file→target CALLS per (file, target) pair, even when a\n // file names the same host on several lines (function-level is deferred).\n const seen = new Set<string>()\n for (const file of files) {\n // ADR-065 #1 — test-scope exclusion.\n if (isTestPath(file.path)) continue\n const parser = path.extname(file.path) === '.py' ? pyParser : jsParser\n let sites: HttpCallSite[]\n try {\n sites = callsFromSource(file.content, parser, knownHosts)\n } catch (err) {\n recordExtractionError('http call extraction', file.path, err)\n continue\n }\n if (sites.length === 0) continue\n const relFile = toPosix(path.relative(service.dir, file.path))\n for (const site of sites) {\n const targetId = hostToNodeId.get(site.host)\n if (!targetId || targetId === service.node.id) continue\n const dedupKey = `${relFile}|${targetId}`\n if (seen.has(dedupKey)) continue\n seen.add(dedupKey)\n // URL-string match against a registered service hostname is the\n // hostname-shape tier per ADR-066 — structurally tight (urlMatchesHost\n // requires scheme + exact hostname) but no framework-aware recognizer\n // confirms the call. Drops below the default precision floor (0.7).\n const confidence = confidenceForExtracted('hostname-shape-match')\n const ev = {\n file: relFile,\n line: site.line,\n snippet: snippet(file.content, site.line),\n }\n // The matched call site is a parsed fact: materialize the FileNode and\n // its `service ──CONTAINS──▶ file` edge regardless of target precision\n // (file-awareness.md §1, ADR-089 amendment). The file surfaces even\n // when the resolved target sits below the floor.\n const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relFile,\n )\n nodesAdded += n\n edgesAdded += e\n // The file→target CALLS edge alone is subject to the precision floor.\n // A sub-floor target is recorded as a drop (banner accounting) and not\n // claimed as a resolved edge — the file and its call site still stand.\n if (!passesExtractedFloor(confidence)) {\n noteExtractedDropped({\n source: fileNodeId,\n target: targetId,\n type: EdgeType.CALLS,\n confidence,\n confidenceKind: 'hostname-shape-match',\n evidence: ev,\n })\n continue\n }\n const edgeId = makeEdgeId(fileNodeId, targetId, EdgeType.CALLS)\n if (!graph.hasEdge(edgeId)) {\n const edge: GraphEdge = {\n id: edgeId,\n source: fileNodeId,\n target: targetId,\n type: EdgeType.CALLS,\n provenance: Provenance.EXTRACTED,\n confidence,\n evidence: ev,\n }\n graph.addEdgeWithKey(edgeId, fileNodeId, targetId, edge)\n edgesAdded++\n }\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { EdgeEvidence, ExtractedConfidenceKind, FileNode, GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForExtracted,\n extractedEdgeId,\n fileId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { IGNORED_DIRS, SERVICE_FILE_EXTENSIONS, isPythonVenvDir } from '../shared.js'\n\nexport interface SourceFile {\n path: string\n content: string\n}\n\nexport interface ExternalEndpoint {\n // Stable id of the InfraNode this evidence implies. Format\n // `infra:<kind>:<name>` so the orchestrator can dedupe across services.\n infraId: string\n // Display name on the InfraNode (e.g., \"orders\" for kafka-topic:orders).\n name: string\n kind: string\n edgeType: 'CALLS' | 'PUBLISHES_TO' | 'CONSUMES_FROM'\n evidence: EdgeEvidence\n // Confidence grade per ADR-066 — set by the per-shape detector. The\n // orchestrator (calls/index.ts) writes this onto the EXTRACTED edge and\n // applies the precision floor before adding the edge to the graph.\n confidenceKind: ExtractedConfidenceKind\n}\n\nexport async function walkSourceFiles(dir: string): Promise<string[]> {\n const out: string[] = []\n async function walk(current: string): Promise<void> {\n const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n const full = path.join(current, entry.name)\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n if (await isPythonVenvDir(full)) continue\n await walk(full)\n } else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(full)\n }\n }\n }\n await walk(dir)\n return out\n}\n\nexport async function loadSourceFiles(dir: string): Promise<SourceFile[]> {\n const paths = await walkSourceFiles(dir)\n const out: SourceFile[] = []\n for (const p of paths) {\n try {\n const content = await fs.readFile(p, 'utf8')\n out.push({ path: p, content })\n } catch {\n // unreadable, skip\n }\n }\n return out\n}\n\n// Locate the line of the first occurrence of `needle` in `text`, 1-indexed.\n// Falls back to line 1 if the needle isn't found verbatim — better to point at\n// the file than to drop the evidence entirely.\nexport function lineOf(text: string, needle: string): number {\n const idx = text.indexOf(needle)\n if (idx < 0) return 1\n return text.slice(0, idx).split('\\n').length\n}\n\nexport function snippet(text: string, line: number): string {\n const lines = text.split('\\n')\n return (lines[line - 1] ?? '').trim()\n}\n\n// Forward-slash a path so a FileNode id is byte-stable across platforms (the\n// `relPath` segment of `file:<service>:<relPath>` must not vary by OS).\nexport function toPosix(p: string): string {\n return p.split('\\\\').join('/')\n}\n\n// Extension → language tag for a FileNode. Returns undefined for extensions we\n// don't name rather than guessing — evidence is never fabricated (§6).\nexport function languageForPath(relPath: string): string | undefined {\n switch (path.extname(relPath).toLowerCase()) {\n case '.py':\n return 'python'\n case '.ts':\n case '.tsx':\n return 'typescript'\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return 'javascript'\n default:\n return undefined\n }\n}\n\n// File-first emission (file-awareness.md §1–2). Ensure the FileNode for\n// `relPath` and the owning `service ──CONTAINS──▶ file` edge both exist, then\n// return the FileNode id so the caller can originate a relationship from it.\n// `relPath` must already be service-relative and forward-slashed (use toPosix).\n// CONTAINS is structural ownership — graded at the 'structural' tier like\n// CONFIGURED_BY, never a flat value. Idempotent: re-running extraction over an\n// unchanged file is a no-op.\nexport function ensureFileNode(\n graph: NeatGraph,\n serviceName: string,\n serviceNodeId: string,\n relPath: string,\n): { fileNodeId: string; nodesAdded: number; edgesAdded: number } {\n let nodesAdded = 0\n let edgesAdded = 0\n const fileNodeId = fileId(serviceName, relPath)\n if (!graph.hasNode(fileNodeId)) {\n const language = languageForPath(relPath)\n const node: FileNode = {\n id: fileNodeId,\n type: NodeType.FileNode,\n service: serviceName,\n path: relPath,\n ...(language ? { language } : {}),\n discoveredVia: 'static',\n }\n graph.addNode(fileNodeId, node)\n nodesAdded++\n }\n const containsId = extractedEdgeId(serviceNodeId, fileNodeId, EdgeType.CONTAINS)\n if (!graph.hasEdge(containsId)) {\n const edge: GraphEdge = {\n id: containsId,\n source: serviceNodeId,\n target: fileNodeId,\n type: EdgeType.CONTAINS,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: relPath },\n }\n graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n edgesAdded++\n }\n return { fileNodeId, nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Match `producer.send({ topic: \"orders\" ... })` and `producer.send({\n// topic: 'orders' })` plus the two-arg form `producer.send(\"orders\", ...)`.\n// Kafka client libraries vary; these two forms cover kafkajs + node-rdkafka\n// well enough for static extraction. Same shape covers consumer.subscribe.\nconst PRODUCER_TOPIC_RE =\n /(?:producer|kafkaProducer)[\\s\\S]{0,40}?\\.send\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst CONSUMER_TOPIC_RE =\n /(?:consumer|kafkaConsumer)[\\s\\S]{0,40}?\\.(?:subscribe|run)\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic[s]?\\s*:\\s*(?:\\[\\s*)?['\"`]([^'\"`]+)['\"`]/g\n\nfunction findAll(re: RegExp, text: string): { topic: string; index: number }[] {\n re.lastIndex = 0\n const out: { topic: string; index: number }[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n out.push({ topic: m[1]!, index: m.index })\n }\n return out\n}\n\nexport function kafkaEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const make = (topic: string, edgeType: 'PUBLISHES_TO' | 'CONSUMES_FROM'): void => {\n const key = `${edgeType}|${topic}`\n if (seen.has(key)) return\n seen.add(key)\n const line = lineOf(file.content, topic)\n out.push({\n infraId: infraId('kafka-topic', topic),\n name: topic,\n kind: 'kafka-topic',\n edgeType,\n // `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})` —\n // framework-aware (kafkajs / node-rdkafka shape). Verified-call-site\n // tier (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n\n for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, 'PUBLISHES_TO')\n for (const { topic } of findAll(CONSUMER_TOPIC_RE, file.content)) make(topic, 'CONSUMES_FROM')\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Redis URLs in source — `redis://host[:port]` or `rediss://...`. We only\n// catch literal strings; env-driven URLs go through the database parsers\n// (.env, ormconfig, etc.) and don't need a CALLS edge.\nconst REDIS_URL_RE = /redis(?:s)?:\\/\\/(?:[^@'\"`\\s]+@)?([^:/'\"`\\s]+)(?::(\\d+))?/g\n\nexport function redisEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n REDIS_URL_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = REDIS_URL_RE.exec(file.content)) !== null) {\n const host = m[1]!\n if (seen.has(host)) continue\n seen.add(host)\n const line = lineOf(file.content, host)\n out.push({\n infraId: infraId('redis', host),\n name: host,\n kind: 'redis',\n edgeType: 'CALLS',\n // `redis://host` URL literal — the scheme is structural support, but no\n // call expression is verified to wire it through. URL-with-structural-\n // support tier (ADR-066).\n confidenceKind: 'url-with-structural-support',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// AWS SDK v3 calls. We catch S3 (`Bucket: \"x\"` near a `S3Client`-using\n// PutObjectCommand / GetObjectCommand / DeleteObjectCommand) and DynamoDB\n// (`TableName: \"x\"` near GetCommand / PutCommand / DynamoDBClient). The\n// pattern is intentionally permissive: a literal Bucket/TableName near an\n// SDK constant is good enough evidence; misses are fine because non-static\n// resources can't be catalogued anyway.\nconst S3_BUCKET_RE = /Bucket\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst DYNAMO_TABLE_RE = /TableName\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\n\nfunction hasMarker(text: string, markers: string[]): boolean {\n return markers.some((m) => text.includes(m))\n}\n\nfunction findAll(re: RegExp, text: string): { name: string; index: number }[] {\n re.lastIndex = 0\n const out: { name: string; index: number }[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n out.push({ name: m[1]!, index: m.index })\n }\n return out\n}\n\nexport function awsEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const make = (kind: string, name: string): void => {\n const key = `${kind}|${name}`\n if (seen.has(key)) return\n seen.add(key)\n const line = lineOf(file.content, name)\n out.push({\n infraId: infraId(kind, name),\n name,\n kind,\n edgeType: 'CALLS',\n // SDK marker (S3Client, GetCommand, etc.) plus a Bucket/TableName\n // literal — framework-aware recognizer, verified-call-site tier\n // (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n\n if (hasMarker(file.content, ['S3Client', 'PutObjectCommand', 'GetObjectCommand', 'DeleteObjectCommand'])) {\n for (const { name } of findAll(S3_BUCKET_RE, file.content)) make('s3-bucket', name)\n }\n if (\n hasMarker(file.content, [\n 'DynamoDBClient',\n 'DynamoDBDocumentClient',\n 'GetCommand',\n 'PutCommand',\n 'QueryCommand',\n 'UpdateCommand',\n 'DeleteCommand',\n ])\n ) {\n for (const { name } of findAll(DYNAMO_TABLE_RE, file.content)) make('dynamodb-table', name)\n }\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Client-construction in JS/TS:\n//\n// const client = new orders_proto.OrderService(...)\n// const client = new OrdersClient('orders.internal:50051', ...)\n// const client = new S3Client({ region: 'us-east-1' })\n//\n// The same `new <Name>Client(...)` shape is used by gRPC client stubs, AWS\n// SDK v3 service clients, and a long tail of other SDKs. v0.3.0 mapped every\n// `*Client(...)` to `infra:grpc-service:*`, which was true for the demo and\n// false for every AWS service medusa imported.\n//\n// Per ADR-065 / #238, classification is import-aware:\n// 1. file imports `@aws-sdk/client-<suffix>` and `<Name>` lowercases to the\n// same alphanumeric tail (`S3Client` ↔ `client-s3`,\n// `CognitoIdentityProviderClient` ↔ `client-cognito-identity-provider`)\n// → kind `aws-<suffix>` (e.g. `infra:aws-s3:S3`).\n// 2. file imports `@grpc/grpc-js` or any `*_grpc_pb` generated stub\n// → kind `grpc-service` (the legitimate gRPC path; demo unchanged).\n// 3. otherwise → kind `service` (the safe default — accurate but\n// uninformative, the v0.3.0 grpc lie is removed).\nconst GRPC_CLIENT_RE = /new\\s+([A-Z][A-Za-z0-9_]*)Client\\s*\\(\\s*['\"`]?([^,'\"`)]+)?/g\nconst AWS_SDK_IMPORT_RE =\n /(?:from\\s+['\"`]|require\\(\\s*['\"`])@aws-sdk\\/client-([a-z0-9-]+)['\"`]/g\nconst GRPC_IMPORT_RE =\n /(?:from\\s+['\"`]|require\\(\\s*['\"`])@grpc\\/grpc-js['\"`]|_grpc_pb['\"`]/\n\nfunction isLikelyAddress(value: string | undefined): boolean {\n if (!value) return false\n return /:\\d{2,5}$/.test(value) || value.includes('.')\n}\n\nfunction normaliseForMatch(s: string): string {\n return s.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n\ninterface ImportContext {\n awsSdkSuffixes: Map<string, string> // normalised → raw suffix (e.g. 's3' → 's3')\n hasGrpcImport: boolean\n}\n\nfunction readImports(content: string): ImportContext {\n const awsSdkSuffixes = new Map<string, string>()\n AWS_SDK_IMPORT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = AWS_SDK_IMPORT_RE.exec(content)) !== null) {\n const raw = m[1]!\n awsSdkSuffixes.set(normaliseForMatch(raw), raw)\n }\n return {\n awsSdkSuffixes,\n hasGrpcImport: GRPC_IMPORT_RE.test(content),\n }\n}\n\nfunction classifyClient(\n symbol: string,\n ctx: ImportContext,\n): { kind: string } | null {\n const key = normaliseForMatch(symbol)\n const awsRaw = ctx.awsSdkSuffixes.get(key)\n if (awsRaw) return { kind: `aws-${awsRaw}` }\n if (ctx.hasGrpcImport) return { kind: 'grpc-service' }\n // ADR-065 #5-adjacent — a bare `new <Name>Client()` with no AWS or gRPC\n // import context is ambiguous; could be an in-process client object\n // (`new QueryClient()` from @tanstack/react-query, `new PrismaClient()`,\n // a domain Client class, etc.). Refuse to emit an edge rather than guess\n // a `service` kind that produces false positives. v0.3.3 medusa run had\n // a QueryClient false positive before this guard.\n return null\n}\n\nexport function grpcEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const ctx = readImports(file.content)\n GRPC_CLIENT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = GRPC_CLIENT_RE.exec(file.content)) !== null) {\n const symbol = m[1]!\n const addr = m[2]?.trim()\n const name = isLikelyAddress(addr) ? addr! : symbol\n if (seen.has(name)) continue\n const classified = classifyClient(symbol, ctx)\n if (!classified) continue\n seen.add(name)\n const { kind } = classified\n const line = lineOf(file.content, m[0])\n out.push({\n infraId: infraId(kind, name),\n name,\n kind,\n edgeType: 'CALLS',\n // `new <Name>Client(...)` with @aws-sdk/* or @grpc/grpc-js import\n // context — import-aware classification per #238. Verified-call-site\n // tier (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n return out\n}\n","import type { NeatGraph } from '../../graph.js'\nimport { type DiscoveredService } from '../shared.js'\nimport { addComposeInfra } from './docker-compose.js'\nimport { addDockerfileRuntimes } from './dockerfile.js'\nimport { addTerraformResources } from './terraform.js'\nimport { addK8sResources } from './k8s.js'\n\nexport interface InfraExtractResult {\n nodesAdded: number\n edgesAdded: number\n}\n\n// Phase 5 — infrastructure. Runs after services so RUNS_ON edges have a\n// ServiceNode to anchor on. Each sub-source contributes its own nodes/edges\n// independently; nothing here mutates ServiceNodes themselves.\nexport async function addInfra(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<InfraExtractResult> {\n const compose = await addComposeInfra(graph, scanPath, services)\n const dockerfile = await addDockerfileRuntimes(graph, services, scanPath)\n const terraform = await addTerraformResources(graph, scanPath)\n const k8s = await addK8sResources(graph, scanPath)\n\n return {\n nodesAdded:\n compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,\n edgesAdded:\n compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded,\n }\n}\n","import path from 'node:path'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, readYaml, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { classifyImage, makeInfraNode } from './shared.js'\n\ninterface ComposeService {\n image?: string\n build?: string | { context?: string }\n depends_on?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\nfunction dependsOnList(value: ComposeService['depends_on']): string[] {\n if (!value) return []\n if (Array.isArray(value)) return value\n return Object.keys(value)\n}\n\nfunction serviceNameToServiceNode(\n name: string,\n services: DiscoveredService[],\n): string | null {\n for (const s of services) {\n if (s.node.name === name || path.basename(s.dir) === name) return s.node.id\n }\n return null\n}\n\n// Project-level docker-compose.yml describes deployment topology. Each compose\n// service that is *not* one of the discovered ServiceNodes becomes an\n// InfraNode (databases, brokers, caches). depends_on lists become DEPENDS_ON\n// edges from the dependent to its dependency, regardless of whether the\n// endpoint is a ServiceNode or InfraNode — the edge itself is the deployment\n// fact, not the role.\nexport async function addComposeInfra(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n let composePath: string | null = null\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(scanPath, name)\n if (await exists(abs)) {\n composePath = abs\n break\n }\n }\n if (!composePath) return { nodesAdded, edgesAdded }\n\n let compose: ComposeFile\n try {\n compose = await readYaml<ComposeFile>(composePath)\n } catch (err) {\n recordExtractionError(\n 'infra docker-compose',\n path.relative(scanPath, composePath),\n err,\n )\n return { nodesAdded, edgesAdded }\n }\n if (!compose?.services) return { nodesAdded, edgesAdded }\n const evidenceFile = path.relative(scanPath, composePath).split(path.sep).join('/')\n\n const composeNameToNodeId = new Map<string, string>()\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const matchedServiceId = serviceNameToServiceNode(composeName, services)\n if (matchedServiceId) {\n composeNameToNodeId.set(composeName, matchedServiceId)\n continue\n }\n const kind = svc.image ? classifyImage(svc.image) : 'container'\n const node = makeInfraNode(kind, composeName)\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n composeNameToNodeId.set(composeName, node.id)\n }\n\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const sourceId = composeNameToNodeId.get(composeName)\n if (!sourceId) continue\n for (const dep of dependsOnList(svc.depends_on)) {\n const targetId = composeNameToNodeId.get(dep)\n if (!targetId) continue\n const edgeId = makeEdgeId(sourceId, targetId, EdgeType.DEPENDS_ON)\n if (graph.hasEdge(edgeId)) continue\n // depends_on declaration from docker-compose.yml — structural deployment\n // fact, structural tier per ADR-066.\n const edge: GraphEdge = {\n id: edgeId,\n source: sourceId,\n target: targetId,\n type: EdgeType.DEPENDS_ON,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: evidenceFile },\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import type { InfraNode } from '@neat.is/types'\nimport { NodeType, infraId } from '@neat.is/types'\n\n// ADR-010 reserves the `infra:` prefix; the kind segment lets traversal and\n// MCP tools sub-type without inventing a new top-level NodeType per source.\nexport function makeInfraNode(\n kind: string,\n name: string,\n provider = 'self',\n extras?: { region?: string },\n): InfraNode {\n return {\n id: infraId(kind, name),\n type: NodeType.InfraNode,\n name,\n provider,\n kind,\n ...(extras?.region ? { region: extras.region } : {}),\n }\n}\n\n// Stable kind for an image string like \"postgres:15-alpine\" or \"mysql:8\".\n// The image name itself ends up in the InfraNode `name` field; this function\n// only classifies what the image *is*, so callers can group similar runtimes.\nexport function classifyImage(image: string): string {\n const lower = image.toLowerCase()\n const repo = lower.split(':')[0]!\n const last = repo.split('/').pop() ?? repo\n if (last.startsWith('postgres')) return 'postgres'\n if (last.startsWith('mysql') || last.startsWith('mariadb')) return 'mysql'\n if (last.startsWith('mongo')) return 'mongodb'\n if (last.startsWith('redis')) return 'redis'\n if (last.startsWith('rabbitmq')) return 'rabbitmq'\n if (last.startsWith('kafka') || last.includes('kafka')) return 'kafka'\n if (last.startsWith('memcached')) return 'memcached'\n return 'container'\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { makeInfraNode } from './shared.js'\n\n// Pull the first non-`scratch` `FROM` line out of a Dockerfile, ignoring\n// multi-stage `as` aliases. Returns the image including tag (e.g. `node:20`,\n// `python:3.11-slim`). Multi-stage builds report the *runtime* image — the\n// last FROM that isn't aliasing a previous stage.\nfunction runtimeImage(content: string): string | null {\n const lines = content.split('\\n')\n let last: string | null = null\n for (const raw of lines) {\n const line = raw.trim()\n if (!line || line.startsWith('#')) continue\n if (!/^from\\s+/i.test(line)) continue\n const tokens = line.split(/\\s+/)\n const image = tokens[1]\n if (!image || image.toLowerCase() === 'scratch') continue\n last = image\n }\n return last\n}\n\n// For each ServiceNode that has a Dockerfile in its dir, emit a\n// `infra:container-image:<image>` InfraNode and a RUNS_ON edge from the\n// service to the image.\nexport async function addDockerfileRuntimes(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const dockerfilePath = path.join(service.dir, 'Dockerfile')\n if (!(await exists(dockerfilePath))) continue\n let content: string\n try {\n content = await fs.readFile(dockerfilePath, 'utf8')\n } catch (err) {\n recordExtractionError(\n 'infra dockerfile',\n path.relative(scanPath, dockerfilePath),\n err,\n )\n continue\n }\n const image = runtimeImage(content)\n if (!image) continue\n\n const node = makeInfraNode('container-image', image)\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n\n const edgeId = makeEdgeId(service.node.id, node.id, EdgeType.RUNS_ON)\n if (!graph.hasEdge(edgeId)) {\n // Dockerfile FROM line — direct file fact, structural tier per ADR-066.\n const edge: GraphEdge = {\n id: edgeId,\n source: service.node.id,\n target: node.id,\n type: EdgeType.RUNS_ON,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: {\n file: path.relative(scanPath, dockerfilePath).split(path.sep).join('/'),\n },\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { NeatGraph } from '../../graph.js'\nimport { IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { makeInfraNode } from './shared.js'\n\n// Light pass: catalogue `resource \"aws_*\" \"name\"` blocks in any *.tf file.\n// We don't interpret references — a real Terraform backend would resolve\n// those — but the resource-type/name pair is enough to register the node so\n// later cross-references can hang off it.\nconst RESOURCE_RE = /resource\\s+\"(aws_[A-Za-z0-9_]+)\"\\s+\"([A-Za-z0-9_-]+)\"/g\n\nasync function walkTfFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name) || entry.name === '.terraform') continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkTfFiles(child, depth + 1, max)))\n } else if (entry.isFile() && entry.name.endsWith('.tf')) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\nexport async function addTerraformResources(\n graph: NeatGraph,\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n const files = await walkTfFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n RESOURCE_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = RESOURCE_RE.exec(content)) !== null) {\n const kind = m[1]!\n const name = m[2]!\n const node = makeInfraNode(kind, name, 'aws')\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded: 0 }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseAllDocuments } from 'yaml'\nimport type { NeatGraph } from '../../graph.js'\nimport { CONFIG_FILE_EXTENSIONS, IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { makeInfraNode } from './shared.js'\n\ninterface K8sDoc {\n kind?: string\n metadata?: { name?: string; namespace?: string }\n}\n\nconst K8S_KIND_TO_INFRA_KIND: Record<string, string> = {\n Service: 'k8s-service',\n Deployment: 'k8s-deployment',\n StatefulSet: 'k8s-statefulset',\n DaemonSet: 'k8s-daemonset',\n CronJob: 'k8s-cronjob',\n Job: 'k8s-job',\n Ingress: 'k8s-ingress',\n}\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkYamlFiles(child, depth + 1, max)))\n } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\n// Multi-document YAML with kind/metadata.name. We keep the matching simple:\n// any file whose first doc looks k8s-shaped. The match is on `kind` only —\n// random YAML configs (db-config.yaml, etc.) are usually flat objects with no\n// `kind` field, so they're ignored without false positives.\nexport async function addK8sResources(\n graph: NeatGraph,\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n const files = await walkYamlFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n let docs: K8sDoc[]\n try {\n docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n } catch {\n continue\n }\n for (const doc of docs) {\n if (!doc?.kind || !doc.metadata?.name) continue\n const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind]\n if (!infraKind) continue\n const namespaced = doc.metadata.namespace\n ? `${doc.metadata.namespace}/${doc.metadata.name}`\n : doc.metadata.name\n const node = makeInfraNode(infraKind, namespaced, 'kubernetes')\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded: 0 }\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\n\n// Drop any FileNode left with no edges. A FileNode exists to originate a\n// relationship (file-awareness.md §1); once its CALLS / CONTAINS edges are\n// retired and no OBSERVED traffic remains, the bare node carries nothing and\n// goes too. Called after edge retirement so the snapshot stays consistent with\n// what's on disk. Returns the count dropped.\nfunction dropOrphanedFileNodes(graph: NeatGraph): number {\n const orphans: string[] = []\n graph.forEachNode((id, attrs) => {\n if ((attrs as GraphNode).type !== NodeType.FileNode) return\n if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {\n orphans.push(id)\n }\n })\n for (const id of orphans) graph.dropNode(id)\n return orphans.length\n}\n\n// Drop every EXTRACTED edge whose evidence.file matches the given path, then\n// sweep any FileNode the retirement left orphaned. Called from watch.ts before\n// re-running an extract phase, so the producer's idempotent re-write recreates\n// only the edges that still apply. Edges from the deleted code stay deleted.\n// See docs/contracts/static-extraction.md §Ghost-edge cleanup. Mutation\n// authority lives under extract/* per ADR-030, so the dropEdge call must happen\n// here, not in watch.ts. The returned count is edges dropped (FileNode cleanup\n// is a structural side effect, not a ghost-edge count).\nexport function retireEdgesByFile(graph: NeatGraph, file: string): number {\n const normalized = file.split('\\\\').join('/')\n const toDrop: string[] = []\n graph.forEachEdge((id, attrs) => {\n const edge = attrs as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) return\n if (!edge.evidence?.file) return\n if (edge.evidence.file === normalized) toDrop.push(id)\n })\n for (const id of toDrop) graph.dropEdge(id)\n dropOrphanedFileNodes(graph)\n return toDrop.length\n}\n\n// #140 — full-pass cleanup. Walk every EXTRACTED edge in the graph; if its\n// `evidence.file` cannot be resolved on disk against the scan root or any\n// discovered service directory, drop it. extractFromDirectory calls this at\n// the end of every pass so a daemon bootstrap (or a re-init after the\n// operator deleted some source) gets a snapshot consistent with what's\n// actually on disk.\n//\n// Handles the deleted-file half of the ghost-edge bug. The edited-file half\n// (file still exists, producer no longer emits the edge) is handled by\n// watch.ts's per-file `retireEdgesByFile` on the mtime trigger.\n//\n// Path resolution is tolerant: producers in this tree are inconsistent about\n// whether `evidence.file` is scanPath-relative (configs, databases, infra)\n// or service-dir-relative (calls/*). We try every candidate base before\n// concluding the file is gone — the cost is one extra `existsSync` per\n// service dir per ghost candidate, which is cheap.\nexport function retireExtractedEdgesByMissingFile(\n graph: NeatGraph,\n scanPath: string,\n serviceDirs: readonly string[] = [],\n): number {\n const toDrop: string[] = []\n const bases = [scanPath, ...serviceDirs]\n graph.forEachEdge((id, attrs) => {\n const edge = attrs as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) return\n const evidenceFile = edge.evidence?.file\n if (!evidenceFile) return\n if (path.isAbsolute(evidenceFile)) {\n if (!existsSync(evidenceFile)) toDrop.push(id)\n return\n }\n // Tolerant: the file is \"present\" if any base resolves it.\n const found = bases.some((base) => existsSync(path.join(base, evidenceFile)))\n if (!found) toDrop.push(id)\n })\n for (const id of toDrop) graph.dropEdge(id)\n dropOrphanedFileNodes(graph)\n return toDrop.length\n}\n","// computeDivergences — the thesis surface, derived (ADR-060).\n//\n// Walks the live graph and surfaces the five locked divergence shapes:\n// missing-observed, missing-extracted, version-mismatch, host-mismatch,\n// and compat-violation. Pure: no I/O, no mutation, no async. The function\n// operates on a NeatGraph reference and returns a fresh DivergenceResult\n// each call — there is no persistence (binding rule 2).\n//\n// Mutation authority (ADR-030 / contract #3) is locked to ingest.ts and\n// extract/*; this module reads only. The contract test\n// `packages/core/test/audits/contracts.test.ts` enforces it.\n\nimport type {\n CompatRuleRef,\n Divergence,\n DivergenceResult,\n DivergenceType,\n GraphEdge,\n GraphNode,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n DivergenceResultSchema,\n EdgeType,\n NodeType,\n parseEdgeId,\n Provenance,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n compatPairs,\n deprecatedApis,\n} from './compat.js'\nimport { confidenceForEdge } from './traverse.js'\n\nexport interface DivergenceQueryOpts {\n // Filter the result to a subset of divergence types. Undefined keeps all\n // five. Empty set returns nothing.\n type?: ReadonlySet<DivergenceType>\n // Drop divergences below this confidence threshold. Undefined keeps all.\n minConfidence?: number\n // Scope to divergences that involve this node (as source or target).\n node?: string\n}\n\n// (source, target, type) → which provenance variants are present. Each\n// bucket is the unit the missing-observed / missing-extracted detectors\n// operate over.\ninterface EdgeBucket {\n source: string\n target: string\n type: GraphEdge['type']\n extracted?: GraphEdge\n observed?: GraphEdge\n inferred?: GraphEdge\n stale?: GraphEdge\n}\n\nfunction bucketKey(source: string, target: string, type: string): string {\n return `${type}|${source}|${target}`\n}\n\nfunction bucketEdges(graph: NeatGraph): Map<string, EdgeBucket> {\n const buckets = new Map<string, EdgeBucket>()\n graph.forEachEdge((id, attrs) => {\n const e = attrs as GraphEdge\n const parsed = parseEdgeId(id)\n // parseEdgeId can fall through to EXTRACTED for unknown shapes — fall\n // back to the edge's own provenance when the id doesn't parse cleanly.\n const provenance = parsed?.provenance ?? e.provenance\n const key = bucketKey(e.source, e.target, e.type)\n const cur =\n buckets.get(key) ?? { source: e.source, target: e.target, type: e.type }\n switch (provenance) {\n case Provenance.EXTRACTED:\n cur.extracted = e\n break\n case Provenance.OBSERVED:\n cur.observed = e\n break\n case Provenance.INFERRED:\n cur.inferred = e\n break\n default:\n // STALE rides on what used to be an OBSERVED edge — the id format\n // stays OBSERVED per identity.ts, so this branch is mostly defensive.\n if (e.provenance === Provenance.STALE) cur.stale = e\n }\n buckets.set(key, cur)\n })\n return buckets\n}\n\nfunction nodeIsFrontier(graph: NeatGraph, nodeId: string): boolean {\n if (!graph.hasNode(nodeId)) return false\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n return attrs.type === NodeType.FrontierNode\n}\n\nfunction clampConfidence(n: number): number {\n if (!Number.isFinite(n)) return 0\n return Math.max(0, Math.min(1, n))\n}\n\nfunction reasonForMissingObserved(source: string, target: string, type: string): string {\n return `Code declares ${source} → ${target} (${type}) but no production traffic has been observed for this edge.`\n}\n\nfunction reasonForMissingExtracted(source: string, target: string, type: string): string {\n return `Production observed ${source} → ${target} (${type}) but static analysis did not surface this edge.`\n}\n\nconst RECOMMENDATION_MISSING_OBSERVED =\n 'Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.'\nconst RECOMMENDATION_MISSING_EXTRACTED =\n 'Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.'\nconst RECOMMENDATION_HOST_MISMATCH =\n 'Check environment-specific config overrides — the runtime host differs from what static configuration declares.'\n\n// ADR-066 §4 — reweight against graded confidence.\n//\n// `missing-extracted` (OBSERVED-led) cascades from the OBSERVED edge's\n// graded confidence (signal-block grade per ADR-066 §2). `missing-observed`\n// weights by the EXTRACTED edge's graded confidence (per-extractor grade\n// per ADR-066 §1). Sub-floor EXTRACTED candidates never enter the graph\n// (precision floor, §3) so what surfaces here is backed by structural or\n// verified-call-site evidence.\n//\n// Falls back to confidenceForEdge for legacy edges loaded from a pre-v0.3.4\n// snapshot that don't carry a stored `confidence` field.\nfunction gradedConfidence(edge: GraphEdge): number {\n if (typeof edge.confidence === 'number') return clampConfidence(edge.confidence)\n return clampConfidence(confidenceForEdge(edge))\n}\n\nfunction detectMissingDivergences(\n graph: NeatGraph,\n bucket: EdgeBucket,\n): Divergence[] {\n const out: Divergence[] = []\n\n // CONTAINS is structural ownership (service → file), not a declared-vs-\n // observed relationship — comparing its tiers would surface an OTel-only\n // file node as a spurious missing-extracted finding (file-awareness.md §2).\n // Divergence compares CALLS-family edges at the shared grain (§7).\n if (bucket.type === EdgeType.CONTAINS) return out\n\n if (bucket.extracted && !bucket.observed) {\n // Skip when the would-be target is a FrontierNode — those represent\n // unresolved span peers, not real entities we expect OBSERVED traffic\n // to. The coexistence contract is between EXTRACTED and OBSERVED on\n // real nodes; FRONTIER is unknown territory.\n if (!nodeIsFrontier(graph, bucket.target)) {\n // ADR-066 §4 — weight by the EXTRACTED edge's graded confidence.\n // Substring/hostname-shape candidates already dropped at the precision\n // floor; what remains is structural or verified-call-site evidence.\n out.push({\n type: 'missing-observed',\n source: bucket.source,\n target: bucket.target,\n edgeType: bucket.type,\n extracted: bucket.extracted,\n confidence: gradedConfidence(bucket.extracted),\n reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),\n recommendation: RECOMMENDATION_MISSING_OBSERVED,\n })\n }\n }\n\n if (bucket.observed && !bucket.extracted) {\n // ADR-066 §4 — cascade from the OBSERVED edge's graded confidence.\n // OBSERVED-led finding; the headline divergence type.\n out.push({\n type: 'missing-extracted',\n source: bucket.source,\n target: bucket.target,\n edgeType: bucket.type,\n observed: bucket.observed,\n confidence: gradedConfidence(bucket.observed),\n reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),\n recommendation: RECOMMENDATION_MISSING_EXTRACTED,\n })\n }\n\n return out\n}\n\n// Returns the declared host of the service's static DB target, when\n// recoverable. ServiceNode.dbConnectionTarget is the static-extraction\n// surface for \"this service connects to X\" — `X` is host[:port] or a\n// docker-compose-style service name. Empty / undefined means we have no\n// EXTRACTED host to compare against and host-mismatch can't fire.\nfunction declaredHostFor(svc: ServiceNode): string | null {\n const raw = svc.dbConnectionTarget?.trim()\n if (!raw) return null\n // Strip a trailing port if present so it lines up with DatabaseNode.host\n // (ADR-028 §6 — DatabaseNode id excludes port).\n const colon = raw.lastIndexOf(':')\n if (colon === -1) return raw\n const port = raw.slice(colon + 1)\n if (/^\\d+$/.test(port)) return raw.slice(0, colon)\n return raw\n}\n\nfunction hasExtractedConfiguredBy(graph: NeatGraph, svcId: string): boolean {\n for (const edgeId of graph.outboundEdges(svcId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type === EdgeType.CONFIGURED_BY && e.provenance === Provenance.EXTRACTED) {\n return true\n }\n }\n return false\n}\n\nfunction detectHostMismatch(\n graph: NeatGraph,\n svcId: string,\n svc: ServiceNode,\n): Divergence[] {\n const declaredHost = declaredHostFor(svc)\n if (!declaredHost) return []\n if (!hasExtractedConfiguredBy(graph, svcId)) return []\n\n const out: Divergence[] = []\n for (const edgeId of graph.outboundEdges(svcId)) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.type !== EdgeType.CONNECTS_TO) continue\n if (edge.provenance !== Provenance.OBSERVED) continue\n const target = graph.getNodeAttributes(edge.target) as GraphNode\n if (target.type !== NodeType.DatabaseNode) continue\n const observedHost = target.host?.trim()\n if (!observedHost) continue\n if (observedHost === declaredHost) continue\n\n out.push({\n type: 'host-mismatch',\n source: svcId,\n target: edge.target,\n extractedHost: declaredHost,\n observedHost,\n confidence: clampConfidence(confidenceForEdge(edge)),\n reason: `Config declares ${svcId} connects to ${declaredHost}; production connects to ${observedHost}.`,\n recommendation: RECOMMENDATION_HOST_MISMATCH,\n })\n }\n return out\n}\n\nfunction detectCompatDivergences(\n graph: NeatGraph,\n svcId: string,\n svc: ServiceNode,\n): Divergence[] {\n const out: Divergence[] = []\n const deps = svc.dependencies ?? {}\n\n for (const edgeId of graph.outboundEdges(svcId)) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.type !== EdgeType.CONNECTS_TO) continue\n if (edge.provenance !== Provenance.OBSERVED) continue\n const target = graph.getNodeAttributes(edge.target) as GraphNode\n if (target.type !== NodeType.DatabaseNode) continue\n\n // Driver-engine compat. Definitive — when a rule fires it's a\n // version-mismatch with confidence 1.0.\n for (const pair of compatPairs()) {\n if (pair.engine !== target.engine) continue\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(\n pair.driver,\n declared,\n target.engine,\n target.engineVersion,\n )\n if (!result.compatible && result.reason) {\n out.push({\n type: 'version-mismatch',\n source: svcId,\n target: edge.target,\n extractedVersion: declared,\n observedVersion: target.engineVersion,\n compatibility: 'incompatible',\n confidence: 1.0,\n reason: result.reason,\n recommendation: result.minDriverVersion\n ? `Upgrade ${pair.driver} to >= ${result.minDriverVersion}.`\n : `Update the ${pair.driver} driver to a version compatible with ${target.engine} ${target.engineVersion}.`,\n })\n }\n }\n\n // Deprecated-api compat. Broader than version-mismatch — surfaces as\n // compat-violation. Driver-engine rules above already covered the\n // \"version is too low\" shape; deprecated covers \"version is too high\n // / no longer supported.\"\n for (const rule of deprecatedApis()) {\n const declared = deps[rule.package]\n if (!declared) continue\n const result = checkDeprecatedApi(rule, declared)\n if (!result.compatible && result.reason) {\n const ruleRef: CompatRuleRef = {\n kind: rule.kind ?? 'deprecated-api',\n reason: result.reason,\n package: rule.package,\n }\n out.push({\n type: 'compat-violation',\n source: svcId,\n target: edge.target,\n rule: ruleRef,\n observed: edge,\n confidence: 1.0,\n reason: result.reason,\n recommendation: `Replace deprecated ${rule.package}@${declared} with a supported version.`,\n })\n }\n }\n }\n return out\n}\n\nfunction involvesNode(d: Divergence, nodeId: string): boolean {\n return d.source === nodeId || d.target === nodeId\n}\n\nexport function computeDivergences(\n graph: NeatGraph,\n opts: DivergenceQueryOpts = {},\n): DivergenceResult {\n const all: Divergence[] = []\n\n // Pass 1 — bucket every edge and emit missing-observed / missing-extracted.\n const buckets = bucketEdges(graph)\n for (const bucket of buckets.values()) {\n for (const d of detectMissingDivergences(graph, bucket)) all.push(d)\n }\n\n // Pass 2 — per-service host + compat rules.\n graph.forEachNode((nodeId, attrs) => {\n const n = attrs as GraphNode\n if (n.type !== NodeType.ServiceNode) return\n const svc = n as ServiceNode\n for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d)\n for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d)\n })\n\n // Filter + sort. Higher confidence first; within the same confidence,\n // stable on (type, source, target) so callers see deterministic output.\n let filtered = all\n if (opts.type) {\n const allowed = opts.type\n filtered = filtered.filter((d) => allowed.has(d.type))\n }\n if (opts.minConfidence !== undefined) {\n const threshold = opts.minConfidence\n filtered = filtered.filter((d) => d.confidence >= threshold)\n }\n if (opts.node) {\n const target = opts.node\n filtered = filtered.filter((d) => involvesNode(d, target))\n }\n\n // ADR-066 §4 / §5 — confidence desc; missing-extracted leads\n // missing-observed at equal confidence (OBSERVED-led tiebreaker); then\n // stable on (type, source, target).\n const TYPE_LEADERSHIP: Record<DivergenceType, number> = {\n 'missing-extracted': 0,\n 'missing-observed': 1,\n 'version-mismatch': 2,\n 'host-mismatch': 3,\n 'compat-violation': 4,\n }\n filtered.sort((a, b) => {\n if (b.confidence !== a.confidence) return b.confidence - a.confidence\n const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type]\n if (lead !== 0) return lead\n if (a.type !== b.type) return a.type.localeCompare(b.type)\n if (a.source !== b.source) return a.source.localeCompare(b.source)\n return a.target.localeCompare(b.target)\n })\n\n return DivergenceResultSchema.parse({\n divergences: filtered,\n totalAffected: filtered.length,\n computedAt: new Date().toISOString(),\n })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { Provenance, observedEdgeId } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport const SCHEMA_VERSION = 4\n\nexport interface PersistedGraph {\n schemaVersion: number\n exportedAt: string\n graph: ReturnType<NeatGraph['export']>\n}\n\n// v1 → v2: ServiceNode shed `pgDriverVersion` (ADR-019). Compat traversal reads\n// `dependencies[driver]` instead. Strip the field from any v1 snapshot rather\n// than hard-failing — a stale snapshot on disk shouldn't cost a re-extract.\nfunction migrateV1ToV2(payload: PersistedGraph): PersistedGraph {\n const nodes = (payload.graph as { nodes?: Array<{ attributes?: Record<string, unknown> }> })\n .nodes\n if (Array.isArray(nodes)) {\n for (const node of nodes) {\n if (node.attributes && 'pgDriverVersion' in node.attributes) {\n delete node.attributes.pgDriverVersion\n }\n }\n }\n return { ...payload, schemaVersion: 2 }\n}\n\n// v2 → v3: Provenance enum shrinks to four values (ADR-068). Any edge whose\n// provenance still carries the pre-v0.3.5 'FRONTIER' literal is rewritten to\n// Provenance.OBSERVED on load. The target ref is unchanged — FrontierNodes\n// remain placeholders for unresolved peers; only how the edge was labelled\n// changes. If the edge id still carries the legacy provenance segment, it\n// is re-keyed to the OBSERVED wire format so consumers that parse the id\n// (traversal, divergence query, MCP) see the same shape downstream.\n//\n// The 'FRONTIER' string literal here is the only place in the codebase that\n// recognises the legacy value; the Rule 1 contract scan exempts persist.ts\n// for exactly this reason.\n// v3 → v4: ServiceNode identity gains an optional env discriminator\n// (ADR-074 §2). The v4 wire format reads as a superset of v3 — the\n// env-less `service:<name>` form is preserved as the env=`'unknown'`\n// node and the v3 → v4 migration is a version-only bump.\n//\n// Edges and node ids that pre-date the env discriminator remain valid v4\n// ids; no rewrite is needed. Idempotent — re-running on a v4 snapshot\n// produces an identical payload.\nfunction migrateV3ToV4(payload: PersistedGraph): PersistedGraph {\n return { ...payload, schemaVersion: 4 }\n}\n\nfunction migrateV2ToV3(payload: PersistedGraph): PersistedGraph {\n const edges = (payload.graph as {\n edges?: Array<{\n key?: string\n attributes?: Record<string, unknown>\n }>\n }).edges\n if (Array.isArray(edges)) {\n for (const edge of edges) {\n const attrs = edge.attributes\n // 'FRONTIER' is the pre-v0.3.5 literal — read-only here, never written\n // by current producers. The rewrite swaps to Provenance.OBSERVED.\n if (!attrs || attrs.provenance !== 'FRONTIER') continue\n attrs.provenance = Provenance.OBSERVED\n const type = typeof attrs.type === 'string' ? attrs.type : undefined\n const source = typeof attrs.source === 'string' ? attrs.source : undefined\n const target = typeof attrs.target === 'string' ? attrs.target : undefined\n if (type && source && target) {\n const newId = observedEdgeId(source, target, type)\n attrs.id = newId\n if (edge.key) edge.key = newId\n }\n }\n }\n return { ...payload, schemaVersion: 3 }\n}\n\nasync function ensureDir(filePath: string): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n}\n\nexport async function saveGraphToDisk(graph: NeatGraph, outPath: string): Promise<void> {\n await ensureDir(outPath)\n const payload: PersistedGraph = {\n schemaVersion: SCHEMA_VERSION,\n exportedAt: new Date().toISOString(),\n graph: graph.export(),\n }\n // Atomic write: drop into <name>.tmp first, then rename. A crash mid-write\n // leaves the previous snapshot intact instead of a half-truncated file.\n const tmp = `${outPath}.tmp`\n await fs.writeFile(tmp, JSON.stringify(payload), 'utf8')\n await fs.rename(tmp, outPath)\n}\n\nexport async function loadGraphFromDisk(graph: NeatGraph, outPath: string): Promise<void> {\n let raw: string\n try {\n raw = await fs.readFile(outPath, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return\n throw err\n }\n let payload = JSON.parse(raw) as PersistedGraph\n if (payload.schemaVersion === 1) {\n payload = migrateV1ToV2(payload)\n }\n if (payload.schemaVersion === 2) {\n payload = migrateV2ToV3(payload)\n }\n if (payload.schemaVersion === 3) {\n payload = migrateV3ToV4(payload)\n }\n if (payload.schemaVersion !== SCHEMA_VERSION) {\n throw new Error(\n `persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`,\n )\n }\n graph.clear()\n graph.import(payload.graph)\n}\n\n// Periodic save + best-effort save on SIGTERM/SIGINT. Returns a cleanup that\n// clears the interval and unhooks the signal handlers — important for tests so\n// they don't keep the process alive.\nexport function startPersistLoop(\n graph: NeatGraph,\n outPath: string,\n intervalMs = 60_000,\n): () => void {\n let stopped = false\n\n const tick = async (): Promise<void> => {\n if (stopped) return\n try {\n await saveGraphToDisk(graph, outPath)\n } catch (err) {\n console.error('persist: periodic save failed', err)\n }\n }\n\n const interval = setInterval(() => {\n void tick()\n }, intervalMs)\n\n const onSignal = (signal: NodeJS.Signals): void => {\n void (async () => {\n try {\n await saveGraphToDisk(graph, outPath)\n } catch (err) {\n console.error(`persist: ${signal} save failed`, err)\n } finally {\n process.exit(0)\n }\n })()\n }\n\n process.on('SIGTERM', onSignal)\n process.on('SIGINT', onSignal)\n\n return () => {\n stopped = true\n clearInterval(interval)\n process.off('SIGTERM', onSignal)\n process.off('SIGINT', onSignal)\n }\n}\n\n// Snapshot merge (ADR-074 §1) lives in ingest.ts — that's the mutation-\n// authority boundary per the lifecycle contract (Rule 3 / ADR-030). The\n// merge is a form of ingestion: an external snapshot lands on the live graph\n// the same way an OTel span does, preserving the EXTRACTED + OBSERVED\n// coexistence contract along the way.\n","/**\n * `.gitignore` automation for the init flow (ADR-073 §6).\n *\n * Init writes a snapshot under `<projectDir>/neat-out/`. Un-ignored, that\n * directory leaks the snapshot into git history within one commit. The\n * helper here ensures `neat-out/` is present in `<projectDir>/.gitignore` —\n * appending to an existing file with a NEAT comment header, creating the\n * file when absent, no-oping when the line is already there.\n *\n * Idempotency rule: an exact-match line (`neat-out/` or `neat-out`, with\n * any surrounding whitespace) counts as already-present. No duplicate\n * line is written on a re-run.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport const NEAT_OUT_LINE = 'neat-out/'\nconst NEAT_HEADER = '# NEAT — machine-local snapshots and events'\n\nexport interface EnsureNeatOutResult {\n // 'added' when the line was appended to an existing .gitignore.\n // 'created' when the file did not exist and was created with a single line.\n // 'unchanged' when the line was already present.\n action: 'added' | 'created' | 'unchanged'\n // Absolute path to the .gitignore file, regardless of action.\n file: string\n}\n\nfunction isNeatOutLine(line: string): boolean {\n const trimmed = line.trim()\n return trimmed === 'neat-out/' || trimmed === 'neat-out'\n}\n\nexport async function ensureNeatOutIgnored(projectDir: string): Promise<EnsureNeatOutResult> {\n const file = path.join(projectDir, '.gitignore')\n let existing: string | null = null\n try {\n existing = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n\n if (existing === null) {\n await fs.writeFile(file, `${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`, 'utf8')\n return { action: 'created', file }\n }\n\n for (const line of existing.split(/\\r?\\n/)) {\n if (isNeatOutLine(line)) return { action: 'unchanged', file }\n }\n\n // Append with a leading newline if the file doesn't already end in one,\n // so the comment header sits on its own line.\n const needsLeadingNewline = existing.length > 0 && !existing.endsWith('\\n')\n const appended = `${needsLeadingNewline ? '\\n' : ''}\\n${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`\n await fs.writeFile(file, existing + appended, 'utf8')\n return { action: 'added', file }\n}\n","/**\n * Value-forward CLI summary (issue #305, ADR-073 §5).\n *\n * Replaces the per-type node/edge counts that ended `neat init` with a\n * findings-first block — compat violations, top divergences, services\n * that never produced an OBSERVED edge, and the OTel env-vars block the\n * operator pastes into their deploy platform. Per-type counts move behind\n * `--verbose`.\n *\n * The renderer is a pure string builder so tests can assert against its\n * output without spawning the CLI.\n */\n\nimport type { Divergence, GraphEdge, GraphNode, ServiceNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport interface SummaryInput {\n graph: NeatGraph\n divergences: Divergence[]\n // True → render the per-type counts after the value-forward block.\n verbose: boolean\n}\n\n// Static placeholder. The orchestrator and `neat deploy` print the same\n// block; `neat deploy` substitutes the actual token + host. This shape\n// lives in one place so the wire format stays in step.\nexport function renderOtelEnvBlock(): string {\n return [\n 'for prod OTel routing, set these in your deploy platform\\'s env:',\n ' OTEL_EXPORTER_OTLP_ENDPOINT=https://<your-neat-host>:4318',\n ' OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer <NEAT_AUTH_TOKEN>',\n ].join('\\n')\n}\n\nfunction findIncompatServices(nodes: GraphNode[]): ServiceNode[] {\n return nodes.filter(\n (n): n is ServiceNode =>\n n.type === NodeType.ServiceNode &&\n Array.isArray((n as ServiceNode).incompatibilities) &&\n ((n as ServiceNode).incompatibilities ?? []).length > 0,\n )\n}\n\n// Services that show up in the EXTRACTED graph but have no OBSERVED edge\n// pointing at or out of them. The thesis says: when the OBSERVED layer is\n// silent on a service, the gap is a load-bearing signal for the operator.\nfunction servicesWithoutObserved(nodes: GraphNode[], edges: GraphEdge[]): ServiceNode[] {\n const seen = new Set<string>()\n for (const e of edges) {\n if (e.provenance === Provenance.OBSERVED) {\n seen.add(e.source)\n seen.add(e.target)\n }\n }\n return nodes.filter(\n (n): n is ServiceNode => n.type === NodeType.ServiceNode && !seen.has(n.id),\n )\n}\n\nfunction formatDivergence(d: Divergence): string {\n // Short, scannable, one-line-per-finding. The reason field already carries\n // the load-bearing detail; the recommendation rides on a second indent.\n const conf = d.confidence.toFixed(2)\n return ` [${conf}] ${d.type} ${d.source} → ${d.target} — ${d.reason}`\n}\n\nexport function renderValueForwardSummary(input: SummaryInput): string {\n const { graph, divergences, verbose } = input\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => nodes.push(attrs))\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n const lines: string[] = []\n lines.push('=== neat: findings ===')\n lines.push('')\n\n // ── Compat violations (driver/engine mismatches) ───────────────────────\n const incompatServices = findIncompatServices(nodes)\n const totalIncompats = incompatServices.reduce(\n (acc, s) => acc + (s.incompatibilities?.length ?? 0),\n 0,\n )\n lines.push(`compat violations: ${totalIncompats}`)\n for (const svc of incompatServices) {\n for (const inc of svc.incompatibilities ?? []) {\n const detail = formatIncompat(inc)\n lines.push(` ${svc.name}: ${detail}`)\n }\n }\n lines.push('')\n\n // ── Top divergences (top 3 by confidence desc) ─────────────────────────\n const top = [...divergences].sort((a, b) => b.confidence - a.confidence).slice(0, 3)\n lines.push(`top divergences: ${divergences.length} total${top.length > 0 ? ', top 3:' : ''}`)\n for (const d of top) lines.push(formatDivergence(d))\n lines.push('')\n\n // ── Services missing OBSERVED coverage ─────────────────────────────────\n const noObserved = servicesWithoutObserved(nodes, edges)\n if (noObserved.length > 0) {\n lines.push(`services without OBSERVED coverage: ${noObserved.length}`)\n for (const svc of noObserved) lines.push(` ${svc.name}`)\n lines.push(' → run your services with the generated otel-init to populate OBSERVED edges.')\n lines.push('')\n }\n\n // ── OTel env-vars block (static; `neat deploy` substitutes real values)\n lines.push(renderOtelEnvBlock())\n lines.push('')\n\n // ── --verbose: per-type node/edge counts ──────────────────────────────\n if (verbose) {\n const byNode = new Map<string, number>()\n for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n const byEdge = new Map<string, number>()\n for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n lines.push('=== graph (verbose) ===')\n lines.push(`total: ${graph.order} nodes, ${graph.size} edges`)\n lines.push('nodes:')\n for (const [t, c] of [...byNode.entries()].sort()) lines.push(` ${t}: ${c}`)\n lines.push('edges:')\n for (const [t, c] of [...byEdge.entries()].sort()) lines.push(` ${t}: ${c}`)\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\nfunction formatIncompat(inc: NonNullable<ServiceNode['incompatibilities']>[number]): string {\n if (inc.kind === 'node-engine') {\n const range = inc.declaredNodeEngine ? ` (engines.node=\"${inc.declaredNodeEngine}\")` : ''\n return `${inc.package}@${inc.packageVersion ?? '?'} requires Node ${inc.requiredNodeVersion}${range} — ${inc.reason}`\n }\n if (inc.kind === 'package-conflict') {\n const found = inc.foundVersion ? `@${inc.foundVersion}` : ' (missing)'\n return `${inc.package}@${inc.packageVersion ?? '?'} requires ${inc.requires.name}>=${inc.requires.minVersion}; found ${inc.requires.name}${found} — ${inc.reason}`\n }\n if (inc.kind === 'deprecated-api') {\n return `${inc.package}@${inc.packageVersion ?? '?'} is deprecated — ${inc.reason}`\n }\n return `${inc.driver}@${inc.driverVersion} vs ${inc.engine} ${inc.engineVersion} — ${inc.reason}`\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport type { FastifyInstance } from 'fastify'\nimport type { NeatGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\nimport { ensureCompatLoaded } from './compat.js'\nimport { discoverServices, addServiceNodes } from './extract/services.js'\nimport { addServiceAliases } from './extract/aliases.js'\nimport { addDatabasesAndCompat } from './extract/databases/index.js'\nimport { addConfigNodes } from './extract/configs.js'\nimport { addCallEdges } from './extract/calls/index.js'\nimport { addInfra } from './extract/infra/index.js'\nimport { retireEdgesByFile } from './extract/retire.js'\nimport {\n makeErrorSpanWriter,\n makeSpanHandler,\n promoteFrontierNodes,\n startStalenessLoop,\n} from './ingest.js'\nimport {\n evaluateAllPolicies,\n loadPolicyFile,\n PolicyViolationsLog,\n} from './policy.js'\nimport type { Policy } from '@neat.is/types'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildSearchIndex, type SearchIndex } from './search.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { Projects, pathsForProject } from './projects.js'\nimport { attachGraphToEventBus, emitNeatEvent } from './events.js'\n\nexport type ExtractPhase =\n | 'services'\n | 'aliases'\n | 'databases'\n | 'configs'\n | 'calls'\n | 'infra'\n\nconst ALL_PHASES: ExtractPhase[] = [\n 'services',\n 'aliases',\n 'databases',\n 'configs',\n 'calls',\n 'infra',\n]\n\n// Map a changed path to the phases that need re-running. Anything not matched\n// here falls back to a full re-extract — better an extra ~50ms of work than a\n// missed update because the path didn't fit a regex.\n//\n// Mapping:\n// package.json / requirements.txt / pyproject.toml → services + aliases + databases\n// (deps drive compat; aliases pull from manifest fields)\n// .env / *.env.* / prisma / knex / ormconfig → databases + configs\n// docker-compose / Dockerfile / *.tf / k8s yaml → infra + aliases\n// (compose labels and Dockerfile labels feed alias discovery)\n// *.js / *.ts / *.tsx / *.py / *.jsx / *.mjs / *.cjs → calls\n// *.yaml / *.yml that isn't compose → databases + configs (ORM yaml fallbacks)\nexport function classifyChange(relPath: string): Set<ExtractPhase> {\n const phases = new Set<ExtractPhase>()\n const base = path.basename(relPath).toLowerCase()\n const segments = relPath.split(path.sep).map((s) => s.toLowerCase())\n\n if (\n base === 'package.json' ||\n base === 'requirements.txt' ||\n base === 'pyproject.toml' ||\n base === 'setup.py'\n ) {\n phases.add('services')\n phases.add('aliases')\n phases.add('databases')\n }\n\n if (\n base === '.env' ||\n base.startsWith('.env.') ||\n base === 'schema.prisma' ||\n /^knexfile\\.(?:js|ts|cjs|mjs)$/.test(base) ||\n /^ormconfig\\.(?:js|ts|json|ya?ml)$/.test(base)\n ) {\n phases.add('databases')\n phases.add('configs')\n }\n\n if (\n base === 'dockerfile' ||\n /^docker-compose.*\\.ya?ml$/.test(base) ||\n base.endsWith('.tf') ||\n segments.includes('k8s') ||\n segments.includes('kustomize') ||\n segments.includes('manifests')\n ) {\n phases.add('infra')\n phases.add('aliases')\n }\n\n if (/\\.(?:js|jsx|mjs|cjs|ts|tsx|py)$/.test(base)) {\n phases.add('calls')\n }\n\n if (/\\.ya?ml$/.test(base) && !/^docker-compose.*\\.ya?ml$/.test(base)) {\n // Generic yaml — could be an ORM file, k8s manifest, or random config.\n // Cheap to run databases + configs; if it was infra, the dir-name check\n // above already added that phase.\n phases.add('databases')\n phases.add('configs')\n }\n\n return phases\n}\n\ninterface RunPhasesResult {\n phases: ExtractPhase[]\n nodesAdded: number\n edgesAdded: number\n frontiersPromoted: number\n durationMs: number\n}\n\nexport async function runExtractPhases(\n graph: NeatGraph,\n scanPath: string,\n phases: Set<ExtractPhase>,\n // Project tag passed through for the runtime event bus (ADR-051) — not\n // required for extraction logic itself but threaded for parity with\n // extractFromDirectory's project option.\n project: string = DEFAULT_PROJECT,\n): Promise<RunPhasesResult> {\n void project\n const started = Date.now()\n await ensureCompatLoaded()\n // Discovery is cheap and every phase needs the same DiscoveredService list,\n // so we always re-walk. If the user moved a service directory, this is also\n // the path that picks it up.\n const services = await discoverServices(scanPath)\n\n let nodesAdded = 0\n let edgesAdded = 0\n\n if (phases.has('services')) {\n nodesAdded += addServiceNodes(graph, services)\n }\n if (phases.has('aliases')) {\n await addServiceAliases(graph, scanPath, services)\n }\n if (phases.has('databases')) {\n const r = await addDatabasesAndCompat(graph, services, scanPath)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('configs')) {\n const r = await addConfigNodes(graph, services, scanPath)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('calls')) {\n const r = await addCallEdges(graph, services)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('infra')) {\n const r = await addInfra(graph, scanPath, services)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n const frontiersPromoted = promoteFrontierNodes(graph)\n\n return {\n phases: ALL_PHASES.filter((p) => phases.has(p)),\n nodesAdded,\n edgesAdded,\n frontiersPromoted,\n durationMs: Date.now() - started,\n }\n}\n\nexport interface WatchOptions {\n scanPath: string\n outPath: string\n errorsPath: string\n staleEventsPath: string\n embeddingsCachePath?: string\n // Project name this watch instance owns. Defaults to `default` for the\n // single-project workflow that's been the only one until #83.\n project?: string\n host?: string\n port?: number\n otelPort?: number\n otelGrpc?: boolean\n otelGrpcPort?: number\n debounceMs?: number\n}\n\nexport interface WatchHandle {\n api: FastifyInstance\n stop: () => Promise<void>\n}\n\n// Anymatch-compatible ignore set passed to chokidar (#233). The earlier\n// implementation passed a function alone, which forced chokidar to descend\n// into every subdirectory before testing the path. On macOS with kqueue\n// (chokidar 4 dropped fsevents in favour of kqueue), each subdir under the\n// scan root opens a watch handle; nested `node_modules` blew through the\n// per-process kqueue cap with EMFILE before the function-based ignore ever\n// fired. Globs let chokidar prune at descent time — the dirs are never\n// opened in the first place.\nconst IGNORED_WATCH_GLOBS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/.turbo/**',\n '**/.next/**',\n '**/neat-out/**',\n // Python venv shapes (issue #344). chokidar opens one watch handle per\n // descended dir; a CPython venv carries 20k+ files and trivially blows\n // through the macOS kqueue cap before extraction even runs.\n '**/.venv/**',\n '**/venv/**',\n '**/__pypackages__/**',\n '**/.tox/**',\n '**/site-packages/**',\n '**/.DS_Store',\n]\n\n// Backstop regex set — covers anything chokidar surfaces post-descent that\n// the globs missed (e.g. a path containing one of these segments at an\n// unexpected depth). Same shape as before; the globs are the load-bearing\n// pruning, this is defence in depth.\nconst IGNORED_WATCH_PATHS = [\n /(?:^|[\\\\/])node_modules[\\\\/]/,\n /(?:^|[\\\\/])\\.git[\\\\/]/,\n /(?:^|[\\\\/])dist[\\\\/]/,\n /(?:^|[\\\\/])build[\\\\/]/,\n /(?:^|[\\\\/])\\.turbo[\\\\/]/,\n /(?:^|[\\\\/])\\.next[\\\\/]/,\n /(?:^|[\\\\/])neat-out[\\\\/]/,\n /(?:^|[\\\\/])\\.venv[\\\\/]/,\n /(?:^|[\\\\/])venv[\\\\/]/,\n /(?:^|[\\\\/])__pypackages__[\\\\/]/,\n /(?:^|[\\\\/])\\.tox[\\\\/]/,\n /(?:^|[\\\\/])site-packages[\\\\/]/,\n /[\\\\/]?\\.DS_Store$/,\n]\n\nfunction shouldIgnore(absPath: string): boolean {\n return IGNORED_WATCH_PATHS.some((re) => re.test(absPath))\n}\n\n// Roughly the number of immediate, non-ignored subdirectories in the scan\n// root above which `neat watch` should fall back to polling on darwin. kqueue\n// opens one handle per watched dir; macOS's per-process file-descriptor cap\n// is typically 256 (soft) / unlimited (hard) but raising the hard cap doesn't\n// help with the kqueue-specific limits. Empirically anything north of ~500\n// non-ignored dirs starts to flirt with EMFILE. Threshold sits comfortably\n// under that.\nconst DARWIN_POLLING_DIR_THRESHOLD = 400\n\n// Fast non-recursive count: walk top-level entries only, descending one\n// level into non-ignored subdirs to capture the medusa-shaped case where\n// `packages/*` itself looks small but each contains a heavy `node_modules`.\n// Returns early once it crosses the threshold so we don't waste time on huge\n// repos.\nfunction countWatchableDirs(scanPath: string, limit: number): number {\n let count = 0\n const visit = (dir: string, depth: number): void => {\n if (count >= limit) return\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n for (const e of entries) {\n if (count >= limit) return\n if (!e.isDirectory()) continue\n if (IGNORED_WATCH_PATHS.some((re) => re.test(path.join(dir, e.name) + path.sep))) continue\n count++\n // One level deeper — enough to surface nested `node_modules` shapes\n // without traversing the whole tree.\n if (depth < 2) visit(path.join(dir, e.name), depth + 1)\n }\n }\n visit(scanPath, 0)\n return count\n}\n\n// Darwin heuristic (#233). Forces chokidar onto polling when the scan root\n// is large enough that kqueue would EMFILE. Override via NEAT_WATCH_POLLING:\n// - \"1\" / \"true\" → force polling regardless of platform/threshold\n// - \"0\" / \"false\" → never poll (matches pre-#233 behaviour)\n// - unset → auto-detect on darwin\nfunction shouldUsePolling(scanPath: string): boolean {\n const env = process.env.NEAT_WATCH_POLLING\n if (env === '1' || env === 'true') return true\n if (env === '0' || env === 'false') return false\n if (process.platform !== 'darwin') return false\n return countWatchableDirs(scanPath, DARWIN_POLLING_DIR_THRESHOLD) >= DARWIN_POLLING_DIR_THRESHOLD\n}\n\nexport async function startWatch(\n graph: NeatGraph,\n opts: WatchOptions,\n): Promise<WatchHandle> {\n const debounceMs = opts.debounceMs ?? 1000\n const projectName = opts.project ?? DEFAULT_PROJECT\n\n await loadGraphFromDisk(graph, opts.outPath)\n\n // Wire graph mutations into the event bus (ADR-051) before extract begins\n // so the initial pass also produces node/edge events. Detached on stop().\n const detachEventBus = attachGraphToEventBus(graph, { project: projectName })\n\n // Load policies + open the violations log once at startup. policy.json\n // lives at the project root per ADR-042 §File location; absent file is\n // a perfectly fine state (loadPolicyFile returns []). Reload-on-change\n // is queued for v0.2.5 — the kickoff doc tracks it.\n const policyFilePath = path.join(opts.scanPath, 'policy.json')\n const policyViolationsPath = path.join(path.dirname(opts.outPath), 'policy-violations.ndjson')\n let policies: Policy[] = []\n try {\n policies = await loadPolicyFile(policyFilePath)\n if (policies.length > 0) {\n console.log(`policies: loaded ${policies.length} from ${policyFilePath}`)\n }\n } catch (err) {\n console.warn(`policies: failed to load ${policyFilePath} — ${(err as Error).message}`)\n }\n const policyLog = new PolicyViolationsLog(policyViolationsPath, projectName)\n\n // Single shared trigger callback wired into post-ingest, post-extract, and\n // post-stale per ADR-043. Failures append to console.warn but don't kill\n // the daemon — a malformed evaluator shouldn't take down ingest.\n const onPolicyTrigger = async (g: NeatGraph): Promise<void> => {\n if (policies.length === 0) return\n try {\n const violations = evaluateAllPolicies(g, policies, { now: () => Date.now() })\n for (const v of violations) await policyLog.append(v)\n } catch (err) {\n console.warn(`policies: evaluation failed — ${(err as Error).message}`)\n }\n }\n\n // The post-extract trigger fires from extractFromDirectory via opts.\n // For the initial extract here we run it inline so violations land on\n // startup before the receiver opens. Subsequent watch-driven re-extract\n // passes go through runExtractPhases which doesn't take the hook directly\n // — we run it after each flush() instead.\n const initial = await runExtractPhases(\n graph,\n opts.scanPath,\n new Set(ALL_PHASES),\n projectName,\n )\n console.log(\n `extract: ${initial.nodesAdded} new nodes, ${initial.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n // extraction-complete for the initial pass (ADR-051). runExtractPhases\n // doesn't emit on its own — the event lives at the watch / orchestrator\n // boundary so the daemon can swap in its own emission shape.\n emitNeatEvent({\n type: 'extraction-complete',\n project: projectName,\n payload: {\n project: projectName,\n fileCount: 0,\n nodesAdded: initial.nodesAdded,\n edgesAdded: initial.edgesAdded,\n },\n })\n await onPolicyTrigger(graph)\n\n const stopPersist = startPersistLoop(graph, opts.outPath)\n const stopStaleness = startStalenessLoop(graph, {\n staleEventsPath: opts.staleEventsPath,\n project: projectName,\n onPolicyTrigger,\n })\n\n // ADR-073 §3/§4 + issue #341 — `neat watch` follows the same bind discipline\n // as the daemon: an explicit host wins; otherwise loopback-only without a\n // token (laptop dev), public bind once `NEAT_AUTH_TOKEN` is set. buildApi\n // mounts the bearer gate from the same env, so a token-protected watch\n // returns 401 to unauthenticated callers exactly as `neatd` does.\n const auth = readAuthEnv()\n const host = opts.host ?? (auth.authToken ? '0.0.0.0' : '127.0.0.1')\n assertBindAuthority(host, auth.authToken)\n const port = opts.port ?? 8080\n const otelPort = opts.otelPort ?? 4318\n\n const cachePath =\n opts.embeddingsCachePath ?? path.join(path.dirname(opts.outPath), 'embeddings.json')\n let searchIndex: SearchIndex | undefined\n try {\n searchIndex = await buildSearchIndex(graph, { cachePath })\n console.log(`semantic_search: ${searchIndex.provider} provider`)\n } catch (err) {\n console.warn(\n `semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n }\n\n const registry = new Projects()\n registry.set(projectName, {\n graph,\n scanPath: opts.scanPath,\n paths: {\n // Paths are derived from the explicit options the watch caller passes\n // — pathsForProject is only used to fill in the embeddings/snapshot\n // fields so the registry shape is complete.\n ...pathsForProject(projectName, path.dirname(opts.outPath)),\n snapshotPath: opts.outPath,\n errorsPath: opts.errorsPath,\n staleEventsPath: opts.staleEventsPath,\n },\n searchIndex,\n })\n\n const api = await buildApi({ projects: registry })\n await api.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` scan path: ${opts.scanPath} (watching for changes)`)\n console.log(` snapshot path: ${opts.outPath}`)\n console.log(` errors log: ${opts.errorsPath}`)\n\n // The receiver writes ErrorEvents synchronously before reply (durability).\n // makeSpanHandler runs on the async queue and skips the inline write\n // because the receiver already handled it. Ad-hoc callers that bypass the\n // receiver (CLI tests, fixtures) leave writeErrorEventInline at its default\n // and get the in-handleSpan write. ADR-033 §Error events.\n const onSpan = makeSpanHandler({\n graph,\n errorsPath: opts.errorsPath,\n scanPath: opts.scanPath,\n project: projectName,\n writeErrorEventInline: false,\n onPolicyTrigger,\n })\n const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath)\n const otelHttp = await buildOtelReceiver({ onSpan, onErrorSpanSync })\n await otelHttp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n let grpcReceiver: { stop: () => Promise<void> } | null = null\n if (opts.otelGrpc) {\n const grpcPort = opts.otelGrpcPort ?? 4317\n // gRPC handler keeps the inline ErrorEvent write — the gRPC receiver\n // awaits onSpan synchronously (otel-grpc.ts), so the same durability\n // guarantee is met without a separate sync hook. Non-blocking gRPC\n // ingest is out of scope for the v0.2.2 batch.\n const onSpanGrpc = makeSpanHandler({\n graph,\n errorsPath: opts.errorsPath,\n scanPath: opts.scanPath,\n project: projectName,\n onPolicyTrigger,\n })\n const r = await startOtelGrpcReceiver({ onSpan: onSpanGrpc, host, port: grpcPort })\n console.log(`neat-core OTLP/gRPC receiver on ${r.address}`)\n grpcReceiver = r\n }\n\n // Coalesce bursts of changes into a single re-extract. chokidar fires one\n // event per affected path; an editor save can produce 3+ events on the same\n // file in <50ms.\n const pending = new Set<ExtractPhase>()\n const pendingPaths = new Set<string>()\n let timer: NodeJS.Timeout | null = null\n let inflight: Promise<void> | null = null\n\n const flush = async (): Promise<void> => {\n if (pending.size === 0) return\n const phases = new Set(pending)\n const paths = new Set(pendingPaths)\n pending.clear()\n pendingPaths.clear()\n try {\n // Drop EXTRACTED edges keyed to changed paths first, so the producer's\n // idempotent re-extract recreates only the edges that still apply.\n // Without this, edges from deleted code would survive forever\n // (docs/contracts/static-extraction.md §Ghost-edge cleanup).\n let retired = 0\n for (const p of paths) retired += retireEdgesByFile(graph, p)\n const result = await runExtractPhases(graph, opts.scanPath, phases, projectName)\n console.log(\n `[watch] re-extract phases=${result.phases.join(',')} retired=${retired} +${result.nodesAdded}n/+${result.edgesAdded}e in ${result.durationMs}ms`,\n )\n // extraction-complete after every re-extract pass (ADR-051). fileCount\n // is the number of paths that drove the pass — closest signal we have\n // for \"how much source moved\" without per-phase accounting.\n emitNeatEvent({\n type: 'extraction-complete',\n project: projectName,\n payload: {\n project: projectName,\n fileCount: paths.size,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n },\n })\n if (searchIndex) {\n try {\n await searchIndex.refresh(graph)\n } catch (err) {\n console.warn('[watch] semantic_search refresh failed', err)\n }\n }\n // Post-extract policy trigger (ADR-043). The runExtractPhases call\n // doesn't take the hook directly — it runs through promoteFrontierNodes\n // for FRONTIER → OBSERVED upgrades but doesn't load policies itself.\n // Firing the evaluator here keeps the trigger surface symmetric across\n // ingest / extract / stale paths.\n await onPolicyTrigger(graph)\n } catch (err) {\n console.error('[watch] re-extract failed', err)\n }\n }\n\n const schedule = (): void => {\n if (timer) clearTimeout(timer)\n timer = setTimeout(() => {\n timer = null\n // Serialise re-extracts so two flushes can't interleave on the graph.\n inflight = (inflight ?? Promise.resolve()).then(flush)\n }, debounceMs)\n }\n\n const onPath = (absPath: string): void => {\n if (shouldIgnore(absPath)) return\n const rel = path.relative(opts.scanPath, absPath)\n if (!rel || rel.startsWith('..')) return\n pendingPaths.add(rel.split(path.sep).join('/'))\n const phases = classifyChange(rel)\n if (phases.size === 0) {\n // Unknown file kind — fall back to full re-extract rather than silently\n // miss it. Cheaper than the user wondering why their change didn't show.\n for (const p of ALL_PHASES) pending.add(p)\n } else {\n for (const p of phases) pending.add(p)\n }\n schedule()\n }\n\n const usePolling = shouldUsePolling(opts.scanPath)\n if (usePolling) {\n const reason =\n process.env.NEAT_WATCH_POLLING === '1' || process.env.NEAT_WATCH_POLLING === 'true'\n ? 'NEAT_WATCH_POLLING env override'\n : 'darwin heuristic — large scan root, kqueue cap risk'\n console.log(`[${projectName}] watch: usePolling=true (${reason})`)\n }\n const watcher: FSWatcher = chokidar.watch(opts.scanPath, {\n ignoreInitial: true,\n // Glob array prunes at descent time (#233) so chokidar never opens a\n // kqueue handle for `node_modules` and friends. The function backstop\n // catches any path that slipped through and matches the regex set.\n ignored: [...IGNORED_WATCH_GLOBS, (p: string) => shouldIgnore(p)],\n persistent: true,\n usePolling,\n awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },\n })\n watcher.on('add', onPath)\n watcher.on('change', onPath)\n watcher.on('unlink', onPath)\n watcher.on('addDir', onPath)\n watcher.on('unlinkDir', onPath)\n\n let stopped = false\n const stop = async (): Promise<void> => {\n if (stopped) return\n stopped = true\n if (timer) clearTimeout(timer)\n timer = null\n if (inflight) {\n try {\n await inflight\n } catch {\n // surfaced already in flush()\n }\n }\n await watcher.close()\n stopStaleness()\n stopPersist()\n detachEventBus()\n await api.close()\n await otelHttp.close()\n if (grpcReceiver) await grpcReceiver.stop()\n }\n\n return { api, stop }\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n} from 'fastify'\nimport cors from '@fastify/cors'\nimport type {\n ErrorEvent,\n GraphEdge,\n GraphNode,\n Policy,\n PolicyViolation,\n} from '@neat.is/types'\nimport { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } from '@neat.is/types'\nimport type { DivergenceType } from '@neat.is/types'\nimport { computeDivergences } from './divergences.js'\nimport {\n evaluateAllPolicies,\n loadPolicyFile,\n PolicyViolationsLog,\n} from './policy.js'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { readErrorEvents, readStaleEvents } from './ingest.js'\nimport {\n getBlastRadius,\n getRootCause,\n getTransitiveDependencies,\n TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n TRANSITIVE_DEPENDENCIES_MAX_DEPTH,\n} from './traverse.js'\nimport { computeGraphDiff, loadSnapshotForDiff } from './diff.js'\nimport { mergeSnapshot } from './ingest.js'\nimport { SCHEMA_VERSION, type PersistedGraph } from './persist.js'\nimport type { SearchIndex } from './search.js'\nimport type { Projects, ProjectContext } from './projects.js'\nimport { Projects as ProjectsClass, pathsForProject } from './projects.js'\nimport { getProject as getRegistryProject, listProjects as listRegistryProjects } from './registry.js'\nimport { handleSse } from './streaming.js'\nimport { mountBearerAuth, readAuthEnv } from './auth.js'\n\nexport interface BuildApiOptions {\n // Multi-project shape. Optional — when absent we synthesise a single-\n // project registry from the legacy fields below so existing callers\n // (mainly tests) keep working unchanged.\n projects?: Projects\n startedAt?: number\n\n // Legacy single-project shape. Mapped to project=`default` if `projects`\n // isn't provided.\n graph?: NeatGraph\n scanPath?: string\n errorsPath?: string\n staleEventsPath?: string\n searchIndex?: SearchIndex\n\n // ADR-073 §3 — bearer token required on `/api/*` and `/events`. Undefined\n // leaves the middleware off (loopback-only callers; the bind-authority\n // gate in startDaemon refuses to bind publicly without one).\n authToken?: string\n // ADR-073 §3 — when the operator runs behind a reverse proxy that already\n // authenticates the request, the daemon-side check is bypassed.\n trustProxy?: boolean\n // ADR-073 §3 amendment — public-read mode. When `true`, GET / HEAD / OPTIONS\n // bypass the bearer check; writes still require it. OTLP ingest is gated\n // independently and is unaffected by this flag.\n publicRead?: boolean\n // Issue #340 — per-project bootstrap status. When provided, project-scoped\n // routes for projects still extracting return 503 with `{ready: false}`\n // instead of 404.\n bootstrap?: {\n status: (name: string) => 'bootstrapping' | 'active' | 'broken' | undefined\n list: () => Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken'; elapsedMs: number }>\n }\n}\n\ninterface SerializedGraph {\n nodes: GraphNode[]\n edges: GraphEdge[]\n}\n\nfunction serializeGraph(graph: NeatGraph): SerializedGraph {\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => {\n nodes.push(attrs)\n })\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => {\n edges.push(attrs)\n })\n return { nodes, edges }\n}\n\nfunction projectFromReq(req: FastifyRequest): string {\n // `:project` is optional in the URL — the request hits either\n // /projects/:project/X or /X (which means default). Coerce the missing\n // param to DEFAULT_PROJECT here so handlers don't repeat the fallback.\n const params = req.params as { project?: string }\n return params.project ?? DEFAULT_PROJECT\n}\n\nfunction resolveProject(\n registry: Projects,\n req: FastifyRequest,\n reply: FastifyReply,\n bootstrap?: BuildApiOptions['bootstrap'],\n): ProjectContext | null {\n const name = projectFromReq(req)\n const ctx = registry.get(name)\n if (!ctx) {\n // Issue #340 — registered but still bootstrapping: surface 503 so the\n // probe consumer knows the project is real and incoming, not missing.\n const phase = bootstrap?.status(name)\n if (phase === 'bootstrapping') {\n void reply.code(503).send({ ready: false, project: name, status: 'bootstrapping' })\n return null\n }\n if (phase === 'broken') {\n void reply.code(503).send({ ready: false, project: name, status: 'broken' })\n return null\n }\n void reply.code(404).send({ error: 'project not found', project: name })\n return null\n }\n return ctx\n}\n\nfunction buildLegacyRegistry(opts: BuildApiOptions): Projects {\n if (opts.projects) return opts.projects\n if (!opts.graph) {\n throw new Error('buildApi: either `projects` or `graph` must be provided')\n }\n const registry = new ProjectsClass()\n // pathsForProject only matters here for the snapshot/embeddings paths\n // routes never read; the ingest paths come from explicit options below.\n const paths = pathsForProject(DEFAULT_PROJECT, '')\n registry.set(DEFAULT_PROJECT, {\n graph: opts.graph,\n scanPath: opts.scanPath,\n paths: {\n snapshotPath: paths.snapshotPath,\n errorsPath: opts.errorsPath ?? paths.errorsPath,\n staleEventsPath: opts.staleEventsPath ?? paths.staleEventsPath,\n embeddingsCachePath: paths.embeddingsCachePath,\n policyViolationsPath: paths.policyViolationsPath,\n },\n searchIndex: opts.searchIndex,\n })\n return registry\n}\n\ninterface RouteContext {\n registry: Projects\n startedAt: number\n // Where the routes are getting mounted. `'root'` is the legacy unprefixed\n // mount that historically resolved every request to the `default` project;\n // `'project'` is the `/projects/:project` plugin scope where the project\n // segment is always present. The /health handler branches on this so the\n // root mount can answer daemon-wide while the scoped mount stays\n // per-project (issue #343).\n scope: 'root' | 'project'\n // Legacy callers passed `errorsPath`/`staleEventsPath` explicitly and\n // expected absent values to disable the read. Track that intent so the\n // /incidents handlers don't accidentally read a phantom file.\n errorsPathFor: (ctx: ProjectContext) => string | undefined\n staleEventsPathFor: (ctx: ProjectContext) => string | undefined\n // policy.json lives at the project root (per ADR-042 §File location), not\n // under neat-out/. Routes that read it map a project context to the path.\n policyFilePathFor: (ctx: ProjectContext) => string | undefined\n // Issue #340 — flips per-project routes from 404 to 503 while a slot is\n // still extracting.\n bootstrap?: BuildApiOptions['bootstrap']\n}\n\n// Registers every project-scoped route on `scope`. Called twice from\n// buildApi: once on the root app (so /graph etc. land at default), once\n// inside a `register(_, { prefix: '/projects/:project' })` plugin so the\n// same handlers run when the URL names a project explicitly.\nfunction registerRoutes(scope: FastifyInstance, ctx: RouteContext): void {\n const { registry, startedAt, errorsPathFor, staleEventsPathFor } = ctx\n\n // SSE event stream (ADR-051 #1). Dual-mounted: hits /events for default\n // project and /projects/:project/events when scoped. The handler keeps\n // the connection open and writes one frame per bus envelope whose\n // `project` matches.\n scope.get<{ Params: { project?: string } }>('/events', (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n handleSse(req, reply, { project: proj.name })\n })\n\n // Per-project /health stays scoped. The unscoped `/health` at the root\n // mount is handled by the daemon-wide handler below (issue #343) —\n // daemon-wide readiness mustn't pivot on whether the `default` project\n // exists. The scoped variant carries the bootstrap-aware shape from\n // issue #340.\n if (ctx.scope === 'project') {\n scope.get<{ Params: { project?: string } }>('/health', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const uptimeMs = Date.now() - startedAt\n return {\n ok: true,\n project: proj.name,\n uptimeMs,\n // Legacy fields kept additively. The web shell's StatusBar reads\n // nodeCount / edgeCount; ADR-061's HealthResponseSchema validates\n // the canonical triple and lets the extras pass through.\n uptime: Math.floor(uptimeMs / 1000),\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n lastUpdated: new Date().toISOString(),\n }\n })\n }\n\n scope.get<{ Params: { project?: string } }>('/graph', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n return serializeGraph(proj.graph)\n })\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/node/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n return { node: proj.graph.getNodeAttributes(id) as GraphNode }\n },\n )\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/edges/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n const inbound = proj.graph\n .inboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n const outbound = proj.graph\n .outboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n return { inbound, outbound }\n },\n )\n\n // Transitive dependencies (issue #144). BFS outbound to depth N, returning\n // a flat list with distance + edgeType + provenance per dependency.\n // Default depth 3, max 10. The MCP get_dependencies tool calls this.\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { depth?: string }\n }>('/graph/dependencies/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const depth = req.query.depth ? Number(req.query.depth) : TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH\n if (!Number.isFinite(depth) || depth < 1 || depth > TRANSITIVE_DEPENDENCIES_MAX_DEPTH) {\n return reply.code(400).send({\n error: `depth must be an integer in [1, ${TRANSITIVE_DEPENDENCIES_MAX_DEPTH}]`,\n })\n }\n return getTransitiveDependencies(proj.graph, nodeId, depth)\n })\n\n // Divergence query — the thesis surface (ADR-060). Read-only, derived,\n // dual-mounted via registerRoutes. Query params filter the result set;\n // body shape is DivergenceResult.\n scope.get<{\n Params: { project?: string }\n Querystring: { type?: string; minConfidence?: string; node?: string }\n }>('/graph/divergences', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n let typeFilter: Set<DivergenceType> | undefined\n if (req.query.type) {\n const candidates = req.query.type\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0)\n const parsed: DivergenceType[] = []\n for (const c of candidates) {\n const r = DivergenceTypeSchema.safeParse(c)\n if (!r.success) {\n return reply.code(400).send({\n error: `unknown divergence type \"${c}\"`,\n allowed: DivergenceTypeSchema.options,\n })\n }\n parsed.push(r.data)\n }\n typeFilter = new Set(parsed)\n }\n let minConfidence: number | undefined\n if (req.query.minConfidence !== undefined) {\n const n = Number(req.query.minConfidence)\n if (!Number.isFinite(n) || n < 0 || n > 1) {\n return reply.code(400).send({\n error: 'minConfidence must be a number in [0, 1]',\n })\n }\n minConfidence = n\n }\n return computeDivergences(proj.graph, {\n ...(typeFilter ? { type: typeFilter } : {}),\n ...(minConfidence !== undefined ? { minConfidence } : {}),\n ...(req.query.node ? { node: req.query.node } : {}),\n })\n })\n\n // ADR-061 envelope rule: list endpoints return { count, total, events }.\n // `total` is the size of the underlying collection; `count` is the size of\n // the slice we're handing back. The web shell counts on both.\n scope.get<{\n Params: { project?: string }\n Querystring: { limit?: string }\n }>('/incidents', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const epath = errorsPathFor(proj)\n if (!epath) return { count: 0, total: 0, events: [] }\n const events = await readErrorEvents(epath)\n const total = events.length\n const limit = req.query.limit ? Number(req.query.limit) : 50\n const safeLimit =\n Number.isFinite(limit) && limit > 0 ? Math.min(limit, 200) : 50\n const sliced = events.slice(0, safeLimit)\n return { count: sliced.length, total, events: sliced }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { limit?: string; edgeType?: string }\n }>('/stale-events', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const spath = staleEventsPathFor(proj)\n if (!spath) return { count: 0, total: 0, events: [] }\n const events = await readStaleEvents(spath)\n const filtered = req.query.edgeType\n ? events.filter((e) => e.edgeType === req.query.edgeType)\n : events\n const ordered = [...filtered].reverse()\n const total = ordered.length\n const limit = req.query.limit ? Number(req.query.limit) : 50\n const sliced = ordered.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 50)\n return { count: sliced.length, total, events: sliced }\n })\n\n scope.get<{ Params: { project?: string; nodeId: string } }>(\n '/incidents/:nodeId',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const epath = errorsPathFor(proj)\n if (!epath) return { count: 0, total: 0, events: [] }\n const events = await readErrorEvents(epath)\n const filtered = events.filter(\n (e) =>\n e.affectedNode === nodeId || e.service === nodeId.replace(/^service:/, ''),\n )\n return { count: filtered.length, total: filtered.length, events: filtered }\n },\n )\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { errorId?: string }\n }>('/graph/root-cause/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n let errorEvent: ErrorEvent | undefined\n const epath = errorsPathFor(proj)\n if (req.query.errorId && epath) {\n const events = await readErrorEvents(epath)\n errorEvent = events.find((e) => e.id === req.query.errorId)\n if (!errorEvent) {\n return reply\n .code(404)\n .send({ error: 'error event not found', id: req.query.errorId })\n }\n }\n const result = getRootCause(proj.graph, nodeId, errorEvent)\n if (!result) return reply.code(404).send({ error: 'no root cause found', id: nodeId })\n return result\n })\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { depth?: string }\n }>('/graph/blast-radius/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const depth = req.query.depth ? Number(req.query.depth) : undefined\n if (depth !== undefined && (!Number.isFinite(depth) || depth < 0)) {\n return reply.code(400).send({ error: 'depth must be a non-negative number' })\n }\n return getBlastRadius(proj.graph, nodeId, depth)\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { q?: string; limit?: string }\n }>('/search', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const raw = (req.query.q ?? '').trim()\n if (!raw) return reply.code(400).send({ error: 'query parameter `q` is required' })\n const limit = req.query.limit ? Number(req.query.limit) : undefined\n const safeLimit =\n limit !== undefined && Number.isFinite(limit) && limit > 0 ? limit : undefined\n if (proj.searchIndex) {\n const result = await proj.searchIndex.search(raw, safeLimit)\n return {\n query: result.query,\n provider: result.provider,\n matches: result.matches.map((m) => ({ ...m.node, score: m.score })),\n }\n }\n const q = raw.toLowerCase()\n const matches: (GraphNode & { score: number })[] = []\n proj.graph.forEachNode((id, attrs) => {\n const name = (attrs as { name?: string }).name ?? ''\n if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n matches.push({ ...(attrs as GraphNode), score: 1 })\n }\n })\n return {\n query: q,\n provider: 'substring' as const,\n matches: matches.slice(0, safeLimit),\n }\n })\n\n scope.get<{ Params: { project?: string }; Querystring: { against?: string } }>(\n '/graph/diff',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const against = req.query.against\n if (!against) {\n return reply.code(400).send({ error: 'query parameter `against` is required' })\n }\n try {\n const snapshot = await loadSnapshotForDiff(against)\n return computeGraphDiff(proj.graph, snapshot)\n } catch (err) {\n return reply\n .code(400)\n .send({ error: 'failed to load snapshot', against, detail: (err as Error).message })\n }\n },\n )\n\n // Snapshot push (ADR-074 §1). `neat sync` POSTs a snapshot here; we merge\n // it into the live graph through `mergeSnapshot`, which preserves any\n // accumulated OBSERVED edges per the Rule 2 coexistence contract. Body\n // shape is the same JSON `persist.ts` writes to disk. Dual-mounted at\n // `/snapshot` and `/projects/:project/snapshot` via registerRoutes.\n scope.post<{\n Params: { project?: string }\n Body: { snapshot?: PersistedGraph }\n }>('/snapshot', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const body = req.body\n if (!body || typeof body !== 'object' || !body.snapshot) {\n return reply\n .code(400)\n .send({ error: 'request body must be { snapshot: <persisted-graph> }' })\n }\n const snap = body.snapshot\n if (typeof snap.schemaVersion !== 'number' || snap.schemaVersion !== SCHEMA_VERSION) {\n return reply.code(400).send({\n error: `unsupported snapshot schemaVersion ${snap.schemaVersion} (expected ${SCHEMA_VERSION})`,\n })\n }\n try {\n const result = mergeSnapshot(proj.graph, snap)\n return {\n project: proj.name,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n }\n } catch (err) {\n return reply.code(400).send({\n error: 'snapshot merge failed',\n details: (err as Error).message,\n })\n }\n })\n\n scope.post<{ Params: { project?: string } }>('/graph/scan', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply\n .code(409)\n .send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const result = await extractFromDirectory(proj.graph, proj.scanPath)\n return {\n project: proj.name,\n scanned: proj.scanPath,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n }\n })\n\n // Policy surface (ADR-045 / contract #18). /policies returns the parsed\n // policy.json; /policies/violations is the persistent log; /policies/check\n // is dry-run evaluation. All dual-mounted via registerRoutes.\n scope.get<{ Params: { project?: string } }>('/policies', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const policyPath = ctx.policyFilePathFor(proj)\n if (!policyPath) {\n // No policy file configured for this project — return the empty file\n // shape so consumers don't have to special-case \"no policies yet.\"\n return { version: 1, policies: [] }\n }\n try {\n const policies = await loadPolicyFile(policyPath)\n return { version: 1, policies }\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { severity?: string; policyId?: string }\n }>('/policies/violations', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const log = new PolicyViolationsLog(proj.paths.policyViolationsPath)\n let violations = await log.readAll()\n if (req.query.severity) {\n const sev = PolicySeveritySchema.safeParse(req.query.severity)\n if (!sev.success) {\n return reply.code(400).send({\n error: 'invalid severity',\n details: sev.error.format(),\n })\n }\n violations = violations.filter((v) => v.severity === sev.data)\n }\n if (req.query.policyId) {\n violations = violations.filter((v) => v.policyId === req.query.policyId)\n }\n return { violations }\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { hypotheticalAction?: unknown }\n }>('/policies/check', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const parsed = PoliciesCheckBodySchema.safeParse(req.body ?? {})\n if (!parsed.success) {\n return reply.code(400).send({\n error: 'invalid /policies/check body',\n details: parsed.error.format(),\n })\n }\n\n const policyPath = ctx.policyFilePathFor(proj)\n let policies: Policy[] = []\n if (policyPath) {\n try {\n policies = await loadPolicyFile(policyPath)\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n }\n\n // No hypothetical → return current violations against the live graph.\n // With a hypothetical → simulate the action against a deep-copy graph\n // (avoids mutation authority concerns), evaluate, return the delta.\n const evalCtx = { now: () => Date.now() }\n if (!parsed.data.hypotheticalAction) {\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return { allowed: blocking.length === 0, violations }\n }\n\n // For now the dry-run simulation re-uses evaluateAllPolicies on the\n // current graph. Full hypothetical simulation (e.g. \"what if I added\n // this OBSERVED edge?\") is the v0.2.4-δ scope; #117 ships the surface,\n // #118 fills in the action shapes' simulation logic.\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return {\n allowed: blocking.length === 0,\n hypotheticalAction: parsed.data.hypotheticalAction,\n violations,\n } as { allowed: boolean; hypotheticalAction: unknown; violations: PolicyViolation[] }\n })\n}\n\nexport async function buildApi(opts: BuildApiOptions): Promise<FastifyInstance> {\n const app = Fastify({ logger: false })\n await app.register(cors, { origin: true })\n\n // ADR-073 §3/§4 — `buildApi` owns auth enforcement so every listener that\n // serves the REST surface gets the same gate, whoever builds it. When a\n // caller doesn't pass auth options explicitly, they resolve from the\n // environment (`NEAT_AUTH_TOKEN` / `NEAT_AUTH_PROXY` / `NEAT_PUBLIC_READ`)\n // through the single `readAuthEnv` reader. A caller that does pass them\n // wins, so the daemon and `serve` keep their explicit wiring; a caller that\n // omits them — `neat watch` — inherits the same token rather than serving\n // open by omission. The bind-host loopback refusal stays with the binding\n // caller via `assertBindAuthority`, which reads the same env.\n const env = readAuthEnv()\n const authToken = opts.authToken ?? env.authToken\n const trustProxy = opts.trustProxy ?? env.trustProxy\n const publicRead = opts.publicRead ?? env.publicRead\n\n // ADR-073 §3 — bearer middleware sits ahead of every route handler. No-op\n // when the resolved token is undefined; loopback-only callers (the laptop\n // dev path) hit that branch. `publicRead` opens GET / HEAD / OPTIONS to\n // anonymous callers while keeping writes gated.\n mountBearerAuth(app, {\n token: authToken,\n trustProxy,\n publicRead,\n })\n\n // ADR-073 §3 amendment — `/api/config` is always unauthenticated. The web\n // shell hits it before any bearer-carrying request to learn which mode the\n // daemon is in. Exposes exactly two booleans — `publicRead` and\n // `authProxy` — and nothing else; no project list, no version, no env.\n app.get('/api/config', async () => ({\n publicRead: publicRead === true,\n authProxy: trustProxy === true,\n }))\n\n const startedAt = opts.startedAt ?? Date.now()\n const registry = buildLegacyRegistry(opts)\n\n const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== undefined\n const legacyStaleExplicit = !opts.projects && opts.staleEventsPath !== undefined\n\n const errorsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyErrorsExplicit ? opts.errorsPath : undefined\n }\n return proj.paths.errorsPath\n }\n const staleEventsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyStaleExplicit ? opts.staleEventsPath : undefined\n }\n return proj.paths.staleEventsPath\n }\n\n // policy.json lives at the project's scanPath root per ADR-042. Without a\n // scanPath we have nowhere to read it from — those projects show as\n // \"no policies configured\" via the empty-file response.\n const policyFilePathFor = (proj: ProjectContext): string | undefined => {\n if (!proj.scanPath) return undefined\n return `${proj.scanPath}/policy.json`\n }\n\n const routeCtx: RouteContext = {\n registry,\n startedAt,\n scope: 'root',\n errorsPathFor,\n staleEventsPathFor,\n policyFilePathFor,\n bootstrap: opts.bootstrap,\n }\n\n // Daemon-wide /health (issue #343). Per ADR-049 the daemon is the unit of\n // readiness; the response answers \"is this process up and what's it\n // currently serving?\" without depending on a `default` project. Probes —\n // orchestrator, kubelet readiness, systemd, supervisors — read this.\n //\n // The `projects` array surfaces every slot the daemon knows about. When\n // the bootstrap tracker is wired (issue #340), the per-entry `status`\n // and `elapsedMs` come from there so the orchestrator's wait loop can\n // tell `bootstrapping` apart from `active` without per-project probes.\n app.get('/health', async () => {\n const uptimeMs = Date.now() - startedAt\n const bootstrapList = opts.bootstrap?.list() ?? []\n const byName = new Map(bootstrapList.map((p) => [p.name, p]))\n const names = new Set<string>([\n ...registry.list(),\n ...bootstrapList.map((p) => p.name),\n ])\n const projects = [...names].sort().map((name) => {\n const proj = registry.get(name)\n const tracked = byName.get(name)\n return {\n name,\n nodeCount: proj?.graph.order ?? 0,\n edgeCount: proj?.graph.size ?? 0,\n ...(tracked ? { status: tracked.status, elapsedMs: tracked.elapsedMs } : {}),\n }\n })\n return {\n ok: true,\n uptimeMs,\n projects,\n }\n })\n\n // Multi-project switcher (ADR-051 #4). Direct passthrough of the\n // machine-level registry from registry.ts (ADR-048) — distinct from the\n // dual-mount routing in ADR-026, which exposes per-project endpoints.\n // Returns Array<{ name, path, status, registeredAt, lastSeenAt?, languages }>.\n app.get('/projects', async (_req, reply) => {\n try {\n return await listRegistryProjects()\n } catch (err) {\n return reply.code(500).send({\n error: 'failed to read project registry',\n details: (err as Error).message,\n })\n }\n })\n\n // Singular project lookup (ADR-061 #7). Distinct route from the\n // `/projects/:project/...` dual-mount prefix because Fastify matches on\n // the full path; the trailing-segment-less request lands here.\n app.get<{ Params: { project: string } }>('/projects/:project', async (req, reply) => {\n try {\n const entry = await getRegistryProject(req.params.project)\n if (!entry) {\n return reply\n .code(404)\n .send({ error: 'project not found', project: req.params.project })\n }\n return { project: entry }\n } catch (err) {\n return reply.code(500).send({\n error: 'failed to read project registry',\n details: (err as Error).message,\n })\n }\n })\n\n // Default mount: /graph, /incidents, etc. resolve to project=default.\n // `/health` at this scope is the daemon-wide handler registered above,\n // not the per-project one (issue #343).\n registerRoutes(app, routeCtx)\n\n // Project-scoped mount: same handlers, URL params include `:project`,\n // and `/health` answers per project.\n await app.register(\n async (scope) => {\n registerRoutes(scope, { ...routeCtx, scope: 'project' })\n },\n { prefix: '/projects/:project' },\n )\n\n return app\n}\n","import { promises as fs } from 'node:fs'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Diff a snapshot on disk (or fetched over HTTP) against the live in-memory\n// graph. The \"base\" is the snapshot you supplied; the \"current\" is whatever\n// the server has loaded right now. Symmetric in shape, but consumers usually\n// want to read it as \"what changed since base.\"\n//\n// The shape mirrors the issue's spec (#77):\n// { added: { nodes, edges }, removed: { nodes, edges },\n// changed: { nodes: [{id, before, after}], edges: [{id, before, after}] } }\n//\n// Both timestamps are echoed back so the caller doesn't have to track them\n// separately.\n\ninterface PersistedNodeEntry {\n key?: string\n attributes?: Record<string, unknown>\n}\n\ninterface PersistedEdgeEntry {\n key?: string\n source?: string\n target?: string\n attributes?: Record<string, unknown>\n}\n\nexport interface PersistedSnapshot {\n schemaVersion?: number\n exportedAt?: string\n graph?: {\n nodes?: PersistedNodeEntry[]\n edges?: PersistedEdgeEntry[]\n }\n}\n\nexport interface GraphDiff {\n base: { exportedAt?: string }\n current: { exportedAt: string }\n added: { nodes: GraphNode[]; edges: GraphEdge[] }\n removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n changed: {\n nodes: { id: string; before: GraphNode; after: GraphNode }[]\n edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n }\n}\n\nexport async function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot> {\n if (/^https?:\\/\\//i.test(target)) {\n const res = await fetch(target)\n if (!res.ok) {\n throw new Error(`fetch ${target} failed: ${res.status} ${res.statusText}`)\n }\n return (await res.json()) as PersistedSnapshot\n }\n const raw = await fs.readFile(target, 'utf8')\n return JSON.parse(raw) as PersistedSnapshot\n}\n\nfunction indexEntries<T>(\n entries: { key?: string; attributes?: Record<string, unknown> }[] | undefined,\n): Map<string, T> {\n const m = new Map<string, T>()\n if (!entries) return m\n for (const entry of entries) {\n const id = (entry.attributes?.id as string | undefined) ?? entry.key\n if (!id) continue\n m.set(id, entry.attributes as T)\n }\n return m\n}\n\nexport function computeGraphDiff(\n liveGraph: NeatGraph,\n baseSnapshot: PersistedSnapshot,\n currentExportedAt: string = new Date().toISOString(),\n): GraphDiff {\n const baseNodes = indexEntries<GraphNode>(baseSnapshot.graph?.nodes)\n const baseEdges = indexEntries<GraphEdge>(baseSnapshot.graph?.edges)\n\n const liveNodes = new Map<string, GraphNode>()\n liveGraph.forEachNode((id, attrs) => liveNodes.set(id, attrs as GraphNode))\n const liveEdges = new Map<string, GraphEdge>()\n liveGraph.forEachEdge((id, attrs) => liveEdges.set(id, attrs as GraphEdge))\n\n const result: GraphDiff = {\n base: { exportedAt: baseSnapshot.exportedAt },\n current: { exportedAt: currentExportedAt },\n added: { nodes: [], edges: [] },\n removed: { nodes: [], edges: [] },\n changed: { nodes: [], edges: [] },\n }\n\n for (const [id, after] of liveNodes) {\n const before = baseNodes.get(id)\n if (!before) {\n result.added.nodes.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.nodes.push({ id, before, after })\n }\n }\n for (const [id, before] of baseNodes) {\n if (!liveNodes.has(id)) result.removed.nodes.push(before)\n }\n for (const [id, after] of liveEdges) {\n const before = baseEdges.get(id)\n if (!before) {\n result.added.edges.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.edges.push({ id, before, after })\n }\n }\n for (const [id, before] of baseEdges) {\n if (!liveEdges.has(id)) result.removed.edges.push(before)\n }\n\n return result\n}\n\n// Stable JSON comparison. Snapshot order isn't guaranteed, so canonicalising\n// keys before stringify keeps the comparison robust against re-ordered fields.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n return canonicalJson(a) === canonicalJson(b)\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(value, (_key, v) => {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n return Object.keys(v as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = (v as Record<string, unknown>)[k]\n return acc\n }, {})\n }\n return v\n })\n}\n","// Project registry — owns the per-project state that lives alongside the\n// graph map: snapshot/error/stale paths, scan path, optional search index.\n//\n// Routes use it via `resolve(project)`. Server / watch construct it once at\n// boot and pass it to buildApi. Tests can mock it with a small literal.\n\nimport path from 'node:path'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport type { SearchIndex } from './search.js'\n\nexport interface ProjectPaths {\n snapshotPath: string\n errorsPath: string\n staleEventsPath: string\n embeddingsCachePath: string\n // Policy-violations log per ADR-041 § Append-only ndjson sidecars. Lives\n // in the same neat-out directory as the other ndjson sidecars; daemons\n // wire PolicyViolationsLog to it.\n policyViolationsPath: string\n}\n\n// Default project keeps the legacy filenames so existing M5 / β / γ users\n// see no behaviour change. Named projects fan out by name (ADR-026).\nexport function pathsForProject(project: string, baseDir: string): ProjectPaths {\n if (project === DEFAULT_PROJECT) {\n return {\n snapshotPath: path.join(baseDir, 'graph.json'),\n errorsPath: path.join(baseDir, 'errors.ndjson'),\n staleEventsPath: path.join(baseDir, 'stale-events.ndjson'),\n embeddingsCachePath: path.join(baseDir, 'embeddings.json'),\n policyViolationsPath: path.join(baseDir, 'policy-violations.ndjson'),\n }\n }\n return {\n snapshotPath: path.join(baseDir, `${project}.json`),\n errorsPath: path.join(baseDir, `errors.${project}.ndjson`),\n staleEventsPath: path.join(baseDir, `stale-events.${project}.ndjson`),\n embeddingsCachePath: path.join(baseDir, `embeddings.${project}.json`),\n policyViolationsPath: path.join(baseDir, `policy-violations.${project}.ndjson`),\n }\n}\n\nexport interface ProjectContext {\n name: string\n graph: NeatGraph\n scanPath?: string\n paths: ProjectPaths\n searchIndex?: SearchIndex\n}\n\nexport class Projects {\n private contexts = new Map<string, ProjectContext>()\n\n upsert(ctx: ProjectContext): void {\n this.contexts.set(ctx.name, ctx)\n }\n\n set(\n name: string,\n init: Omit<ProjectContext, 'name' | 'graph'> & { graph?: NeatGraph },\n ): ProjectContext {\n const ctx: ProjectContext = {\n name,\n graph: init.graph ?? getGraph(name),\n scanPath: init.scanPath,\n paths: init.paths,\n searchIndex: init.searchIndex,\n }\n this.contexts.set(name, ctx)\n return ctx\n }\n\n get(name: string): ProjectContext | undefined {\n return this.contexts.get(name)\n }\n\n has(name: string): boolean {\n return this.contexts.has(name)\n }\n\n list(): string[] {\n return [...this.contexts.keys()].sort()\n }\n\n attachSearchIndex(name: string, index: SearchIndex | undefined): void {\n const ctx = this.contexts.get(name)\n if (ctx) ctx.searchIndex = index\n }\n}\n\n// Parses NEAT_PROJECTS=a,b,c; trims whitespace, drops empty entries.\n// `default` is implicit (always loaded), so callers usually filter it out\n// before iterating extra projects.\nexport function parseExtraProjects(raw: string | undefined): string[] {\n if (!raw) return []\n return raw\n .split(',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0 && p !== DEFAULT_PROJECT)\n}\n","/**\n * Machine-level project registry (ADR-048).\n *\n * One file: `~/.neat/projects.json`. Per-user, machine-local. Not synced.\n * `registry.ts` is the only module that opens it. Everything else — `init`,\n * `daemon`, `cli` — calls into the helpers below.\n *\n * Two safety properties matter:\n * 1. Atomic writes. We tmp + fsync + rename so the daemon never sees a torn\n * file when init races against it.\n * 2. Cross-process exclusion. We hold an exclusive lock on\n * `~/.neat/projects.json.lock` for the read-modify-write window. Two\n * concurrent `neat init` runs cannot both win and overwrite each other.\n *\n * The lock is a file we exclusively-create (`O_EXCL`), hold while we mutate,\n * and unlink on the way out. Crude but cross-platform; matches what\n * `proper-lockfile` does internally without pulling the dep in.\n */\n\nimport { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport {\n RegistryFileSchema,\n type RegistryEntry,\n type RegistryFile,\n type RegistryStatus,\n} from '@neat.is/types'\n\nconst LOCK_TIMEOUT_MS = 5_000\nconst LOCK_RETRY_MS = 50\n\n// Resolve `~/.neat/` per call so tests can override `HOME` / `NEAT_HOME`\n// before each run without module-load order mattering.\nfunction neatHome(): string {\n const override = process.env.NEAT_HOME\n if (override && override.length > 0) return path.resolve(override)\n return path.join(os.homedir(), '.neat')\n}\n\nexport function registryPath(): string {\n return path.join(neatHome(), 'projects.json')\n}\n\nexport function registryLockPath(): string {\n return path.join(neatHome(), 'projects.json.lock')\n}\n\n// The daemon writes its PID here on startup (daemon.ts). It's the authoritative\n// \"is a neat daemon running\" signal — more reliable than matching the lock's\n// own PID, since the daemon holds the registry lock only for brief read-modify-\n// write windows and an init that contends usually catches an orphaned lock\n// rather than the daemon mid-write.\nfunction daemonPidPath(): string {\n return path.join(neatHome(), 'neatd.pid')\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #432 — distinguish a live daemon from a genuinely stale lock.\n//\n// `neat init` used to hang the full timeout on any contended lock and then\n// print one remediation: \"remove the file by hand.\" That advice is actively\n// dangerous when a neat daemon is alive — the daemon grabs the lock for its\n// own registry writes, so hand-removing it races the daemon and corrupts the\n// registry for the live process. The lock now carries the holder PID, and the\n// timeout (or first contention with a live daemon) resolves to a message that\n// names who holds it and what's safe to do.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type LockHolder =\n | { kind: 'daemon'; pid: number }\n | { kind: 'command'; pid: number }\n | { kind: 'stale' }\n\n// Probes the holder-resolution logic depends on, broken out so tests can drive\n// each branch without a real daemon or live PIDs.\nexport interface LockHolderProbe {\n // POSIX liveness via `process.kill(pid, 0)`: true if the process exists\n // (including EPERM — alive but owned by another user), false if it's gone.\n isPidAlive(pid: number): boolean\n // PID recorded in `~/.neat/neatd.pid`, or undefined if there's no pidfile.\n daemonPidFromFile(): Promise<number | undefined>\n // Whether the daemon's always-open `/health` endpoint answers. Confirms a\n // live neatd.pid is actually our daemon and not a reused PID.\n daemonResponds(): Promise<boolean>\n}\n\nfunction isPidAliveDefault(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err) {\n // ESRCH → no such process (dead). EPERM → exists but owned by another user\n // (alive). Treat anything else as not-alive: we'd rather under-claim a live\n // holder than wrongly block on a lock we can't verify.\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nasync function readPidFile(file: string): Promise<number | undefined> {\n try {\n const raw = await fs.readFile(file, 'utf8')\n const pid = Number.parseInt(raw.trim(), 10)\n return Number.isInteger(pid) && pid > 0 ? pid : undefined\n } catch {\n return undefined\n }\n}\n\nconst defaultLockHolderProbe: LockHolderProbe = {\n isPidAlive: isPidAliveDefault,\n daemonPidFromFile: () => readPidFile(daemonPidPath()),\n async daemonResponds(): Promise<boolean> {\n const base = process.env.NEAT_API_URL ?? 'http://localhost:8080'\n try {\n // `/health` stays unauthenticated in every mode (auth.ts), so a reachable\n // daemon answers it even with a bearer token set. Any HTTP response — not\n // just 2xx — means a daemon owns the port. A short timeout keeps the\n // fail-fast path well under a second.\n await fetch(`${base}/health`, { signal: AbortSignal.timeout(750) })\n return true\n } catch {\n return false\n }\n },\n}\n\n// Read the PID a lock holder recorded when it created the lock. Undefined for a\n// legacy empty lock, an unreadable file, or a lock unlinked out from under us.\nasync function readLockPid(lockPath: string): Promise<number | undefined> {\n return readPidFile(lockPath)\n}\n\n// Decide who holds (or orphaned) the lock. A live daemon dominates: while neatd\n// is alive, hand-removing the lock is never safe, so we surface the daemon\n// message even when the lock itself is an empty orphan. We never classify our\n// own process as the blocking daemon — a daemon serializing two of its own\n// registry writes contends with itself briefly and should just retry.\nexport async function classifyLockHolder(\n lockPath: string,\n probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<LockHolder> {\n const lockPid = await readLockPid(lockPath)\n const daemonPid = await probe.daemonPidFromFile()\n if (\n daemonPid !== undefined &&\n daemonPid !== process.pid &&\n probe.isPidAlive(daemonPid) &&\n // The lock already names the daemon, or the daemon answers on its port.\n // Either confirms a live daemon is in the picture (the second guards\n // against a stale pidfile whose PID got reused).\n (daemonPid === lockPid || (await probe.daemonResponds()))\n ) {\n return { kind: 'daemon', pid: daemonPid }\n }\n if (lockPid !== undefined && lockPid !== process.pid && probe.isPidAlive(lockPid)) {\n return { kind: 'command', pid: lockPid }\n }\n return { kind: 'stale' }\n}\n\nexport function lockHolderMessage(holder: LockHolder, lockPath: string, timeoutMs: number): string {\n switch (holder.kind) {\n case 'daemon':\n return (\n `The neat daemon (pid ${holder.pid}) is holding the registry lock. ` +\n 'Register this project through the daemon, or stop neatd and re-run `neat init`.'\n )\n case 'command':\n return (\n `Another neat command (pid ${holder.pid}) is holding the registry lock. ` +\n \"Wait for it to finish, or check `ps` if you're not sure what's running.\"\n )\n case 'stale':\n return (\n `neat registry: timed out after ${timeoutMs}ms waiting for ${lockPath}. ` +\n 'Another neat process is holding the lock; if no such process exists, remove the file by hand.'\n )\n }\n}\n\n/**\n * Path normalisation per ADR-048 #7. Two `init` calls from different relative\n * paths to the same dir must collapse to one entry. `path.resolve` handles\n * relative-to-cwd; we pass it through `fs.realpath` when the dir exists so\n * symlinked paths land on the same canonical entry too.\n */\nexport async function normalizeProjectPath(input: string): Promise<string> {\n const resolved = path.resolve(input)\n try {\n return await fs.realpath(resolved)\n } catch {\n return resolved\n }\n}\n\n/**\n * tmp + fsync + rename. The fsync on the data fd guarantees the bytes are on\n * disk before rename swaps the inode; rename itself is atomic on POSIX.\n *\n * Exported so the init flow and test harnesses can use the same helper.\n */\nexport async function writeAtomically(target: string, contents: string): Promise<void> {\n await fs.mkdir(path.dirname(target), { recursive: true })\n const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`\n const fd = await fs.open(tmp, 'w')\n try {\n await fd.writeFile(contents, 'utf8')\n await fd.sync()\n } finally {\n await fd.close()\n }\n await fs.rename(tmp, target)\n}\n\nasync function acquireLock(\n lockPath: string,\n timeoutMs: number = LOCK_TIMEOUT_MS,\n probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<void> {\n const deadline = Date.now() + timeoutMs\n await fs.mkdir(path.dirname(lockPath), { recursive: true })\n let probedHolder = false\n while (true) {\n try {\n const fd = await fs.open(lockPath, 'wx')\n try {\n // Stamp the lock with our PID so a contender can name who holds it and\n // tell a live holder apart from a stale file. Best-effort: an empty\n // lock still excludes correctly, it just can't be diagnosed.\n await fd.writeFile(`${process.pid}\\n`, 'utf8')\n } finally {\n await fd.close()\n }\n return\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code !== 'EEXIST') throw err\n // A live daemon holds the registry continuously enough that spinning the\n // full timeout is pointless — surface the routed remediation on the first\n // contention. Peer commands and stale locks fall through to the retry:\n // peers clear on their own, and a stale lock wants the timeout's guidance.\n if (!probedHolder) {\n probedHolder = true\n const holder = await classifyLockHolder(lockPath, probe)\n if (holder.kind === 'daemon') throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n }\n if (Date.now() >= deadline) {\n const holder = await classifyLockHolder(lockPath, probe)\n throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n }\n await new Promise((r) => setTimeout(r, LOCK_RETRY_MS))\n }\n }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {})\n}\n\nasync function withLock<T>(fn: () => Promise<T>): Promise<T> {\n const lock = registryLockPath()\n await acquireLock(lock)\n try {\n return await fn()\n } finally {\n await releaseLock(lock)\n }\n}\n\n/**\n * Read the registry from disk. Returns an empty registry if the file does\n * not exist yet — first run, never registered anything.\n *\n * Throws on parse / schema errors. The contract is single-source-of-truth;\n * a corrupt file is louder than a silent reset.\n */\nexport async function readRegistry(): Promise<RegistryFile> {\n const file = registryPath()\n let raw: string\n try {\n raw = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { version: 1, projects: [] }\n }\n throw err\n }\n const parsed = JSON.parse(raw)\n return RegistryFileSchema.parse(parsed)\n}\n\nasync function writeRegistry(reg: RegistryFile): Promise<void> {\n // Re-parse before writing to surface schema drift introduced by callers\n // mutating the in-memory object directly.\n const validated = RegistryFileSchema.parse(reg)\n await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + '\\n')\n}\n\nexport interface AddProjectOptions {\n name: string\n path: string\n languages?: string[]\n status?: RegistryStatus\n}\n\nexport class ProjectNameCollisionError extends Error {\n readonly projectName: string\n constructor(name: string) {\n super(`neat registry: a project named \"${name}\" is already registered`)\n this.name = 'ProjectNameCollisionError'\n this.projectName = name\n }\n}\n\n/**\n * Register a project, or update its `lastSeenAt` if the same path is already\n * registered under the same name (idempotent re-init).\n *\n * Hard error on name collision against a different path — ADR-046 #7. The\n * caller can recover by passing `--project <new-name>`.\n */\nexport async function addProject(opts: AddProjectOptions): Promise<RegistryEntry> {\n const resolvedPath = await normalizeProjectPath(opts.path)\n return withLock(async () => {\n const reg = await readRegistry()\n const byName = reg.projects.find((p) => p.name === opts.name)\n const byPath = reg.projects.find((p) => p.path === resolvedPath)\n\n if (byName && byName.path !== resolvedPath) {\n throw new ProjectNameCollisionError(opts.name)\n }\n\n const now = new Date().toISOString()\n\n if (byName && byName.path === resolvedPath) {\n // Idempotent re-register: same name, same path. Refresh languages /\n // status if the caller passed new ones.\n byName.lastSeenAt = now\n if (opts.languages) byName.languages = opts.languages\n if (opts.status) byName.status = opts.status\n await writeRegistry(reg)\n return byName\n }\n\n if (byPath && byPath.name !== opts.name) {\n // Same dir already registered under a different name. Treat as a\n // collision so the user is forced to decide which name wins.\n throw new ProjectNameCollisionError(byPath.name)\n }\n\n const entry: RegistryEntry = {\n name: opts.name,\n path: resolvedPath,\n registeredAt: now,\n languages: opts.languages ?? [],\n status: opts.status ?? 'active',\n }\n reg.projects.push(entry)\n await writeRegistry(reg)\n return entry\n })\n}\n\nexport async function getProject(name: string): Promise<RegistryEntry | undefined> {\n const reg = await readRegistry()\n return reg.projects.find((p) => p.name === name)\n}\n\nexport async function listProjects(): Promise<RegistryEntry[]> {\n const reg = await readRegistry()\n return reg.projects\n}\n\nexport async function setStatus(name: string, status: RegistryStatus): Promise<RegistryEntry> {\n return withLock(async () => {\n const reg = await readRegistry()\n const entry = reg.projects.find((p) => p.name === name)\n if (!entry) throw new Error(`neat registry: no project named \"${name}\"`)\n entry.status = status\n await writeRegistry(reg)\n return entry\n })\n}\n\nexport async function touchLastSeen(name: string, at: string = new Date().toISOString()): Promise<void> {\n await withLock(async () => {\n const reg = await readRegistry()\n const entry = reg.projects.find((p) => p.name === name)\n if (!entry) return\n entry.lastSeenAt = at\n await writeRegistry(reg)\n })\n}\n\n/**\n * Remove the registry entry for `name`. Per ADR-048 #6: this only removes the\n * registry row. It does **not** touch `neat-out/`, `policy.json`, or any user\n * file in the project directory. SDK-install rollback is a separate flow\n * (`neat-rollback.patch`) that the caller opts in to.\n */\nexport async function removeProject(name: string): Promise<RegistryEntry | undefined> {\n return withLock(async () => {\n const reg = await readRegistry()\n const idx = reg.projects.findIndex((p) => p.name === name)\n if (idx < 0) return undefined\n const [removed] = reg.projects.splice(idx, 1)\n await writeRegistry(reg)\n return removed\n })\n}\n\n","// SSE handler for the frontend-facing event stream (ADR-051 #1).\n// Subscribes to the bus in events.ts, filters by project, writes\n// `event: <type>\\ndata: <json>\\n\\n` frames to the client.\n//\n// Backpressure: per-connection queue cap of 1000 outstanding writes; once\n// hit, the connection is dropped with `event: error data: { reason:\n// 'backpressure' }` per ADR-051 #8. Heartbeat: comment line every 30s\n// keeps proxies from idle-timing out (ADR-051 #3).\n\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport {\n EVENT_BUS_CHANNEL,\n eventBus,\n type NeatEventEnvelope,\n} from './events.js'\n\nexport const SSE_HEARTBEAT_MS = 30_000\nexport const SSE_BACKPRESSURE_CAP = 1000\n\nexport interface HandleSseOptions {\n project: string\n heartbeatMs?: number\n backpressureCap?: number\n}\n\nexport function handleSse(\n req: FastifyRequest,\n reply: FastifyReply,\n opts: HandleSseOptions,\n): void {\n const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS\n const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP\n\n reply.raw.setHeader('Content-Type', 'text/event-stream')\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n reply.raw.setHeader('Connection', 'keep-alive')\n reply.raw.setHeader('X-Accel-Buffering', 'no')\n reply.raw.flushHeaders?.()\n\n let pending = 0\n let dropped = false\n\n const closeConnection = (): void => {\n if (dropped) return\n dropped = true\n eventBus.off(EVENT_BUS_CHANNEL, listener)\n clearInterval(heartbeat)\n if (!reply.raw.writableEnded) reply.raw.end()\n }\n\n const writeFrame = (frame: string): void => {\n if (dropped) return\n if (pending >= backpressureCap) {\n // Past the cap — emit one final error frame and drop. Don't try to\n // gracefully drain; a slow consumer that's already 1000 frames behind\n // is not going to catch up.\n const errFrame = `event: error\\ndata: ${JSON.stringify({ reason: 'backpressure' })}\\n\\n`\n reply.raw.write(errFrame)\n closeConnection()\n return\n }\n pending++\n reply.raw.write(frame, () => {\n pending = Math.max(0, pending - 1)\n })\n }\n\n const listener = (envelope: NeatEventEnvelope): void => {\n if (envelope.project !== opts.project) return\n writeFrame(`event: ${envelope.type}\\ndata: ${JSON.stringify(envelope.payload)}\\n\\n`)\n }\n\n eventBus.on(EVENT_BUS_CHANNEL, listener)\n\n const heartbeat = setInterval(() => {\n if (dropped) return\n reply.raw.write(':heartbeat\\n\\n')\n }, heartbeatMs)\n if (typeof heartbeat.unref === 'function') heartbeat.unref()\n\n req.raw.on('close', closeConnection)\n reply.raw.on('close', closeConnection)\n reply.raw.on('error', closeConnection)\n}\n","// semantic_search — embedding-based node retrieval with a three-tier\n// fallback chain. The chain is settled in ADR-025; this file is the\n// implementation. Public API:\n//\n// buildSearchIndex(graph, opts) → SearchIndex\n// SearchIndex.search(query, limit) → { provider, matches }\n// SearchIndex.refresh(graph) → re-embeds new/changed nodes,\n// drops vanished ones\n//\n// The `/search` route in api.ts holds a single SearchIndex, refreshing it\n// after any extraction. MCP's `semantic_search` tool reads the same shape.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { createHash } from 'node:crypto'\nimport type { GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport interface ScoredNode {\n node: GraphNode\n score: number\n}\n\nexport interface SearchResponse {\n query: string\n provider: 'ollama' | 'transformers' | 'substring'\n matches: ScoredNode[]\n}\n\nexport interface SearchIndex {\n readonly provider: SearchResponse['provider']\n search(query: string, limit?: number): Promise<SearchResponse>\n refresh(graph: NeatGraph): Promise<void>\n}\n\ninterface Embedder {\n provider: 'ollama' | 'transformers'\n model: string\n dim: number\n embed(texts: string[]): Promise<Float32Array[]>\n}\n\nconst DEFAULT_LIMIT = 10\nconst NOMIC_DIM = 768\nconst MINI_LM_DIM = 384\n\n// FrontierNodes are noise by design (placeholders that should disappear).\n// Embedding them would just clutter results.\nfunction shouldEmbed(node: GraphNode): boolean {\n return node.type !== 'FrontierNode'\n}\n\n// Deterministic per-node text. Stable keys let the cache hit across\n// extractions when nothing material changed.\nexport function embedText(node: GraphNode): string {\n const parts: string[] = [node.id]\n const name = (node as { name?: string }).name\n if (name) parts.push(name)\n switch (node.type) {\n case 'ServiceNode': {\n const lang = (node as { language?: string }).language\n if (lang) parts.push(`language=${lang}`)\n break\n }\n case 'DatabaseNode': {\n const eng = (node as { engine?: string }).engine\n const ver = (node as { engineVersion?: string }).engineVersion\n if (eng) parts.push(`engine=${eng}`)\n if (ver) parts.push(`engineVersion=${ver}`)\n break\n }\n case 'InfraNode': {\n const kind = (node as { kind?: string }).kind\n if (kind) parts.push(`kind=${kind}`)\n break\n }\n case 'ConfigNode': {\n const filePath = (node as { path?: string }).path\n if (filePath) parts.push(`path=${filePath}`)\n break\n }\n default:\n break\n }\n return parts.join(' ')\n}\n\nfunction attrsHash(node: GraphNode): string {\n return createHash('sha1').update(embedText(node)).digest('hex').slice(0, 16)\n}\n\nexport function cosine(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) return 0\n let dot = 0\n let na = 0\n let nb = 0\n for (let i = 0; i < a.length; i++) {\n const ai = a[i] ?? 0\n const bi = b[i] ?? 0\n dot += ai * bi\n na += ai * ai\n nb += bi * bi\n }\n if (na === 0 || nb === 0) return 0\n return dot / (Math.sqrt(na) * Math.sqrt(nb))\n}\n\n// ---------------------------------------------------------------- Embedders\n\nfunction ollamaHost(): string | null {\n return process.env.OLLAMA_HOST ?? null\n}\n\nasync function ollamaReachable(host: string): Promise<boolean> {\n try {\n const res = await fetch(`${host.replace(/\\/$/, '')}/api/tags`, {\n signal: AbortSignal.timeout(500),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nfunction makeOllamaEmbedder(host: string, model = 'nomic-embed-text'): Embedder {\n const root = host.replace(/\\/$/, '')\n return {\n provider: 'ollama',\n model,\n dim: NOMIC_DIM,\n async embed(texts: string[]): Promise<Float32Array[]> {\n const out: Float32Array[] = []\n // Ollama's /api/embeddings is one-text-per-request. ≤10K nodes × ~30ms\n // each is fine for a one-shot index build; if it ever isn't, the API\n // also accepts batched input on /api/embed (newer routes).\n for (const text of texts) {\n const res = await fetch(`${root}/api/embeddings`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model, prompt: text }),\n })\n if (!res.ok) {\n throw new Error(`ollama embeddings: ${res.status} ${res.statusText}`)\n }\n const data = (await res.json()) as { embedding: number[] }\n out.push(Float32Array.from(data.embedding))\n }\n return out\n },\n }\n}\n\ninterface XenovaPipeline {\n (text: string | string[], options?: { pooling?: string; normalize?: boolean }): Promise<{\n data: Float32Array\n }>\n}\n\nasync function makeTransformersEmbedder(): Promise<Embedder | null> {\n let pipelineFn: ((task: string, model: string) => Promise<XenovaPipeline>) | null = null\n try {\n // Lazy require so server.ts boot doesn't pay the WASM init cost when\n // Ollama is available. The package is heavy — only load it on demand.\n // The package is optional so its types may not be installed in every\n // environment. Use a dynamic specifier so tsc keeps the import dynamic\n // and doesn't try to resolve types at build time.\n const specifier = '@xenova/transformers'\n const mod = (await import(specifier)) as unknown as {\n pipeline: (task: string, model: string) => Promise<XenovaPipeline>\n }\n pipelineFn = mod.pipeline\n } catch {\n return null\n }\n if (!pipelineFn) return null\n const model = 'Xenova/all-MiniLM-L6-v2'\n const extractor = await pipelineFn('feature-extraction', model)\n return {\n provider: 'transformers',\n model,\n dim: MINI_LM_DIM,\n async embed(texts: string[]): Promise<Float32Array[]> {\n const out: Float32Array[] = []\n for (const text of texts) {\n // Mean-pooled, L2-normalized → cosine reduces to dot product but\n // we keep the explicit cosine() for clarity.\n const result = await extractor(text, { pooling: 'mean', normalize: true })\n out.push(Float32Array.from(result.data))\n }\n return out\n },\n }\n}\n\n// Picks the highest-tier embedder available. Returns null when only\n// substring is available (caller decides what to build).\nexport async function pickEmbedder(): Promise<Embedder | null> {\n const host = ollamaHost()\n if (host && (await ollamaReachable(host))) {\n return makeOllamaEmbedder(host)\n }\n return makeTransformersEmbedder()\n}\n\n// ------------------------------------------------------------------ Cache\n\ninterface CacheEntry {\n nodeId: string\n attrsHash: string\n vector: number[]\n}\n\ninterface CacheFile {\n version: 1\n provider: 'ollama' | 'transformers'\n model: string\n dim: number\n entries: CacheEntry[]\n}\n\nasync function readCache(cachePath: string): Promise<CacheFile | null> {\n try {\n const raw = await fs.readFile(cachePath, 'utf8')\n const parsed = JSON.parse(raw) as CacheFile\n if (parsed.version !== 1) return null\n return parsed\n } catch {\n return null\n }\n}\n\nasync function writeCache(cachePath: string, cache: CacheFile): Promise<void> {\n await fs.mkdir(path.dirname(cachePath), { recursive: true })\n await fs.writeFile(cachePath, JSON.stringify(cache))\n}\n\n// ----------------------------------------------------------------- Indexes\n\nclass VectorIndex implements SearchIndex {\n readonly provider: 'ollama' | 'transformers'\n private vectors = new Map<string, { node: GraphNode; vector: Float32Array; hash: string }>()\n\n constructor(\n private embedder: Embedder,\n private cachePath: string | null,\n ) {\n this.provider = embedder.provider\n }\n\n async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n const trimmed = query.trim()\n if (!trimmed || this.vectors.size === 0) {\n return { query: trimmed, provider: this.provider, matches: [] }\n }\n const embedded = await this.embedder.embed([trimmed])\n const qv = embedded[0]\n if (!qv) {\n return { query: trimmed, provider: this.provider, matches: [] }\n }\n const scored: ScoredNode[] = []\n for (const { node, vector } of this.vectors.values()) {\n const score = cosine(qv, vector)\n scored.push({ node, score })\n }\n scored.sort((a, b) => b.score - a.score)\n return { query: trimmed, provider: this.provider, matches: scored.slice(0, limit) }\n }\n\n async refresh(graph: NeatGraph): Promise<void> {\n const present = new Set<string>()\n const toEmbed: { id: string; node: GraphNode; hash: string; text: string }[] = []\n\n graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n if (!shouldEmbed(node)) return\n present.add(id)\n const hash = attrsHash(node)\n const cached = this.vectors.get(id)\n if (cached && cached.hash === hash) {\n cached.node = node\n return\n }\n toEmbed.push({ id, node, hash, text: embedText(node) })\n })\n\n // Drop vanished nodes\n for (const id of [...this.vectors.keys()]) {\n if (!present.has(id)) this.vectors.delete(id)\n }\n\n if (toEmbed.length > 0) {\n const vectors = await this.embedder.embed(toEmbed.map((e) => e.text))\n toEmbed.forEach((entry, i) => {\n const v = vectors[i]\n if (!v) return\n this.vectors.set(entry.id, { node: entry.node, vector: v, hash: entry.hash })\n })\n }\n\n if (this.cachePath) {\n const entries: CacheEntry[] = []\n for (const [id, { vector, hash }] of this.vectors) {\n entries.push({ nodeId: id, attrsHash: hash, vector: Array.from(vector) })\n }\n await writeCache(this.cachePath, {\n version: 1,\n provider: this.embedder.provider,\n model: this.embedder.model,\n dim: this.embedder.dim,\n entries,\n })\n }\n }\n\n // Hydrate the in-memory map from a previously-written cache. Validates\n // shape against the current embedder; mismatch → empty start.\n loadFromCache(cache: CacheFile, graph: NeatGraph): void {\n if (\n cache.provider !== this.embedder.provider ||\n cache.model !== this.embedder.model ||\n cache.dim !== this.embedder.dim\n ) {\n return\n }\n const present = new Map<string, GraphNode>()\n graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n if (shouldEmbed(node)) present.set(id, node)\n })\n for (const entry of cache.entries) {\n const node = present.get(entry.nodeId)\n if (!node) continue\n // Skip cache entries whose attrs no longer match — they'll be\n // re-embedded by the next refresh().\n if (attrsHash(node) !== entry.attrsHash) continue\n if (entry.vector.length !== this.embedder.dim) continue\n this.vectors.set(entry.nodeId, {\n node,\n hash: entry.attrsHash,\n vector: Float32Array.from(entry.vector),\n })\n }\n }\n}\n\nclass SubstringIndex implements SearchIndex {\n readonly provider = 'substring' as const\n private graph: NeatGraph | null = null\n\n async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n const q = query.trim().toLowerCase()\n const out: ScoredNode[] = []\n if (!q || !this.graph) {\n return { query: q, provider: 'substring', matches: [] }\n }\n this.graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n const name = (node as { name?: string }).name ?? ''\n if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n out.push({ node, score: 1 })\n }\n })\n return { query: q, provider: 'substring', matches: out.slice(0, limit) }\n }\n\n async refresh(graph: NeatGraph): Promise<void> {\n this.graph = graph\n }\n}\n\n// ------------------------------------------------------------ Public factory\n\nexport interface BuildSearchIndexOptions {\n // Where to read/write the embedding cache. Falls back to in-memory only\n // if not provided. Pass `null` to explicitly disable caching.\n cachePath?: string | null\n // Override the embedder selection. Useful for tests (substring-only mode\n // skips the Ollama probe + the Transformers.js download).\n forceProvider?: 'ollama' | 'transformers' | 'substring'\n // Pre-built embedder (test injection). Wins over forceProvider.\n embedder?: Embedder\n}\n\nexport async function buildSearchIndex(\n graph: NeatGraph,\n options: BuildSearchIndexOptions = {},\n): Promise<SearchIndex> {\n let embedder: Embedder | null = null\n if (options.embedder) {\n embedder = options.embedder\n } else if (options.forceProvider !== 'substring') {\n embedder = await pickEmbedder()\n if (options.forceProvider === 'ollama' && embedder?.provider !== 'ollama') {\n embedder = null\n }\n if (options.forceProvider === 'transformers' && embedder?.provider !== 'transformers') {\n embedder = null\n }\n }\n\n if (!embedder) {\n const idx = new SubstringIndex()\n await idx.refresh(graph)\n return idx\n }\n\n const cachePath = options.cachePath === undefined ? null : options.cachePath\n const idx = new VectorIndex(embedder, cachePath)\n if (cachePath) {\n const cache = await readCache(cachePath)\n if (cache) idx.loadFromCache(cache, graph)\n }\n await idx.refresh(graph)\n return idx\n}\n","/**\n * `neat deploy` substrate detection + artifact generation (ADR-073 §2).\n *\n * Three substrates, detected in order:\n *\n * 1. Docker + `docker compose` present → emit `docker-compose.neat.yml`.\n * 2. Bare machine with `systemctl` available → emit `neat.service`.\n * 3. Fallback → print a `docker run` snippet to stdout.\n *\n * Every branch generates a fresh `NEAT_AUTH_TOKEN` (32 bytes, base64url),\n * prints it once, and never embeds it in the on-disk artifact — the file\n * names the env-var, the operator stores the value out of band.\n *\n * Every branch also prints the OTel env-vars block the operator pastes into\n * their application services' deploy platform.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport { randomBytes } from 'node:crypto'\n\nexport type Substrate = 'docker-compose' | 'systemd' | 'docker-run'\n\nexport interface DetectOptions {\n cwd?: string\n // Detection is shellable-out by injected probes; tests pass these to avoid\n // depending on the local docker / systemctl installation.\n hasDocker?: () => Promise<boolean>\n hasSystemd?: () => Promise<boolean>\n}\n\nexport interface DeployArtifact {\n substrate: Substrate\n // Path written to disk; undefined for the docker-run fallback (stdout-only).\n artifactPath?: string\n // The newly generated bearer token. Printed once by the caller, never\n // re-read from disk.\n token: string\n // The body of the artifact. Always returned so callers (and tests) can\n // inspect what was written without re-reading the file.\n contents: string\n // The shell command the operator runs to bring NEAT up on this substrate.\n startCommand: string\n}\n\nexport function generateToken(): string {\n // 32 bytes → 43-byte base64url (no padding). Plenty of entropy; URL-safe\n // so the operator can paste it into env-var dashboards that escape `=`.\n return randomBytes(32).toString('base64url')\n}\n\nasync function probeBinary(binary: string, arg: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(binary, [arg], { stdio: 'ignore' })\n const timer = setTimeout(() => {\n child.kill('SIGKILL')\n resolve(false)\n }, 2000)\n child.once('error', () => {\n clearTimeout(timer)\n resolve(false)\n })\n child.once('exit', (code) => {\n clearTimeout(timer)\n resolve(code === 0)\n })\n })\n}\n\nexport async function detectSubstrate(opts: DetectOptions = {}): Promise<Substrate> {\n const hasDocker = opts.hasDocker ?? (() => probeBinary('docker', 'version'))\n const hasSystemd = opts.hasSystemd ?? (() => probeBinary('systemctl', '--version'))\n if (await hasDocker()) return 'docker-compose'\n if (await hasSystemd()) return 'systemd'\n return 'docker-run'\n}\n\nconst IMAGE = 'ghcr.io/neat-technologies/neat:latest'\n\nexport function emitDockerCompose(cwd: string): string {\n // Compose v3 — declares the three documented ports + a data volume. The\n // operator's deploy platform supplies `NEAT_AUTH_TOKEN`; the file names\n // the var with no default, so a missing env stops the container from\n // coming up rather than running unauthenticated.\n return [\n 'services:',\n ' neat:',\n ` image: ${IMAGE}`,\n ' restart: unless-stopped',\n ' environment:',\n ' NEAT_AUTH_TOKEN: ${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}',\n ' ports:',\n ' - \"8080:8080\"',\n ' - \"4318:4318\"',\n ' - \"6328:6328\"',\n ' volumes:',\n ` - ${cwd}:/workspace`,\n ' - ./neat-data:/neat-out',\n '',\n ].join('\\n')\n}\n\nexport function emitSystemdUnit(cwd: string): string {\n // Token lives in /etc/neat/neatd.env (NEAT_AUTH_TOKEN=...) so it's readable\n // only by root and the service user. The unit itself stays version-\n // controllable without leaking the secret.\n return [\n '# NEAT_AUTH_TOKEN is read from /etc/neat/neatd.env at startup.',\n '# Put `NEAT_AUTH_TOKEN=<value>` in that file with mode 0640 root:root.',\n '[Unit]',\n 'Description=NEAT daemon',\n 'After=network-online.target',\n 'Wants=network-online.target',\n '',\n '[Service]',\n 'Type=simple',\n 'ExecStart=/usr/local/bin/neatd start --foreground',\n `WorkingDirectory=${cwd}`,\n 'EnvironmentFile=/etc/neat/neatd.env',\n 'Restart=always',\n 'RestartSec=5',\n '',\n '[Install]',\n 'WantedBy=multi-user.target',\n '',\n ].join('\\n')\n}\n\nexport function emitDockerRunSnippet(): string {\n // Single-line `docker run` for substrates we can't detect. Operator pastes\n // their own token in; the variable name keeps the bearer-token-must-be-set\n // shape consistent across all three branches.\n return [\n '#!/usr/bin/env bash',\n 'set -euo pipefail',\n '',\n '# Generate a fresh token once, then store it where your secrets live.',\n ': \"${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}\"',\n '',\n `docker run -d --name neat \\\\`,\n ' -e NEAT_AUTH_TOKEN=\"$NEAT_AUTH_TOKEN\" \\\\',\n ' -p 8080:8080 -p 4318:4318 -p 6328:6328 \\\\',\n ' -v \"$PWD\":/workspace -v /var/lib/neat:/neat-out \\\\',\n ` ${IMAGE}`,\n '',\n ].join('\\n')\n}\n\nexport interface RenderDeployBlockOptions {\n substrate: Substrate\n // Host the operator's services will reach NEAT at. Defaults to a\n // placeholder so the operator notices and fills it in.\n host?: string\n}\n\n// The OTel env-vars block the operator pastes into their deploy platform.\n// Format matches the orchestrator summary so the two never drift.\nexport function renderOtelEnvBlock(token: string, host: string = '<host>'): string {\n return [\n `OTEL_EXPORTER_OTLP_ENDPOINT=https://${host}:4318`,\n `OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer ${token}`,\n 'OTEL_SERVICE_NAME=<service>',\n ].join('\\n')\n}\n\nexport async function runDeploy(opts: DetectOptions = {}): Promise<DeployArtifact> {\n const cwd = opts.cwd ?? process.cwd()\n const substrate = await detectSubstrate(opts)\n const token = generateToken()\n\n switch (substrate) {\n case 'docker-compose': {\n const artifactPath = path.join(cwd, 'docker-compose.neat.yml')\n const contents = emitDockerCompose(cwd)\n await fs.writeFile(artifactPath, contents, 'utf8')\n return {\n substrate,\n artifactPath,\n token,\n contents,\n startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${path.basename(artifactPath)} up -d`,\n }\n }\n case 'systemd': {\n const artifactPath = path.join(cwd, 'neat.service')\n const contents = emitSystemdUnit(cwd)\n await fs.writeFile(artifactPath, contents, 'utf8')\n return {\n substrate,\n artifactPath,\n token,\n contents,\n startCommand: [\n `sudo install -m 0640 -o root -g root <(echo NEAT_AUTH_TOKEN=${token}) /etc/neat/neatd.env`,\n `sudo install -m 0644 neat.service /etc/systemd/system/neat.service`,\n 'sudo systemctl daemon-reload && sudo systemctl enable --now neat',\n ].join(' && '),\n }\n }\n case 'docker-run':\n default: {\n const contents = emitDockerRunSnippet()\n // No on-disk artifact for the fallback — operator copies the snippet.\n return {\n substrate: 'docker-run',\n token,\n contents,\n startCommand: `NEAT_AUTH_TOKEN=${token} bash <(cat <<'EOF'\\n${contents}EOF\\n)`,\n }\n }\n }\n}\n","/**\n * Installer registry. v0.2.5 step 2 ships the scaffolding; the JavaScript\n * installer (step 3) and Python installer (step 4) populate `INSTALLERS`.\n */\n\nimport type { Installer, InstallPlan } from './shared.js'\nimport { javascriptInstaller } from './javascript.js'\nimport { pythonInstaller } from './python.js'\nexport { isEmptyPlan } from './shared.js'\nexport { javascriptInstaller } from './javascript.js'\nexport { pythonInstaller } from './python.js'\nexport type {\n ApplyOutcome,\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n GeneratedFile,\n Installer,\n InstallPlan,\n} from './shared.js'\n\n// Lockfile basenames installers must never write to (ADR-047 — \"lockfiles\n// never touched\"). Used by the patch renderer's safety check below.\nexport const FORBIDDEN_LOCKFILES: ReadonlySet<string> = new Set([\n 'package-lock.json',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'poetry.lock',\n 'Pipfile.lock',\n 'Gemfile.lock',\n 'Cargo.lock',\n 'go.sum',\n])\n\n// Order is priority — first match wins per service. JavaScript leads because\n// it's the most common shape in the projects NEAT targets; Python follows.\nexport const INSTALLERS: Installer[] = [javascriptInstaller, pythonInstaller]\n\n/**\n * Resolve the first installer that claims a given service directory. Returns\n * `null` if none match.\n *\n * Per language, the first matching installer wins. Order in `INSTALLERS`\n * defines that priority — declarations are explicit, not alphabetical.\n */\nexport async function pickInstaller(serviceDir: string): Promise<Installer | null> {\n for (const inst of INSTALLERS) {\n if (await inst.detect(serviceDir)) return inst\n }\n return null\n}\n\nexport interface PatchSection {\n installer: string\n plan: InstallPlan\n}\n\n/**\n * Render install plans into a single review-friendly text patch. The format\n * is intentionally human-shaped, not unified-diff: agents and humans both\n * read this. Determinism — same input, byte-identical output — is the\n * load-bearing property (ADR-047 #6).\n */\nexport function renderPatch(sections: PatchSection[]): string {\n if (sections.length === 0) {\n return [\n '# neat install plan',\n '',\n 'No SDK installers matched the discovered services. Two reasons this',\n 'normally happens:',\n ' - the project uses a language NEAT does not yet instrument',\n ' (Java / Ruby / .NET / Go / Rust are out of MVP scope per ADR-047);',\n ' - the SDK is already installed, so the installer returned an empty',\n ' plan.',\n '',\n 'You can re-run `neat init --apply` later to pick up new services.',\n '',\n ].join('\\n')\n }\n\n const lines: string[] = ['# neat install plan', '']\n for (const section of sections) {\n const { installer, plan } = section\n lines.push(`## ${installer} (${plan.language}) — ${plan.serviceDir}`)\n lines.push('')\n\n if (plan.libOnly) {\n lines.push('### skipped — no resolvable entry point (lib-only)')\n lines.push('')\n continue\n }\n\n if (plan.entryFile) {\n lines.push(`entry: ${plan.entryFile}`)\n lines.push('')\n }\n\n if (plan.dependencyEdits.length > 0) {\n lines.push('### dependencies')\n // Group by manifest file so each section names the path the apply phase\n // will write, satisfying the dry-run/apply path-parity contract\n // (ADR-069 §8).\n const byFile = new Map<string, typeof plan.dependencyEdits>()\n for (const dep of plan.dependencyEdits) {\n // Hard-fail rather than render a patch that could mislead the user\n // into thinking NEAT touches lockfiles.\n const base = dep.file.split(/[\\\\/]/).pop() ?? dep.file\n if (FORBIDDEN_LOCKFILES.has(base)) {\n throw new Error(\n `installer \"${installer}\" produced a dependency edit against a lockfile (${dep.file}); ` +\n `lockfiles must never be touched (ADR-047).`,\n )\n }\n const existing = byFile.get(dep.file) ?? []\n existing.push(dep)\n byFile.set(dep.file, existing)\n }\n for (const [file, deps] of byFile) {\n lines.push(`--- ${file}`)\n for (const dep of deps) {\n lines.push(`+ \"${dep.name}\": \"${dep.version}\"`)\n }\n }\n lines.push('')\n }\n\n if (plan.generatedFiles && plan.generatedFiles.length > 0) {\n lines.push('### generated files')\n for (const gen of plan.generatedFiles) {\n lines.push(`--- (new file) ${gen.file}`)\n for (const ln of gen.contents.split(/\\r?\\n/)) {\n lines.push(`+ ${ln}`)\n }\n }\n lines.push('')\n }\n\n if (plan.entrypointEdits.length > 0) {\n lines.push('### entry-point injection')\n for (const e of plan.entrypointEdits) {\n lines.push(`--- ${e.file}`)\n lines.push(`+ ${e.after}`)\n lines.push(` ${e.before}`)\n }\n lines.push('')\n }\n\n if (plan.envEdits.length > 0) {\n lines.push('### env (written to <package-dir>/.env.neat)')\n for (const env of plan.envEdits) {\n lines.push(`- ${env.key}=${env.value}`)\n }\n lines.push('')\n }\n\n // ADR-073 §1 — surface the next.config edit in the dry-run patch so the\n // operator can review the framework-flag change before it lands.\n if (plan.nextConfigEdit) {\n lines.push('### next.config (framework flag)')\n lines.push(`--- ${plan.nextConfigEdit.file}`)\n lines.push(`+ experimental: { instrumentationHook: true }, // ${plan.nextConfigEdit.reason}`)\n lines.push('')\n }\n }\n return lines.join('\\n')\n}\n","/**\n * Node / TypeScript SDK installer (ADR-047 + ADR-069).\n *\n * Detects services by the presence of a `package.json` carrying a `name`\n * field — same shape `extract/services.ts` uses to decide what counts as a\n * Node service. The plan adds four OTel-adjacent packages to `dependencies`\n * (api, sdk-node, auto-instrumentations-node, dotenv), writes a generated\n * `otel-init.{js,ts}` adjacent to the resolved entry, and injects the\n * require/import as the first non-shebang line of that entry. Per-package\n * `.env.neat` carries `OTEL_SERVICE_NAME` (scope-preserved) so dashboards\n * joining OBSERVED spans against the EXTRACTED graph use the same key.\n *\n * Lockfiles are never touched (ADR-047 §4). The apply phase writes only to\n * package.json, otel-init.{js,ts}, and .env.neat (ADR-069 §7). After\n * `--apply`, init prints \"run npm install\" so the user owns the lockfile\n * commit.\n *\n * Idempotency (ADR-069 §6): the generated otel-init's presence is the\n * primary signal that a package is instrumented end-to-end — when it\n * exists, the apply phase logs `already instrumented` and skips the file\n * write and the entry-point injection together. Existing `.env.neat` files\n * are preserved (never overwritten).\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n GeneratedFile,\n Installer,\n InstallPlan,\n PlanOptions,\n} from './shared.js'\nimport {\n ASTRO_MIDDLEWARE_JS,\n ASTRO_MIDDLEWARE_TS,\n ASTRO_OTEL_INIT_JS,\n ASTRO_OTEL_INIT_TS,\n NEXT_INSTRUMENTATION_HEADER,\n NEXT_INSTRUMENTATION_JS,\n NEXT_INSTRUMENTATION_NODE_JS,\n NEXT_INSTRUMENTATION_NODE_TS,\n NEXT_INSTRUMENTATION_TS,\n NUXT_OTEL_INIT_JS,\n NUXT_OTEL_INIT_TS,\n NUXT_OTEL_PLUGIN_JS,\n NUXT_OTEL_PLUGIN_TS,\n OTEL_INIT_CJS,\n OTEL_INIT_ESM,\n OTEL_INIT_HEADER,\n OTEL_INIT_STAMP,\n OTEL_INIT_TS,\n REMIX_OTEL_SERVER_JS,\n REMIX_OTEL_SERVER_TS,\n SVELTEKIT_HOOKS_SERVER_JS,\n SVELTEKIT_HOOKS_SERVER_TS,\n SVELTEKIT_OTEL_INIT_JS,\n SVELTEKIT_OTEL_INIT_TS,\n renderEnvNeat,\n renderFrameworkOtelInit,\n renderNextInstrumentationNode,\n renderNodeOtelInit,\n} from './templates.js'\n\n// ADR-069 §5 — three OTel packages land in `dependencies`. `dotenv` was a\n// fourth from v0.3.6 through v0.4.3; the generated `otel-init` templates\n// no longer load `.env.neat` from disk (issue #369), so it's gone from the\n// dep set.\nconst SDK_PACKAGES = [\n { name: '@opentelemetry/api', version: '^1.9.0' },\n { name: '@opentelemetry/sdk-node', version: '^0.57.0' },\n { name: '@opentelemetry/auto-instrumentations-node', version: '^0.55.0' },\n] as const\n\n// Issue #376 — non-bundled instrumentations. The auto-instrumentations-node\n// set covers HTTP, fetch, and the common DB drivers via the wire protocol,\n// but libraries that bypass those wires (Prisma's Rust query engine talks\n// to its own engine binary; LangChain wraps model calls in its own SDK)\n// need their own instrumentation package registered explicitly. The detected\n// entries here compose into the generated otel-init's `instrumentations`\n// array — one `instrumentations.push(...)` line per entry — and join the\n// package.json dep set so the registration line resolves at runtime.\n//\n// v0.4.5 scope is Prisma alone (first library that meaningfully widens\n// NEAT's OBSERVED coverage on real codebases). The function's interface is\n// stable so the v0.5.0 instrumentation registry (ADR-080) can return more\n// entries without revisiting the template.\ninterface NonBundledInstrumentation {\n pkg: string\n version: string\n registration: string\n}\n\n// Pull the leading integer out of a semver range. `^6.2.0`, `~6.2.0`, `6.x`,\n// `>=6.0.0 <7` all return 6. Anything we can't parse (workspace:*, file:…,\n// undefined) returns 0 so the caller falls through to the pre-Prisma-6 path.\nexport function getMajor(versionRange: string | undefined): number {\n if (!versionRange) return 0\n const match = versionRange.match(/(\\d+)/)\n return match ? parseInt(match[1], 10) : 0\n}\n\nexport function detectNonBundledInstrumentations(\n pkg: PackageJsonShape,\n): NonBundledInstrumentation[] {\n const deps = allDeps(pkg)\n const out: NonBundledInstrumentation[] = []\n if ('@prisma/client' in deps) {\n // Issue #381 — `@prisma/instrumentation@^5` doesn't speak Prisma 6's\n // tracing-helper API. Connecting the client throws\n // `this.getGlobalTracingHelper(...).dispatchEngineSpans is not a function`\n // before any user query lands. Mirror the Prisma major so the\n // instrumentation package matches the client surface.\n const prismaMajor = getMajor(deps['@prisma/client'])\n const prismaInstrVersion = prismaMajor >= 6 ? '^6.0.0' : '^5.0.0'\n out.push({\n pkg: '@prisma/instrumentation',\n version: prismaInstrVersion,\n registration:\n \"instrumentations.push(new (require('@prisma/instrumentation').PrismaInstrumentation)())\",\n })\n }\n return out\n}\n\nconst OTEL_ENV: EnvEdit = {\n // ADR-069 §4 — endpoint moves into the per-package .env.neat (written\n // by the apply phase). The envEdits surface stays for the dry-run\n // patch render: it documents the key/value the user can inspect in the\n // generated .env.neat.\n file: null,\n key: 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT',\n value: 'http://localhost:4318/projects/<project>/v1/traces',\n}\n\ninterface PackageJsonShape {\n name?: string\n type?: string\n main?: string\n bin?: string | Record<string, string>\n scripts?: Record<string, string>\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n}\n\n// v0.4.4 — `OTEL_SERVICE_NAME` regains its proper semantic role: the\n// ServiceNode id inside the project's graph, not the project name. v0.4.1\n// papered over the missing routing key by writing the project basename here;\n// the project-scoped OTLP URL (issue #367) means the URL carries the routing\n// key and the env var goes back to naming the ServiceNode.\nfunction serviceNodeName(pkg: PackageJsonShape, serviceDir: string): string {\n return pkg.name ?? path.basename(serviceDir)\n}\n\n// The URL routing key. When the orchestrator threads a project through we use\n// it verbatim; ad-hoc / test usage falls back to the package's own name so\n// the generated file is still well-formed.\nfunction projectToken(\n pkg: PackageJsonShape,\n serviceDir: string,\n project: string | undefined,\n): string {\n if (project && project.length > 0) return project\n return pkg.name ?? path.basename(serviceDir)\n}\n\n// Issue #370 — runtime-kind detection. The installer historically treated\n// every JavaScript package as a Node service; Brief's frontend workspace\n// showed that wrong assumption write `instrumentation-node/register` into a\n// Vite browser bundle and an Expo React Native entry, where the Node SDK\n// can't execute. Detection runs after framework dispatch (Next / Remix /\n// SvelteKit / Nuxt / Astro all render server-side, so they classify as\n// `node`); only the framework-less packages reach the bucket here.\ntype RuntimeKind = 'node' | 'browser-bundle' | 'react-native'\n\nasync function readJsonFile(p: string): Promise<unknown> {\n try {\n const raw = await fs.readFile(p, 'utf8')\n return JSON.parse(raw) as unknown\n } catch {\n return null\n }\n}\n\nasync function detectRuntimeKind(\n pkgRoot: string,\n pkg: PackageJsonShape,\n): Promise<RuntimeKind> {\n const deps = allDeps(pkg)\n if ('react-native' in deps || 'expo' in deps) return 'react-native'\n // Expo apps sometimes carry the SDK only as a transitive dep but always\n // ship an `app.json` carrying an `expo` block — that's the canonical Expo\n // signal.\n const appJson = await readJsonFile(path.join(pkgRoot, 'app.json'))\n if (appJson && typeof appJson === 'object' && 'expo' in (appJson as Record<string, unknown>)) {\n return 'react-native'\n }\n if (\n (await exists(path.join(pkgRoot, 'vite.config.js'))) ||\n (await exists(path.join(pkgRoot, 'vite.config.ts'))) ||\n (await exists(path.join(pkgRoot, 'vite.config.mjs'))) ||\n 'vite' in deps\n ) {\n return 'browser-bundle'\n }\n return 'node'\n}\n\n// Issue #368 — `OTel deps in package.json` is no longer the signal for\n// `already-instrumented`. The hook file is. Each `plan<Framework>` reads its\n// canonical hook path off disk via `await exists(...)` before queueing the\n// generated-file write, so deps-present-but-hook-absent correctly buckets\n// the package as `instrumented` (the installer writes the hook), not\n// `already-instrumented`. The next-deps-no-hook fixture in the contract\n// suite locks this against regression.\n\nasync function readPackageJson(serviceDir: string): Promise<PackageJsonShape | null> {\n try {\n const raw = await fs.readFile(path.join(serviceDir, 'package.json'), 'utf8')\n return JSON.parse(raw) as PackageJsonShape\n } catch {\n return null\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.stat(p)\n return true\n } catch {\n return false\n }\n}\n\n// Read a file's contents, or null when it doesn't exist. Used by the\n// otel-init migration check (file-awareness.md §4) so a single read decides\n// between write / migrate / preserve.\nasync function readFileMaybe(p: string): Promise<string | null> {\n try {\n return await fs.readFile(p, 'utf8')\n } catch {\n return null\n }\n}\n\n// Decide what to do with the generated otel-init at `file`, given its rendered\n// current contents. A missing file is written (skipIfExists honours a race\n// where it appears between plan and apply). A NEAT-owned file (carries\n// OTEL_INIT_HEADER) on an older template — no current stamp — is regenerated so\n// a re-run upgrades the install. A current-stamp NEAT file is already current,\n// and a hand-written init (no header) is never touched.\nasync function planOtelInitGeneration(\n file: string,\n contents: string,\n): Promise<GeneratedFile | null> {\n const existing = await readFileMaybe(file)\n if (existing === null) {\n return { file, contents, skipIfExists: true }\n }\n if (existing.includes(OTEL_INIT_HEADER) && !existing.includes(OTEL_INIT_STAMP)) {\n return { file, contents, skipIfExists: false }\n }\n return null\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n const pkg = await readPackageJson(serviceDir)\n return pkg !== null && typeof pkg.name === 'string'\n}\n\n// ADR-073 §1 — Next.js detection. A package is Next-flavored when it\n// declares `next` as a (dev)dependency AND ships a `next.config.{js,ts,mjs}`\n// at the package root. Both are required: a stray `next` import without the\n// config file isn't a Next app, and a config file without the dep is dead\n// configuration.\nconst NEXT_CONFIG_CANDIDATES = ['next.config.js', 'next.config.ts', 'next.config.mjs']\n\nasync function findNextConfig(serviceDir: string): Promise<string | null> {\n for (const name of NEXT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nfunction hasNextDependency(pkg: PackageJsonShape): boolean {\n return (\n (pkg.dependencies?.next !== undefined) ||\n (pkg.devDependencies?.next !== undefined)\n )\n}\n\n// Read the merged dep + devDep map once per detection step. Framework checks\n// only care about presence, not version.\nfunction allDeps(pkg: PackageJsonShape): Record<string, string> {\n return { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n}\n\n// ADR-074 §3 — Remix detection. A package is Remix-flavored when it declares\n// `remix` or any `@remix-run/*` package AND ships an entry-server file at one\n// of the canonical paths (`app/entry.server.{ts,tsx,js,jsx}`).\nconst REMIX_ENTRY_CANDIDATES = [\n 'app/entry.server.ts',\n 'app/entry.server.tsx',\n 'app/entry.server.js',\n 'app/entry.server.jsx',\n]\n\nfunction hasRemixDependency(pkg: PackageJsonShape): boolean {\n const deps = allDeps(pkg)\n if ('remix' in deps) return true\n for (const name of Object.keys(deps)) {\n if (name.startsWith('@remix-run/')) return true\n }\n return false\n}\n\nasync function findRemixEntry(serviceDir: string): Promise<string | null> {\n for (const rel of REMIX_ENTRY_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — SvelteKit detection. `@sveltejs/kit` dep, plus either an\n// existing `src/hooks.server.{ts,js}` or a top-level `svelte.config.{js,ts}`\n// (the absent-hooks case where the installer creates the hook file).\nconst SVELTEKIT_HOOKS_CANDIDATES = ['src/hooks.server.ts', 'src/hooks.server.js']\nconst SVELTEKIT_CONFIG_CANDIDATES = ['svelte.config.js', 'svelte.config.ts']\n\nfunction hasSvelteKitDependency(pkg: PackageJsonShape): boolean {\n return '@sveltejs/kit' in allDeps(pkg)\n}\n\nasync function findSvelteKitHooks(serviceDir: string): Promise<string | null> {\n for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nasync function findSvelteKitConfig(serviceDir: string): Promise<string | null> {\n for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — Nuxt detection. `nuxt` dep + `nuxt.config.{ts,js,mjs}`.\nconst NUXT_CONFIG_CANDIDATES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\n\nfunction hasNuxtDependency(pkg: PackageJsonShape): boolean {\n return 'nuxt' in allDeps(pkg)\n}\n\nasync function findNuxtConfig(serviceDir: string): Promise<string | null> {\n for (const name of NUXT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — Astro detection. `astro` dep + `astro.config.{mjs,ts,js}`.\nconst ASTRO_CONFIG_CANDIDATES = ['astro.config.mjs', 'astro.config.ts', 'astro.config.js']\n\nfunction hasAstroDependency(pkg: PackageJsonShape): boolean {\n return 'astro' in allDeps(pkg)\n}\n\nasync function findAstroConfig(serviceDir: string): Promise<string | null> {\n for (const name of ASTRO_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// Parse the leading major version out of a semver range like \"^14.0.3\" or\n// \"~15.0\" or \"15.0.0\". Returns null when the range can't be read (workspace\n// links, git refs, \"*\", etc.).\nexport function parseNextMajor(range: string | undefined): number | null {\n if (!range) return null\n const cleaned = range.trim().replace(/^[\\^~>=<\\s]+/, '')\n const match = cleaned.match(/^(\\d+)/)\n if (!match) return null\n const n = Number(match[1])\n return Number.isFinite(n) ? n : null\n}\n\nasync function isTypeScriptProject(serviceDir: string): Promise<boolean> {\n return exists(path.join(serviceDir, 'tsconfig.json'))\n}\n\n// ADR-069 §2 + ADR-070 — entry resolution: pkg.main → pkg.bin → scripts.start\n// → scripts.dev → src/index.* → src/{server,main,app}.* → root index.*.\n// Returns the absolute path to the resolved entry, or null when the package\n// is lib-only (no resolvable entry).\nconst INDEX_EXTENSIONS = ['.ts', '.tsx', '.js', '.mjs', '.cjs']\nconst INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`)\nconst SRC_INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `src/index${ext}`)\nconst SRC_NAMED_CANDIDATES = ['server', 'main', 'app'].flatMap((name) =>\n INDEX_EXTENSIONS.map((ext) => `src/${name}${ext}`),\n)\n\n// ADR-070 — script-entry tokeniser. Launchers and similar wrappers we strip\n// before reading the first file-shaped argument. Anything not in this set is\n// treated as a candidate entry if it looks like a relative file path.\nconst SCRIPT_LAUNCHERS = new Set([\n 'node',\n 'ts-node',\n 'tsx',\n 'ts-node-dev',\n 'nodemon',\n 'npx',\n 'pnpm',\n 'yarn',\n 'npm',\n 'cross-env',\n 'dotenv',\n '--',\n])\n\n// True when the token resembles a path inside the package — contains a `/` or\n// ends in one of the JS/TS extensions we instrument.\nfunction looksLikeEntryPath(token: string): boolean {\n if (token.length === 0) return false\n if (token.startsWith('-')) return false\n if (token.includes('=')) return false // env-var assignments\n if (token.includes('/')) return true\n return /\\.(?:m?[jt]sx?|c[jt]s)$/.test(token)\n}\n\n// Bail when the script chains commands or pipes — those scripts mean an\n// orchestrator runs multiple things and our heuristic can't pick safely.\nfunction scriptHasShellChain(script: string): boolean {\n return /(?:&&|\\|\\||;|\\|(?!\\|))/.test(script)\n}\n\n// Pull the first file-shaped argument out of a script invocation, after\n// stripping recognised launchers and inline env-var assignments. Returns\n// undefined when no candidate surfaces (or when shell chaining bails us out).\nexport function entryFromScript(script: string | undefined): string | undefined {\n if (!script) return undefined\n if (scriptHasShellChain(script)) return undefined\n const tokens = script.split(/\\s+/).filter((t) => t.length > 0)\n for (const token of tokens) {\n const lower = token.toLowerCase()\n if (SCRIPT_LAUNCHERS.has(lower)) continue\n // Strip a leading `./` so the existence check resolves cleanly.\n const cleaned = token.startsWith('./') ? token.slice(2) : token\n if (looksLikeEntryPath(cleaned)) return cleaned\n }\n return undefined\n}\n\nexport async function resolveEntry(\n serviceDir: string,\n pkg: PackageJsonShape,\n): Promise<string | null> {\n // 1) pkg.main — but only when it actually exists on disk (ADR-070).\n if (typeof pkg.main === 'string' && pkg.main.length > 0) {\n const candidate = path.resolve(serviceDir, pkg.main)\n if (await exists(candidate)) return candidate\n // Manifest points main at a missing build output (e.g. dist/index.js\n // pre-build). Fall through to bin/scripts/src heuristics rather than\n // marking lib-only.\n }\n // 2) pkg.bin (string or pkg.name-keyed map).\n if (pkg.bin) {\n let binEntry: string | undefined\n if (typeof pkg.bin === 'string') {\n binEntry = pkg.bin\n } else if (pkg.name && typeof pkg.bin[pkg.name] === 'string') {\n binEntry = pkg.bin[pkg.name]\n } else {\n const first = Object.values(pkg.bin)[0]\n if (typeof first === 'string') binEntry = first\n }\n if (binEntry) {\n const candidate = path.resolve(serviceDir, binEntry)\n if (await exists(candidate)) return candidate\n }\n }\n // 3) scripts.start — ADR-070.\n const startEntry = entryFromScript(pkg.scripts?.start)\n if (startEntry) {\n const candidate = path.resolve(serviceDir, startEntry)\n if (await exists(candidate)) return candidate\n }\n // 4) scripts.dev — ADR-070.\n const devEntry = entryFromScript(pkg.scripts?.dev)\n if (devEntry) {\n const candidate = path.resolve(serviceDir, devEntry)\n if (await exists(candidate)) return candidate\n }\n // 5) src/index.* — ADR-070.\n for (const rel of SRC_INDEX_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n // 6) src/server.*, src/main.*, src/app.* — ADR-070.\n for (const rel of SRC_NAMED_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n // 7) root index.* — original ADR-069 §3 fallback.\n for (const name of INDEX_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-069 §1, §3 — dispatch by entry extension + pkg.type.\ntype EntryFlavor = 'cjs' | 'esm' | 'ts'\n\nexport function dispatchEntry(entryFile: string, pkg: PackageJsonShape): EntryFlavor {\n const ext = path.extname(entryFile).toLowerCase()\n if (ext === '.ts' || ext === '.tsx') return 'ts'\n if (ext === '.mjs') return 'esm'\n if (ext === '.cjs') return 'cjs'\n // .js — disambiguate on pkg.type. \"module\" → ESM, anything else → CJS.\n return pkg.type === 'module' ? 'esm' : 'cjs'\n}\n\n// Generated-file basename per flavor.\nfunction otelInitFilename(flavor: EntryFlavor): string {\n if (flavor === 'ts') return 'otel-init.ts'\n if (flavor === 'esm') return 'otel-init.mjs'\n return 'otel-init.cjs'\n}\n\nfunction otelInitContents(flavor: EntryFlavor): string {\n if (flavor === 'ts') return OTEL_INIT_TS\n if (flavor === 'esm') return OTEL_INIT_ESM\n return OTEL_INIT_CJS\n}\n\n// Build the injection line per flavor. The relative path is computed against\n// the entry's directory so the injection works regardless of the entry's\n// depth inside the package.\nexport function injectionLine(\n flavor: EntryFlavor,\n entryFile: string,\n otelInitFile: string,\n): string {\n let rel = path.relative(path.dirname(entryFile), otelInitFile)\n if (!rel.startsWith('.')) rel = `./${rel}`\n // Normalize to forward slashes for cross-platform module specifiers.\n rel = rel.split(path.sep).join('/')\n if (flavor === 'cjs') return `require('${rel}')`\n if (flavor === 'esm') return `import '${rel}'`\n // TS: drop the .ts extension so the resolver doesn't choke on it under\n // either tsc-output or runtime-loader pipelines.\n const tsRel = rel.replace(/\\.ts$/, '')\n return `import '${tsRel}'`\n}\n\n// Detect whether a given line already matches an injection of our otel-init.\n// Used for the entry-point idempotency check (ADR-069 §6).\nfunction lineIsOtelInjection(line: string): boolean {\n const trimmed = line.trim()\n if (trimmed.length === 0) return false\n // Match require('./otel-init…') and import './otel-init…' shapes.\n return /(?:require\\(|import\\s+)['\"]\\.\\/otel-init[^'\"]*['\"]/.test(trimmed)\n}\n\n// `create-next-app --src-dir` puts source under `src/` and Next then resolves\n// the instrumentation hook from `src/instrumentation.ts`. Routing the\n// generated files to root in that case means the hook never loads. We detect\n// src-layout by the presence of `src/app/` or `src/pages/` AND the absence of\n// the same at the package root — a project with both is treated as flat, the\n// safer default for monorepos that vendor a `src/` subpackage.\nasync function detectsSrcLayout(serviceDir: string): Promise<boolean> {\n const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([\n exists(path.join(serviceDir, 'src', 'app')),\n exists(path.join(serviceDir, 'src', 'pages')),\n exists(path.join(serviceDir, 'app')),\n exists(path.join(serviceDir, 'pages')),\n ])\n return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages\n}\n\n// ADR-073 §1 — Next.js apply path. Emits `instrumentation.{ts,js}` and\n// `instrumentation.node.{ts,js}` at the package root (or under `src/` for\n// `--src-dir` layouts), plus `.env.neat` co-located with them. Skips\n// entry-point injection entirely — Next loads the instrumentation file\n// through its own runtime hook. Queues a next.config edit only when the\n// declared major is < 15 (the flag is on-by-default from Next 15 on).\nasync function planNext(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n nextConfigPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const srcLayout = await detectsSrcLayout(serviceDir)\n // Co-locate the generated files with where Next looks for the hook. When\n // src-layout is detected the framework resolves `src/instrumentation.{ts,js}`\n // and we route the .env.neat alongside so an operator reading the codebase\n // finds the wiring in one place. The flat layout keeps the existing root\n // placement.\n const baseDir = srcLayout ? path.join(serviceDir, 'src') : serviceDir\n const instrumentationFile = path.join(baseDir, useTs ? 'instrumentation.ts' : 'instrumentation.js')\n const instrumentationNodeFile = path.join(\n baseDir,\n useTs ? 'instrumentation.node.ts' : 'instrumentation.node.js',\n )\n const envNeatFile = path.join(baseDir, '.env.neat')\n\n // Dependency edits — `dotenv` is gone repo-wide from v0.4.4 (issue #369),\n // so SDK_PACKAGES has the three OTel packages the apply phase adds and the\n // Next branch shares the same loop as every other framework. Issue #376\n // adds non-bundled instrumentations (Prisma in v0.4.5) — each detected\n // entry contributes one dep + one registration line into the generated\n // instrumentation.node file.\n const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n const dependencyEdits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) continue\n dependencyEdits.push({\n file: manifestPath,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n const nonBundled = detectNonBundledInstrumentations(pkg)\n for (const inst of nonBundled) {\n if (inst.pkg in existingDeps) continue\n dependencyEdits.push({\n file: manifestPath,\n kind: 'add',\n name: inst.pkg,\n version: inst.version,\n })\n }\n\n // Generated files — instrumentation pair + .env.neat. Existing files are\n // preserved (skipIfExists honours user customisations and keeps the apply\n // phase idempotent per ADR-069 §6). The instrumentation.node template\n // carries `__SERVICE_NAME__` (the ServiceNode id) and `__PROJECT__` (the\n // registered project basename — the URL routing key) placeholders we\n // substitute here so the bundler-survivable `process.env.X ||=` lines land\n // with both values verbatim.\n const svcName = serviceNodeName(pkg, serviceDir)\n const projectName = projectToken(pkg, serviceDir, project)\n const registrations = nonBundled.map((i) => i.registration)\n const generatedFiles: GeneratedFile[] = []\n if (!(await exists(instrumentationFile))) {\n generatedFiles.push({\n file: instrumentationFile,\n contents: useTs ? NEXT_INSTRUMENTATION_TS : NEXT_INSTRUMENTATION_JS,\n skipIfExists: true,\n })\n }\n if (!(await exists(instrumentationNodeFile))) {\n generatedFiles.push({\n file: instrumentationNodeFile,\n contents: renderNextInstrumentationNode(\n useTs ? NEXT_INSTRUMENTATION_NODE_TS : NEXT_INSTRUMENTATION_NODE_JS,\n svcName,\n projectName,\n registrations,\n ),\n skipIfExists: true,\n })\n }\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(svcName, projectName),\n skipIfExists: true,\n })\n }\n\n // ADR-073 §1 — `experimental.instrumentationHook: true` is required for\n // Next 13 / 14 and a no-op on Next 15+. Plan the edit only when the\n // declared major is < 15 and the flag isn't already present.\n let nextConfigEdit: InstallPlan['nextConfigEdit']\n const nextRange = pkg.dependencies?.next ?? pkg.devDependencies?.next\n const nextMajor = parseNextMajor(nextRange)\n if (nextMajor !== null && nextMajor < 15) {\n try {\n const raw = await fs.readFile(nextConfigPath, 'utf8')\n if (!raw.includes('instrumentationHook')) {\n nextConfigEdit = {\n file: nextConfigPath,\n reason: `enable experimental.instrumentationHook (Next ${nextMajor} requires the opt-in flag)`,\n }\n }\n } catch {\n // Config disappeared between detect and plan. Skip the edit.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n nextConfigEdit === undefined\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'next',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits: [],\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'next',\n ...(nextConfigEdit ? { nextConfigEdit } : {}),\n }\n}\n\n// ── Meta-framework planners (ADR-074 §3). ───────────────────────────────\n//\n// Each planner mirrors planNext's shape: build dep edits via the same\n// SDK_PACKAGES + existing-deps filter, queue generated files for the\n// framework-canonical hook surface, record `framework: '<name>'`, never\n// inject into pkg.main. Idempotency rides on `skipIfExists` for generated\n// files and on a re-read header-grep for the inject-into-existing case.\n\nfunction buildDependencyEdits(\n pkg: PackageJsonShape,\n manifestPath: string,\n): DependencyEdit[] {\n const existingDeps = allDeps(pkg)\n const edits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) continue\n edits.push({\n file: manifestPath,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n return edits\n}\n\nasync function queueEnvNeat(\n serviceDir: string,\n pkg: PackageJsonShape,\n project: string | undefined,\n generatedFiles: GeneratedFile[],\n): Promise<void> {\n const envNeatFile = path.join(serviceDir, '.env.neat')\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(\n serviceNodeName(pkg, serviceDir),\n projectToken(pkg, serviceDir, project),\n ),\n skipIfExists: true,\n })\n }\n}\n\nfunction renderFrameworkOtelInitForPkg(\n template: string,\n pkg: PackageJsonShape,\n serviceDir: string,\n project: string | undefined,\n): string {\n return renderFrameworkOtelInit(\n template,\n serviceNodeName(pkg, serviceDir),\n projectToken(pkg, serviceDir, project),\n )\n}\n\nfunction fileImportsOtelHook(raw: string, specifiers: readonly string[]): boolean {\n const lines = raw.split(/\\r?\\n/)\n for (const line of lines) {\n const trimmed = line.trim()\n for (const spec of specifiers) {\n const escaped = spec.replace(/\\./g, '\\\\.')\n const pattern = new RegExp(\n `(?:import\\\\s+['\"]${escaped}['\"]|require\\\\(['\"]${escaped}['\"]\\\\))`,\n )\n if (pattern.test(trimmed)) return true\n }\n }\n return false\n}\n\nasync function planRemix(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n entryFile: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelServerFile = path.join(\n serviceDir,\n useTs ? 'app/otel.server.ts' : 'app/otel.server.js',\n )\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n\n if (!(await exists(otelServerFile))) {\n generatedFiles.push({\n file: otelServerFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? REMIX_OTEL_SERVER_TS : REMIX_OTEL_SERVER_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n const entrypointEdits: EntrypointEdit[] = []\n try {\n const raw = await fs.readFile(entryFile, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel.server'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: entryFile,\n before: firstReal,\n after: \"import './otel.server'\",\n })\n }\n } catch {\n // Entry file disappeared between detect and plan; fall through.\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'remix',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'remix',\n }\n}\n\nasync function planSvelteKit(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n hooksFile: string | null,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n )\n const resolvedHooksFile =\n hooksFile ??\n path.join(serviceDir, useTs ? 'src/hooks.server.ts' : 'src/hooks.server.js')\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n const entrypointEdits: EntrypointEdit[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? SVELTEKIT_OTEL_INIT_TS : SVELTEKIT_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n if (hooksFile === null) {\n generatedFiles.push({\n file: resolvedHooksFile,\n contents: useTs ? SVELTEKIT_HOOKS_SERVER_TS : SVELTEKIT_HOOKS_SERVER_JS,\n skipIfExists: true,\n })\n } else {\n try {\n const raw = await fs.readFile(hooksFile, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: hooksFile,\n before: firstReal,\n after: \"import './otel-init'\",\n })\n }\n } catch {\n // Disappeared between detect and plan; fall through.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'sveltekit',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'sveltekit',\n }\n}\n\nasync function planNuxt(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelPluginFile = path.join(\n serviceDir,\n useTs ? 'server/plugins/otel.ts' : 'server/plugins/otel.js',\n )\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'server/plugins/otel-init.ts' : 'server/plugins/otel-init.js',\n )\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? NUXT_OTEL_INIT_TS : NUXT_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n if (!(await exists(otelPluginFile))) {\n generatedFiles.push({\n file: otelPluginFile,\n contents: useTs ? NUXT_OTEL_PLUGIN_TS : NUXT_OTEL_PLUGIN_JS,\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n const empty = dependencyEdits.length === 0 && generatedFiles.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'nuxt',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits: [],\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'nuxt',\n }\n}\n\nconst ASTRO_MIDDLEWARE_CANDIDATES = ['src/middleware.ts', 'src/middleware.js']\n\nasync function findAstroMiddleware(serviceDir: string): Promise<string | null> {\n for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nasync function planAstro(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n )\n const existingMiddleware = await findAstroMiddleware(serviceDir)\n const middlewareFile =\n existingMiddleware ??\n path.join(serviceDir, useTs ? 'src/middleware.ts' : 'src/middleware.js')\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n const entrypointEdits: EntrypointEdit[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? ASTRO_OTEL_INIT_TS : ASTRO_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n if (existingMiddleware === null) {\n generatedFiles.push({\n file: middlewareFile,\n contents: useTs ? ASTRO_MIDDLEWARE_TS : ASTRO_MIDDLEWARE_JS,\n skipIfExists: true,\n })\n } else {\n try {\n const raw = await fs.readFile(existingMiddleware, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: existingMiddleware,\n before: firstReal,\n after: \"import './otel-init'\",\n })\n }\n } catch {\n // Disappeared between detect and plan; fall through.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'astro',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'astro',\n }\n}\n\ntype FrameworkDispatch = () => Promise<InstallPlan>\n\n// ADR-073 §1 + ADR-074 §3 — framework signal lookup. Returns a thunk that\n// invokes the framework-specific planner when a match lands, or null when\n// none do. Detection precedence is Next → Remix → SvelteKit → Nuxt → Astro;\n// the chain bails on the first match. Pulled out of `plan()` so issue\n// #375's lib-only check can see the framework signal upfront — a package\n// with no framework hook AND no Node entry buckets as lib-only regardless\n// of stray Vite config or Expo deps.\nasync function findFrameworkDispatch(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<FrameworkDispatch | null> {\n if (hasNextDependency(pkg)) {\n const nextConfig = await findNextConfig(serviceDir)\n if (nextConfig) {\n return () => planNext(serviceDir, pkg, manifestPath, nextConfig, project)\n }\n }\n if (hasRemixDependency(pkg)) {\n const remixEntry = await findRemixEntry(serviceDir)\n if (remixEntry) {\n return () => planRemix(serviceDir, pkg, manifestPath, remixEntry, project)\n }\n }\n if (hasSvelteKitDependency(pkg)) {\n const hooks = await findSvelteKitHooks(serviceDir)\n const config = await findSvelteKitConfig(serviceDir)\n if (hooks || config) {\n return () => planSvelteKit(serviceDir, pkg, manifestPath, hooks, project)\n }\n }\n if (hasNuxtDependency(pkg)) {\n const nuxtConfig = await findNuxtConfig(serviceDir)\n if (nuxtConfig) {\n return () => planNuxt(serviceDir, pkg, manifestPath, project)\n }\n }\n if (hasAstroDependency(pkg)) {\n const astroConfig = await findAstroConfig(serviceDir)\n if (astroConfig) {\n return () => planAstro(serviceDir, pkg, manifestPath, project)\n }\n }\n return null\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n const pkg = await readPackageJson(serviceDir)\n const manifestPath = path.join(serviceDir, 'package.json')\n const project = opts?.project\n const empty: InstallPlan = {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n }\n if (!pkg) return empty\n\n // Issue #375 — classification pipeline order: lib-only → framework →\n // runtime-kind → emit. A package with no framework hook AND no resolvable\n // Node entry is lib-only regardless of stray Vite config or Expo deps. The\n // runtime-kind dispatch only fires for non-framework packages that\n // actually have an entry to instrument; without this ordering, a UI library\n // that ships a `vite.config.ts` for its build pipeline would bucket as\n // browser-bundle and surface in the operator summary as if it were a real\n // SPA the installer was choosing to skip.\n const frameworkDispatch = await findFrameworkDispatch(\n serviceDir,\n pkg,\n manifestPath,\n project,\n )\n\n // Resolve the Node entry up front so the lib-only check can read both\n // signals together. Skipped on the framework branch — frameworks own their\n // boot path and never need a `pkg.main` injection (the chain returns\n // before this line runs).\n let entryFile: string | null = null\n if (!frameworkDispatch) {\n entryFile = await resolveEntry(serviceDir, pkg)\n if (!entryFile) {\n return { ...empty, libOnly: true }\n }\n }\n\n if (frameworkDispatch) {\n return frameworkDispatch()\n }\n\n // Issue #370 — runtime-kind detection sits between the lib-only check and\n // vanilla Node template emission. Browser bundles (Vite) and React Native\n // / Expo packages bucket here so the apply phase skips every write and\n // surfaces the package in the summary instead of injecting a Node SDK hook\n // into code that can't run it.\n const runtimeKind = await detectRuntimeKind(serviceDir, pkg)\n if (runtimeKind !== 'node') {\n return { ...empty, runtimeKind }\n }\n\n // entryFile resolved above on the non-framework branch; the null path\n // already returned lib-only.\n if (!entryFile) {\n return { ...empty, libOnly: true }\n }\n const flavor = dispatchEntry(entryFile, pkg)\n const otelInitFile = path.join(path.dirname(entryFile), otelInitFilename(flavor))\n const envNeatFile = path.join(serviceDir, '.env.neat')\n\n // ── Dependency edits (four-deps invariant; ADR-069 §5). ────────────────\n // Issue #376 — non-bundled instrumentations append additional deps when\n // the host package declares libraries whose runtime traffic bypasses the\n // auto-instrumentation set (Prisma's Rust query engine for v0.4.5; the\n // v0.5.0 registry feeds the same loop with more entries).\n const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n const dependencyEdits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) continue\n dependencyEdits.push({\n file: manifestPath,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n const nonBundled = detectNonBundledInstrumentations(pkg)\n for (const inst of nonBundled) {\n if (inst.pkg in existingDeps) continue\n dependencyEdits.push({\n file: manifestPath,\n kind: 'add',\n name: inst.pkg,\n version: inst.version,\n })\n }\n\n // ── Entry-point injection edit (ADR-069 §3). ───────────────────────────\n const entrypointEdits: EntrypointEdit[] = []\n try {\n const raw = await fs.readFile(entryFile, 'utf8')\n const lines = raw.split(/\\r?\\n/)\n // Preserve a shebang on line 1 and check line 2 (the first non-shebang\n // line) for an existing injection.\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n if (!lineIsOtelInjection(firstReal)) {\n const inject = injectionLine(flavor, entryFile, otelInitFile)\n // Use the existing first-real line as the `before` marker so the apply\n // phase can splice the injection cleanly even if the file shifts.\n entrypointEdits.push({\n file: entryFile,\n before: firstReal,\n after: inject,\n })\n }\n } catch {\n // Entry file disappeared between resolve and plan (rare). Treat as\n // lib-only.\n return { ...empty, libOnly: true }\n }\n\n // ── Generated files (ADR-069 §1, §4). ──────────────────────────────────\n // v0.4.4 — the otel-init template carries `__SERVICE_NAME__` (the\n // ServiceNode id) and `__PROJECT__` (the URL routing key) placeholders we\n // substitute here. The .env.neat shape lands with the same pair so an\n // operator can grep for both fields in one place.\n // v0.4.5 — `__INSTRUMENTATION_BLOCK__` substitutes to the registration\n // snippets for any non-bundled instrumentations detected above (Prisma\n // for v0.4.5; the v0.5.0 registry will feed more entries through the same\n // path). Empty list collapses cleanly to nothing.\n const svcName = serviceNodeName(pkg, serviceDir)\n const projectName = projectToken(pkg, serviceDir, project)\n const registrations = nonBundled.map((i) => i.registration)\n const generatedFiles: GeneratedFile[] = []\n const otelInitGen = await planOtelInitGeneration(\n otelInitFile,\n renderNodeOtelInit(otelInitContents(flavor), svcName, projectName, registrations),\n )\n if (otelInitGen) generatedFiles.push(otelInitGen)\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(svcName, projectName),\n skipIfExists: true,\n })\n }\n\n // ── Idempotency check (ADR-069 §6). ────────────────────────────────────\n // If the package is already instrumented end-to-end — deps present, entry\n // already injected, generated files already there — return an empty plan.\n if (\n dependencyEdits.length === 0 &&\n entrypointEdits.length === 0 &&\n generatedFiles.length === 0\n ) {\n return empty\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n entryFile,\n libOnly: false,\n }\n}\n\n// ADR-069 §7 + ADR-073 §1 + ADR-074 §3 — allowed write paths. Anything\n// outside this set inside an installer's apply phase is a contract violation.\nfunction isAllowedWritePath(serviceDir: string, target: string): boolean {\n const rel = path.relative(serviceDir, target)\n if (rel.startsWith('..')) return false\n const base = path.basename(target)\n if (base === 'package.json') return true\n if (base === '.env.neat') return true\n if (/^otel-init\\.(?:js|cjs|mjs|ts)$/.test(base)) return true\n // ADR-073 §1 — Next framework files at the package root, or under src/\n // when create-next-app's --src-dir layout is in use. The instrumentation\n // hook resolves from `src/` in that layout; routing files there is the\n // load-bearing fix for the src-dir shape.\n const relPosix = rel.split(path.sep).join('/')\n if (/^instrumentation(?:\\.node)?\\.(?:js|cjs|mjs|ts)$/.test(base)) {\n if (relPosix === base) return true\n if (relPosix === `src/${base}`) return true\n return false\n }\n if (/^next\\.config\\.(?:js|mjs|ts)$/.test(base)) return true\n // ADR-074 §3 — meta-framework hook surfaces.\n if (relPosix === 'app/otel.server.ts' || relPosix === 'app/otel.server.js') return true\n if (/^app\\/entry\\.server\\.(?:tsx?|jsx?)$/.test(relPosix)) return true\n if (relPosix === 'src/otel-init.ts' || relPosix === 'src/otel-init.js') return true\n if (relPosix === 'src/hooks.server.ts' || relPosix === 'src/hooks.server.js') return true\n if (relPosix === 'server/plugins/otel.ts' || relPosix === 'server/plugins/otel.js') return true\n if (relPosix === 'server/plugins/otel-init.ts' || relPosix === 'server/plugins/otel-init.js') return true\n if (relPosix === 'src/middleware.ts' || relPosix === 'src/middleware.js') return true\n return false\n}\n\nasync function writeAtomic(file: string, contents: string): Promise<void> {\n // Meta-framework branches write to convention-driven subdirs that the user\n // may not have scaffolded yet (`server/plugins/`, `src/`, `app/`). Ensure\n // the parent directory exists before the atomic write; existing parents\n // are a no-op under `recursive: true`.\n await fs.mkdir(path.dirname(file), { recursive: true })\n const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, contents, 'utf8')\n await fs.rename(tmp, file)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n const { serviceDir } = installPlan\n if (installPlan.libOnly) {\n return {\n serviceDir,\n outcome: 'lib-only',\n reason: 'no resolvable entry point',\n writtenFiles: [],\n }\n }\n\n // Issue #370 — non-Node runtimes write nothing. The CLI surfaces the\n // outcome in the summary so the operator can see which packages were\n // skipped and why.\n if (installPlan.runtimeKind === 'browser-bundle') {\n return {\n serviceDir,\n outcome: 'browser-bundle',\n reason: 'browser bundle; Node OTel SDK cannot run here',\n writtenFiles: [],\n }\n }\n if (installPlan.runtimeKind === 'react-native') {\n return {\n serviceDir,\n outcome: 'react-native',\n reason: 'React Native / Expo target; Node OTel SDK cannot run here',\n writtenFiles: [],\n }\n }\n\n // Already-instrumented check: an empty plan means there's nothing to do.\n if (\n installPlan.dependencyEdits.length === 0 &&\n installPlan.entrypointEdits.length === 0 &&\n (installPlan.generatedFiles?.length ?? 0) === 0 &&\n installPlan.nextConfigEdit === undefined\n ) {\n return {\n serviceDir,\n outcome: 'already-instrumented',\n writtenFiles: [],\n }\n }\n\n // Validate every target we plan to touch against the allowed-path set.\n // Bail out before any write if a violation slipped through.\n const allTargets = new Set<string>()\n for (const d of installPlan.dependencyEdits) allTargets.add(d.file)\n for (const e of installPlan.entrypointEdits) allTargets.add(e.file)\n for (const g of installPlan.generatedFiles ?? []) allTargets.add(g.file)\n if (installPlan.nextConfigEdit) allTargets.add(installPlan.nextConfigEdit.file)\n for (const target of allTargets) {\n // Entry-point edits land in user source files, not the allowed set —\n // they're explicitly carved out below.\n const isEntryEdit = installPlan.entrypointEdits.some((e) => e.file === target)\n if (isEntryEdit) continue\n if (!isAllowedWritePath(serviceDir, target)) {\n throw new Error(\n `javascript installer: refusing to write outside the allowed path set (ADR-069 §7): ${target}`,\n )\n }\n }\n\n // Snapshot every file we may touch so a partial failure can roll back the\n // batch (ADR-047 §7). Newly-generated files have no prior contents — they\n // get tracked separately so rollback unlinks them instead of restoring.\n const originals = new Map<string, string>()\n const createdFiles: string[] = []\n for (const target of allTargets) {\n if (await exists(target)) {\n try {\n originals.set(target, await fs.readFile(target, 'utf8'))\n } catch {\n // Best-effort. The mutation loop below will throw if this matters.\n }\n }\n }\n\n const writtenFiles: string[] = []\n try {\n // ── 1. Manifest edits (package.json) ─────────────────────────────────\n const manifestTargets = installPlan.dependencyEdits\n .reduce<Set<string>>((acc, e) => {\n acc.add(e.file)\n return acc\n }, new Set())\n for (const file of manifestTargets) {\n const raw = originals.get(file)\n if (raw === undefined) {\n throw new Error(`javascript installer: cannot read ${file} during apply`)\n }\n const pkg = JSON.parse(raw) as PackageJsonShape\n pkg.dependencies = pkg.dependencies ?? {}\n for (const dep of installPlan.dependencyEdits) {\n if (dep.file !== file) continue\n if (dep.kind === 'add') {\n if (!(dep.name in (pkg.dependencies ?? {}))) {\n pkg.dependencies[dep.name] = dep.version\n }\n // No version bump on existing entries (ADR-069 §6).\n } else {\n delete pkg.dependencies[dep.name]\n }\n }\n const newRaw = JSON.stringify(pkg, null, 2) + '\\n'\n await writeAtomic(file, newRaw)\n writtenFiles.push(file)\n }\n\n // ── 2. Generated files (otel-init, .env.neat) ────────────────────────\n for (const gen of installPlan.generatedFiles ?? []) {\n if (gen.skipIfExists && (await exists(gen.file))) {\n // Skip silently; the contract treats this as part of the\n // already-instrumented path.\n continue\n }\n await writeAtomic(gen.file, gen.contents)\n if (!originals.has(gen.file)) createdFiles.push(gen.file)\n writtenFiles.push(gen.file)\n }\n\n // ── 3. Entry-point injection (require/import on first non-shebang line)\n for (const ep of installPlan.entrypointEdits) {\n const raw = originals.get(ep.file)\n if (raw === undefined) {\n throw new Error(`javascript installer: cannot read entry ${ep.file} during apply`)\n }\n const lines = raw.split(/\\r?\\n/)\n const hasShebang = lines[0]?.startsWith('#!') ?? false\n const insertAt = hasShebang ? 1 : 0\n // Idempotency: if the first non-shebang line already matches our\n // injection pattern, skip — never double-inject.\n const firstReal = lines[insertAt] ?? ''\n if (lineIsOtelInjection(firstReal)) continue\n lines.splice(insertAt, 0, ep.after)\n const newRaw = lines.join('\\n')\n await writeAtomic(ep.file, newRaw)\n writtenFiles.push(ep.file)\n }\n\n // ── 4. Next.js config flag (ADR-073 §1) — only present on the Next\n // path when the declared major is < 15 and the flag isn't already\n // mentioned in the file. Best-effort regex insertion into the first\n // config object literal; bails silently when the shape isn't\n // recognisable so we never corrupt a user-customised config.\n if (installPlan.nextConfigEdit) {\n const target = installPlan.nextConfigEdit.file\n const raw = originals.get(target)\n if (raw !== undefined && !raw.includes('instrumentationHook')) {\n const updated = injectInstrumentationHook(raw)\n if (updated !== null) {\n await writeAtomic(target, updated)\n writtenFiles.push(target)\n }\n }\n }\n } catch (err) {\n await rollback(installPlan, originals, createdFiles)\n throw err\n }\n\n return {\n serviceDir,\n outcome: 'instrumented',\n writtenFiles,\n }\n}\n\nasync function rollback(\n installPlan: InstallPlan,\n originals: Map<string, string>,\n createdFiles: string[],\n): Promise<void> {\n const restored: string[] = []\n const removed: string[] = []\n for (const [file, raw] of originals.entries()) {\n try {\n await fs.writeFile(file, raw, 'utf8')\n restored.push(file)\n } catch {\n // Best-effort: keep going so we restore as much as we can.\n }\n }\n for (const file of createdFiles) {\n try {\n await fs.unlink(file)\n removed.push(file)\n } catch {\n // Best-effort.\n }\n }\n const lines = [\n '# neat-rollback.patch',\n '',\n `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n '# Files listed below were restored to their pre-apply contents.',\n '',\n ...restored.map((f) => `restored: ${f}`),\n ...removed.map((f) => `removed: ${f}`),\n '',\n ]\n const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\n// ADR-073 §1 — best-effort injection of `experimental.instrumentationHook:\n// true` into a next.config.{js,ts,mjs}. Returns the rewritten contents on\n// success, or null when the config shape isn't recognisable (in which case\n// the apply phase leaves the file alone — partial Next coverage is fine,\n// silent corruption of a user's config is not).\n//\n// Recognised shapes:\n// - `module.exports = { ... }` (CJS)\n// - `module.exports = { ... } satisfies NextConfig` (TS-via-CJS)\n// - `export default { ... }` (ESM / TS)\n// - `const nextConfig = { ... }; module.exports = nextConfig` (named CJS)\n// - `const nextConfig: NextConfig = { ... }; export default nextConfig` (TS)\nexport function injectInstrumentationHook(raw: string): string | null {\n if (raw.includes('instrumentationHook')) return raw\n\n // Strategy: find the first config object literal whose contents we can\n // edit, then either merge into an existing `experimental: { ... }` block\n // or insert a fresh `experimental: { instrumentationHook: true }` entry.\n //\n // We look for one of four anchors near a top-level `{` and splice from\n // there. The regexes capture the `{` so we can splice right after it.\n const anchors: Array<{ pattern: RegExp; label: string }> = [\n { pattern: /(module\\.exports\\s*=\\s*\\{)/, label: 'cjs-default' },\n { pattern: /(export\\s+default\\s*\\{)/, label: 'esm-default' },\n { pattern: /(?:const|let|var)\\s+\\w+(?:\\s*:\\s*[^=]+)?\\s*=\\s*(\\{)/, label: 'named-config' },\n ]\n\n for (const { pattern } of anchors) {\n const match = pattern.exec(raw)\n if (!match) continue\n const insertAfter = match.index + match[0].length\n const before = raw.slice(0, insertAfter)\n const after = raw.slice(insertAfter)\n // Insert a leading newline so the injection sits on its own line and\n // doesn't fight any existing trailing-comma style. Two-space indent\n // covers most code-styled configs.\n const injection = '\\n experimental: { instrumentationHook: true },'\n return `${before}${injection}${after}`\n }\n\n return null\n}\n\nexport const javascriptInstaller: Installer = {\n name: 'javascript',\n detect,\n plan,\n apply,\n}\n\n// Re-exports used by the contract test surface.\nexport { NEXT_INSTRUMENTATION_HEADER, OTEL_INIT_HEADER }\n","/**\n * Generated-file templates for the Node SDK installer (ADR-069 §1).\n *\n * Three flavors so the inserted file matches the host package's module\n * system: CJS for `require`-based packages, ESM for `import`-based, TS for\n * TypeScript entries. Env vars are inlined as `process.env.X ||=` defaults\n * rather than loaded from `.env.neat` at runtime — `__dirname` /\n * `import.meta.url` resolve unpredictably once a bundler rewrites the\n * generated file (Brief-smoke evidence, issue #369), so we let the OTel SDK\n * read its config from the same `process.env` either way. Platform env\n * (Vercel / Railway / Fly / etc.) stays authoritative at deploy time;\n * `||=` keeps the local default for laptop dev only.\n */\n\n// Header comment that ships at the top of every generated otel-init. Stable\n// across flavors so a grep for the header line finds every generated file in\n// a target codebase. Used by the idempotency check too (ADR-069 §6).\nexport const OTEL_INIT_HEADER = '// Generated by `neat init --apply` (ADR-069). OpenTelemetry auto-instrumentation hook.'\n\n// Version stamp on the generated otel-init (file-awareness.md §4). A NEAT-owned\n// file carries OTEL_INIT_HEADER; the stamp records which template revision wrote\n// it. On re-run, an existing NEAT-owned file whose stamp is older than the\n// current one is regenerated (a hand-written init — no header — is never\n// touched). Bump the revision whenever the generated body changes shape.\nexport const OTEL_INIT_STAMP =\n '// neat-template-version: 4 — layered file-first capture (ADR-090): stack walk + handler-entry + off-stack facades.'\n\n// OTLP exporter auth (ADR-073 §3/§4, #410). When the operator runs the\n// instrumented app with `NEAT_OTEL_TOKEN` set — the same secret the daemon's\n// OTLP receiver reads (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) — the exporter\n// sends `Authorization: Bearer <token>` so a secured daemon accepts the spans.\n// Unset (laptop dev against a loopback daemon with no token) sends no header,\n// matching the daemon's unauthenticated loopback path. The token is the single\n// source: it lives in the environment, never inlined into the generated file.\n// `||=` keeps any platform-set header (Vercel / Railway / Fly) authoritative.\nexport const OTEL_OTLP_HEADERS_JS =\n \"if (process.env.NEAT_OTEL_TOKEN) process.env.OTEL_EXPORTER_OTLP_HEADERS ||= 'Authorization=Bearer ' + process.env.NEAT_OTEL_TOKEN\"\n\n// Inlined layered call-site capture (file-awareness.md §4–6, ADR-090). The\n// whole mechanism is self-contained — NEAT can't import its own package into a\n// user's generated file, so the runtime logic is inlined verbatim. The exact\n// bytes that ship are exercised by the capture spike\n// (test/callsite-processor.test.ts) so a regression here fails CI before it\n// ships. The `ts` flag adds the few type annotations a strict tsconfig needs;\n// the runtime logic is identical across flavors.\n//\n// Three layers land the user's `file:line:function` on every CLIENT / PRODUCER\n// / SERVER span:\n// 1. Synchronous stack walk at span start — covers the sync-wrapper majority.\n// 2. Handler-entry attribution — stamps the framework SERVER span and pushes\n// the handler frame into the active context so downstream CLIENT/PRODUCER\n// spans inherit it (the floor).\n// 3. Off-stack facades — undici / built-in `fetch` (diagnostics_channel) and\n// Prisma (backdated dispatch) push the call-site frame into context for\n// the inner call; the processor reads it as a fallback.\nfunction neatCaptureSource(ts: boolean): string {\n const spanT = ts ? ': any' : ''\n const strOpt = ts ? ': string | undefined' : ''\n const anyT = ts ? ': any' : ''\n const fnT = ts ? ': any' : ''\n const arrAny = ts ? ': any[]' : ''\n return `// Context key shared by the facade/handler wraps (writers) and the\n// processor fallback (reader). Symbol.for keeps it stable even if the wraps\n// and the processor end up in different module instances.\nconst NEAT_USER_FRAME = Symbol.for('neat.user-frame')\n\nfunction __neatPickUserFrame(stack${strOpt}) {\n const lines = String(stack || '').split('\\\\n')\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i].trim()\n if (raw.indexOf('at ') !== 0) continue\n if (raw.indexOf('node_modules') !== -1) continue\n if (raw.indexOf('@opentelemetry') !== -1) continue\n if (raw.indexOf('node:') !== -1) continue\n if (raw.indexOf('NeatCallSiteSpanProcessor') !== -1) continue\n // Skip NEAT's own inlined wraps/helpers (all carry the __neat prefix) so a\n // facade frame never masquerades as the user's call site.\n if (raw.indexOf('__neat') !== -1) continue\n const bodyText = raw.slice(3)\n const loc = bodyText.match(/:(\\\\d+):(\\\\d+)\\\\)?$/)\n if (!loc) continue\n const paren = bodyText.lastIndexOf('(')\n let filepath${strOpt}\n let fn${strOpt}\n if (paren !== -1) {\n fn = bodyText.slice(0, paren).trim()\n if (fn.indexOf('async ') === 0) fn = fn.slice(6)\n if (fn.indexOf('new ') === 0) fn = fn.slice(4)\n filepath = bodyText.slice(paren + 1, bodyText.length - loc[0].length)\n } else {\n filepath = bodyText.slice(0, bodyText.length - loc[0].length)\n }\n if (filepath.indexOf('file://') === 0) filepath = filepath.slice(7)\n if (!filepath) continue\n return { filepath: filepath, lineno: Number(loc[1]), function: fn || undefined }\n }\n return null\n}\n\n// Layer 2/3 fallback source: the frame a handler-entry or facade wrap pushed\n// into context. Reads the span's own parent context first, then the active\n// context — the capture spike confirmed both return the value for undici.\nfunction __neatFrameFromContext(parentContext${anyT}) {\n try {\n const fromParent =\n parentContext && typeof parentContext.getValue === 'function'\n ? parentContext.getValue(NEAT_USER_FRAME)\n : undefined\n return fromParent || context.active().getValue(NEAT_USER_FRAME) || null\n } catch (_e) {\n return null\n }\n}\n\nfunction __neatSetCodeAttrs(span${spanT}, frame${anyT}) {\n span.setAttribute('code.filepath', frame.filepath)\n if (typeof frame.lineno === 'number') span.setAttribute('code.lineno', frame.lineno)\n if (frame.function) span.setAttribute('code.function', frame.function)\n}\n\nclass NeatCallSiteSpanProcessor {\n onStart(span${spanT}, parentContext${anyT}) {\n if (!span || (span.kind !== 2 && span.kind !== 3)) return\n // Layer 1 — synchronous stack walk (sync-wrapper instrumentations).\n let frame = __neatPickUserFrame(new Error().stack)\n // Layer 2/3 — the handler-entry or off-stack-facade frame from context.\n if (!frame) frame = __neatFrameFromContext(parentContext)\n if (!frame) return\n __neatSetCodeAttrs(span, frame)\n }\n onEnd() {}\n forceFlush() { return Promise.resolve() }\n shutdown() { return Promise.resolve() }\n}\n\n// Capture the caller's synchronous frame at the wrap point and run \\`fn\\` with\n// that frame pushed into the active context (file-awareness.md §4 layer 3). An\n// off-stack instrumentation that creates its span inside \\`fn\\` inherits the\n// frame; the processor reads it via __neatFrameFromContext.\nfunction __neatRunWithUserFrame(fn${fnT}) {\n const frame = __neatPickUserFrame(new Error().stack)\n if (!frame) return fn()\n return context.with(context.active().setValue(NEAT_USER_FRAME, frame), fn)\n}\n\n// Handler-entry attribution (file-awareness.md §4 layer 2). Stamp the framework\n// SERVER span with the handler frame captured at route registration, and push\n// the same frame into context so downstream CLIENT/PRODUCER spans inherit the\n// handler-file floor when their own stack carries none.\nfunction __neatStampHandler(frame${anyT}, run${fnT}) {\n try {\n const active = trace.getActiveSpan()\n if (active && active.kind === 1 && typeof active.setAttribute === 'function') {\n __neatSetCodeAttrs(active, frame)\n }\n } catch (_e) {}\n try {\n return context.with(context.active().setValue(NEAT_USER_FRAME, frame), run)\n } catch (_e) {\n return run()\n }\n}\n\n// require-in-the-middle is a transitive dependency of the OTel instrumentation\n// packages NEAT installs, so it resolves in any instrumented CJS service.\n// Guarded: when it's absent (or the host runs as pure ESM, where require isn't\n// defined) the off-stack/handler wraps degrade to the stack walk + context\n// floor, never to a crash.\nfunction __neatHook(modules${arrAny}, onload${fnT}) {\n try {\n const RITM = require('require-in-the-middle')\n const Hook = RITM && RITM.Hook ? RITM.Hook : RITM\n new Hook(modules, { internals: false }, onload)\n return true\n } catch (_e) {\n return false\n }\n}\n\n// Off-stack facade: Node's built-in fetch / undici. The instrumentation creates\n// the CLIENT span inside a diagnostics_channel handler detached from the\n// caller's stack, so wrap the global so the user frame is in context when the\n// span is created. The capture spike (2026-05-28) validated this on real\n// undici. .name is restored to 'fetch' for ecosystem compatibility; the inner\n// __neat name is what the frame skip keys on.\nfunction __neatWrapFetch() {\n try {\n const g${anyT} = globalThis\n if (typeof g.fetch === 'function' && !g.fetch.__neatWrapped) {\n const realFetch = g.fetch\n // The wrapper keeps its __neat-prefixed name so the frame skip in\n // __neatPickUserFrame never mistakes the wrapper's own frame for the\n // user's call site (renaming it to 'fetch' would defeat the skip).\n const __neatFetch${anyT} = function (input${anyT}, init${anyT}) {\n return __neatRunWithUserFrame(function () { return realFetch(input, init) })\n }\n __neatFetch.__neatWrapped = true\n g.fetch = __neatFetch\n }\n } catch (_e) {}\n}\n\n// Off-stack facade: @prisma/client. Prisma's query engine backdates its spans\n// from Rust, off the caller's stack. Wrap the model methods on the client\n// prototype so the call-site frame (still synchronous at \\`prisma.user.find\\`)\n// is pushed into context for the engine dispatch.\nfunction __neatWrapPrisma() {\n __neatHook(['@prisma/client'], function (exports${anyT}) {\n try {\n const Client = exports && exports.PrismaClient\n if (typeof Client === 'function' && !Client.__neatWrapped) {\n const ops = ['findUnique','findUniqueOrThrow','findFirst','findFirstOrThrow','findMany','create','createMany','update','updateMany','upsert','delete','deleteMany','count','aggregate','groupBy']\n const __neatPrismaWrapModel = function (model${anyT}) {\n if (!model || model.__neatWrapped) return model\n for (let i = 0; i < ops.length; i++) {\n const op = ops[i]\n const orig = model[op]\n if (typeof orig !== 'function') continue\n model[op] = function __neatPrismaOp(${ts ? '...args: any[]' : '...args'}) {\n const self = this\n return __neatRunWithUserFrame(function () { return orig.apply(self, args) })\n }\n }\n model.__neatWrapped = true\n return model\n }\n const proto = Client.prototype\n const handler = function (model${anyT}) { return __neatPrismaWrapModel(model) }\n // Model accessors are lazily created getters on the instance; wrap the\n // \\`$extends\\`-free common path by trapping property access via a proxy\n // on each constructed client.\n exports.PrismaClient = new Proxy(Client, {\n construct(Target${anyT}, argList${anyT}, NewTarget${anyT}) {\n const instance = Reflect.construct(Target, argList, NewTarget)\n return new Proxy(instance, {\n get(target${anyT}, prop${anyT}, receiver${anyT}) {\n const value = Reflect.get(target, prop, receiver)\n if (value && typeof value === 'object' && typeof prop === 'string' && prop[0] !== '$' && prop[0] !== '_') {\n return handler(value)\n }\n return value\n },\n })\n },\n })\n exports.PrismaClient.__neatWrapped = true\n void proto\n }\n } catch (_e) {}\n return exports\n })\n}\n\n// Handler-entry facades. express / connect share the Layer model (each route\n// handler is a function registered on a Router); the wrap captures the\n// registration frame and stamps + propagates it when the handler runs. The\n// registry is the extensibility seam — koa, fastify (via @fastify/otel),\n// nestjs, restify, and hapi add an entry as their patch surface is wired.\nfunction __neatWrapConnectStyle(mod${anyT}) {\n try {\n // express() returns an app whose route verbs live on Router.prototype and\n // the application proto; connect apps expose \\`use\\`. Wrap the registration\n // verbs so the user handler is wound with its registration frame.\n const verbs = ['use','get','post','put','delete','patch','all','options','head']\n const wrapTarget = function (target${anyT}) {\n if (!target || target.__neatVerbsWrapped) return\n for (let i = 0; i < verbs.length; i++) {\n const verb = verbs[i]\n const orig = target[verb]\n if (typeof orig !== 'function') continue\n target[verb] = function __neatVerb(${ts ? '...args: any[]' : '...args'}) {\n const frame = __neatPickUserFrame(new Error().stack)\n if (frame) {\n for (let a = 0; a < args.length; a++) {\n const h = args[a]\n if (typeof h === 'function' && !h.__neatHandlerWrapped && h.length <= 4) {\n const inner = h\n const __neatHandler${anyT} = function (${ts ? '...hargs: any[]' : '...hargs'}) {\n const self = this\n return __neatStampHandler(frame, function () { return inner.apply(self, hargs) })\n }\n __neatHandler.__neatHandlerWrapped = true\n args[a] = __neatHandler\n }\n }\n }\n return orig.apply(this, args)\n }\n }\n target.__neatVerbsWrapped = true\n }\n if (mod && mod.Router && mod.Router.prototype) wrapTarget(mod.Router.prototype)\n if (mod && mod.application) wrapTarget(mod.application)\n if (mod && mod.prototype) wrapTarget(mod.prototype)\n } catch (_e) {}\n}\n\nfunction __neatInstallHandlerEntry() {\n __neatHook(['express'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n __neatHook(['connect'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n}\n\n// Install every off-stack and handler-entry wrap. Called once after sdk.start()\n// — before user code requires the framework / Prisma modules, so the hooks land\n// on first require. Each wrap is independently guarded.\nfunction __neatInstallFacades() {\n __neatWrapFetch()\n __neatWrapPrisma()\n __neatInstallHandlerEntry()\n}`\n}\n\n// The runtime capture source, exported so the capture spike can materialise and\n// exercise the exact bytes that ship in the generated file.\nexport const CALLSITE_PROCESSOR_JS = neatCaptureSource(false)\nexport const CALLSITE_PROCESSOR_TS = neatCaptureSource(true)\n\n// Post-`sdk.start()` wiring. NodeSDK keeps its env-configured OTLP exporter\n// (passing `spanProcessors` to the constructor would replace it); we add the\n// call-site processor to the started provider via the public `getDelegate()` +\n// `addSpanProcessor()` surface, then assert it actually attached (file-\n// awareness.md §4 / ADR-090). A wiring regression that would silently drop\n// file-first capture throws loudly at boot instead of shipping service-level-\n// only spans. The facade/handler wraps install last, so a span export path is\n// live before any user module loads.\nfunction neatWireCaptureSource(ts: boolean): string {\n const providerT = ts ? ': any' : ''\n return `try {\n const provider${providerT} = trace.getTracerProvider()\n const delegate = provider && typeof provider.getDelegate === 'function' ? provider.getDelegate() : provider\n if (!delegate || typeof delegate.addSpanProcessor !== 'function') {\n throw new Error('[neat] could not resolve a TracerProvider to attach the call-site processor; file-first OBSERVED capture would be silent (file-awareness.md §4)')\n }\n const __neatProcessor = new NeatCallSiteSpanProcessor()\n delegate.addSpanProcessor(__neatProcessor)\n // Post-init assertion: confirm attachment on providers that expose their\n // processor list. An un-introspectable provider is trusted (we just called\n // its addSpanProcessor); a list that exists and lacks our processor throws.\n const registered = delegate._registeredSpanProcessors\n if (Array.isArray(registered) && registered.indexOf(__neatProcessor) === -1) {\n throw new Error('[neat] call-site processor did not attach to the active TracerProvider (file-awareness.md §4)')\n }\n} catch (err) {\n throw err\n}\ntry {\n __neatInstallFacades()\n} catch (_e) {\n // Facade install is best-effort: the stack-walk + handler-entry floor still\n // attribute the sync-wrapper majority even if an off-stack wrap fails.\n}`\n}\n\n// __SERVICE_NAME__ → the ServiceNode id (the package's `pkg.name`, or the\n// directory basename for nameless packages); __PROJECT__ → the registered\n// project basename; __INSTRUMENTATION_BLOCK__ → a (possibly empty) sequence\n// of `instrumentations.push(...)` lines for non-bundled instrumentations\n// (Prisma for v0.4.5; more libraries via the v0.5.0 registry). All three are\n// substituted at apply time via renderNodeOtelInit().\n//\n// v0.4.5 — explicit `NodeSDK` construction replaces the\n// `auto-instrumentations-node/register` shorthand so non-bundled libraries\n// (Prisma's Rust query engine bypasses node-pg; Drizzle, BetterAuth, etc.\n// have their own packages) can compose into the same `instrumentations`\n// array without templating a different file shape per library.\nexport const OTEL_INIT_CJS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\nconst { trace, context } = require('@opentelemetry/api')\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(false)}\n`\n\nexport const OTEL_INIT_ESM = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(false)}\n`\n\nexport const OTEL_INIT_TS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\n// @ts-nocheck — generated runtime shim. The layered capture mechanism uses\n// dynamic patterns (facade wraps, Proxy traps, a createRequire bridge) that a\n// strict user tsconfig would reject; suppressing type-checking here keeps the\n// generated file from breaking the host project's \\`tsc\\` gate (#427) without\n// constraining the runtime logic. The file is regenerated, never hand-edited.\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_TS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(true)}\n`\n\n// Substitute __SERVICE_NAME__, __PROJECT__, and __INSTRUMENTATION_BLOCK__\n// at apply time. The third arg is a list of registration snippets — one per\n// non-bundled instrumentation the installer detected (e.g. Prisma). An empty\n// list collapses the placeholder to nothing so the generated file stays\n// readable on the common \"auto-instrumentations covers everything\" path.\nexport function renderNodeOtelInit(\n template: string,\n serviceName: string,\n projectName: string,\n registrations: readonly string[] = [],\n): string {\n const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// .env.neat shape (ADR-069 §4, amended v0.4.1 — refs #339, v0.4.4 — refs\n// #367 + #369, v0.4.8 — refs #410). Two keys: OTEL_SERVICE_NAME (the\n// ServiceNode id — the package's own name, scope-preserved, so spans land on\n// per-service nodes inside the project's graph) and\n// OTEL_EXPORTER_OTLP_TRACES_ENDPOINT (the project-scoped URL the daemon mounts\n// at /projects/<project>/v1/traces). Both env vars are advisory only — the\n// generated `otel-init` inlines them via `process.env.X ||=` so bundlers can't\n// lose them; the file is kept so operators can grep for service.name → project\n// mapping in one place. A commented `NEAT_OTEL_TOKEN` hint documents the single\n// source of the OTLP bearer (#410): set it to the secret the daemon's receiver\n// expects and the generated init sends `Authorization: Bearer <token>`.\nexport function renderEnvNeat(serviceName: string, projectName: string): string {\n return [\n '# Generated by `neat init --apply` (ADR-069).',\n `OTEL_SERVICE_NAME=${serviceName}`,\n `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/projects/${projectName}/v1/traces`,\n '# Set NEAT_OTEL_TOKEN to the daemon\\'s OTLP secret to authenticate exported spans (#410).',\n '# NEAT_OTEL_TOKEN=',\n '',\n ].join('\\n')\n}\n\n// ── Next.js framework-aware templates (ADR-073 §1, ADR-069 §3). ─────────\n//\n// Next.js owns its own boot — `pkg.main` is unused, and the auto-instrumentation\n// register hook can't run before user code. Next 13+ ships an `instrumentation`\n// file at the project root with an async `register()` export the framework\n// invokes during server start (Node runtime only). For Edge / browser runtimes\n// the file is ignored.\n//\n// Two-file shape: `instrumentation.{ts,js}` keeps the runtime gate so the\n// Node SDK doesn't load on the Edge runtime; `instrumentation.node.{ts,js}`\n// carries the SDK init itself. Both files sit at the project root.\n\nexport const NEXT_INSTRUMENTATION_HEADER =\n '// Generated by `neat init --apply` (ADR-073). Next.js instrumentation hook.'\n\nexport const NEXT_INSTRUMENTATION_TS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('./instrumentation.node')\n }\n}\n`\n\nexport const NEXT_INSTRUMENTATION_JS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('./instrumentation.node')\n }\n}\n`\n\n// Env vars are inlined as process.env defaults so they survive Turbopack /\n// Webpack bundling — `import.meta.url` resolves to a path under .next/dev/\n// server/chunks/ once Next compiles this file, which would miss .env.neat.\n// `process.env.X ||=` keeps platform env (Vercel / Railway / Fly / etc.)\n// authoritative at deploy time while the local default carries the routing\n// key the daemon needs to map spans back to this project. The endpoint uses\n// the project-scoped URL form so the daemon never has to guess which project\n// owns the span (issue #367); the OTel SDK reads the env vars from\n// process.env directly, so no file-system lookup is required at runtime.\nexport const NEXT_INSTRUMENTATION_NODE_TS = `${NEXT_INSTRUMENTATION_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\nexport const NEXT_INSTRUMENTATION_NODE_JS = `${NEXT_INSTRUMENTATION_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\n// Substitute the placeholders at apply time so the generated file carries the\n// ServiceNode id (`__SERVICE_NAME__`) and the registered project name\n// (`__PROJECT__`) verbatim. The two roles diverged in v0.4.4: the service name\n// names the ServiceNode inside one project's graph, the project basename is\n// the URL routing key. v0.4.5 adds __INSTRUMENTATION_BLOCK__ — a (possibly\n// empty) sequence of `instrumentations.push(...)` calls for non-bundled\n// libraries like Prisma whose query engines bypass the auto-instrumentation\n// set's coverage.\nexport function renderNextInstrumentationNode(\n template: string,\n serviceName: string,\n projectName: string,\n registrations: readonly string[] = [],\n): string {\n const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// ── Meta-framework templates (ADR-074 §3). ──────────────────────────────\n//\n// Remix, SvelteKit, Nuxt, and Astro each own their boot path. The installer\n// emits one OTel-init module that loads `.env.neat` and starts the Node SDK,\n// then either creates or injects an import into the framework's canonical\n// hook file. Templates mirror the Next.js pair in shape — one generated init\n// module, one optional framework-hook stub for the absent-file case.\n\nexport const FRAMEWORK_OTEL_INIT_HEADER =\n '// Generated by `neat init --apply` (ADR-074). OpenTelemetry SDK hook.'\n\n// Same inline-defaults pattern as the plain-Node + Next templates: env vars\n// arrive on `process.env` via the apply-time substitution below so bundler\n// path mangling (issue #369) can't lose them. `__SERVICE_NAME__` /\n// `__PROJECT__` are substituted via renderFrameworkOtelInit().\nconst FRAMEWORK_OTEL_INIT_TS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst sdk = new NodeSDK({\n serviceName: process.env.OTEL_SERVICE_NAME,\n instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n`\n\nconst FRAMEWORK_OTEL_INIT_JS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst sdk = new NodeSDK({\n serviceName: process.env.OTEL_SERVICE_NAME,\n instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n`\n\nexport function renderFrameworkOtelInit(\n template: string,\n serviceName: string,\n projectName: string,\n): string {\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n}\n\n// Remix — `app/otel.server.{ts,js}` carries the SDK bootstrap. The framework\n// loads `entry.server.*` at server-process start, and a top-of-module import\n// of `./otel.server` runs the bootstrap before any request handler imports.\nexport const REMIX_OTEL_SERVER_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const REMIX_OTEL_SERVER_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\n// SvelteKit — `src/otel-init.{ts,js}` carries the SDK bootstrap; the\n// framework's `src/hooks.server.{ts,js}` imports it. When hooks.server is\n// absent, the installer writes the stub below alongside the import.\nexport const SVELTEKIT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const SVELTEKIT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const SVELTEKIT_HOOKS_SERVER_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport type { Handle } from '@sveltejs/kit'\n\nexport const handle: Handle = async ({ event, resolve }) => {\n return resolve(event)\n}\n`\n\nexport const SVELTEKIT_HOOKS_SERVER_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\n/** @type {import('@sveltejs/kit').Handle} */\nexport const handle = async ({ event, resolve }) => {\n return resolve(event)\n}\n`\n\n// Nuxt — `server/plugins/otel.{ts,js}` is the convention-loaded plugin file;\n// it imports the sibling `otel-init.{ts,js}` which carries the SDK bootstrap.\nexport const NUXT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const NUXT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const NUXT_OTEL_PLUGIN_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nexport default defineNitroPlugin(() => {\n // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\nexport const NUXT_OTEL_PLUGIN_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nrequire('./otel-init')\n\nmodule.exports = defineNitroPlugin(() => {\n // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\n// Astro — `src/middleware.{ts,js}` runs once at module-load (and then per\n// request via onRequest). The top-of-module import of `./otel-init` boots\n// the SDK before the first request lands.\nexport const ASTRO_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const ASTRO_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const ASTRO_MIDDLEWARE_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n return next()\n})\n`\n\nexport const ASTRO_MIDDLEWARE_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n return next()\n})\n`\n","/**\n * Python SDK installer (ADR-047).\n *\n * `detect` matches on the canonical Python project markers — requirements.txt,\n * pyproject.toml, setup.py. `plan` produces dependency edits against the\n * primary manifest and entrypoint edits against a Procfile when one exists.\n *\n * MVP scope:\n * - requirements.txt is the full-fidelity manifest (read / append).\n * - pyproject.toml dependencies live inside a TOML `dependencies = [...]`\n * block; we line-insert into that block when found, otherwise hold off\n * on rewriting until a successor ADR addresses TOML editing properly.\n * - Procfile lines starting with `python` get prefixed with\n * `opentelemetry-instrument`.\n *\n * Lockfiles (poetry.lock, Pipfile.lock) are never touched. After `--apply`,\n * init's summary tells the user to run `pip install -r requirements.txt`\n * (or `poetry lock && poetry install`) so they own the lockfile commit.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n Installer,\n InstallPlan,\n} from './shared.js'\n\nconst SDK_PACKAGES = [\n { name: 'opentelemetry-distro', version: '>=0.49b0' },\n { name: 'opentelemetry-exporter-otlp', version: '>=1.28.0' },\n] as const\n\nconst OTEL_ENV: EnvEdit = {\n file: null,\n key: 'OTEL_EXPORTER_OTLP_ENDPOINT',\n value: 'http://localhost:4318',\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.stat(p)\n return true\n } catch {\n return false\n }\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n const markers = ['requirements.txt', 'pyproject.toml', 'setup.py']\n for (const m of markers) {\n if (await exists(path.join(serviceDir, m))) return true\n }\n return false\n}\n\n// Strip a requirements.txt line down to its lower-cased package name.\n// `flask==3.0.0` → `flask`, `Flask>=2 ; python_version>\"3.6\"` → `flask`.\nfunction reqPackageName(line: string): string {\n const stripped = line.split('#')[0]?.trim() ?? ''\n const head = stripped.split(/[\\s;]/)[0] ?? ''\n return head.replace(/[<>=!~].*$/, '').toLowerCase()\n}\n\nasync function planRequirementsTxtEdits(\n serviceDir: string,\n): Promise<{ manifest: string; missing: typeof SDK_PACKAGES[number][] } | null> {\n const file = path.join(serviceDir, 'requirements.txt')\n if (!(await exists(file))) return null\n const raw = await fs.readFile(file, 'utf8')\n const presentNames = new Set(\n raw\n .split(/\\r?\\n/)\n .map(reqPackageName)\n .filter((n) => n.length > 0),\n )\n const missing = SDK_PACKAGES.filter((p) => !presentNames.has(p.name.toLowerCase()))\n return { manifest: file, missing: [...missing] }\n}\n\nasync function planProcfileEdits(serviceDir: string): Promise<EntrypointEdit[]> {\n const procfile = path.join(serviceDir, 'Procfile')\n if (!(await exists(procfile))) return []\n const raw = await fs.readFile(procfile, 'utf8')\n const edits: EntrypointEdit[] = []\n for (const line of raw.split(/\\r?\\n/)) {\n if (line.length === 0) continue\n // Procfile lines look like `<process>: <cmd>`. Prefix the cmd when it\n // starts with python and isn't already wrapped.\n const m = line.match(/^([a-zA-Z0-9_-]+):\\s*(.+)$/)\n if (!m) continue\n const cmd = m[2]!\n if (!/^python\\b/.test(cmd)) continue\n if (cmd.startsWith('opentelemetry-instrument ')) continue\n const after = `${m[1]}: opentelemetry-instrument ${cmd}`\n edits.push({ file: procfile, before: line, after })\n }\n return edits\n}\n\nasync function plan(serviceDir: string): Promise<InstallPlan> {\n const empty: InstallPlan = {\n language: 'python',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n }\n\n const dependencyEdits: DependencyEdit[] = []\n const reqs = await planRequirementsTxtEdits(serviceDir)\n if (reqs) {\n for (const sdk of reqs.missing) {\n dependencyEdits.push({\n file: reqs.manifest,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n }\n // pyproject.toml / setup.py without requirements.txt: deferred to a\n // successor ADR. The patch will note it; apply is a no-op for those\n // manifests in the MVP.\n\n const entrypointEdits = await planProcfileEdits(serviceDir)\n\n if (dependencyEdits.length === 0 && entrypointEdits.length === 0) {\n return empty\n }\n return {\n language: 'python',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n }\n}\n\nasync function applyRequirementsTxt(\n manifest: string,\n edits: DependencyEdit[],\n original: string,\n): Promise<void> {\n // Append missing packages on their own lines. Preserve a trailing newline.\n const newlines = edits\n .filter((e) => e.kind === 'add')\n .map((e) => `${e.name}${e.version}`)\n const trailing = original.endsWith('\\n') ? '' : '\\n'\n const next = `${original}${trailing}${newlines.join('\\n')}\\n`\n const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, next, 'utf8')\n await fs.rename(tmp, manifest)\n}\n\nasync function applyProcfile(\n procfile: string,\n edits: EntrypointEdit[],\n original: string,\n): Promise<void> {\n let next = original\n for (const e of edits) {\n if (!next.includes(e.before)) continue\n next = next.replace(e.before, e.after)\n }\n const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, next, 'utf8')\n await fs.rename(tmp, procfile)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n const { serviceDir } = installPlan\n const touched = new Set<string>()\n for (const e of installPlan.dependencyEdits) touched.add(e.file)\n for (const e of installPlan.entrypointEdits) touched.add(e.file)\n if (touched.size === 0) {\n return { serviceDir, outcome: 'already-instrumented', writtenFiles: [] }\n }\n\n const originals = new Map<string, string>()\n for (const file of touched) {\n try {\n originals.set(file, await fs.readFile(file, 'utf8'))\n } catch {\n // Mutation will fail loudly below; rollback covers what did land.\n }\n }\n\n const writtenFiles: string[] = []\n try {\n for (const file of touched) {\n const raw = originals.get(file)\n if (raw === undefined) {\n throw new Error(`python installer: cannot read ${file} during apply`)\n }\n const base = path.basename(file)\n if (base === 'requirements.txt') {\n const edits = installPlan.dependencyEdits.filter((e) => e.file === file)\n if (edits.length > 0) {\n await applyRequirementsTxt(file, edits, raw)\n writtenFiles.push(file)\n }\n } else if (base === 'Procfile') {\n const edits = installPlan.entrypointEdits.filter((e) => e.file === file)\n if (edits.length > 0) {\n await applyProcfile(file, edits, raw)\n writtenFiles.push(file)\n }\n }\n // pyproject.toml / setup.py: MVP no-op as planned above.\n }\n } catch (err) {\n await rollback(installPlan, originals)\n throw err\n }\n\n return { serviceDir, outcome: 'instrumented', writtenFiles }\n}\n\nasync function rollback(\n installPlan: InstallPlan,\n originals: Map<string, string>,\n): Promise<void> {\n const restored: string[] = []\n for (const [file, raw] of originals.entries()) {\n try {\n await fs.writeFile(file, raw, 'utf8')\n restored.push(file)\n } catch {\n // Best-effort.\n }\n }\n const lines = [\n '# neat-rollback.patch',\n '',\n `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n '# Files listed below were restored to their pre-apply contents.',\n '',\n ...restored.map((f) => `restored: ${f}`),\n '',\n ]\n const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\nexport const pythonInstaller: Installer = {\n name: 'python',\n detect,\n plan,\n apply,\n}\n","/**\n * Shared types for SDK installer modules (ADR-047).\n *\n * Each language has its own installer at `installers/<language>.ts` exporting\n * a `detect / plan / apply` triple. Plans are pure data — no fs side effects\n * during planning — so `init --dry-run` can render a patch without ever\n * touching the project. `apply` runs the codemod in place.\n *\n * Step 2 (this PR) ships the interface and an empty registry. Step 3 (Node\n * installer) and step 4 (Python installer) populate it.\n */\n\n// Field names match ADR-047's documented patch shape exactly: `file`, `kind`,\n// `name`, `version`. Patches will be reviewed by humans and matched in tests\n// by name; renaming for clarity would have cost more than it bought.\n\nexport interface DependencyEdit {\n file: string\n kind: 'add' | 'remove'\n name: string\n version: string\n}\n\nexport interface EntrypointEdit {\n file: string\n before: string\n after: string\n}\n\nexport interface EnvEdit {\n // `null` denotes a recommendation only — the user will set the env var in\n // their orchestration layer, NEAT does not write a `.env` file.\n file: string | null\n key: string\n value: string\n}\n\n// Files the installer generates from scratch (ADR-069 §1). The generated\n// `otel-init.{js,ts}` for the Node installer rides here, along with the\n// per-package `.env.neat` (ADR-069 §4). Treated as additive writes — the\n// apply phase skips any file already present (ADR-069 §6).\nexport interface GeneratedFile {\n file: string\n contents: string\n // When true, write only if the file does not already exist. The apply\n // phase logs an `already instrumented` / `already present` notice instead\n // of overwriting (ADR-069 §6).\n skipIfExists?: boolean\n}\n\nexport interface InstallPlan {\n // Free-form language tag matching the service node's language: `'javascript'`,\n // `'python'`, …\n language: string\n // Service directory the plan targets. Absolute path.\n serviceDir: string\n dependencyEdits: DependencyEdit[]\n entrypointEdits: EntrypointEdit[]\n envEdits: EnvEdit[]\n // ADR-069 §1, §4 — generated files (otel-init, .env.neat). Optional so\n // installers that don't generate files (the Python installer at MVP) can\n // omit it.\n generatedFiles?: GeneratedFile[]\n // ADR-069 §2 — flagged when entry-point resolution found nothing.\n // The apply phase records this in the summary and skips all file writes\n // for the package.\n libOnly?: boolean\n // ADR-069 §2 — resolved entry-point path (absolute). Present when the\n // installer is going to inject the require/import. Absent for libOnly\n // packages and for the Python installer.\n entryFile?: string\n // ADR-073 §1 + ADR-074 §3 — when a framework owns its own boot, the\n // installer skips `pkg.main` injection and emits framework-native\n // instrumentation files instead. Five values today: Next.js from v0.3.8,\n // then Remix / SvelteKit / Nuxt / Astro from v0.3.9.\n framework?: 'next' | 'remix' | 'sveltekit' | 'nuxt' | 'astro'\n // v0.4.4 / issue #370 — when a JavaScript package isn't a Node service\n // (browser bundle, React Native), the installer records the runtime here\n // and writes nothing. Absent → vanilla Node default (the existing apply\n // path). Browser-side OTel support (`@opentelemetry/sdk-trace-web`) lands\n // in a future release.\n runtimeKind?: 'browser-bundle' | 'react-native'\n // ADR-073 §1 — Next.js' `next.config.{js,ts,mjs}` may need the\n // `experimental.instrumentationHook: true` flag set when the major\n // version is < 15. The apply phase mutates the file in place when this\n // field is set. Absent → no config mutation planned.\n nextConfigEdit?: {\n file: string\n // Reason this edit is queued — surfaces in the dry-run patch and the\n // apply summary so the operator knows why their next.config moved.\n reason: string\n }\n}\n\n// ADR-069 §9 — apply outcome per service. The CLI surfaces these counts\n// at the end of `neat init --apply`. v0.4.4 / issue #370 — two new buckets\n// for non-Node JavaScript runtimes: `browser-bundle` (Vite, esbuild-shipped\n// SPAs) and `react-native` (Expo / RN bare). The Node SDK can't run in\n// either; both buckets skip every write and surface the package in the\n// summary so the operator knows the frontend wasn't instrumented.\nexport type ApplyOutcome =\n | 'instrumented'\n | 'already-instrumented'\n | 'lib-only'\n | 'failed'\n | 'browser-bundle'\n | 'react-native'\n\nexport interface ApplyResult {\n serviceDir: string\n outcome: ApplyOutcome\n // Free-form reason string for `lib-only` / `failed` outcomes. Surfaced\n // in the CLI summary so the user knows why a package was skipped.\n reason?: string\n // Absolute paths the apply phase actually wrote to. Used by the contract\n // test that asserts the allowed-path-set restriction (ADR-069 §7).\n writtenFiles: string[]\n}\n\n// Plan-time inputs the orchestrator threads through (v0.4.1 — refs #339).\n// `project` is the registered project name — the routing key the daemon\n// owns. When present the installer writes it as `OTEL_SERVICE_NAME` so the\n// OTLP wire and the registry agree end-to-end. Absent → installers fall\n// back to a package-local default for ad-hoc / test usage.\nexport interface PlanOptions {\n project?: string\n}\n\nexport interface Installer {\n // Free-form module name. Used for the patch header and for diagnostics.\n name: string\n // Returns true if the installer thinks `serviceDir` is shaped like a project\n // it can instrument. Cheap; no fs writes.\n detect(serviceDir: string): boolean | Promise<boolean>\n // Builds an `InstallPlan` describing the edits the installer would make.\n // Pure data; no fs writes. An empty plan (every edits array empty) means\n // the SDK is already installed and there is nothing to do.\n plan(serviceDir: string, opts?: PlanOptions): InstallPlan | Promise<InstallPlan>\n // Apply a previously-produced plan. Mutates files in place. On failure,\n // produces `<serviceDir>/neat-rollback.patch` per ADR-047 #7. Returns a\n // structured outcome so the CLI can surface coverage (ADR-069 §9).\n apply(plan: InstallPlan): Promise<ApplyResult>\n}\n\nexport function isEmptyPlan(plan: InstallPlan): boolean {\n return (\n plan.dependencyEdits.length === 0 &&\n plan.entrypointEdits.length === 0 &&\n plan.envEdits.length === 0 &&\n (plan.generatedFiles?.length ?? 0) === 0 &&\n plan.nextConfigEdit === undefined\n )\n}\n","/**\n * One-command orchestrator (ADR-073 §1).\n *\n * Bare `neat <path>` dispatches here when the first positional argument\n * resolves to a directory and doesn't match a registered verb. Six steps,\n * in order:\n *\n * 1. Discovery + extraction (per static-extraction contract).\n * 2. `.gitignore` automation (ADR-073 §6) + project registration.\n * 3. SDK install apply — patches manifests + writes otel-init + writes\n * `.env.neat`. Default yes; `--no-instrument` opts out.\n * 4. Daemon spawn — `neatd start --detach` if no daemon is running.\n * Polls `/health` up to 15s for readiness.\n * 5. Browser open against the web UI on port 6328 (T9 NEAT).\n * Default yes; `--no-open` and headless runs skip the launch.\n * 6. Summary block — value-forward findings + OTel env-vars block.\n *\n * `neat init` retains its patch-by-default contract (ADR-046 §5). The\n * orchestrator runs apply unconditionally because the bare-`<path>` shape's\n * user intent is \"make this work end-to-end.\"\n */\n\nimport { promises as fs } from 'node:fs'\nimport http from 'node:http'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport readline from 'node:readline'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { discoverServices } from './extract/services.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { pathsForProject } from './projects.js'\nimport { addProject, listProjects, ProjectNameCollisionError, setStatus } from './registry.js'\nimport {\n isEmptyPlan,\n pickInstaller,\n type InstallPlan,\n} from './installers/index.js'\nimport {\n detectPackageManager,\n runPackageManagerInstall,\n type PackageManager,\n type PackageManagerInvocation,\n} from './installers/package-manager.js'\n\nexport interface OrchestratorOptions {\n scanPath: string\n // Project name resolution mirrors `neat init` — basename of the scan\n // path unless overridden via --project.\n project: string\n projectExplicit: boolean\n // Skip step 3 (SDK install apply).\n noInstrument: boolean\n // Skip step 5 (browser open).\n noOpen: boolean\n // Skip the interactive prompt (CI invocation flag — implied when\n // stdin/stdout aren't a TTY).\n yes: boolean\n // Dashboard URL — defaults to http://localhost:6328 (T9 NEAT, ADR-059).\n dashboardUrl?: string\n // Health-check timeout in ms. Default 15s.\n daemonReadyTimeoutMs?: number\n}\n\nexport interface OrchestratorResult {\n exitCode: number\n // High-level step-by-step status for the test surface.\n steps: {\n discovery: { services: number; languages: string[] }\n extraction: { nodesAdded: number; edgesAdded: number }\n gitignore: 'added' | 'created' | 'unchanged'\n apply: {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n skipped: boolean\n // Issue #381 — package-manager invocations the orchestrator ran\n // after apply() mutated package.json. Absent for `--no-instrument`\n // runs and runs where every plan was empty.\n packageManagerInstalls?: PackageManagerInvocation[]\n }\n daemon: 'spawned' | 'already-running' | 'timed-out' | 'skipped'\n browser: 'opened' | 'skipped' | 'failed'\n }\n}\n\n// Shared sub-pipeline `neat sync` re-uses (ADR-074 §1). Discovery + extract\n// + snapshot write. Distinct from the first-run-only steps (registry add,\n// daemon spawn, browser open, summary block) that the orchestrator owns\n// directly.\nexport interface ExtractAndPersistOptions {\n scanPath: string\n project: string\n projectExplicit: boolean\n // When true, skip persisting to disk — for `neat sync --dry-run`.\n dryRun?: boolean\n}\n\nexport interface ExtractAndPersistResult {\n graph: ReturnType<typeof getGraph>\n graphKey: string\n services: Awaited<ReturnType<typeof discoverServices>>\n languages: string[]\n nodesAdded: number\n edgesAdded: number\n snapshotPath: string\n errorsPath: string\n}\n\nexport async function extractAndPersist(\n opts: ExtractAndPersistOptions,\n): Promise<ExtractAndPersistResult> {\n const services = await discoverServices(opts.scanPath)\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n\n const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n resetGraph(graphKey)\n const graph = getGraph(graphKey)\n const projectPaths = pathsForProject(graphKey, path.join(opts.scanPath, 'neat-out'))\n const extraction = await extractFromDirectory(graph, opts.scanPath, {\n errorsPath: projectPaths.errorsPath,\n })\n if (!opts.dryRun) {\n await saveGraphToDisk(graph, projectPaths.snapshotPath)\n }\n return {\n graph,\n graphKey,\n services,\n languages,\n nodesAdded: extraction.nodesAdded,\n edgesAdded: extraction.edgesAdded,\n snapshotPath: projectPaths.snapshotPath,\n errorsPath: projectPaths.errorsPath,\n }\n}\n\n// SDK-install apply over a discovered service list. Returns the same shape\n// the orchestrator's result.steps.apply uses so callers (orchestrator + sync)\n// share the rollup logic. v0.4.1 / refs #339 — `project` is threaded through\n// to the installer so the per-package `.env.neat` carries\n// `OTEL_SERVICE_NAME=<project>`, matching the daemon's routing key.\nexport interface ApplyInstallersTally {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n browserBundle: number\n reactNative: number\n // Issue #381 — package-manager invocations the orchestrator ran after\n // apply() mutated package.json. One entry per distinct lockfile-owning\n // directory (monorepos share a single install run regardless of how\n // many sub-packages got instrumented). Empty when nothing was added to\n // any package.json.\n packageManagerInstalls: PackageManagerInvocation[]\n}\n\n// Knobs the test surface uses to swap the real spawn for a no-op. Default\n// uses the real installer; the contract suite passes a stub so the wiring\n// can be asserted without spawning npm against an unreliable registry.\nexport interface ApplyInstallersOptions {\n runInstall?: (cmd: { pm: PackageManager; cwd: string; args: string[] }) => Promise<PackageManagerInvocation>\n resolveManager?: (serviceDir: string) => Promise<{ pm: PackageManager; cwd: string; args: string[] }>\n}\n\nexport async function applyInstallersOver(\n services: Awaited<ReturnType<typeof discoverServices>>,\n project: string,\n options: ApplyInstallersOptions = {},\n): Promise<ApplyInstallersTally> {\n const resolveManager = options.resolveManager ?? detectPackageManager\n const runInstall = options.runInstall ?? runPackageManagerInstall\n let instrumented = 0\n let already = 0\n let libOnly = 0\n let browserBundle = 0\n let reactNative = 0\n // Distinct install commands keyed by `<pm>:<cwd>` so a monorepo with\n // multiple instrumented sub-packages still runs install exactly once at\n // its workspace root. The first plan that landed a dep edit for a given\n // root wins; later sub-packages skip the re-run.\n const installPlans = new Map<string, { pm: PackageManager; cwd: string; args: string[] }>()\n for (const svc of services) {\n const installer = await pickInstaller(svc.dir)\n if (!installer) continue\n const plan: InstallPlan = await installer.plan(svc.dir, { project })\n if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) {\n already++\n continue\n }\n const outcome = await installer.apply(plan)\n if (outcome.outcome === 'instrumented') {\n instrumented++\n // Schedule an install whenever apply() actually added deps. The\n // generated otel-init file lives under the service dir but the\n // packages the user must resolve at runtime (`@opentelemetry/sdk-node`,\n // `@prisma/instrumentation`) live in package.json — without the\n // install, the next `npm run dev` throws `Cannot find module ...`\n // before any of NEAT's code even loads.\n if (plan.dependencyEdits.length > 0) {\n const cmd = await resolveManager(svc.dir)\n const key = `${cmd.pm}:${cmd.cwd}`\n if (!installPlans.has(key)) installPlans.set(key, cmd)\n }\n } else if (outcome.outcome === 'already-instrumented') already++\n else if (outcome.outcome === 'lib-only') libOnly++\n else if (outcome.outcome === 'browser-bundle') {\n browserBundle++\n console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`)\n } else if (outcome.outcome === 'react-native') {\n reactNative++\n console.log(`skipping ${svc.dir}: React Native target; browser-OTel support lands in a future release.`)\n }\n }\n\n // Run each distinct install command serially. Parallelism would race the\n // lockfile in the rare monorepo-of-monorepos case and most package\n // managers serialise themselves internally anyway — the time saving is\n // tiny next to the operator-trust cost of a corrupted lockfile.\n const packageManagerInstalls: PackageManagerInvocation[] = []\n for (const cmd of installPlans.values()) {\n console.log(`running \\`${cmd.pm} ${cmd.args.join(' ')}\\` in ${cmd.cwd}`)\n const result = await runInstall(cmd)\n packageManagerInstalls.push(result)\n if (result.exitCode !== 0) {\n console.error(\n `neat: ${cmd.pm} install failed in ${cmd.cwd} (exit ${result.exitCode}); run it manually to surface the error.`,\n )\n if (result.stderr.length > 0) {\n for (const line of result.stderr.split(/\\r?\\n/).slice(0, 20)) {\n console.error(` ${line}`)\n }\n }\n }\n }\n\n return {\n instrumented,\n alreadyInstrumented: already,\n libOnly,\n browserBundle,\n reactNative,\n packageManagerInstalls,\n }\n}\n\nasync function promptYesNo(question: string): Promise<boolean> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n return new Promise((resolve) => {\n rl.question(`${question} [Y/n] `, (answer) => {\n rl.close()\n const trimmed = answer.trim().toLowerCase()\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes')\n })\n })\n}\n\n// 60s covers boot + per-project graph load across a registry with several\n// sibling projects. Issue #340 — `app.listen()` now returns the moment the\n// socket binds, so the steady-state happy path lands well inside the first\n// second; the longer ceiling is the cold-clone window where multi-project\n// bootstraps run in the background after listen.\nconst DEFAULT_DAEMON_READY_TIMEOUT_MS = 60_000\n\n// 500ms poll cadence — responsive enough that the operator sees a fresh\n// status line on every transition without spamming the daemon.\nconst PROBE_INTERVAL_MS = 500\n\ninterface DaemonHealthResponse {\n ok?: boolean\n uptimeMs?: number\n projects?: Array<{\n name: string\n status?: 'bootstrapping' | 'active' | 'broken'\n elapsedMs?: number\n }>\n}\n\nasync function fetchDaemonHealth(restPort: number): Promise<DaemonHealthResponse | null> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${restPort}/health`, (res) => {\n const ok = res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300\n if (!ok) {\n res.resume()\n resolve(null)\n return\n }\n let body = ''\n res.setEncoding('utf8')\n res.on('data', (chunk: string) => { body += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(body) as DaemonHealthResponse)\n } catch {\n resolve({ ok: true })\n }\n })\n })\n req.on('error', () => resolve(null))\n req.setTimeout(1000, () => {\n req.destroy()\n resolve(null)\n })\n })\n}\n\nasync function checkDaemonHealth(restPort: number): Promise<boolean> {\n const body = await fetchDaemonHealth(restPort)\n return body !== null\n}\n\nasync function probeProjectHealth(\n restPort: number,\n name: string,\n): Promise<'bootstrapping' | 'active' | 'broken'> {\n return new Promise((resolve) => {\n const req = http.get(\n `http://127.0.0.1:${restPort}/projects/${encodeURIComponent(name)}/health`,\n (res) => {\n const code = res.statusCode ?? 0\n res.resume()\n if (code >= 200 && code < 300) resolve('active')\n else resolve('bootstrapping')\n },\n )\n req.on('error', () => resolve('bootstrapping'))\n req.setTimeout(1000, () => {\n req.destroy()\n resolve('bootstrapping')\n })\n })\n}\n\n// Resolve the project-status set the wait loop branches on. Prefers the\n// daemon-wide /health response when it carries the list; otherwise reads\n// the registry directly and probes each project's per-project /health.\n// The fallback handles the case where the daemon-wide /health hasn't\n// landed in this branch's main yet.\nasync function snapshotProjectStatus(\n restPort: number,\n body: DaemonHealthResponse,\n): Promise<Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken' }>> {\n if (body.projects && body.projects.length > 0) {\n return body.projects.map((p) => ({\n name: p.name,\n status: p.status ?? 'active',\n }))\n }\n const entries = await listProjects().catch(() => [])\n if (entries.length === 0) return []\n return Promise.all(\n entries.map(async (entry) => ({\n name: entry.name,\n status: await probeProjectHealth(restPort, entry.name),\n })),\n )\n}\n\ninterface DaemonReadyResult {\n ready: boolean\n brokenProjects: string[]\n stillBootstrapping: string[]\n}\n\nasync function waitForDaemonReady(restPort: number, timeoutMs: number): Promise<DaemonReadyResult> {\n const deadline = Date.now() + timeoutMs\n let lastBootstrapping: string[] = []\n while (Date.now() < deadline) {\n const body = await fetchDaemonHealth(restPort)\n if (body !== null) {\n const projects = await snapshotProjectStatus(restPort, body)\n const bootstrapping = projects\n .filter((p) => p.status === 'bootstrapping')\n .map((p) => p.name)\n const broken = projects.filter((p) => p.status === 'broken').map((p) => p.name)\n if (bootstrapping.length === 0) {\n return { ready: true, brokenProjects: broken, stillBootstrapping: [] }\n }\n const key = bootstrapping.slice().sort().join(',')\n const prevKey = lastBootstrapping.slice().sort().join(',')\n if (key !== prevKey) {\n const plural = bootstrapping.length === 1 ? '' : 's'\n console.log(\n `neat: waiting on ${bootstrapping.length} project${plural}: ${bootstrapping.join(', ')}`,\n )\n lastBootstrapping = bootstrapping\n }\n }\n await new Promise((r) => setTimeout(r, PROBE_INTERVAL_MS))\n }\n const final = await fetchDaemonHealth(restPort)\n const projects = final ? await snapshotProjectStatus(restPort, final) : []\n return {\n ready: false,\n brokenProjects: projects.filter((p) => p.status === 'broken').map((p) => p.name),\n stillBootstrapping: projects\n .filter((p) => p.status === 'bootstrapping')\n .map((p) => p.name),\n }\n}\n\n// Port-availability probe (#377 / ADR-079 §2).\n//\n// The orchestrator's daemon-spawn step assumes `:8080` (REST), `:4318` (OTLP\n// HTTP), and `:6328` (web UI) are free. When a sibling daemon from another\n// terminal session — or any unrelated listener — is holding one of them, the\n// spawn exits 1 with no actionable message. The probe runs before\n// `spawnDaemonDetached()` and surfaces the named port plus recovery commands\n// on collision, exiting with code 3 (environmental) per the CLI exit-code\n// surface.\nexport const NEAT_PORTS = [8080, 4318, 6328] as const\n\nexport async function isPortFree(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer()\n server.once('error', () => resolve(false))\n server.once('listening', () => server.close(() => resolve(true)))\n server.listen(port, '127.0.0.1')\n })\n}\n\nexport async function probePortsFree(): Promise<\n { free: true } | { free: false; held: number }\n> {\n for (const port of NEAT_PORTS) {\n if (!(await isPortFree(port))) return { free: false, held: port }\n }\n return { free: true }\n}\n\nexport function formatPortCollisionMessage(port: number): string[] {\n return [\n `neat: port ${port} is in use; the NEAT daemon needs it.`,\n ` run \\`neatd stop\\` to release the previous daemon, or`,\n ` \\`lsof -i :${port}\\` to find the holding process.`,\n ]\n}\n\n// Spawn the daemon as a child process the orchestrator drives. Returns the\n// child handle so the caller can read its stderr verbatim when the bind\n// gate (or any other startup failure) reports back through that pipe\n// (issue #341). The `detached: true` + `unref()` pair survives the\n// orchestrator exiting cleanly; the inherited stderr keeps the operator\n// informed when something does fail.\nfunction spawnDaemonDetached(): import('node:child_process').ChildProcess {\n // Resolve the neatd entry inside the @neat.is/core dist next to this\n // file. `import.meta.url` is post-bundling — at runtime, this resolves\n // to `<core>/dist/neatd.{js,cjs}`. We pick the .cjs because tsup ships\n // it in both forms and node tolerates either.\n const here = path.dirname(new URL(import.meta.url).pathname)\n const candidates = [\n path.join(here, 'neatd.cjs'),\n path.join(here, 'neatd.js'),\n ]\n let entry: string | null = null\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fsSync = require('node:fs') as typeof import('node:fs')\n for (const c of candidates) {\n try {\n fsSync.accessSync(c)\n entry = c\n break\n } catch {\n // try next\n }\n }\n if (!entry) {\n throw new Error(`orchestrator: cannot locate neatd entry in ${here}`)\n }\n\n // ADR-073 §3 + issue #341 — first-touch path is loopback-only. When the\n // operator hasn't set `NEAT_AUTH_TOKEN` the orchestrator hard-pins\n // HOST=127.0.0.1 in the child env so `assertBindAuthority` lets the bind\n // through. Public-bind is opt-in via the token (and an explicit\n // `HOST=0.0.0.0` if the operator wants the literal). The parent's HOST is\n // preserved untouched when the token is set — that's the deploy path,\n // where the platform owns the bind decision.\n const env = { ...process.env }\n const hasToken = typeof env.NEAT_AUTH_TOKEN === 'string' && env.NEAT_AUTH_TOKEN.length > 0\n if (!hasToken && (!env.HOST || env.HOST.length === 0)) {\n env.HOST = '127.0.0.1'\n }\n\n const child = spawn(process.execPath, [entry, 'start'], {\n detached: true,\n // stderr inherits the orchestrator's fd so the daemon's\n // `BindAuthorityError` message lands in front of the operator instead\n // of being swallowed (issue #341).\n stdio: ['ignore', 'ignore', 'inherit'],\n env,\n })\n child.unref()\n return child\n}\n\nfunction openBrowser(url: string): 'opened' | 'failed' {\n // Skip when running headlessly; we don't want CI invocations to fail\n // because xdg-open isn't installed.\n if (!process.stdout.isTTY) return 'failed'\n const platform = process.platform\n const cmd =\n platform === 'darwin' ? 'open' :\n platform === 'win32' ? 'cmd' :\n 'xdg-open'\n const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]\n try {\n const child = spawn(cmd, args, { detached: true, stdio: 'ignore' })\n child.on('error', () => {})\n child.unref()\n return 'opened'\n } catch {\n return 'failed'\n }\n}\n\nexport async function runOrchestrator(opts: OrchestratorOptions): Promise<OrchestratorResult> {\n const result: OrchestratorResult = {\n exitCode: 0,\n steps: {\n discovery: { services: 0, languages: [] },\n extraction: { nodesAdded: 0, edgesAdded: 0 },\n gitignore: 'unchanged',\n apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: false },\n daemon: 'skipped',\n browser: 'skipped',\n },\n }\n\n // ── Path validation ───────────────────────────────────────────────────\n const stat = await fs.stat(opts.scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat: ${opts.scanPath} is not a directory`)\n result.exitCode = 2\n return result\n }\n\n console.log(`neat: ${opts.scanPath}`)\n console.log('')\n\n // ── Step 1: discovery, Step 2: extraction + snapshot ─────────────────\n // Shared with `neat sync` (ADR-074 §1) via extractAndPersist.\n const persisted = await extractAndPersist({\n scanPath: opts.scanPath,\n project: opts.project,\n projectExplicit: opts.projectExplicit,\n })\n const { graph, services, languages } = persisted\n result.steps.discovery = { services: services.length, languages }\n console.log(`discovered ${services.length} service(s) across ${languages.length} language(s)`)\n\n // ── Confirmation prompt (default yes; --no-instrument or no-TTY skip)\n let runApply = !opts.noInstrument\n if (runApply && !opts.yes && process.stdout.isTTY && process.stdin.isTTY) {\n runApply = await promptYesNo('instrument your services and open the dashboard?')\n }\n\n result.steps.extraction = {\n nodesAdded: persisted.nodesAdded,\n edgesAdded: persisted.edgesAdded,\n }\n\n const gi = await ensureNeatOutIgnored(opts.scanPath)\n result.steps.gitignore = gi.action\n if (gi.action !== 'unchanged') {\n console.log(`${gi.action} .gitignore (neat-out/)`)\n }\n\n let currentProjectName = opts.project\n try {\n const entry = await addProject({\n name: opts.project,\n path: opts.scanPath,\n languages,\n status: 'active',\n })\n currentProjectName = entry.name\n } catch (err) {\n if (!(err instanceof ProjectNameCollisionError)) throw err\n // Same path, same name → re-init. Different path → bail with a clear\n // message so the operator can pass --project <other-name>.\n console.error(`neat: ${err.message}`)\n console.error('pass --project <other-name> to register under a different name.')\n result.exitCode = 1\n return result\n }\n\n // Narrow the active-project surface to what the operator is currently in.\n // Every other `active` entry transitions to `paused`; `broken` is left alone\n // so the daemon's broken-path handling still surfaces. `neat resume <name>`\n // brings any of them back when cross-project work is the explicit intent.\n const siblings = await listProjects()\n const paused: string[] = []\n for (const p of siblings) {\n if (p.name !== currentProjectName && p.status === 'active') {\n await setStatus(p.name, 'paused')\n paused.push(p.name)\n }\n }\n if (paused.length > 0) {\n const plural = paused.length === 1 ? '' : 's'\n console.log(\n `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n )\n }\n\n // ── Step 3: SDK install apply (default yes; --no-instrument skips) ───\n if (!runApply) {\n result.steps.apply.skipped = true\n console.log('skipped instrumentation (--no-instrument)')\n } else {\n const tally = await applyInstallersOver(services, opts.project)\n result.steps.apply = { ...tally, skipped: false }\n console.log(\n `instrumented ${tally.instrumented}, already ${tally.alreadyInstrumented}, lib-only ${tally.libOnly}`,\n )\n const failedInstalls = tally.packageManagerInstalls.filter((i) => i.exitCode !== 0)\n if (failedInstalls.length > 0) {\n result.exitCode = 1\n }\n }\n\n // ── Step 4: daemon spawn + health poll ───────────────────────────────\n const restPort = Number(process.env.PORT ?? 8080)\n const timeoutMs = opts.daemonReadyTimeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS\n if (await checkDaemonHealth(restPort)) {\n result.steps.daemon = 'already-running'\n } else {\n const probe = await probePortsFree()\n if (!probe.free) {\n for (const line of formatPortCollisionMessage(probe.held)) {\n console.error(line)\n }\n result.exitCode = 3\n return result\n }\n try {\n spawnDaemonDetached()\n } catch (err) {\n console.error(`neat: daemon spawn failed — ${(err as Error).message}`)\n result.exitCode = 1\n return result\n }\n const ready = await waitForDaemonReady(restPort, timeoutMs)\n result.steps.daemon = ready.ready ? 'spawned' : 'timed-out'\n if (!ready.ready) {\n console.error(`neat: daemon did not become ready within ${timeoutMs}ms`)\n if (ready.stillBootstrapping.length > 0) {\n console.error(\n `neat: still bootstrapping: ${ready.stillBootstrapping.join(', ')}`,\n )\n }\n if (ready.brokenProjects.length > 0) {\n console.error(`neat: broken projects: ${ready.brokenProjects.join(', ')}`)\n }\n result.exitCode = 1\n return result\n }\n if (ready.brokenProjects.length > 0) {\n console.warn(\n `neat: ${ready.brokenProjects.length} project(s) reported broken: ${ready.brokenProjects.join(', ')}`,\n )\n }\n }\n\n // ── Step 5: browser open ─────────────────────────────────────────────\n const dashboardUrl = opts.dashboardUrl ?? 'http://localhost:6328'\n if (opts.noOpen || !process.stdout.isTTY) {\n result.steps.browser = 'skipped'\n } else {\n result.steps.browser = openBrowser(dashboardUrl)\n }\n\n // ── Step 6: summary (stub — PR 4 replaces with the value-forward shape)\n printSummary(result, graph, dashboardUrl)\n\n return result\n}\n\nfunction printSummary(\n result: OrchestratorResult,\n graph: ReturnType<typeof getGraph>,\n dashboardUrl: string,\n): void {\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => nodes.push(attrs))\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n const byNode = new Map<string, number>()\n for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n const byEdge = new Map<string, number>()\n for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n\n console.log('')\n console.log('=== summary ===')\n console.log(`graph: ${graph.order} nodes, ${graph.size} edges`)\n for (const [t, c] of [...byNode.entries()].sort()) console.log(` ${t}: ${c}`)\n for (const [t, c] of [...byEdge.entries()].sort()) console.log(` ${t}: ${c}`)\n console.log('')\n console.log(`dashboard: ${dashboardUrl}`)\n}\n","/**\n * Package-manager detection + install invocation.\n *\n * Issue #381 — the apply phase adds dependencies to package.json but\n * relies on the operator to run `npm install` afterwards. The v0.4.5\n * smoke surfaced this as a hard regression on Brief: the installer\n * adds `@opentelemetry/sdk-node` (and `@prisma/instrumentation` when\n * Prisma is in deps) and the next `npm run dev` fails with\n * `Cannot find module '@opentelemetry/sdk-node'` before the OTel SDK\n * even gets a chance to load.\n *\n * ADR-046's \"lockfiles never touched\" rule is about NEAT not directly\n * editing lockfile contents; letting the user's own package manager\n * update them as a side effect of `<pm> install` is consistent with\n * that contract. The clarification is documented in\n * docs/contracts/sdk-install.md.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\n\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm'\n\nexport interface PackageManagerCommand {\n pm: PackageManager\n // The directory the install command runs in. Monorepo workspaces install\n // from the lockfile root, not the per-package directory, so detection\n // walks up from `serviceDir` and reports the lockfile-owning parent.\n cwd: string\n // The argv passed to spawn(). Each entry is one positional token. Selected\n // to keep install output quiet on the happy path; failures still print\n // because stderr is streamed verbatim.\n args: string[]\n}\n\n// Lockfile basename → package manager + the install args we run for it.\n// Priority order — first match wins when multiple lockfiles coexist (rare,\n// but `package-lock.json` alongside `pnpm-lock.yaml` happens during a\n// migration). Bun leads because a project that opted into Bun deliberately\n// rejects npm; pnpm and yarn follow for similar reasons; npm is the default\n// when nothing else applies.\nconst LOCKFILE_PRIORITY: ReadonlyArray<{\n lockfile: string\n pm: PackageManager\n args: string[]\n}> = [\n { lockfile: 'bun.lockb', pm: 'bun', args: ['install', '--no-summary'] },\n { lockfile: 'pnpm-lock.yaml', pm: 'pnpm', args: ['install', '--no-summary'] },\n { lockfile: 'yarn.lock', pm: 'yarn', args: ['install', '--silent'] },\n {\n lockfile: 'package-lock.json',\n pm: 'npm',\n args: ['install', '--no-audit', '--no-fund', '--prefer-offline'],\n },\n]\n\n// Default when no lockfile is present anywhere in the ancestor chain — a\n// fresh project the operator hasn't installed yet. npm is the safe pick:\n// it's available on every Node install and produces a `package-lock.json`\n// the user can later swap out for pnpm/yarn/bun without losing fidelity.\nconst NPM_FALLBACK_ARGS = ['install', '--no-audit', '--no-fund', '--prefer-offline']\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// Resolve the package-manager command for a service directory. Walks up from\n// `serviceDir` looking for a lockfile — the first ancestor that has one\n// owns the install. Monorepos (npm/pnpm/yarn workspaces, Bun workspaces)\n// land their lockfile at the workspace root, so this returns the root cwd\n// even when `serviceDir` is a per-package subdir.\n//\n// No lockfile anywhere → npm at the service dir. A fresh `create-next-app`\n// run sits in this bucket (no install yet, no lockfile to read).\nexport async function detectPackageManager(\n serviceDir: string,\n): Promise<PackageManagerCommand> {\n let dir = path.resolve(serviceDir)\n const stops = new Set<string>()\n for (let i = 0; i < 64; i++) {\n if (stops.has(dir)) break\n stops.add(dir)\n for (const candidate of LOCKFILE_PRIORITY) {\n const lockPath = path.join(dir, candidate.lockfile)\n if (await exists(lockPath)) {\n return { pm: candidate.pm, cwd: dir, args: [...candidate.args] }\n }\n }\n const parent = path.dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n return { pm: 'npm', cwd: path.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] }\n}\n\nexport interface PackageManagerInvocation {\n pm: PackageManager\n cwd: string\n args: string[]\n // 0 → success; non-zero → install failed. Reported in the orchestrator\n // summary so the operator can act before the daemon goes hunting for\n // spans that never arrive.\n exitCode: number\n // Stderr captured from the child process, trimmed. Empty on success.\n // Surfaces the underlying failure cause without dumping the entire\n // install log into the summary.\n stderr: string\n}\n\n// Run the install command and resolve with the outcome. Stdout is dropped\n// (`<pm> install --silent`-style flags already keep it short); stderr is\n// captured so a failure can be relayed up to the orchestrator's summary.\nexport async function runPackageManagerInstall(\n cmd: PackageManagerCommand,\n): Promise<PackageManagerInvocation> {\n return new Promise((resolve) => {\n const child = spawn(cmd.pm, cmd.args, {\n cwd: cmd.cwd,\n // Inherit PATH + HOME so the user's installed managers resolve.\n env: process.env,\n // `false` keeps the parent in control of cleanup if the orchestrator\n // exits before install finishes. Cross-platform-safe.\n shell: false,\n stdio: ['ignore', 'ignore', 'pipe'],\n })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n child.on('error', (err) => {\n resolve({\n pm: cmd.pm,\n cwd: cmd.cwd,\n args: cmd.args,\n exitCode: 127,\n stderr: stderr + `\\n${err.message}`,\n })\n })\n child.on('close', (code) => {\n resolve({\n pm: cmd.pm,\n cwd: cmd.cwd,\n args: cmd.args,\n exitCode: code ?? 1,\n stderr: stderr.trim(),\n })\n })\n })\n}\n","/**\n * Lifecycle-verb implementations for the CLI. Query verbs live in\n * `cli-client.ts` next to the REST client; lifecycle verbs (currently\n * `neat sync`) live here because they orchestrate filesystem work and\n * daemon-state probes rather than wrapping a single REST endpoint.\n */\n\nimport path from 'node:path'\nimport type { RegistryEntry } from '@neat.is/types'\nimport {\n applyInstallersOver,\n extractAndPersist,\n type ExtractAndPersistResult,\n} from './orchestrator.js'\nimport { listProjects, normalizeProjectPath } from './registry.js'\nimport { saveGraphToDisk, type PersistedGraph } from './persist.js'\nimport {\n HttpError,\n pushSnapshotToRemote,\n resolveAuthToken,\n TransportError,\n} from './cli-client.js'\n\nexport interface SyncOptions {\n // Project name from `--project <name>`. When absent, sync resolves the\n // project by matching the cwd against the registered project paths.\n project?: string\n // Push the snapshot to a remote daemon URL. When absent, sync runs against\n // the local daemon on http://localhost:8080.\n to?: string\n // Bearer token for the remote daemon. Falls back to NEAT_REMOTE_TOKEN env.\n token?: string\n // Skip writing the snapshot or notifying the daemon. Mirrors `neat <path>\n // --dry-run`.\n dryRun: boolean\n // Skip the SDK install apply step.\n noInstrument: boolean\n // Emit a structured JSON payload on stdout instead of human text.\n json: boolean\n // Override the local daemon URL. Defaults to NEAT_API_URL or\n // http://localhost:8080. Useful for tests.\n daemonUrl?: string\n // Working directory the verb resolves against when `--project` isn't\n // passed. Defaults to process.cwd(); tests override.\n cwd?: string\n}\n\nexport interface SyncResult {\n exitCode: number\n // Stable shape across human / json output paths. cli.ts decides which\n // formatter to invoke based on `--json`.\n project: string\n scanPath: string\n nodesAdded: number\n edgesAdded: number\n snapshotPath: string | null\n // Tracks which branch the run took for `--json` consumers.\n mode: 'dry-run' | 'local' | 'remote'\n daemon: 'reloaded' | 'down' | 'remote-ok' | 'skipped'\n apply: {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n skipped: boolean\n }\n // Soft warning lines surfaced to stderr in the human path. Empty when the\n // run was fully clean.\n warnings: string[]\n}\n\nasync function resolveProjectEntry(opts: SyncOptions): Promise<RegistryEntry | null> {\n const entries = await listProjects()\n if (opts.project) {\n const match = entries.find((e) => e.name === opts.project)\n return match ?? null\n }\n const cwd = opts.cwd ?? process.cwd()\n const resolvedCwd = await normalizeProjectPath(cwd)\n // Match by path: the cwd must be inside (or equal to) the registered path.\n for (const entry of entries) {\n if (\n resolvedCwd === entry.path ||\n resolvedCwd.startsWith(`${entry.path}${path.sep}`)\n ) {\n return entry\n }\n }\n return null\n}\n\nasync function checkDaemonHealth(baseUrl: string): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl.replace(/\\/$/, '')}/health`, {\n signal: AbortSignal.timeout(1500),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nfunction snapshotForGraph(persisted: ExtractAndPersistResult): PersistedGraph {\n return {\n schemaVersion: 3,\n exportedAt: new Date().toISOString(),\n graph: persisted.graph.export(),\n }\n}\n\nfunction emitResult(result: SyncResult, json: boolean): void {\n if (json) {\n process.stdout.write(JSON.stringify(result, null, 2) + '\\n')\n return\n }\n const verb =\n result.mode === 'dry-run'\n ? 'dry-run'\n : result.mode === 'remote'\n ? 'pushed'\n : 'synced'\n console.log(\n `${verb}: ${result.project} — ${result.nodesAdded} node(s) and ${result.edgesAdded} edge(s) added` +\n (result.snapshotPath ? `; snapshot at ${result.snapshotPath}` : ''),\n )\n if (!result.apply.skipped) {\n const { instrumented, alreadyInstrumented, libOnly } = result.apply\n console.log(\n `instrumented ${instrumented}, already ${alreadyInstrumented}, lib-only ${libOnly}`,\n )\n } else {\n console.log('skipped instrumentation (--no-instrument)')\n }\n for (const warn of result.warnings) console.error(warn)\n}\n\nexport async function runSync(opts: SyncOptions): Promise<SyncResult> {\n const entry = await resolveProjectEntry(opts)\n if (!entry) {\n const target = opts.project ?? opts.cwd ?? process.cwd()\n console.error(\n `neat sync: no registered project ${\n opts.project ? `named \"${opts.project}\"` : `covers ${target}`\n }. Run \\`neat <path>\\` or \\`neat init <path>\\` first.`,\n )\n return {\n exitCode: 1,\n project: opts.project ?? '',\n scanPath: target,\n nodesAdded: 0,\n edgesAdded: 0,\n snapshotPath: null,\n mode: opts.to ? 'remote' : 'local',\n daemon: 'skipped',\n apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: true },\n warnings: [],\n }\n }\n\n // ── Step 1 + 2: discovery + extraction (no snapshot in dry-run) ─────\n const persisted = await extractAndPersist({\n scanPath: entry.path,\n project: entry.name,\n projectExplicit: true,\n dryRun: true,\n })\n\n let snapshotPath: string | null = null\n if (!opts.dryRun) {\n const target = persisted.snapshotPath\n await saveGraphToDisk(persisted.graph, target)\n snapshotPath = target\n }\n\n // ── Step 3: SDK install apply (default yes; --dry-run + --no-instrument skip)\n const skipApply = opts.dryRun || opts.noInstrument\n const applyTally = skipApply\n ? { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, browserBundle: 0, reactNative: 0 }\n : await applyInstallersOver(persisted.services, entry.name)\n\n // ── Step 4: daemon notify ────────────────────────────────────────────\n const warnings: string[] = []\n let daemonState: SyncResult['daemon'] = 'skipped'\n let exitCode = 0\n const mode: SyncResult['mode'] = opts.dryRun ? 'dry-run' : opts.to ? 'remote' : 'local'\n\n if (!opts.dryRun) {\n const snapshot = snapshotForGraph(persisted)\n if (opts.to) {\n const token = opts.token ?? process.env.NEAT_REMOTE_TOKEN\n try {\n await pushSnapshotToRemote({\n baseUrl: opts.to,\n token,\n project: entry.name,\n snapshot,\n })\n daemonState = 'remote-ok'\n } catch (err) {\n if (err instanceof HttpError) {\n console.error(`neat sync: ${err.message}`)\n exitCode = 1\n } else if (err instanceof TransportError) {\n console.error(`neat sync: ${err.message}`)\n exitCode = 3\n } else {\n console.error(`neat sync: ${(err as Error).message}`)\n exitCode = 1\n }\n daemonState = 'skipped'\n }\n } else {\n const daemonUrl =\n opts.daemonUrl ?? process.env.NEAT_API_URL ?? 'http://localhost:8080'\n const healthy = await checkDaemonHealth(daemonUrl)\n if (healthy) {\n try {\n await pushSnapshotToRemote({\n baseUrl: daemonUrl,\n token: resolveAuthToken(),\n project: entry.name,\n snapshot,\n })\n daemonState = 'reloaded'\n } catch (err) {\n warnings.push(\n `neat sync: daemon merge failed — ${(err as Error).message}. Snapshot is on disk at ${snapshotPath}.`,\n )\n daemonState = 'down'\n exitCode = 2\n }\n } else {\n warnings.push(\n 'neat sync: daemon not running; snapshot updated, run `neatd start` to serve it',\n )\n daemonState = 'down'\n exitCode = 2\n }\n }\n }\n\n const result: SyncResult = {\n exitCode,\n project: entry.name,\n scanPath: entry.path,\n nodesAdded: persisted.nodesAdded,\n edgesAdded: persisted.edgesAdded,\n snapshotPath,\n mode,\n daemon: daemonState,\n apply: { ...applyTally, skipped: skipApply },\n warnings,\n }\n\n emitResult(result, opts.json)\n return result\n}\n","// REST helper + CLI verb implementations for `neat <verb>` (ADR-050).\n//\n// The HttpClient and its createHttpClient factory are the \"shared REST helper\n// module\" the contract calls for — one endpoint surface, two consumers\n// (`packages/mcp/src/client.ts` re-exports from here, the CLI dispatcher\n// imports it directly).\n//\n// Verb handlers live alongside the client because they're tightly coupled:\n// each verb maps 1:1 to an MCP tool from ADR-039, but produces the structured\n// `{ summary, block, confidence, provenance }` shape (ADR-050 #3) in pure\n// data form. cli.ts formats that shape into either human-readable text or\n// `--json` output.\n\nimport type {\n BlastRadiusAffectedNode,\n BlastRadiusResult,\n Divergence,\n DivergenceResult,\n DivergenceType,\n ErrorEvent,\n GraphEdge,\n GraphNode,\n HypotheticalAction,\n PolicyViolation,\n RootCauseResult,\n TransitiveDependenciesResult,\n} from '@neat.is/types'\nimport { Provenance } from '@neat.is/types'\n\n// ──────────────────────────────────────────────────────────────────────────\n// REST client\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface HttpClient {\n get<T>(path: string): Promise<T>\n post?<T>(path: string, body: unknown): Promise<T>\n}\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly responseBody: string = '',\n ) {\n super(message)\n this.name = 'HttpError'\n }\n}\n\n// Network-level failures (ECONNREFUSED, ETIMEDOUT, DNS) — distinct from\n// HttpError so the CLI can map them to exit code 3 (daemon-down) without\n// parsing error strings.\nexport class TransportError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'TransportError'\n }\n}\n\n// Single-source the bearer for every first-party read (ADR-073 §3). The CLI\n// query verbs, `neat sync`, the MCP server, and the snapshot push all read the\n// token from here so a new read site can't quietly skip auth. Returns\n// undefined when the env var is unset or empty — a loopback dev daemon stays\n// reachable without a token.\nexport function resolveAuthToken(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const t = env.NEAT_AUTH_TOKEN\n return t && t.length > 0 ? t : undefined\n}\n\nexport function createHttpClient(baseUrl: string, bearerToken?: string): HttpClient {\n const root = baseUrl.replace(/\\/$/, '')\n const authHeader = bearerToken && bearerToken.length > 0\n ? { authorization: `Bearer ${bearerToken}` }\n : {}\n return {\n async get<T>(path: string): Promise<T> {\n let res: Response\n try {\n res = await fetch(`${root}${path}`, {\n headers: { ...authHeader },\n })\n } catch (err) {\n throw new TransportError(\n `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n )\n }\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new HttpError(\n res.status,\n `${res.status} ${res.statusText} on GET ${path}: ${body}`,\n body,\n )\n }\n return (await res.json()) as T\n },\n async post<T>(path: string, body: unknown): Promise<T> {\n let res: Response\n try {\n res = await fetch(`${root}${path}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...authHeader },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new TransportError(\n `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n )\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new HttpError(\n res.status,\n `${res.status} ${res.statusText} on POST ${path}: ${text}`,\n text,\n )\n }\n return (await res.json()) as T\n },\n }\n}\n\n// Project routing per ADR-050 #2: `--project <name>` (handled in cli.ts) →\n// `NEAT_PROJECT` env → `default`. The default routes hit the legacy\n// unprefixed URLs which the core resolves to project=`default`.\nfunction projectPath(project: string | undefined, suffix: string): string {\n if (!project) return suffix\n return `/projects/${encodeURIComponent(project)}${suffix}`\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verb result shape (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface VerbResult {\n // NL paragraph. What was found and why it matters.\n summary: string\n // Structured payload — usually a bulleted list. Empty when the summary\n // already conveys everything.\n block?: string\n // Per-result confidence in [0, 1]. Undefined → footer reads \"n/a\".\n confidence?: number\n // Per-result provenance. String, array (mixed paths), or undefined.\n provenance?: string | string[]\n}\n\n// Common shape the nine verbs produce. cli.ts renders this to text or JSON.\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verbs\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface RootCauseInput {\n errorNode: string\n errorId?: string\n project?: string\n}\n\nexport async function runRootCause(\n client: HttpClient,\n input: RootCauseInput,\n): Promise<VerbResult> {\n const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : ''\n const path = projectPath(\n input.project,\n `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`,\n )\n try {\n const result = await client.get<RootCauseResult>(path)\n const arrowPath = result.traversalPath.join(' ← ')\n const provenances = result.edgeProvenances.length\n ? result.edgeProvenances.join(', ')\n : '(direct, no edges traversed)'\n const summary =\n `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` +\n result.rootCauseReason +\n (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : '')\n const blockLines = [\n `Traversal path: ${arrowPath}`,\n `Edge provenances: ${provenances}`,\n ]\n if (result.fixRecommendation) blockLines.push(`Recommended fix: ${result.fixRecommendation}`)\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: result.confidence,\n provenance: result.edgeProvenances.length ? result.edgeProvenances : undefined,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return {\n summary: `No root cause found for ${input.errorNode}. The node may be healthy, or it may not exist in the graph.`,\n }\n }\n throw err\n }\n}\n\nexport interface BlastRadiusInput {\n nodeId: string\n depth?: number\n project?: string\n}\n\nexport async function runBlastRadius(\n client: HttpClient,\n input: BlastRadiusInput,\n): Promise<VerbResult> {\n const qs = input.depth !== undefined ? `?depth=${input.depth}` : ''\n const path = projectPath(\n input.project,\n `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`,\n )\n try {\n const result = await client.get<BlastRadiusResult>(path)\n if (result.totalAffected === 0) {\n return {\n summary: `${result.origin} has no downstream dependencies. Nothing else would break if it failed.`,\n }\n }\n const sorted = [...result.affectedNodes].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n const blockLines = sorted.map(formatBlastEntry)\n const minConfidence = sorted.reduce(\n (m, n) => Math.min(m, n.confidence),\n Number.POSITIVE_INFINITY,\n )\n const provenances = [...new Set(sorted.map((n) => n.edgeProvenance))]\n return {\n summary: `Blast radius for ${result.origin}: ${result.totalAffected} affected node${result.totalAffected === 1 ? '' : 's'} reachable downstream.`,\n block: blockLines.join('\\n'),\n confidence: Number.isFinite(minConfidence) ? minConfidence : undefined,\n provenance: provenances.length ? provenances : undefined,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\nfunction formatBlastEntry(n: BlastRadiusAffectedNode): string {\n const tag = n.edgeProvenance === Provenance.STALE ? ' [STALE — last seen too long ago]' : ''\n return ` • ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`\n}\n\nexport interface DependenciesInput {\n nodeId: string\n depth?: number\n project?: string\n}\n\nexport async function runDependencies(\n client: HttpClient,\n input: DependenciesInput,\n): Promise<VerbResult> {\n const depth = input.depth ?? 3\n const path = projectPath(\n input.project,\n `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`,\n )\n try {\n const result = await client.get<TransitiveDependenciesResult>(path)\n if (result.total === 0) {\n return {\n summary:\n depth === 1\n ? `${input.nodeId} has no direct dependencies in the graph.`\n : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`,\n }\n }\n const byDistance = new Map<number, typeof result.dependencies>()\n for (const dep of result.dependencies) {\n const ring = byDistance.get(dep.distance) ?? []\n ring.push(dep)\n byDistance.set(dep.distance, ring)\n }\n const blockLines: string[] = []\n for (const distance of [...byDistance.keys()].sort((a, b) => a - b)) {\n const label = distance === 1 ? 'Direct (distance 1)' : `Distance ${distance}`\n blockLines.push(`${label}:`)\n for (const dep of byDistance.get(distance)!) {\n blockLines.push(` • ${dep.nodeId} — ${dep.edgeType} (${dep.provenance})`)\n }\n }\n const provenances = [...new Set(result.dependencies.map((d) => d.provenance))]\n const directCount = byDistance.get(1)?.length ?? 0\n const summary =\n depth === 1\n ? `${input.nodeId} has ${directCount} direct dependenc${directCount === 1 ? 'y' : 'ies'}.`\n : `${input.nodeId} has ${result.total} dependenc${result.total === 1 ? 'y' : 'ies'} reachable to depth ${depth} (${directCount} direct).`\n return { summary, block: blockLines.join('\\n'), provenance: provenances }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\ninterface EdgesResponse {\n inbound: GraphEdge[]\n outbound: GraphEdge[]\n}\n\nexport async function runObservedDependencies(\n client: HttpClient,\n input: DependenciesInput,\n): Promise<VerbResult> {\n try {\n const edges = await client.get<EdgesResponse>(\n projectPath(input.project, `/graph/edges/${encodeURIComponent(input.nodeId)}`),\n )\n const observed = edges.outbound.filter((e) => e.provenance === Provenance.OBSERVED)\n if (observed.length === 0) {\n const hasExtracted = edges.outbound.some((e) => e.provenance === Provenance.EXTRACTED)\n const note = hasExtracted\n ? ' Static (EXTRACTED) dependencies exist but no runtime traffic has been seen — is OTel running?'\n : ''\n return { summary: `No OBSERVED dependencies for ${input.nodeId}.${note}` }\n }\n const blockLines = observed.map((e) => ` • ${e.target} — ${e.type}${edgeMeta(e)}`)\n return {\n summary: `${input.nodeId} has ${observed.length} runtime dependenc${observed.length === 1 ? 'y' : 'ies'} confirmed by OTel.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.OBSERVED,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\nfunction edgeMeta(e: GraphEdge): string {\n const bits: string[] = []\n if (e.signal) {\n bits.push(`spans=${e.signal.spanCount}`)\n if (e.signal.errorCount > 0) bits.push(`errors=${e.signal.errorCount}`)\n if (e.signal.lastObservedAgeMs !== undefined) {\n bits.push(`age=${formatDuration(e.signal.lastObservedAgeMs)}`)\n }\n } else if (e.callCount !== undefined) {\n bits.push(`callCount=${e.callCount}`)\n }\n if (e.lastObserved) bits.push(`lastObserved=${e.lastObserved}`)\n if (e.confidence !== undefined) bits.push(`confidence=${e.confidence}`)\n return bits.length ? ` [${bits.join(', ')}]` : ''\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`\n const s = Math.round(ms / 1000)\n if (s < 60) return `${s}s`\n const m = Math.round(s / 60)\n if (m < 60) return `${m}m`\n const h = Math.round(m / 60)\n if (h < 48) return `${h}h`\n return `${Math.round(h / 24)}d`\n}\n\nexport interface IncidentsInput {\n nodeId?: string\n limit?: number\n project?: string\n}\n\n// `neat incidents` shape: with a node id, returns that node's incidents.\n// Without one, returns the global recent log.\nexport async function runIncidents(\n client: HttpClient,\n input: IncidentsInput,\n): Promise<VerbResult> {\n const path = input.nodeId\n ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`)\n : projectPath(input.project, '/incidents')\n try {\n const body = await client.get<{ count: number; total: number; events: ErrorEvent[] }>(path)\n const events = body.events\n if (events.length === 0) {\n return {\n summary: input.nodeId\n ? `No incidents recorded against ${input.nodeId}.`\n : 'No incidents recorded.',\n }\n }\n const ordered = [...events].reverse().slice(0, input.limit ?? 20)\n const blockLines: string[] = []\n for (const ev of ordered) {\n blockLines.push(` ${ev.timestamp} — ${ev.service}: ${ev.errorMessage}`)\n blockLines.push(` trace=${ev.traceId} span=${ev.spanId}`)\n }\n const target = input.nodeId ?? 'the project'\n return {\n summary: `${target} has ${body.total} recorded incident${body.total === 1 ? '' : 's'}; showing the ${ordered.length} most recent.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.OBSERVED,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId ?? ''} not found in the graph.` }\n }\n throw err\n }\n}\n\nexport interface SearchInput {\n query: string\n project?: string\n}\n\ninterface SearchResponse {\n query: string\n provider?: 'ollama' | 'transformers' | 'substring'\n matches: (GraphNode & { score?: number })[]\n}\n\nexport async function runSearch(\n client: HttpClient,\n input: SearchInput,\n): Promise<VerbResult> {\n const result = await client.get<SearchResponse>(\n projectPath(input.project, `/search?q=${encodeURIComponent(input.query)}`),\n )\n if (result.matches.length === 0) {\n return { summary: `No matches for \"${input.query}\".` }\n }\n const provider = result.provider ?? 'substring'\n const blockLines: string[] = []\n let topScore: number | undefined\n for (const n of result.matches) {\n const score = provider !== 'substring' && typeof n.score === 'number' ? n.score : undefined\n const scoreBit = score !== undefined ? ` [score=${score.toFixed(2)}]` : ''\n if (score !== undefined && (topScore === undefined || score > topScore)) topScore = score\n blockLines.push(\n ` • ${n.id} (${n.type}) — ${(n as { name?: string }).name ?? n.id}${scoreBit}`,\n )\n }\n return {\n summary: `Found ${result.matches.length} match${result.matches.length === 1 ? '' : 'es'} for \"${input.query}\" via ${provider} provider.`,\n block: blockLines.join('\\n'),\n confidence: topScore,\n }\n}\n\nexport interface DiffInput {\n againstSnapshot: string\n project?: string\n}\n\ninterface GraphDiffResponse {\n base: { exportedAt?: string }\n current: { exportedAt: string }\n added: { nodes: GraphNode[]; edges: GraphEdge[] }\n removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n changed: {\n nodes: { id: string; before: GraphNode; after: GraphNode }[]\n edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n }\n}\n\nexport async function runDiff(client: HttpClient, input: DiffInput): Promise<VerbResult> {\n const result = await client.get<GraphDiffResponse>(\n projectPath(\n input.project,\n `/graph/diff?against=${encodeURIComponent(input.againstSnapshot)}`,\n ),\n )\n const total =\n result.added.nodes.length +\n result.added.edges.length +\n result.removed.nodes.length +\n result.removed.edges.length +\n result.changed.nodes.length +\n result.changed.edges.length\n const baseLabel = result.base.exportedAt ?? 'unknown'\n if (total === 0) {\n return {\n summary: `No differences between the current graph and ${input.againstSnapshot} (base exportedAt=${baseLabel}).`,\n }\n }\n const blockLines: string[] = [\n ` base exportedAt: ${baseLabel}`,\n ` current exportedAt: ${result.current.exportedAt}`,\n '',\n ]\n if (result.added.nodes.length || result.added.edges.length) {\n blockLines.push('Added:')\n for (const n of result.added.nodes) blockLines.push(` + node ${n.id} (${n.type})`)\n for (const e of result.added.edges)\n blockLines.push(` + edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n blockLines.push('')\n }\n if (result.removed.nodes.length || result.removed.edges.length) {\n blockLines.push('Removed:')\n for (const n of result.removed.nodes) blockLines.push(` - node ${n.id} (${n.type})`)\n for (const e of result.removed.edges)\n blockLines.push(` - edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n blockLines.push('')\n }\n if (result.changed.nodes.length || result.changed.edges.length) {\n blockLines.push('Changed:')\n for (const c of result.changed.nodes) {\n blockLines.push(` ~ node ${c.id} — ${summariseAttrDiff(c.before, c.after)}`)\n }\n for (const c of result.changed.edges) {\n const provBit =\n c.before.provenance !== c.after.provenance\n ? `provenance ${c.before.provenance} → ${c.after.provenance}`\n : summariseAttrDiff(c.before, c.after)\n blockLines.push(` ~ edge ${c.id} — ${provBit}`)\n }\n }\n return {\n summary: `Diff against ${input.againstSnapshot}: ${total} change${total === 1 ? '' : 's'} between the snapshot and the live graph.`,\n block: blockLines.join('\\n').trimEnd(),\n }\n}\n\nfunction summariseAttrDiff(\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): string {\n const keys = new Set([...Object.keys(before), ...Object.keys(after)])\n const changed: string[] = []\n for (const k of keys) {\n if (JSON.stringify(before[k]) !== JSON.stringify(after[k])) changed.push(k)\n }\n return changed.length === 0 ? 'attributes differ' : `fields changed: ${changed.sort().join(', ')}`\n}\n\nexport interface StaleEdgesInput {\n limit?: number\n edgeType?: string\n project?: string\n}\n\ninterface StaleEventResponse {\n edgeId: string\n source: string\n target: string\n edgeType: string\n thresholdMs: number\n ageMs: number\n lastObserved: string\n transitionedAt: string\n}\n\nexport async function runStaleEdges(\n client: HttpClient,\n input: StaleEdgesInput,\n): Promise<VerbResult> {\n const params = new URLSearchParams()\n if (input.limit !== undefined) params.set('limit', String(input.limit))\n if (input.edgeType) params.set('edgeType', input.edgeType)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const body = await client.get<{ count: number; total: number; events: StaleEventResponse[] }>(\n projectPath(input.project, `/stale-events${qs}`),\n )\n const events = body.events\n if (events.length === 0) {\n return {\n summary: input.edgeType\n ? `No stale ${input.edgeType} edges recorded.`\n : 'No stale-edge transitions recorded yet.',\n }\n }\n const blockLines = events.map(\n (e) =>\n ` ${e.transitionedAt} — ${e.source} -[${e.edgeType}]-> ${e.target}` +\n ` (last seen ${e.lastObserved}, threshold ${formatDuration(e.thresholdMs)})`,\n )\n return {\n summary: `${events.length} stale-edge transition${events.length === 1 ? '' : 's'} recorded${input.edgeType ? ` for ${input.edgeType}` : ''}.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.STALE,\n }\n}\n\nexport interface PoliciesInput {\n nodeId?: string\n policyId?: string\n hypotheticalAction?: HypotheticalAction\n project?: string\n}\n\ninterface PoliciesCheckResponse {\n allowed: boolean\n hypotheticalAction?: HypotheticalAction\n violations: PolicyViolation[]\n}\n\nexport async function runPolicies(\n client: HttpClient,\n input: PoliciesInput,\n): Promise<VerbResult> {\n let violations: PolicyViolation[]\n let allowed = true\n let hypothetical: HypotheticalAction | undefined\n\n if (input.hypotheticalAction) {\n if (typeof client.post !== 'function') {\n throw new Error('HttpClient does not support POST — required for policies dry-run')\n }\n const body = await client.post<PoliciesCheckResponse>(\n projectPath(input.project, '/policies/check'),\n { hypotheticalAction: input.hypotheticalAction },\n )\n violations = body.violations\n allowed = body.allowed\n hypothetical = body.hypotheticalAction\n } else {\n const params = new URLSearchParams()\n if (input.policyId) params.set('policyId', input.policyId)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const body = await client.get<{ violations: PolicyViolation[] }>(\n projectPath(input.project, `/policies/violations${qs}`),\n )\n violations = body.violations\n allowed = violations.every((v) => v.onViolation !== 'block')\n }\n\n // Optional --node filter is applied here against the returned set; the\n // server-side endpoint doesn't take a node-id query yet.\n if (input.nodeId) {\n violations = violations.filter(\n (v) => v.subject.nodeId === input.nodeId || v.subject.path?.includes(input.nodeId!),\n )\n }\n\n if (violations.length === 0) {\n return {\n summary: hypothetical\n ? `No violations would result from the hypothetical action (${hypothetical.kind}).`\n : 'No policy violations recorded.',\n }\n }\n\n const blockCount = violations.filter((v) => v.onViolation === 'block').length\n const summaryParts: string[] = []\n if (hypothetical) {\n summaryParts.push(\n `Hypothetical ${hypothetical.kind} would surface ${violations.length} violation${violations.length === 1 ? '' : 's'}`,\n )\n } else {\n summaryParts.push(\n `${violations.length} policy violation${violations.length === 1 ? '' : 's'} currently recorded`,\n )\n }\n if (blockCount > 0) summaryParts.push(`${blockCount} of which block`)\n if (!allowed && hypothetical) summaryParts.push('action denied')\n const summary = summaryParts.join('; ') + '.'\n\n const blockLines = violations.map((v) => {\n const subject = v.subject.nodeId ?? v.subject.edgeId ?? v.subject.path?.[0] ?? '(global)'\n return ` • [${v.severity}/${v.onViolation}] ${v.policyName}: ${v.message} — ${subject}`\n })\n const severities = [...new Set(violations.map((v) => v.severity))]\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: hypothetical ? 0.7 : 1,\n provenance: severities.join(' '),\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// divergences (ADR-060) — the tenth verb. Amends ADR-050's nine-verb\n// allowlist; the verb mirrors the get_divergences MCP tool.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface DivergencesInput {\n type?: ReadonlyArray<DivergenceType>\n minConfidence?: number\n node?: string\n project?: string\n}\n\nfunction formatDivergenceLine(d: Divergence): string {\n switch (d.type) {\n case 'missing-observed':\n case 'missing-extracted':\n return ` • [${d.type}] ${d.source} → ${d.target} (${d.edgeType}) — confidence ${d.confidence.toFixed(2)}`\n case 'version-mismatch':\n return ` • [${d.type}] ${d.source} → ${d.target} — declared ${d.extractedVersion}, observed engine ${d.observedVersion} (${d.compatibility})`\n case 'host-mismatch':\n return ` • [${d.type}] ${d.source} → ${d.target} — declared host ${d.extractedHost}, observed host ${d.observedHost}`\n case 'compat-violation':\n return ` • [${d.type}] ${d.source} → ${d.target} — ${d.rule.kind}${d.rule.package ? ` (${d.rule.package})` : ''}`\n }\n}\n\nexport async function runDivergences(\n client: HttpClient,\n input: DivergencesInput,\n): Promise<VerbResult> {\n const params = new URLSearchParams()\n if (input.type && input.type.length > 0) params.set('type', input.type.join(','))\n if (input.minConfidence !== undefined) {\n params.set('minConfidence', String(input.minConfidence))\n }\n if (input.node) params.set('node', input.node)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const result = await client.get<DivergenceResult>(\n projectPath(input.project, `/graph/divergences${qs}`),\n )\n if (result.totalAffected === 0) {\n return {\n summary:\n 'No divergences found between the declared (EXTRACTED) and observed (OBSERVED) views of the graph.',\n }\n }\n const headline = result.divergences[0]!\n const summary =\n `Found ${result.totalAffected} divergence${result.totalAffected === 1 ? '' : 's'} between code and production. ` +\n `Highest-confidence: ${headline.type} on ${headline.source} → ${headline.target}. ${headline.reason}`\n const blockLines: string[] = []\n for (const d of result.divergences) {\n blockLines.push(formatDivergenceLine(d))\n blockLines.push(` reason: ${d.reason}`)\n blockLines.push(` recommendation: ${d.recommendation}`)\n }\n const maxConfidence = result.divergences.reduce(\n (m, d) => Math.max(m, d.confidence),\n 0,\n )\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: maxConfidence,\n provenance: 'composite (EXTRACTED + OBSERVED)',\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Output formatting (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction formatFooter(\n confidence: number | undefined,\n provenance: string | string[] | undefined,\n): string {\n const c = confidence === undefined ? 'n/a' : confidence.toFixed(2)\n const p =\n provenance === undefined\n ? 'n/a'\n : Array.isArray(provenance)\n ? [...new Set(provenance)].join(', ')\n : provenance\n return `confidence: ${c} · provenance: ${p}`\n}\n\n// Default human output (NL summary + table-shaped block + footer). Mirrors\n// the three-part MCP response from ADR-039 in plain text.\nexport function formatHuman(result: VerbResult): string {\n const sections: string[] = [result.summary.trim()]\n if (result.block && result.block.trim().length > 0) sections.push(result.block.trimEnd())\n sections.push(formatFooter(result.confidence, result.provenance))\n return sections.join('\\n\\n')\n}\n\n// `--json` output. Same three sections as named fields per ADR-050 #3.\nexport function formatJson(result: VerbResult): string {\n return JSON.stringify(\n {\n summary: result.summary,\n block: result.block ?? '',\n confidence: result.confidence ?? null,\n provenance: result.provenance ?? null,\n },\n null,\n 2,\n )\n}\n\n// Exit-code mapping for thrown errors (ADR-050 #4):\n// 0 — success (handled at the call site, never via throw)\n// 1 — server error (HttpError)\n// 2 — misuse (handled in cli.ts before any network call)\n// 3 — daemon unreachable (TransportError)\nexport function exitCodeForError(err: unknown): number {\n if (err instanceof TransportError) return 3\n if (err instanceof HttpError) return 1\n return 1\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot push (ADR-074 §1)\n//\n// `neat sync` (local + --to <url>) feeds the freshly extracted snapshot into\n// either the local daemon or a remote one. The endpoint is dual-mounted via\n// registerRoutes — default project lands at /snapshot, named projects at\n// /projects/:project/snapshot. The helper goes through the shared\n// HttpClient so the verb stays on the same network path as every query verb.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface PushSnapshotInput {\n baseUrl: string\n token: string | undefined\n project: string\n snapshot: unknown\n}\n\nexport interface PushSnapshotResult {\n project: string\n nodesAdded: number\n edgesAdded: number\n nodeCount: number\n edgeCount: number\n}\n\nexport function createSnapshotPushClient(\n baseUrl: string,\n token: string | undefined,\n): HttpClient {\n return createHttpClient(baseUrl, token && token.length > 0 ? token : undefined)\n}\n\nexport async function pushSnapshotToRemote(\n input: PushSnapshotInput,\n): Promise<PushSnapshotResult> {\n const client = createSnapshotPushClient(input.baseUrl, input.token)\n if (typeof client.post !== 'function') {\n throw new Error('HttpClient does not support POST — required for snapshot push')\n }\n return client.post<PushSnapshotResult>(\n `/projects/${encodeURIComponent(input.project)}/snapshot`,\n { snapshot: input.snapshot },\n )\n}\n"],"mappings":"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","names":["path","path","import_node_path","import_node_crypto","path","protobuf","reshapeGrpcRequest","Fastify","import_node_path","import_node_url","import_fastify","import_node_path","import_node_fs","import_node_url","GraphDefault","import_node_fs","import_node_path","import_node_fs","import_node_path","import_types","path","os","semver","fs","path","serviceId","frontierId","fs","path","import_types","path","entry","fs","path","frontierId","serviceId","fs","path","import_node_fs","import_node_path","import_minimatch","import_types","import_node_fs","import_node_path","import_types","fs","path","parseYaml","import_node_fs","import_node_path","entry","path","fs","parseToml","import_node_fs","import_node_path","path","fs","import_node_fs","import_node_path","fs","path","fs","path","path","fs","ignore","entry","import_node_path","import_node_fs","import_yaml","import_types","serviceId","path","fs","entry","import_node_path","import_types","import_node_path","path","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","path","parse","fs","entry","path","import_node_path","parse","path","parse","parse","import_node_path","parse","path","entry","parse","import_node_path","parse","path","entry","import_node_path","parse","path","path","import_node_fs","import_node_path","import_types","fs","entry","path","import_types","import_node_path","import_types","import_node_fs","import_node_path","import_types","fs","entry","path","toPosix","Parser","JavaScript","Python","path","toPosix","import_node_path","import_types","path","import_node_path","import_types","path","import_node_path","import_types","findAll","path","import_node_path","import_types","path","toPosix","http","import_node_path","import_types","import_types","path","import_node_path","import_node_fs","import_types","path","fs","import_node_fs","import_node_path","fs","entry","path","import_node_fs","import_node_path","import_yaml","walkYamlFiles","fs","entry","path","import_node_path","import_node_fs","import_node_path","import_types","path","path","import_types","import_node_fs","import_node_path","import_types","fs","path","import_node_fs","import_node_path","path","fs","import_types","import_node_fs","import_node_path","import_types","import_node_fs","fs","entry","import_node_path","path","import_node_fs","import_node_os","import_node_path","import_types","path","os","fs","entry","status","violations","blocking","Fastify","cors","entry","import_node_fs","import_node_path","import_node_crypto","fs","path","entry","idx","path","fs","chokidar","import_node_fs","import_node_path","import_node_crypto","renderOtelEnvBlock","path","fs","import_node_fs","import_node_path","path","fs","exists","import_node_fs","import_node_path","SDK_PACKAGES","OTEL_ENV","exists","fs","detect","path","plan","apply","rollback","plan","plan","import_node_fs","import_node_path","import_node_child_process","import_node_fs","import_node_path","import_node_child_process","exists","fs","path","path","plan","readline","http","entry","projects","net","fs","import_node_path","import_types","status","path","entry","path","checkDaemonHealth","import_types","path","plan","fs","entry","snippet","apply","renderOtelEnvBlock"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/tsup/assets/cjs_shims.js","../src/auth.ts","../src/otel-grpc.ts","../src/otel.ts","../src/cli.ts","../src/graph.ts","../src/extract.ts","../src/extract/index.ts","../src/ingest.ts","../src/policy.ts","../src/compat.ts","../compat.json","../src/events.ts","../src/traverse.ts","../src/extract/services.ts","../src/extract/shared.ts","../src/extract/python.ts","../src/extract/owners.ts","../src/extract/errors.ts","../src/extract/aliases.ts","../src/extract/files.ts","../src/extract/calls/shared.ts","../src/extract/imports.ts","../src/extract/databases/index.ts","../src/extract/databases/db-config-yaml.ts","../src/extract/databases/dotenv.ts","../src/extract/databases/shared.ts","../src/extract/databases/prisma.ts","../src/extract/databases/drizzle.ts","../src/extract/databases/knex.ts","../src/extract/databases/ormconfig.ts","../src/extract/databases/typeorm.ts","../src/extract/databases/sequelize.ts","../src/extract/databases/docker-compose.ts","../src/extract/configs.ts","../src/extract/calls/index.ts","../src/extract/calls/http.ts","../src/extract/calls/kafka.ts","../src/extract/calls/redis.ts","../src/extract/calls/aws.ts","../src/extract/calls/grpc.ts","../src/extract/infra/index.ts","../src/extract/infra/docker-compose.ts","../src/extract/infra/shared.ts","../src/extract/infra/dockerfile.ts","../src/extract/infra/terraform.ts","../src/extract/infra/k8s.ts","../src/extract/retire.ts","../src/divergences.ts","../src/persist.ts","../src/gitignore.ts","../src/summary.ts","../src/watch.ts","../src/api.ts","../src/extend/index.ts","../src/installers/package-manager.ts","../src/diff.ts","../src/projects.ts","../src/registry.ts","../src/streaming.ts","../src/search.ts","../src/deploy/detect.ts","../src/installers/index.ts","../src/installers/javascript.ts","../src/installers/templates.ts","../src/installers/python.ts","../src/installers/shared.ts","../src/orchestrator.ts","../src/cli-verbs.ts","../src/cli-client.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\n * Delegated auth at the daemon boundary (ADR-073 §3 + §4).\n *\n * NEAT does not issue, rotate, or distribute the token — that is the deploy\n * platform's job. This module provides the two surfaces the daemon needs:\n *\n * - `assertBindAuthority(host, token)` — fail-loud pre-bind check. When no\n * token is set, the daemon refuses to bind on any non-loopback address.\n * Loopback-only without a token stays unauthenticated (laptop dev path).\n *\n * - `mountBearerAuth(app, opts)` — Fastify `preHandler` that requires\n * `Authorization: Bearer <token>` on every request other than the\n * unauthenticated health/readiness probes. Constant-time comparison.\n *\n * The same shape covers both the REST host and the OTLP receivers; the OTLP\n * side passes a different token (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) so the\n * two surfaces rotate independently.\n */\n\nimport { timingSafeEqual } from 'node:crypto'\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\n\n// Hosts that count as loopback for the bind-authority gate. `0.0.0.0` is\n// explicitly not loopback — it binds on every interface, including any\n// public one the operator's box happens to have.\nconst LOOPBACK_HOSTS: ReadonlySet<string> = new Set([\n '127.0.0.1',\n 'localhost',\n '::1',\n '::ffff:127.0.0.1',\n])\n\nexport function isLoopbackHost(host: string | undefined | null): boolean {\n if (!host) return false\n return LOOPBACK_HOSTS.has(host)\n}\n\nexport class BindAuthorityError extends Error {\n constructor(host: string) {\n super(\n `NEAT refuses to bind on a public interface without \\`NEAT_AUTH_TOKEN\\` set (host=\"${host}\"). Set the token or bind to loopback only.`,\n )\n this.name = 'BindAuthorityError'\n }\n}\n\nexport function assertBindAuthority(host: string, token: string | undefined): void {\n if (token && token.length > 0) return\n if (isLoopbackHost(host)) return\n throw new BindAuthorityError(host)\n}\n\nexport interface AuthOptions {\n // Bearer token required on every protected route. Undefined / empty → the\n // middleware is not mounted and the route stays unauthenticated. The\n // loopback-only gate above is what keeps that case from being public.\n token?: string\n // When `true`, trust an upstream reverse proxy and skip the request-side\n // check. The fail-loud bind-authority gate still applies upstream. Wired\n // to `NEAT_AUTH_PROXY=true` in production.\n trustProxy?: boolean\n // ADR-073 §3 amendment — public-read mode for reference deployments.\n // When `true`, GET / HEAD / OPTIONS pass through without a bearer; every\n // other verb still requires the token. OTLP ingest is excluded — that\n // surface stays gated unconditionally (the receiver mounts its own\n // middleware without this flag).\n publicRead?: boolean\n // Extra paths (or path suffixes) to leave unauthenticated. Used by tests\n // and by ad-hoc callers that mount their own probes.\n extraUnauthenticatedSuffixes?: ReadonlyArray<string>\n}\n\n// Verbs the public-read split treats as reads. Everything else is a write\n// and keeps the bearer requirement.\nconst PUBLIC_READ_METHODS: ReadonlySet<string> = new Set(['GET', 'HEAD', 'OPTIONS'])\n\n// Probes that always stay open. Dual-mounted under `/projects/:project/` too,\n// so the check is a suffix match — `/projects/foo/health` is skipped along\n// with the top-level `/health`. ADR-073 §3 names `/healthz` and `/readyz`\n// explicitly; `/health` is the existing endpoint the web shell and CI smoke\n// already lean on, so it keeps the unauthenticated treatment. `/api/config`\n// is the public-read negotiation endpoint — the web shell hits it before any\n// authed call to learn which mode the daemon is running in.\nconst DEFAULT_UNAUTH_SUFFIXES: ReadonlyArray<string> = [\n '/health',\n '/healthz',\n '/readyz',\n '/api/config',\n]\n\nexport function mountBearerAuth(app: FastifyInstance, opts: AuthOptions): void {\n if (!opts.token || opts.token.length === 0) return\n if (opts.trustProxy) return\n\n const expected = Buffer.from(opts.token, 'utf8')\n const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...(opts.extraUnauthenticatedSuffixes ?? [])]\n const publicRead = opts.publicRead === true\n\n app.addHook('preHandler', (req: FastifyRequest, reply: FastifyReply, done: (err?: Error) => void) => {\n const path = (req.url.split('?')[0] ?? '').replace(/\\/+$/, '')\n for (const suffix of suffixes) {\n if (path === suffix || path.endsWith(suffix)) {\n done()\n return\n }\n }\n\n // Public-read split: GET / HEAD / OPTIONS pass through anonymously, every\n // other verb keeps the bearer check. The token still authorizes writes,\n // and the bind-authority gate above still demands a token for non-loopback\n // binds — public-read enables anonymous reads on top of that, it doesn't\n // replace either invariant.\n if (publicRead && PUBLIC_READ_METHODS.has(req.method)) {\n done()\n return\n }\n\n const header = req.headers.authorization\n if (typeof header !== 'string' || !header.startsWith('Bearer ')) {\n void reply.code(401).send({ error: 'unauthorized' })\n return\n }\n const provided = Buffer.from(header.slice('Bearer '.length).trim(), 'utf8')\n if (provided.length !== expected.length || !timingSafeEqual(provided, expected)) {\n void reply.code(401).send({ error: 'unauthorized' })\n return\n }\n done()\n })\n}\n\n// Read both tokens from the environment in one place so server.ts, daemon.ts,\n// and the OTel receivers all agree on precedence (ADR-073 §4). `publicRead`\n// rides the same shape so callers don't need a second env read.\nexport interface AuthEnv {\n authToken: string | undefined\n otelToken: string | undefined\n trustProxy: boolean\n publicRead: boolean\n}\n\nfunction parseBoolEnv(v: string | undefined): boolean {\n if (!v) return false\n return v === 'true' || v === '1'\n}\n\nexport function readAuthEnv(env: NodeJS.ProcessEnv = process.env): AuthEnv {\n const t = env.NEAT_AUTH_TOKEN\n const ot = env.NEAT_OTEL_TOKEN\n return {\n authToken: t && t.length > 0 ? t : undefined,\n otelToken: ot && ot.length > 0 ? ot : t && t.length > 0 ? t : undefined,\n trustProxy: env.NEAT_AUTH_PROXY === 'true',\n publicRead: parseBoolEnv(env.NEAT_PUBLIC_READ),\n }\n}\n","import { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport { timingSafeEqual } from 'node:crypto'\nimport * as grpc from '@grpc/grpc-js'\nimport * as protoLoader from '@grpc/proto-loader'\nimport {\n parseOtlpRequest,\n type OtlpTracesRequest,\n type ParsedSpan,\n type SpanHandler,\n} from './otel.js'\n\n// OTLP/gRPC receiver. Sits next to buildOtelReceiver (HTTP/JSON) in otel.ts;\n// shares the same parseOtlpRequest decoder so a span looks identical to the\n// downstream onSpan handler whether it came in over JSON or protobuf.\n//\n// Default OFF — opts.enabled (typically NEAT_OTLP_GRPC=true) decides whether\n// server.ts wires this up. We keep gRPC behind a flag so existing HTTP-only\n// deployments don't get a surprise port binding on upgrade.\n\nexport interface BuildOtelGrpcReceiverOptions {\n onSpan: SpanHandler\n // ADR-073 §4 — bearer required in the gRPC call's `authorization` metadata\n // when set. Same precedence as the HTTP receiver: NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN.\n authToken?: string\n // Skip the request-side check when an upstream proxy already authenticated.\n trustProxy?: boolean\n}\n\n// proto-loader output for the trace service has fields like resource_spans,\n// scope_spans, span_id, etc. (snake_case keys, since we leave keepCase: true\n// when loading). The HTTP path uses camelCase JSON, so we shape-shift the\n// gRPC payload onto the HTTP shape and let parseOtlpRequest do the rest.\n//\n// All `bytes` fields arrive as Buffers; the HTTP wire format encodes them as\n// hex strings, so we hex-encode for consistency.\n\ninterface GrpcAnyValue {\n string_value?: string\n bool_value?: boolean\n int_value?: string | number\n double_value?: number\n array_value?: { values?: GrpcAnyValue[] }\n // bytes/kvlist fields exist in the proto but the demo doesn't use them.\n}\n\ninterface GrpcKeyValue {\n key?: string\n value?: GrpcAnyValue\n}\n\ninterface GrpcStatus {\n code?: number\n message?: string\n}\n\ninterface GrpcEvent {\n name?: string\n time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n}\n\ninterface GrpcSpan {\n trace_id?: Buffer\n span_id?: Buffer\n parent_span_id?: Buffer\n name?: string\n kind?: number\n start_time_unix_nano?: string | number\n end_time_unix_nano?: string | number\n attributes?: GrpcKeyValue[]\n events?: GrpcEvent[]\n status?: GrpcStatus\n}\n\ninterface GrpcScopeSpans {\n spans?: GrpcSpan[]\n}\n\ninterface GrpcResourceSpans {\n resource?: { attributes?: GrpcKeyValue[] }\n scope_spans?: GrpcScopeSpans[]\n}\n\ninterface GrpcExportRequest {\n resource_spans?: GrpcResourceSpans[]\n}\n\nfunction bytesToHex(buf: Buffer | undefined): string {\n if (!buf) return ''\n return Buffer.isBuffer(buf) ? buf.toString('hex') : ''\n}\n\nfunction nanosToString(n: string | number | undefined): string {\n if (n === undefined || n === null) return '0'\n return typeof n === 'string' ? n : String(n)\n}\n\nfunction reshapeAttributes(\n attrs: GrpcKeyValue[] | undefined,\n): OtlpTracesRequest['resourceSpans'] extends Array<infer R>\n ? R extends { resource?: { attributes?: infer A } }\n ? A\n : never\n : never {\n // Map snake_case oneof fields to the camelCase the JSON path expects.\n const out = (attrs ?? []).map((kv) => ({\n key: kv.key ?? '',\n value: kv.value\n ? {\n stringValue: kv.value.string_value,\n boolValue: kv.value.bool_value,\n intValue: kv.value.int_value,\n doubleValue: kv.value.double_value,\n arrayValue: kv.value.array_value\n ? {\n values: (kv.value.array_value.values ?? []).map((v) => ({\n stringValue: v.string_value,\n boolValue: v.bool_value,\n intValue: v.int_value,\n doubleValue: v.double_value,\n })),\n }\n : undefined,\n }\n : undefined,\n }))\n return out as never\n}\n\nexport function reshapeGrpcRequest(req: GrpcExportRequest): OtlpTracesRequest {\n return {\n resourceSpans: (req.resource_spans ?? []).map((rs) => ({\n resource: rs.resource ? { attributes: reshapeAttributes(rs.resource.attributes) } : undefined,\n scopeSpans: (rs.scope_spans ?? []).map((ss) => ({\n spans: (ss.spans ?? []).map((s) => ({\n traceId: bytesToHex(s.trace_id),\n spanId: bytesToHex(s.span_id),\n parentSpanId: s.parent_span_id ? bytesToHex(s.parent_span_id) : undefined,\n name: s.name,\n kind: s.kind,\n startTimeUnixNano: nanosToString(s.start_time_unix_nano),\n endTimeUnixNano: nanosToString(s.end_time_unix_nano),\n attributes: reshapeAttributes(s.attributes),\n events: (s.events ?? []).map((e) => ({\n name: e.name,\n timeUnixNano: nanosToString(e.time_unix_nano),\n attributes: reshapeAttributes(e.attributes),\n })),\n status: s.status ? { code: s.status.code, message: s.status.message } : undefined,\n })),\n })),\n })),\n }\n}\n\n// Find the bundled .proto tree at packages/core/proto/. The dev server runs\n// from the source tree (tsx); the built bundles run from dist/. tsup keeps\n// source layout, so __dirname-relative resolution works for both — we look two\n// levels up from this file.\nfunction resolveProtoRoot(): string {\n // Built output (CJS) sets __dirname natively; ESM build is bundled by tsup\n // and keeps a dirname injection. import.meta.url is the safe bet.\n const here = path.dirname(fileURLToPath(import.meta.url))\n // src/ → packages/core/proto/, dist/ → packages/core/proto/.\n return path.resolve(here, '..', 'proto')\n}\n\nfunction loadTraceService(): grpc.ServiceDefinition {\n const protoRoot = resolveProtoRoot()\n const def = protoLoader.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n {\n keepCase: true,\n longs: String,\n enums: Number,\n defaults: true,\n oneofs: true,\n includeDirs: [protoRoot],\n },\n )\n const pkg = grpc.loadPackageDefinition(def) as unknown as {\n opentelemetry: {\n proto: {\n collector: {\n trace: {\n v1: {\n TraceService: { service: grpc.ServiceDefinition }\n }\n }\n }\n }\n }\n }\n return pkg.opentelemetry.proto.collector.trace.v1.TraceService.service\n}\n\nexport interface OtelGrpcReceiver {\n // Bound address (host:port) once .start() has resolved. Useful for tests.\n address: string\n // Stop accepting new requests, shut down the server.\n stop: () => Promise<void>\n}\n\nexport async function startOtelGrpcReceiver(\n opts: BuildOtelGrpcReceiverOptions & { host?: string; port?: number },\n): Promise<OtelGrpcReceiver> {\n const server = new grpc.Server()\n const service = loadTraceService()\n\n const requiresAuth = !opts.trustProxy && !!opts.authToken && opts.authToken.length > 0\n const expectedHeader = requiresAuth ? `Bearer ${opts.authToken}` : ''\n\n server.addService(service, {\n Export: (\n call: grpc.ServerUnaryCall<GrpcExportRequest, unknown>,\n callback: grpc.sendUnaryData<{ partial_success: object }>,\n ) => {\n // ADR-073 §4 — same bearer shape as the HTTP receiver, carried in the\n // `authorization` gRPC metadata header. Constant-time comparison.\n if (requiresAuth) {\n const meta = call.metadata.get('authorization')\n const got = meta.length > 0 ? String(meta[0]) : ''\n const a = Buffer.from(got, 'utf8')\n const b = Buffer.from(expectedHeader, 'utf8')\n const ok = a.length === b.length && timingSafeEqual(a, b)\n if (!ok) {\n callback({ code: grpc.status.UNAUTHENTICATED, message: 'unauthorized' })\n return\n }\n }\n void (async () => {\n try {\n const reshaped = reshapeGrpcRequest(call.request ?? {})\n const spans: ParsedSpan[] = parseOtlpRequest(reshaped)\n for (const span of spans) {\n await opts.onSpan(span)\n }\n callback(null, { partial_success: {} })\n } catch (err) {\n callback({\n code: grpc.status.INTERNAL,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n })()\n },\n })\n\n const host = opts.host ?? '0.0.0.0'\n const port = opts.port ?? 4317\n\n const boundPort = await new Promise<number>((resolve, reject) => {\n server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, p) => {\n if (err) return reject(err)\n resolve(p)\n })\n })\n\n return {\n address: `${host}:${boundPort}`,\n stop: () =>\n new Promise<void>((resolve) => {\n server.tryShutdown(() => resolve())\n }),\n }\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport Fastify, { type FastifyInstance } from 'fastify'\nimport protobuf from 'protobufjs'\nimport { mountBearerAuth } from './auth.js'\n\n// OTLP/HTTP receiver. Listens on /v1/traces and decodes the JSON wire format\n// (collector's `otlphttp` exporter with `encoding: json`). Each span is\n// flattened into a ParsedSpan and handed to the configured handler. The\n// handler is the seam #8 wires its edge mapper into; #7 itself stays decoupled\n// from graph mutation.\n\nexport interface ParsedSpan {\n service: string\n // True when the resource carried a `service.name` attribute. False (or\n // omitted, for legacy producers) routes the span to `service:unidentified`\n // in the resolved project and trips a once-per-session-per-project warning\n // on the ingest side (issue #374). OTel spec requires SDKs to set\n // `service.name`, but customised exporters can omit it — diagnostic\n // visibility beats silent drop. Field is optional so test fixtures that\n // hand-construct ParsedSpan with a known service.name don't need to set\n // a flag they don't care about; the receiver always sets it.\n // See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n // is missing.\n resourceServiceNamePresent?: boolean\n traceId: string\n spanId: string\n parentSpanId?: string\n name: string\n kind?: number\n startTimeUnixNano: string\n endTimeUnixNano: string\n // ISO8601 derived from startTimeUnixNano. Production paths (lastObserved on\n // OBSERVED edges) read this so the recorded time reflects when the span fired,\n // not when the receiver received it. Undefined only when startTimeUnixNano is\n // missing or unparseable — handler falls back to wall-clock in that case.\n // See docs/contracts/otel-ingest.md §lastObserved-from-span-time.\n startTimeIso?: string\n // bigint so the 9-digit-nanos arithmetic doesn't lose precision on long traces.\n durationNanos: bigint\n // Deployment environment from `deployment.environment(.name)`. Span attrs\n // win over resource attrs (per-span overrides a resource-wide declaration);\n // the canonical `deployment.environment.name` (OTel SC v1.27+) wins over\n // the compat form `deployment.environment`. Literal `'unknown'` is the\n // honest fallback when no env signal is present anywhere on the span or\n // its resource. See ADR-074 §2 / docs/contracts/env-dimension.md.\n env: string\n attributes: Record<string, AttributeValue>\n // Convenience accessors for the attributes #8 cares about.\n dbSystem?: string\n dbName?: string\n // 0 = UNSET, 1 = OK, 2 = ERROR per OTLP. We only care that 2 means error.\n statusCode?: number\n errorMessage?: string\n // Pre-extracted from a span event with name=\"exception\". OTLP SDKs record\n // exceptions this way (richer than status.message). handleSpan reads these\n // first, falling back to status.message and span.name. See\n // docs/contracts/otel-ingest.md §exception-data-from-span-events.\n exception?: {\n type?: string\n message?: string\n stacktrace?: string\n }\n}\n\nexport type AttributeValue =\n | string\n | number\n | boolean\n | bigint\n | string[]\n | number[]\n | boolean[]\n | null\n\nexport type SpanHandler = (span: ParsedSpan) => void | Promise<void>\n// Variant that receives the project the URL already resolved to. Used by the\n// project-scoped route mounted at `/projects/:project/v1/traces` (issue #367):\n// the receiver hands the URL-path project to the daemon directly so the\n// daemon never has to guess via `service.name`-against-registry matching.\nexport type ProjectSpanHandler = (project: string, span: ParsedSpan) => void | Promise<void>\n\nexport interface BuildOtelReceiverOptions {\n onSpan: SpanHandler\n // Synchronous handler for spans with statusCode === 2. The receiver awaits\n // it before replying, so a write failure can return 500 → OTel SDK retries.\n // Optional — wiring is expected to plumb appendErrorEvent here when error\n // durability matters; ad-hoc receivers leave it undefined.\n // See docs/contracts/otel-ingest.md §Error events.\n onErrorSpanSync?: (span: ParsedSpan) => Promise<void>\n // Project-scoped variants — used by the `/projects/:project/v1/traces`\n // route. When unset the route is still mounted but falls through to the\n // legacy `onSpan` / `onErrorSpanSync` handlers (the project name is then\n // available to the consumer via the `OTEL_PROJECT_OVERRIDE` attribute on\n // each parsed span; ad-hoc receivers commonly leave both unset).\n onProjectSpan?: ProjectSpanHandler\n onProjectErrorSpanSync?: (project: string, span: ParsedSpan) => Promise<void>\n // Fastify body limit. OTLP batches can be large; default is 16 MB.\n bodyLimit?: number\n // ADR-073 §4 — bearer required on `/v1/traces`. Defaults to `NEAT_AUTH_TOKEN`\n // when unset; `NEAT_OTEL_TOKEN` overrides at the call site so the REST and\n // OTLP surfaces rotate on independent schedules.\n authToken?: string\n // Same shape as the REST middleware: skip the request-side check when an\n // upstream reverse proxy already authenticated.\n trustProxy?: boolean\n}\n\ninterface OtlpKeyValue {\n key: string\n value?: OtlpAnyValue\n}\n\ninterface OtlpAnyValue {\n stringValue?: string\n intValue?: string | number\n doubleValue?: number\n boolValue?: boolean\n arrayValue?: { values?: OtlpAnyValue[] }\n // kvlistValue / bytesValue are skipped — neither is on the demo path.\n}\n\ninterface OtlpStatus {\n code?: number\n message?: string\n}\n\ninterface OtlpEvent {\n name?: string\n timeUnixNano?: string\n attributes?: OtlpKeyValue[]\n}\n\ninterface OtlpSpan {\n traceId?: string\n spanId?: string\n parentSpanId?: string\n name?: string\n kind?: number\n startTimeUnixNano?: string\n endTimeUnixNano?: string\n attributes?: OtlpKeyValue[]\n events?: OtlpEvent[]\n status?: OtlpStatus\n}\n\nfunction extractExceptionFromEvents(events: OtlpEvent[] | undefined): ParsedSpan['exception'] {\n if (!events) return undefined\n for (const ev of events) {\n if (ev.name !== 'exception') continue\n const attrs = attrsToRecord(ev.attributes)\n const out: ParsedSpan['exception'] = {}\n const t = attrs['exception.type']\n const m = attrs['exception.message']\n const s = attrs['exception.stacktrace']\n if (typeof t === 'string') out.type = t\n if (typeof m === 'string') out.message = m\n if (typeof s === 'string') out.stacktrace = s\n if (out.type || out.message || out.stacktrace) return out\n }\n return undefined\n}\n\ninterface OtlpScopeSpans {\n spans?: OtlpSpan[]\n}\n\ninterface OtlpResourceSpans {\n resource?: { attributes?: OtlpKeyValue[] }\n scopeSpans?: OtlpScopeSpans[]\n}\n\nexport interface OtlpTracesRequest {\n resourceSpans?: OtlpResourceSpans[]\n}\n\nfunction flattenAttribute(v: OtlpAnyValue | undefined): AttributeValue {\n if (!v) return null\n if (v.stringValue !== undefined) return v.stringValue\n if (v.boolValue !== undefined) return v.boolValue\n if (v.intValue !== undefined) {\n return typeof v.intValue === 'string' ? Number(v.intValue) : v.intValue\n }\n if (v.doubleValue !== undefined) return v.doubleValue\n if (v.arrayValue?.values) {\n return v.arrayValue.values.map((x) => flattenAttribute(x)) as AttributeValue\n }\n return null\n}\n\nfunction attrsToRecord(attrs: OtlpKeyValue[] | undefined): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {}\n if (!attrs) return out\n for (const kv of attrs) {\n if (kv.key) out[kv.key] = flattenAttribute(kv.value)\n }\n return out\n}\n\nfunction durationNanos(start?: string, end?: string): bigint {\n if (!start || !end) return 0n\n try {\n return BigInt(end) - BigInt(start)\n } catch {\n return 0n\n }\n}\n\n// Convert OTLP's startTimeUnixNano (a base-10 string of nanoseconds since the\n// Unix epoch) to ISO8601. Returns undefined when the input is missing, zero,\n// or unparseable, so the caller can fall back to wall-clock without surfacing\n// a fake timestamp on the edge.\nexport function isoFromUnixNano(nanos: string | undefined): string | undefined {\n if (!nanos || nanos === '0') return undefined\n try {\n const ms = Number(BigInt(nanos) / 1_000_000n)\n if (!Number.isFinite(ms)) return undefined\n return new Date(ms).toISOString()\n } catch {\n return undefined\n }\n}\n\n// Resolve `deployment.environment` per ADR-074 §2. The four-step fallback\n// is: span-attr canonical form → span-attr compat form → resource-attr\n// canonical form → resource-attr compat form → literal `'unknown'`. The\n// literal `'unknown'` is the honest sentinel; defaulting to `'production'`\n// or `'development'` would bake an incorrect assumption into every span\n// from a workload that hasn't yet wired its env signal.\nconst ENV_ATTR_CANONICAL = 'deployment.environment.name'\nconst ENV_ATTR_COMPAT = 'deployment.environment'\nconst ENV_FALLBACK = 'unknown'\n\nfunction pickEnv(\n spanAttrs: Record<string, AttributeValue>,\n resourceAttrs: Record<string, AttributeValue>,\n): string {\n for (const attrs of [spanAttrs, resourceAttrs]) {\n for (const key of [ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT]) {\n const v = attrs[key]\n if (typeof v === 'string' && v.length > 0) return v\n }\n }\n return ENV_FALLBACK\n}\n\nexport function parseOtlpRequest(body: OtlpTracesRequest): ParsedSpan[] {\n const out: ParsedSpan[] = []\n for (const rs of body.resourceSpans ?? []) {\n const resourceAttrs = attrsToRecord(rs.resource?.attributes)\n // OTel spec requires SDKs to set `service.name`, but customised exporters\n // can omit it. Missing `service.name` routes to `service:unidentified`\n // in handleSpan + emits a once-per-session-per-project warning so the\n // diagnostic stays visible (issue #374). Silent drop is not an option.\n const rawServiceName = resourceAttrs['service.name']\n const resourceServiceNamePresent =\n typeof rawServiceName === 'string' && rawServiceName.length > 0\n const service = resourceServiceNamePresent\n ? (rawServiceName as string)\n : 'unidentified'\n\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = attrsToRecord(span.attributes)\n const parsed: ParsedSpan = {\n service,\n resourceServiceNamePresent,\n traceId: span.traceId ?? '',\n spanId: span.spanId ?? '',\n parentSpanId: span.parentSpanId || undefined,\n name: span.name ?? '',\n kind: span.kind,\n startTimeUnixNano: span.startTimeUnixNano ?? '0',\n endTimeUnixNano: span.endTimeUnixNano ?? '0',\n startTimeIso: isoFromUnixNano(span.startTimeUnixNano),\n durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),\n env: pickEnv(attrs, resourceAttrs),\n attributes: attrs,\n dbSystem: typeof attrs['db.system'] === 'string' ? (attrs['db.system'] as string) : undefined,\n dbName: typeof attrs['db.name'] === 'string' ? (attrs['db.name'] as string) : undefined,\n statusCode: span.status?.code,\n errorMessage: span.status?.message,\n exception: extractExceptionFromEvents(span.events),\n }\n out.push(parsed)\n }\n }\n }\n return out\n}\n\nexport interface OtelReceiver {\n app: FastifyInstance\n // Resolves once every span enqueued so far has been handed to opts.onSpan.\n // Test seam — production code never awaits this.\n flushPending: () => Promise<void>\n}\n\n// Lazy-loaded protobuf decoder for ExportTraceServiceRequest. The bundled\n// .proto tree at packages/core/proto/ is shared with the gRPC receiver\n// (ADR-020). Cached after first load so successive receiver builds reuse it.\nlet exportTraceServiceRequestType: protobuf.Type | null = null\nlet exportTraceServiceResponseType: protobuf.Type | null = null\n\nfunction loadProtoRoot(): protobuf.Root {\n const here = path.dirname(fileURLToPath(import.meta.url))\n const protoRoot = path.resolve(here, '..', 'proto')\n const root = new protobuf.Root()\n root.resolvePath = (_origin, target) => path.resolve(protoRoot, target)\n root.loadSync(\n 'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n { keepCase: true },\n )\n return root\n}\n\nfunction loadProtobufDecoder(): protobuf.Type {\n if (exportTraceServiceRequestType) return exportTraceServiceRequestType\n const root = loadProtoRoot()\n exportTraceServiceRequestType = root.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n )\n return exportTraceServiceRequestType\n}\n\nfunction loadProtobufResponseEncoder(): protobuf.Type {\n if (exportTraceServiceResponseType) return exportTraceServiceResponseType\n const root = loadProtoRoot()\n exportTraceServiceResponseType = root.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse',\n )\n return exportTraceServiceResponseType\n}\n\n// Empty-partial-success response, encoded once and cached. Per ADR-033 the\n// receiver always reports \"all accepted\" today — there's no per-span reject\n// path. Caching the bytes avoids re-running the protobuf encoder per request.\nlet cachedProtobufResponseBody: Buffer | null = null\n\nfunction encodeProtobufResponseBody(): Buffer {\n if (cachedProtobufResponseBody) return cachedProtobufResponseBody\n const Type = loadProtobufResponseEncoder()\n // `partial_success` left unset = empty submessage = \"everything accepted\".\n // verify() returns null on success; the empty payload is always valid.\n const msg = Type.create({})\n const encoded = Type.encode(msg).finish()\n cachedProtobufResponseBody = Buffer.from(encoded)\n return cachedProtobufResponseBody\n}\n\nasync function decodeProtobufBody(buf: Buffer): Promise<OtlpTracesRequest> {\n const Type = loadProtobufDecoder()\n // Decode keeps the proto field names verbatim (keepCase: true), matching the\n // GrpcExportRequest shape that reshapeGrpcRequest already understands.\n // Dynamic import sidesteps the circular module dep with otel-grpc.ts.\n const decoded = Type.decode(buf).toJSON() as Record<string, unknown>\n const { reshapeGrpcRequest } = await import('./otel-grpc.js')\n return reshapeGrpcRequest(decoded as never)\n}\n\nexport async function buildOtelReceiver(\n opts: BuildOtelReceiverOptions,\n): Promise<FastifyInstance & { flushPending: () => Promise<void> }> {\n const app = Fastify({\n logger: false,\n bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024,\n })\n\n // ADR-073 §4 — bearer on `/v1/traces`. `/health` stays unauthenticated via\n // the default suffix list (the CI smoke and supervisors lean on it for\n // liveness probes).\n mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy })\n\n // Non-blocking ingest (ADR-033). The receiver replies 200 OK as soon as the\n // body is parsed; mutation runs through this queue, drained on the next tick.\n // OTel SDK exporters retry on timeout, so blocking ingest produces observable\n // backpressure on the system being observed — ambient observation requires no\n // observable effect.\n const queue: ParsedSpan[] = []\n let draining = false\n let drainPromise: Promise<void> = Promise.resolve()\n\n const drain = async (): Promise<void> => {\n if (draining) return\n draining = true\n try {\n while (queue.length > 0) {\n const span = queue.shift()!\n try {\n await opts.onSpan(span)\n } catch (err) {\n console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n }\n }\n } finally {\n draining = false\n }\n }\n\n const enqueue = (spans: ParsedSpan[]): void => {\n if (spans.length === 0) return\n for (const s of spans) queue.push(s)\n // Schedule on the next tick so the 200 response is on the wire before any\n // mutation runs. Each call gets its own promise so flushPending() can wait\n // on the latest drain cycle.\n drainPromise = drainPromise.then(() => drain())\n }\n\n // Per-project queue is reusable across the project-scoped route — the\n // project name rides in the URL, not on the span. Drain semantics mirror\n // the global queue so flushPending() captures both.\n const projectQueue: Array<{ project: string; span: ParsedSpan }> = []\n let projectDraining = false\n let projectDrainPromise: Promise<void> = Promise.resolve()\n const drainProject = async (): Promise<void> => {\n if (projectDraining) return\n projectDraining = true\n try {\n while (projectQueue.length > 0) {\n const { project, span } = projectQueue.shift()!\n try {\n if (opts.onProjectSpan) {\n await opts.onProjectSpan(project, span)\n } else {\n await opts.onSpan(span)\n }\n } catch (err) {\n console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n }\n }\n } finally {\n projectDraining = false\n }\n }\n const enqueueProject = (project: string, spans: ParsedSpan[]): void => {\n if (spans.length === 0) return\n for (const s of spans) projectQueue.push({ project, span: s })\n projectDrainPromise = projectDrainPromise.then(() => drainProject())\n }\n\n // One-time-per-service-name deprecation warning for spans landing on the\n // legacy global endpoint. The replacement is the project-scoped URL\n // (`/projects/<project>/v1/traces`) the installer writes into `.env.neat`\n // from v0.4.4. The warning is once-per-name so a long-running daemon\n // doesn't flood stderr while an operator is migrating.\n const legacyEndpointWarned = new Set<string>()\n function warnLegacyEndpoint(serviceName: string): void {\n if (legacyEndpointWarned.has(serviceName)) return\n legacyEndpointWarned.add(serviceName)\n console.warn(\n `[neatd] received span on the global endpoint; migrate OTEL_EXPORTER_OTLP_TRACES_ENDPOINT to /projects/<name>/v1/traces (service.name=\"${serviceName}\").`,\n )\n }\n\n // Shared body-decode + content-negotiation. Both `/v1/traces` and\n // `/projects/:project/v1/traces` go through this so the protobuf/JSON\n // dispatch stays in one place.\n async function readOtlpBody(req: import('fastify').FastifyRequest): Promise<\n | { ok: true; body: OtlpTracesRequest; flavor: 'json' | 'protobuf' }\n | { ok: false; code: 400 | 415; error: string }\n > {\n const ct = (req.headers['content-type'] ?? '').toString().split(';')[0]!.trim().toLowerCase()\n if (ct === 'application/x-protobuf') {\n try {\n const body = await decodeProtobufBody(req.body as Buffer)\n return { ok: true, body, flavor: 'protobuf' }\n } catch (err) {\n return { ok: false, code: 400, error: `protobuf decode failed: ${(err as Error).message}` }\n }\n }\n if (!ct || ct === 'application/json') {\n return { ok: true, body: (req.body ?? {}) as OtlpTracesRequest, flavor: 'json' }\n }\n return { ok: false, code: 415, error: `unsupported content-type: ${ct}` }\n }\n\n function sendOtlpSuccess(reply: import('fastify').FastifyReply, flavor: 'json' | 'protobuf'): unknown {\n if (flavor === 'protobuf') {\n const buf = encodeProtobufResponseBody()\n return reply\n .code(200)\n .header('content-type', 'application/x-protobuf')\n .send(buf)\n }\n return reply\n .code(200)\n .header('content-type', 'application/json')\n .send({ partialSuccess: {} })\n }\n\n // Buffer application/x-protobuf bodies as raw bytes; the route handler\n // decodes them via the bundled .proto tree (ADR-020).\n app.addContentTypeParser(\n 'application/x-protobuf',\n { parseAs: 'buffer', bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },\n (_req, body, done) => {\n done(null, body)\n },\n )\n\n app.get('/health', async () => ({ ok: true }))\n\n app.post('/v1/traces', async (req, reply) => {\n // Legacy global endpoint. Spans land here when an OTel exporter hasn't\n // migrated to the project-scoped URL yet (issue #367); the daemon still\n // routes by `service.name` against the registry. Per-service-name\n // deprecation warning fires once so an operator notices without their\n // stderr flooding.\n const result = await readOtlpBody(req)\n if (!result.ok) {\n return reply.code(result.code).send({ error: result.error })\n }\n const spans = parseOtlpRequest(result.body)\n for (const s of spans) warnLegacyEndpoint(s.service)\n if (opts.onErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n }\n enqueue(spans)\n return sendOtlpSuccess(reply, result.flavor)\n })\n\n // Project-scoped route (issue #367). The URL `:project` carries the routing\n // key, sidestepping the `service.name`-against-registry heuristic the legacy\n // path uses. Spans get dispatched into the named project's ingest path\n // directly; `OTEL_SERVICE_NAME` regains its proper semantic role of naming\n // the ServiceNode inside the one project the URL already picked.\n app.post<{ Params: { project: string } }>('/projects/:project/v1/traces', async (req, reply) => {\n const project = req.params.project\n const result = await readOtlpBody(req)\n if (!result.ok) {\n return reply.code(result.code).send({ error: result.error })\n }\n const spans = parseOtlpRequest(result.body)\n if (opts.onProjectErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onProjectErrorSpanSync(project, span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n } else if (opts.onErrorSpanSync) {\n try {\n for (const span of spans) {\n if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n }\n } catch (err) {\n return reply.code(500).send({\n error: `error-event write failed: ${(err as Error).message}`,\n })\n }\n }\n enqueueProject(project, spans)\n return sendOtlpSuccess(reply, result.flavor)\n })\n\n // Attach flushPending so tests can wait for the queue without exporting a\n // separate handle. The cast goes through `unknown` because Fastify's typing\n // is parameterised over the raw server type and the simple intersection\n // confuses TS's structural narrowing.\n const decorated = app as unknown as FastifyInstance & { flushPending: () => Promise<void> }\n decorated.flushPending = async () => {\n // Settle both drain chains, then loop until both queues are fully empty\n // (a span enqueued mid-flush would otherwise be missed).\n while (queue.length > 0 || draining || projectQueue.length > 0 || projectDraining) {\n await Promise.all([drainPromise, projectDrainPromise])\n }\n }\n return decorated\n}\n\nexport function logSpanHandler(span: ParsedSpan): void {\n const parent = span.parentSpanId ? span.parentSpanId.slice(0, 8) : '<root>'\n const status = span.statusCode === 2 ? 'ERROR' : 'OK'\n const db = span.dbSystem ? ` db=${span.dbSystem}/${span.dbName ?? '?'}` : ''\n console.log(\n `otel: ${span.service} ${span.name} parent=${parent} status=${status}${db}`,\n )\n}\n","#!/usr/bin/env node\n\nimport path from 'node:path'\nimport { promises as fs, readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport {\n formatExtractionBanner,\n formatPrecisionFloorBanner,\n isStrictExtractionEnabled,\n} from './extract/errors.js'\nimport { discoverServices } from './extract/services.js'\nimport type { DiscoveredService } from './extract/shared.js'\nimport { computeDivergences } from './divergences.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { renderValueForwardSummary } from './summary.js'\nimport { startWatch, type WatchHandle } from './watch.js'\nimport { runDeploy, renderOtelEnvBlock } from './deploy/detect.js'\nimport { pathsForProject } from './projects.js'\nimport {\n addProject,\n listProjects,\n ProjectNameCollisionError,\n removeProject,\n setStatus,\n} from './registry.js'\nimport {\n INSTALLERS,\n isEmptyPlan,\n pickInstaller,\n renderPatch,\n type InstallPlan,\n type PatchSection,\n} from './installers/index.js'\nimport { runOrchestrator } from './orchestrator.js'\nimport { runSync } from './cli-verbs.js'\nimport { DivergenceTypeSchema, type DivergenceType } from '@neat.is/types'\nimport {\n createHttpClient,\n exitCodeForError,\n formatHuman,\n formatJson,\n HttpError,\n resolveAuthToken,\n runBlastRadius,\n runDependencies,\n runDiff,\n runDivergences,\n runIncidents,\n runObservedDependencies,\n runPolicies,\n runRootCause,\n runSearch,\n runStaleEdges,\n TransportError,\n type VerbResult,\n} from './cli-client.js'\n\nexport interface InitOptions {\n scanPath: string\n outPath: string\n // The project's registry name. Defaults to the basename of the scan path\n // when the user didn't pass `--project` (ADR-046 — project naming).\n project: string\n // Whether `project` was set explicitly via `--project`. The flag affects\n // which in-memory graph slot we use: explicit names get isolated slots\n // per ADR-026, the default basename keeps using DEFAULT_PROJECT for\n // back-compat with `neat watch`.\n projectExplicit: boolean\n apply: boolean\n dryRun: boolean\n noInstall: boolean\n // ADR-073 §5 — when true, append the per-type node/edge breakdown after\n // the value-forward findings block. Default false.\n verbose: boolean\n}\n\nexport interface InitResult {\n // Process exit code. 0 on success, 1 on collision / runtime failure,\n // 2 on misuse (handled before we get here, but documented for completeness).\n exitCode: number\n // Paths the run actually wrote to. Empty in `--dry-run` except for\n // `neat.patch`. Useful for tests asserting \"init only wrote X\".\n writtenFiles: string[]\n}\n\nfunction usage(): void {\n console.log('usage: neat <command> [args] [--project <name>]')\n console.log('')\n console.log('lifecycle commands:')\n console.log(' init <path> One-time install: discover, extract, register, plan SDK install.')\n console.log(' Snapshot lands in <path>/neat-out/graph.json by default')\n console.log(' (or <path>/neat-out/<project>.json for non-default).')\n console.log(' Flags:')\n console.log(' --apply run the SDK install patch in place')\n console.log(' --dry-run write only neat.patch; do not register or snapshot')\n console.log(' --no-install skip SDK install planning entirely')\n console.log(' watch <path> Start neat-core, watch <path>, re-extract on changes.')\n console.log(' PORT (default 8080), OTEL_PORT (4318), HOST (0.0.0.0)')\n console.log(' control listeners. NEAT_OTLP_GRPC=true also opens 4317.')\n console.log(' list List every project registered in the machine-level registry.')\n console.log(' pause <name> Mark a project paused — daemon stops watching until resumed.')\n console.log(' resume <name> Mark a project active again.')\n console.log(' uninstall <name>')\n console.log(' Remove a project from the registry. Does not touch')\n console.log(' neat-out/, policy.json, or any user file.')\n console.log(' version Print the installed @neat.is/core version and exit.')\n console.log(' Aliases: --version, -v.')\n console.log(' skill Install or print the Claude Code MCP drop-in.')\n console.log(' Flags:')\n console.log(' --print-config print the JSON snippet to stdout')\n console.log(' --apply merge mcpServers.neat into ~/.claude.json')\n console.log(' deploy Detect the deploy substrate, generate NEAT_AUTH_TOKEN,')\n console.log(' emit a docker-compose / systemd / docker run artifact, and')\n console.log(' print the OTel env-vars block to paste into your platform.')\n console.log(' sync Re-run discovery, extraction, and SDK apply against the')\n console.log(' registered project, then notify the running daemon.')\n console.log(' Flags:')\n console.log(' --project <name> target a registered project by name')\n console.log(' --to <url> push the snapshot to a remote daemon')\n console.log(' --token <token> bearer token for --to (or $NEAT_REMOTE_TOKEN)')\n console.log(' --dry-run run extraction in-memory; do not write')\n console.log(' --no-instrument skip the SDK install apply step')\n console.log(' --json emit the delta summary as JSON')\n console.log('')\n console.log('query commands (mirror the MCP tools, ADR-050):')\n console.log(' root-cause <node-id> Walk inbound edges to find what broke first.')\n console.log(' example: neat root-cause service:<name>')\n console.log(' blast-radius <node-id> BFS outbound — what would break if this dies.')\n console.log(' example: neat blast-radius database:<host>')\n console.log(' dependencies <node-id> Transitive outbound dependencies.')\n console.log(' Flags: --depth N (default 3, max 10)')\n console.log(' example: neat dependencies service:<name> --depth 2')\n console.log(' observed-dependencies <node-id> OBSERVED-only outbound edges (runtime traffic).')\n console.log(' example: neat observed-dependencies service:<name>')\n console.log(' incidents [<node-id>] Recent error events; per-node when an id is given.')\n console.log(' Flags: --limit N (default 20)')\n console.log(' example: neat incidents service:<name> --limit 5')\n console.log(' search <query> Semantic (or substring) match on node names/ids.')\n console.log(' example: neat search \"checkout\"')\n console.log(' diff --against <snapshot> Compare the live graph to a saved snapshot.')\n console.log(' example: neat diff --against ./snapshots/baseline.json')\n console.log(' stale-edges Recent OBSERVED → STALE transitions.')\n console.log(' Flags: --limit N, --edge-type CALLS|CONNECTS_TO|...')\n console.log(' example: neat stale-edges --edge-type CALLS')\n console.log(' policies Current policy violations.')\n console.log(' Flags: --node <id>, --hypothetical-action <json>')\n console.log(' example: neat policies --node service:<name> --json')\n console.log(' divergences Where code (EXTRACTED) and production (OBSERVED) disagree.')\n console.log(' Flags: --type <list>, --min-confidence <0..1>, --node <id>')\n console.log(' example: neat divergences --min-confidence 0.7')\n console.log('')\n console.log('flags:')\n console.log(' --project <name> Name the project this command targets. Default: \"default\".')\n console.log(' --json Emit machine-readable JSON instead of human text. Query verbs only.')\n console.log('')\n console.log('exit codes:')\n console.log(' 0 success')\n console.log(' 1 server error (4xx/5xx body printed to stderr)')\n console.log(' 2 misuse (missing args, bad flags) — handled before any network call')\n console.log(' 3 environmental — daemon unreachable, or one of ports 8080 / 4318 / 6328')\n console.log(' is held by another process when `neat <path>` tries to spawn the daemon')\n console.log('')\n console.log('environment:')\n console.log(' NEAT_API_URL base URL for the core REST API (default http://localhost:8080)')\n console.log(' NEAT_PROJECT project name when --project isn\\'t passed')\n}\n\n// Tiny argv parser — pulls `--project <name>`, the v0.2.5 init flags, and\n// the v0.2.8 verb flags out of `rest`. Boolean / value flags are surfaced\n// unconditionally; per-command validation lives in `main`.\ninterface ParsedArgs {\n project: string | null\n apply: boolean\n dryRun: boolean\n noInstall: boolean\n noInstrument: boolean\n noOpen: boolean\n yes: boolean\n verbose: boolean\n printConfig: boolean\n json: boolean\n depth: number | null\n limit: number | null\n edgeType: string | null\n node: string | null\n since: string | null\n against: string | null\n errorId: string | null\n hypotheticalAction: string | null\n type: string | null\n minConfidence: number | null\n // `neat sync` (ADR-074 §1) — remote daemon URL + bearer token.\n to: string | null\n token: string | null\n positional: string[]\n}\n\n// String-valued flags supported across the verb surface. Each entry maps the\n// canonical `--flag` name (and its `--flag=` equivalent) to the parsed-args\n// field that receives it. Centralising the table keeps misuse diagnostics\n// (exit code 2) consistent across verbs.\nconst STRING_FLAGS = [\n ['--project', 'project'],\n ['--depth', 'depth'],\n ['--limit', 'limit'],\n ['--edge-type', 'edgeType'],\n ['--node', 'node'],\n ['--since', 'since'],\n ['--against', 'against'],\n ['--error-id', 'errorId'],\n ['--hypothetical-action', 'hypotheticalAction'],\n ['--type', 'type'],\n ['--min-confidence', 'minConfidence'],\n ['--to', 'to'],\n ['--token', 'token'],\n] as const\n\nfunction parseArgs(rest: string[]): ParsedArgs {\n const positional: string[] = []\n const out: ParsedArgs = {\n project: null,\n apply: false,\n dryRun: false,\n noInstall: false,\n noInstrument: false,\n noOpen: false,\n yes: false,\n verbose: false,\n printConfig: false,\n json: false,\n depth: null,\n limit: null,\n edgeType: null,\n node: null,\n since: null,\n against: null,\n errorId: null,\n hypotheticalAction: null,\n type: null,\n minConfidence: null,\n to: null,\n token: null,\n positional: [],\n }\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i] as string\n\n // Boolean flags first.\n if (arg === '--apply') { out.apply = true; continue }\n if (arg === '--dry-run') { out.dryRun = true; continue }\n if (arg === '--no-install') { out.noInstall = true; continue }\n if (arg === '--no-instrument') { out.noInstrument = true; continue }\n if (arg === '--no-open') { out.noOpen = true; continue }\n if (arg === '--yes' || arg === '-y') { out.yes = true; continue }\n if (arg === '--verbose') { out.verbose = true; continue }\n if (arg === '--print-config') { out.printConfig = true; continue }\n if (arg === '--json') { out.json = true; continue }\n\n // String/number flags via the shared table.\n let matched = false\n for (const [flag, field] of STRING_FLAGS) {\n if (arg === flag) {\n const next = rest[i + 1]\n if (next === undefined) {\n console.error(`neat: ${flag} requires a value`)\n process.exit(2)\n }\n assignFlag(out, field, next)\n i++\n matched = true\n break\n }\n if (arg.startsWith(`${flag}=`)) {\n assignFlag(out, field, arg.slice(flag.length + 1))\n matched = true\n break\n }\n }\n if (matched) continue\n positional.push(arg)\n }\n out.positional = positional\n return out\n}\n\nexport { parseArgs }\n\n// Number flags get parsed at assignment time so misuse (`--depth foo`)\n// surfaces with exit code 2 before any network call.\nfunction assignFlag(out: ParsedArgs, field: (typeof STRING_FLAGS)[number][1], value: string): void {\n if (field === 'depth' || field === 'limit') {\n const n = Number(value)\n if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n console.error(`neat: --${field === 'depth' ? 'depth' : 'limit'} must be a positive integer`)\n process.exit(2)\n }\n out[field] = n\n return\n }\n if (field === 'minConfidence') {\n const n = Number(value)\n if (!Number.isFinite(n) || n < 0 || n > 1) {\n console.error('neat: --min-confidence must be a number in [0, 1]')\n process.exit(2)\n }\n out.minConfidence = n\n return\n }\n // String fields.\n ;(out as unknown as Record<string, unknown>)[field] = value\n}\n\n// Per-type node/edge counts + compat formatting moved into summary.ts as\n// part of the value-forward findings block (issue #305 / ADR-073 §5).\n\n// The `neat --version` family reads its answer from the bundled package's\n// own package.json. Reading at run time keeps the published bin in lockstep\n// with whatever version `tsup` shipped without a build-time substitution.\n// `dist/cli.cjs` sits one level below the package root.\nexport function readPackageVersion(): string {\n const here =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url))\n // dist/ → package root. tsup writes both cjs and mjs to dist/, so the\n // parent-of-parent walk is the same in either format.\n const candidates = [\n path.resolve(here, '../package.json'),\n path.resolve(here, '../../package.json'),\n ]\n for (const candidate of candidates) {\n try {\n const raw = readFileSync(candidate, 'utf8')\n const parsed = JSON.parse(raw) as { name?: string; version?: string }\n if (parsed.name === '@neat.is/core' && typeof parsed.version === 'string') {\n return parsed.version\n }\n } catch {\n // try the next candidate\n }\n }\n return 'unknown'\n}\n\nfunction printVersion(): void {\n process.stdout.write(`${readPackageVersion()}\\n`)\n}\n\nexport function printBanner(): void {\n console.log('███╗ ██╗███████╗ █████╗ ████████╗')\n console.log('████╗ ██║██╔════╝██╔══██╗╚══██╔══╝')\n console.log('██╔██╗ ██║█████╗ ███████║ ██║ ')\n console.log('██║╚██╗██║██╔══╝ ██╔══██║ ██║ ')\n console.log('██║ ╚████║███████╗██║ ██║ ██║ ')\n console.log('╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═╝ ')\n console.log('')\n console.log(' Network Expressive Architecting Tool')\n console.log(` neat.is · v${readPackageVersion()} · Apache 2.0`)\n console.log('')\n}\n\nfunction printDiscoveryReport(opts: InitOptions, services: DiscoveredService[]): void {\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n const mode = opts.dryRun ? 'dry-run' : opts.apply ? 'apply' : 'patch-only'\n printBanner()\n console.log('=== neat init: discovery ===')\n console.log(`scan path: ${opts.scanPath}`)\n console.log(`project: ${opts.project}`)\n console.log(`mode: ${mode}`)\n console.log(`services: ${services.length}`)\n for (const s of services) {\n const where = s.node.repoPath && s.node.repoPath.length > 0 ? s.node.repoPath : '.'\n console.log(` - ${s.node.name} (${s.node.language}) — ${where}`)\n }\n console.log(`languages: ${languages.length > 0 ? languages.join(', ') : '(none)'}`)\n if (opts.noInstall) {\n console.log('install: skipped (--no-install)')\n } else if (opts.dryRun) {\n console.log('install: patch will be written to neat.patch; nothing else.')\n } else if (opts.apply) {\n console.log('install: patch will be applied in place. Run `npm install` afterwards.')\n } else {\n console.log('install: patch will be written to neat.patch for review.')\n }\n console.log('')\n}\n\nasync function buildPatchSections(\n services: DiscoveredService[],\n project: string,\n): Promise<PatchSection[]> {\n const sections: PatchSection[] = []\n for (const svc of services) {\n const installer = await pickInstaller(svc.dir)\n if (!installer) continue\n // v0.4.1 / refs #339 — pass the registered project name so the per-\n // package `.env.neat` carries `OTEL_SERVICE_NAME=<project>`. The daemon\n // routes spans by registered project name; matching keys end-to-end\n // is what keeps OBSERVED edges landing.\n const plan: InstallPlan = await installer.plan(svc.dir, { project })\n // Lib-only + runtime-kind-skipped packages keep a section so the dry-run\n // patch documents the skip and the apply summary counts them (ADR-069 §2,\n // v0.4.4 / #370). Empty plans without either flag are already-instrumented\n // end-to-end and drop out.\n if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) continue\n sections.push({ installer: installer.name, plan })\n }\n return sections\n}\n\nexport async function runInit(opts: InitOptions): Promise<InitResult> {\n const written: string[] = []\n\n // ── Step 1: validate path ────────────────────────────────────────────\n const stat = await fs.stat(opts.scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat init: ${opts.scanPath} is not a directory`)\n return { exitCode: 2, writtenFiles: written }\n }\n\n // ── Step 2: discovery (ADR-046 #2 — before any mutation) ─────────────\n const services = await discoverServices(opts.scanPath)\n printDiscoveryReport(opts, services)\n\n // ── Step 3: plan SDK install (pure data, no fs writes) ───────────────\n const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project)\n const patch = renderPatch(sections)\n const patchPath = path.join(opts.scanPath, 'neat.patch')\n\n // ── Step 4: dry-run shortcut — only neat.patch is allowed to land ────\n if (opts.dryRun) {\n await fs.writeFile(patchPath, patch, 'utf8')\n written.push(patchPath)\n console.log(`dry-run: patch written to ${patchPath}`)\n // ADR-073 §6 — list the planned `.gitignore` write alongside the other\n // planned writes. No file mutation in dry-run; only the announcement.\n const gitignorePath = path.join(opts.scanPath, '.gitignore')\n const gitignoreExists = await fs.stat(gitignorePath).then(() => true).catch(() => false)\n const verb = gitignoreExists ? 'append' : 'create'\n console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`)\n console.log('rerun without --dry-run to register and snapshot.')\n return { exitCode: 0, writtenFiles: written }\n }\n\n // ── Step 5: extraction + snapshot ────────────────────────────────────\n // Use DEFAULT_PROJECT for the in-memory graph slot when --project wasn't\n // explicitly passed; named projects get isolated slots per ADR-026.\n const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n resetGraph(graphKey)\n const graph = getGraph(graphKey)\n // ADR-065 — per-file extraction failures land alongside the snapshot in\n // <projectDir>/neat-out/errors.ndjson. Same file as OTel error events\n // (ADR-033) with a `source: 'extract'` discriminator.\n const projectPaths = pathsForProject(\n graphKey,\n path.join(opts.scanPath, 'neat-out'),\n )\n const errorsPath = path.join(path.dirname(opts.outPath), path.basename(projectPaths.errorsPath))\n const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath })\n await saveGraphToDisk(graph, opts.outPath)\n written.push(opts.outPath)\n\n // ADR-073 §6 — ensure `neat-out/` is git-ignored. Snapshot just landed on\n // disk; an un-ignored neat-out/ would leak into git history on the next\n // commit. Idempotent: the helper no-ops when the line is already present.\n const gitignoreResult = await ensureNeatOutIgnored(opts.scanPath)\n if (gitignoreResult.action !== 'unchanged') {\n written.push(gitignoreResult.file)\n }\n\n // ── Step 6: register in the machine-level registry ───────────────────\n // Idempotent re-init of the same path under the same name refreshes the\n // entry; collision against a different path exits non-zero (ADR-046 #7).\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n let currentProjectName = opts.project\n try {\n const entry = await addProject({\n name: opts.project,\n path: opts.scanPath,\n languages,\n status: 'active',\n })\n currentProjectName = entry.name\n } catch (err) {\n if (err instanceof ProjectNameCollisionError) {\n console.error(`neat init: ${err.message}`)\n console.error('pass --project <other-name> to register under a different name.')\n return { exitCode: 1, writtenFiles: written }\n }\n throw err\n }\n\n // Narrow the active-project surface to the project the operator just\n // registered. Mirrors the bare-orchestrator behaviour so `neat init` and\n // `neat <path>` agree on the activation contract.\n const siblings = await listProjects()\n const paused: string[] = []\n for (const p of siblings) {\n if (p.name !== currentProjectName && p.status === 'active') {\n await setStatus(p.name, 'paused')\n paused.push(p.name)\n }\n }\n if (paused.length > 0) {\n const plural = paused.length === 1 ? '' : 's'\n console.log(\n `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n )\n }\n\n // ── Step 7: write or apply patch ─────────────────────────────────────\n if (!opts.noInstall) {\n if (opts.apply) {\n let instrumented = 0\n let alreadyInstrumented = 0\n let libOnly = 0\n let browserBundle = 0\n let reactNative = 0\n for (const section of sections) {\n const installer = INSTALLERS.find((i) => i.name === section.installer)\n if (!installer) continue\n const outcome = await installer.apply(section.plan)\n if (outcome.outcome === 'instrumented') {\n instrumented++\n for (const f of outcome.writtenFiles) written.push(f)\n } else if (outcome.outcome === 'already-instrumented') {\n alreadyInstrumented++\n } else if (outcome.outcome === 'lib-only') {\n libOnly++\n } else if (outcome.outcome === 'browser-bundle') {\n browserBundle++\n console.log(`skipping ${section.plan.serviceDir}: browser bundle; browser-OTel support lands in a future release.`)\n } else if (outcome.outcome === 'react-native') {\n reactNative++\n console.log(`skipping ${section.plan.serviceDir}: React Native target; browser-OTel support lands in a future release.`)\n }\n }\n if (sections.length > 0) {\n console.log('')\n const parts = [\n `instrumented ${instrumented}`,\n `already-instrumented ${alreadyInstrumented}`,\n `lib-only ${libOnly}`,\n ]\n if (browserBundle > 0) parts.push(`browser-bundle ${browserBundle}`)\n if (reactNative > 0) parts.push(`react-native ${reactNative}`)\n console.log(`apply: ${parts.join(', ')}`)\n console.log('Run `npm install` (or your language equivalent) to refresh lockfiles.')\n }\n } else {\n await fs.writeFile(patchPath, patch, 'utf8')\n written.push(patchPath)\n }\n }\n\n // ── Step 8: summary + incompatibilities ──────────────────────────────\n // ADR-073 §5 / issue #305 — findings-first: compat violations, top\n // divergences, services without OBSERVED coverage, then the OTel env-vars\n // block. Per-type counts ride behind `--verbose`.\n console.log('')\n console.log(`snapshot: ${opts.outPath}`)\n console.log(`added: ${result.nodesAdded} nodes, ${result.edgesAdded} edges`)\n console.log('')\n const divergenceResult = computeDivergences(graph)\n console.log(\n renderValueForwardSummary({\n graph,\n divergences: divergenceResult.divergences,\n verbose: opts.verbose,\n }),\n )\n // ADR-065 — loud failure mode banner. Unconditional; 0 is a positive\n // signal. When errors > 0, also surface the sidecar path so the operator\n // can read per-file detail.\n console.log(formatExtractionBanner(result.extractionErrors))\n if (result.extractionErrors > 0) {\n console.log(`errors: ${errorsPath}`)\n }\n // ADR-066 — precision-floor drop banner. Always emitted; 0 is observable\n // as a positive signal that no cross-service heuristic edges grew the\n // graph this pass.\n console.log(formatPrecisionFloorBanner(result.extractedDropped))\n\n // ADR-065 — NEAT_STRICT_EXTRACTION=1 makes any per-file failure exit\n // non-zero. Default is forgiving (banner only). Exit code 4 keeps\n // misuse (2) and daemon-down (3) distinguishable per the CLI contract.\n if (result.extractionErrors > 0 && isStrictExtractionEnabled()) {\n return { exitCode: 4, writtenFiles: written }\n }\n\n return { exitCode: 0, writtenFiles: written }\n}\n\n// ── Claude Code skill (ADR-049 / v0.2.5 step 6) ────────────────────────\n//\n// The skill is a one-shot MCP-config drop-in. Source of truth for the\n// snippet lives here (the @neat.is/claude-skill package's\n// claude_code_config.json holds an identical copy for documentation; a\n// contract test keeps the two byte-aligned).\nexport const CLAUDE_SKILL_CONFIG = {\n mcpServers: {\n neat: {\n type: 'stdio' as const,\n command: 'npx',\n args: ['-y', '@neat.is/mcp'],\n env: {\n NEAT_API_URL: 'http://localhost:8080',\n },\n },\n },\n}\n\nfunction claudeConfigPath(): string {\n // ~/.claude.json is Claude Code's user-level MCP config. Tests override\n // via NEAT_CLAUDE_CONFIG so they don't touch the real file.\n const override = process.env.NEAT_CLAUDE_CONFIG\n if (override && override.length > 0) return path.resolve(override)\n const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n return path.join(home, '.claude.json')\n}\n\nexport interface SkillOptions {\n apply: boolean\n printConfig: boolean\n}\n\nexport async function runSkill(opts: SkillOptions): Promise<{ exitCode: number }> {\n const snippet = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + '\\n'\n\n if (opts.printConfig) {\n process.stdout.write(snippet)\n return { exitCode: 0 }\n }\n\n if (opts.apply) {\n const target = claudeConfigPath()\n let existing: Record<string, unknown> = {}\n try {\n existing = JSON.parse(await fs.readFile(target, 'utf8'))\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.error(`neat skill: failed to read ${target} — ${(err as Error).message}`)\n return { exitCode: 1 }\n }\n }\n // Merge mcpServers.neat without disturbing other entries the user\n // might have wired up by hand.\n const mcp =\n (existing as { mcpServers?: Record<string, unknown> }).mcpServers ?? {}\n const merged = {\n ...existing,\n mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat },\n }\n await fs.mkdir(path.dirname(target), { recursive: true })\n await fs.writeFile(target, JSON.stringify(merged, null, 2) + '\\n', 'utf8')\n console.log(`neat skill: wrote mcpServers.neat to ${target}`)\n console.log('restart Claude Code to pick up the new MCP server.')\n return { exitCode: 0 }\n }\n\n console.log('neat skill — Claude Code MCP drop-in for NEAT')\n console.log('')\n console.log(' --print-config print the JSON snippet to stdout')\n console.log(' --apply merge mcpServers.neat into ~/.claude.json')\n console.log('')\n console.log('Manual install: copy mcpServers.neat from --print-config into ~/.claude.json,')\n console.log('then restart Claude Code. See packages/claude-skill/SKILL.md for the tool list.')\n return { exitCode: 0 }\n}\n\nasync function main(): Promise<void> {\n const [, , cmd, ...rest] = process.argv\n\n if (!cmd || cmd === '-h' || cmd === '--help') {\n usage()\n process.exit(0)\n }\n\n if (cmd === '--version' || cmd === '-v' || cmd === 'version') {\n printVersion()\n process.exit(0)\n }\n\n const parsed = parseArgs(rest)\n const { positional, apply, dryRun, noInstall } = parsed\n const project = parsed.project ?? DEFAULT_PROJECT\n\n if (cmd === 'init') {\n const target = positional[0]\n if (!target) {\n console.error('neat init: missing <path>')\n usage()\n process.exit(2)\n }\n if (apply && dryRun) {\n console.error('neat init: --apply and --dry-run are mutually exclusive')\n process.exit(2)\n }\n const scanPath = path.resolve(target)\n // ADR-046 — when --project isn't passed, the registry name defaults to\n // the basename of the scan path. The in-memory graph slot stays on\n // DEFAULT_PROJECT (back-compat with existing `neat watch` invocations).\n const projectExplicit = parsed.project !== null\n const projectName = projectExplicit ? project : path.basename(scanPath)\n // Default project keeps writing to graph.json (ADR-026 back-compat);\n // named projects use <project>.json under the same neat-out directory.\n const projectKey = projectExplicit ? project : DEFAULT_PROJECT\n const fallback = pathsForProject(projectKey, path.join(scanPath, 'neat-out')).snapshotPath\n const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? fallback)\n const result = await runInit({\n scanPath,\n outPath,\n project: projectName,\n projectExplicit,\n apply,\n dryRun,\n noInstall,\n verbose: parsed.verbose,\n })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n if (cmd === 'watch') {\n const target = positional[0]\n if (!target) {\n console.error('neat watch: missing <path>')\n usage()\n process.exit(2)\n }\n const scanPath = path.resolve(target)\n const stat = await fs.stat(scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat watch: ${scanPath} is not a directory`)\n process.exit(2)\n }\n const projectPaths = pathsForProject(project, path.join(scanPath, 'neat-out'))\n const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath)\n const errorsPath = path.resolve(\n process.env.NEAT_ERRORS_PATH ??\n path.join(path.dirname(outPath), path.basename(projectPaths.errorsPath)),\n )\n const staleEventsPath = path.resolve(\n process.env.NEAT_STALE_EVENTS_PATH ??\n path.join(path.dirname(outPath), path.basename(projectPaths.staleEventsPath)),\n )\n\n const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH\n ? path.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH)\n : undefined\n\n const handle: WatchHandle = await startWatch(getGraph(project), {\n scanPath,\n outPath,\n errorsPath,\n staleEventsPath,\n project,\n ...(embeddingsCachePath ? { embeddingsCachePath } : {}),\n host: process.env.HOST ?? '0.0.0.0',\n port: Number(process.env.PORT ?? 8080),\n otelPort: Number(process.env.OTEL_PORT ?? 4318),\n otelGrpc: process.env.NEAT_OTLP_GRPC === 'true',\n otelGrpcPort: process.env.NEAT_OTLP_GRPC_PORT\n ? Number(process.env.NEAT_OTLP_GRPC_PORT)\n : undefined,\n })\n\n // startPersistLoop already wires SIGTERM/SIGINT to flush + exit. Hook in\n // ahead of it so the watcher closes cleanly first; the persist handler's\n // `process.exit(0)` will still run after our stop() resolves.\n let shuttingDown = false\n const shutdown = (signal: NodeJS.Signals): void => {\n if (shuttingDown) return\n shuttingDown = true\n console.log(`neat watch: ${signal} received, stopping…`)\n void handle.stop().catch((err) => {\n console.error('neat watch: shutdown error', err)\n })\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n return\n }\n\n if (cmd === 'list') {\n const projects = await listProjects()\n if (projects.length === 0) {\n console.log('no projects registered. run `neat init <path>` to register one.')\n return\n }\n for (const p of projects) {\n const seen = p.lastSeenAt ? p.lastSeenAt : 'never'\n const langs = p.languages.length > 0 ? p.languages.join(',') : '-'\n console.log(`${p.name}\\t${p.status}\\t${langs}\\t${p.path}\\tlast-seen=${seen}`)\n }\n return\n }\n\n if (cmd === 'pause') {\n const name = positional[0]\n if (!name) {\n console.error('neat pause: missing <name>')\n usage()\n process.exit(2)\n }\n try {\n const entry = await setStatus(name, 'paused')\n console.log(`paused: ${entry.name} (${entry.path})`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return\n }\n\n if (cmd === 'resume') {\n const name = positional[0]\n if (!name) {\n console.error('neat resume: missing <name>')\n usage()\n process.exit(2)\n }\n try {\n const entry = await setStatus(name, 'active')\n console.log(`resumed: ${entry.name} (${entry.path})`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return\n }\n\n if (cmd === 'skill') {\n const result = await runSkill({ apply: parsed.apply, printConfig: parsed.printConfig })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n if (cmd === 'uninstall') {\n const name = positional[0]\n if (!name) {\n console.error('neat uninstall: missing <name>')\n usage()\n process.exit(2)\n }\n const removed = await removeProject(name)\n if (!removed) {\n console.error(`neat uninstall: no project named \"${name}\"`)\n process.exit(1)\n }\n console.log(`unregistered: ${removed.name} (${removed.path})`)\n console.log('note: neat-out/, policy.json, and other files at the project path were left in place.')\n return\n }\n\n if (cmd === 'deploy') {\n // ADR-073 §2 — detect substrate, generate token, emit artifact, print\n // the OTel env-vars block. Token is the only secret printed to stdout;\n // the artifact written to disk names the env-var by reference only.\n const artifact = await runDeploy()\n const block = renderOtelEnvBlock(artifact.token)\n\n console.log()\n console.log(`Substrate detected: ${artifact.substrate}`)\n if (artifact.artifactPath) {\n console.log(`Artifact written: ${artifact.artifactPath}`)\n } else {\n console.log('No on-disk artifact — copy the snippet below into your substrate.')\n console.log()\n console.log(artifact.contents)\n }\n console.log()\n console.log('NEAT_AUTH_TOKEN (store this — it will not be printed again):')\n console.log(` ${artifact.token}`)\n console.log()\n console.log(\"For your application's deploy platform, set these env vars:\")\n console.log(block.split('\\n').map((l) => ` ${l}`).join('\\n'))\n console.log()\n console.log('Once NEAT is running, your dashboard will be at:')\n console.log(' https://<host>:6328')\n console.log()\n console.log('To start NEAT, run:')\n console.log(` ${artifact.startCommand}`)\n return\n }\n\n if (cmd === 'sync') {\n // ADR-074 §1 — re-runs discovery + extract + SDK apply + daemon notify\n // against the registered project. Skips registry registration, browser\n // open, daemon spawn, and the first-run summary block.\n const result = await runSync({\n ...(parsed.project ? { project: parsed.project } : {}),\n ...(parsed.to ? { to: parsed.to } : {}),\n ...(parsed.token ? { token: parsed.token } : {}),\n dryRun: parsed.dryRun,\n noInstrument: parsed.noInstrument,\n json: parsed.json,\n })\n if (result.exitCode !== 0) process.exit(result.exitCode)\n return\n }\n\n // ── Query verbs (ADR-050) ────────────────────────────────────────────\n // The nine verbs mirror the MCP tool allowlist. Same multi-project\n // routing, same three-part response shape (summary + block + footer),\n // exit codes branch on misuse vs server error vs daemon-down.\n if (QUERY_VERBS.has(cmd)) {\n const code = await runQueryVerb(cmd, parsed)\n if (code !== 0) process.exit(code)\n return\n }\n\n // ── Bare-path orchestrator (ADR-073 §1) ──────────────────────────────\n // `neat <path>` — when the first positional doesn't match any verb but\n // resolves to a directory, hand the run off to the orchestrator. This is\n // the `npx neat.is <path>` shape from ADR-073: one command, end-to-end.\n const orchestratorCode = await tryOrchestrator(cmd, parsed)\n if (orchestratorCode !== null) {\n if (orchestratorCode !== 0) process.exit(orchestratorCode)\n return\n }\n\n console.error(`neat: unknown command \"${cmd}\"`)\n usage()\n process.exit(1)\n}\n\n// Returns null when the first positional doesn't resolve to a directory\n// (so the caller can fall through to the unknown-command error). Returns\n// an exit code when the orchestrator ran.\nasync function tryOrchestrator(cmd: string, parsed: ParsedArgs): Promise<number | null> {\n const scanPath = path.resolve(cmd)\n const stat = await fs.stat(scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) return null\n\n const projectExplicit = parsed.project !== null\n const projectName = projectExplicit ? (parsed.project as string) : path.basename(scanPath)\n const result = await runOrchestrator({\n scanPath,\n project: projectName,\n projectExplicit,\n noInstrument: parsed.noInstrument,\n noOpen: parsed.noOpen,\n yes: parsed.yes,\n })\n return result.exitCode\n}\n\n// ── Query verb dispatcher ──────────────────────────────────────────────\n\nexport const QUERY_VERBS: Set<string> = new Set([\n 'root-cause',\n 'blast-radius',\n 'dependencies',\n 'observed-dependencies',\n 'incidents',\n 'search',\n 'diff',\n 'stale-edges',\n 'policies',\n // Tenth verb (ADR-060) — amends ADR-050's locked allowlist of nine.\n 'divergences',\n])\n\n// ADR-050 #2: --project flag → NEAT_PROJECT env → undefined (server's\n// `default` slot). undefined keeps legacy unprefixed routes; explicit names\n// route through /projects/:project/...\nfunction resolveProjectFlag(parsed: ParsedArgs): string | undefined {\n if (parsed.project) return parsed.project\n const env = process.env.NEAT_PROJECT\n if (env && env.length > 0 && env !== DEFAULT_PROJECT) return env\n return undefined\n}\n\nexport async function runQueryVerb(cmd: string, parsed: ParsedArgs): Promise<number> {\n const baseUrl = process.env.NEAT_API_URL ?? 'http://localhost:8080'\n // ADR-073 §3 — read the bearer once and thread it into the single client\n // every verb shares, so no verb path can reach a secured daemon without it.\n const client = createHttpClient(baseUrl, resolveAuthToken())\n const project = resolveProjectFlag(parsed)\n const positional = parsed.positional\n\n // Per-verb arg/flag validation. Misuse exits 2 before any network call.\n let work: Promise<VerbResult>\n switch (cmd) {\n case 'root-cause': {\n const node = positional[0]\n if (!node) {\n console.error('neat root-cause: missing <node-id>')\n return 2\n }\n work = runRootCause(client, {\n errorNode: node,\n ...(parsed.errorId ? { errorId: parsed.errorId } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'blast-radius': {\n const node = positional[0]\n if (!node) {\n console.error('neat blast-radius: missing <node-id>')\n return 2\n }\n work = runBlastRadius(client, {\n nodeId: node,\n ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'dependencies': {\n const node = positional[0]\n if (!node) {\n console.error('neat dependencies: missing <node-id>')\n return 2\n }\n work = runDependencies(client, {\n nodeId: node,\n ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'observed-dependencies': {\n const node = positional[0]\n if (!node) {\n console.error('neat observed-dependencies: missing <node-id>')\n return 2\n }\n work = runObservedDependencies(client, {\n nodeId: node,\n ...(project ? { project } : {}),\n })\n break\n }\n case 'incidents': {\n // node-id is optional — bare `neat incidents` returns the global log.\n work = runIncidents(client, {\n ...(positional[0] ? { nodeId: positional[0] } : {}),\n ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'search': {\n const q = positional.join(' ').trim()\n if (!q) {\n console.error('neat search: missing <query>')\n return 2\n }\n work = runSearch(client, { query: q, ...(project ? { project } : {}) })\n break\n }\n case 'diff': {\n // --against names a snapshot file the core can resolve via\n // loadSnapshotForDiff. --since is reserved for a future date-range\n // mode (the contract lists it as `[--since <date>]`); for MVP, the\n // diff verb requires --against.\n const against = parsed.against ?? parsed.since\n if (!against) {\n console.error('neat diff: --against <snapshot-path> is required')\n return 2\n }\n work = runDiff(client, {\n againstSnapshot: against,\n ...(project ? { project } : {}),\n })\n break\n }\n case 'stale-edges': {\n work = runStaleEdges(client, {\n ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n ...(parsed.edgeType ? { edgeType: parsed.edgeType } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'policies': {\n let hypothetical: ReturnType<typeof JSON.parse> | undefined\n if (parsed.hypotheticalAction) {\n try {\n hypothetical = JSON.parse(parsed.hypotheticalAction)\n } catch (err) {\n console.error(\n `neat policies: --hypothetical-action must be valid JSON: ${(err as Error).message}`,\n )\n return 2\n }\n }\n work = runPolicies(client, {\n ...(parsed.node ? { nodeId: parsed.node } : {}),\n ...(hypothetical ? { hypotheticalAction: hypothetical } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n case 'divergences': {\n let typeFilter: DivergenceType[] | undefined\n if (parsed.type) {\n const parts = parsed.type\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0)\n const out: DivergenceType[] = []\n for (const p of parts) {\n const r = DivergenceTypeSchema.safeParse(p)\n if (!r.success) {\n console.error(\n `neat divergences: unknown --type \"${p}\". allowed: ${DivergenceTypeSchema.options.join(', ')}`,\n )\n return 2\n }\n out.push(r.data)\n }\n typeFilter = out\n }\n work = runDivergences(client, {\n ...(typeFilter ? { type: typeFilter } : {}),\n ...(parsed.minConfidence !== null ? { minConfidence: parsed.minConfidence } : {}),\n ...(parsed.node ? { node: parsed.node } : {}),\n ...(project ? { project } : {}),\n })\n break\n }\n default:\n // Unreachable — QUERY_VERBS gates the dispatch.\n console.error(`neat: unknown query verb \"${cmd}\"`)\n return 2\n }\n\n try {\n const result = await work\n if (parsed.json) process.stdout.write(formatJson(result) + '\\n')\n else process.stdout.write(formatHuman(result) + '\\n')\n return 0\n } catch (err) {\n // Server / transport errors land on stderr per ADR-050 #3 (stderr for\n // diagnostics, stdout for results — never mix). Exit code branches per\n // ADR-050 #4: 1 for HttpError, 3 for TransportError.\n if (err instanceof HttpError) {\n const detail = err.responseBody.length > 0 ? err.responseBody : err.message\n console.error(`neat ${cmd}: ${detail.trim()}`)\n } else if (err instanceof TransportError) {\n console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (NEAT_API_URL=${process.env.NEAT_API_URL ?? 'http://localhost:8080'})`)\n } else {\n console.error(`neat ${cmd}: ${(err as Error).message}`)\n }\n return exitCodeForError(err)\n }\n}\n\n// Only auto-run when invoked as the CLI entry point. Importing this module\n// from tests must not start the parser; otherwise vitest sees a stray\n// `process.exit` from `main()` running with no argv.\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/]cli\\.(?:cjs|js)$/.test(entry) || entry.endsWith('/cli') || entry.endsWith('/neat') || entry.endsWith('/neat.is')) {\n main().catch((err) => {\n console.error(err)\n process.exit(1)\n })\n}\n","import GraphDefault from 'graphology'\nimport type { MultiDirectedGraph as MDGType } from 'graphology'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\n\n// graphology ships as a CJS bundle that does `module.exports = Graph` with\n// the other constructors attached as properties (`Graph.MultiDirectedGraph =\n// ...`). cjs-module-lexer can't see through that attachment, so a named\n// import like `import { MultiDirectedGraph } from 'graphology'` fails under\n// strict Node ESM (Node 22+ via tsx in particular). Pull the constructor off\n// the default export instead — same shape under tsx and tsup-bundled output.\ntype MultiDirectedGraphCtor = typeof MDGType\nconst MultiDirectedGraph: MultiDirectedGraphCtor = (\n GraphDefault as unknown as { MultiDirectedGraph: MultiDirectedGraphCtor }\n).MultiDirectedGraph\n\n// Multi because two nodes can have edges of different types simultaneously\n// (e.g. CALLS and DEPENDS_ON between the same pair of services).\nexport type NeatGraph = MDGType<GraphNode, GraphEdge>\n\nexport const DEFAULT_PROJECT = 'default'\n\n// One graph per project. The map is the source of truth; getGraph() with no\n// arg or with 'default' hits the legacy single-project path so existing\n// callers keep working byte-for-byte (ADR-026).\nconst graphs = new Map<string, NeatGraph>()\n\nfunction makeGraph(): NeatGraph {\n return new MultiDirectedGraph<GraphNode, GraphEdge>({ allowSelfLoops: false })\n}\n\nexport function getGraph(project: string = DEFAULT_PROJECT): NeatGraph {\n let g = graphs.get(project)\n if (!g) {\n g = makeGraph()\n graphs.set(project, g)\n }\n return g\n}\n\nexport function hasProject(project: string): boolean {\n return graphs.has(project)\n}\n\nexport function listProjects(): string[] {\n return [...graphs.keys()].sort()\n}\n\n// Reset a single project, or all of them when the arg is omitted. Tests use\n// the no-arg form between cases; runtime never calls it.\nexport function resetGraph(project?: string): void {\n if (project === undefined) {\n graphs.clear()\n return\n }\n graphs.delete(project)\n}\n","export { extractFromDirectory, type ExtractResult } from './extract/index.js'\n","// Static-extraction pipeline. Phase order is load-bearing:\n// services → aliases → databases (+ compat) → configs → calls → infra → frontier promotion.\n//\n// Contract anchors (see /docs/contracts.md):\n// * Rule 1 — Every emitted edge carries Provenance.EXTRACTED from @neat.is/types.\n// * Rule 2 — EXTRACTED edges use the plain `${type}:src->tgt` id pattern.\n// Never write under the OBSERVED id pattern; that's ingest.ts's territory.\n// * Rule 5 — Nodes/edges constructed against schemas in @neat.is/types; no\n// local interface redefinitions in this tree.\n// * Rule 8 — No demo-name hardcoding. Driver names come from package.json\n// dependencies; engine names from compat.json via compatPairs().\n// * Rule 14 — ConfigNodes record file existence only; never the contents.\nimport type { NeatGraph } from '../graph.js'\nimport { DEFAULT_PROJECT } from '../graph.js'\nimport { promoteFrontierNodes } from '../ingest.js'\nimport { ensureCompatLoaded } from '../compat.js'\nimport { emitNeatEvent } from '../events.js'\nimport { addServiceNodes, discoverServices } from './services.js'\nimport { addServiceAliases } from './aliases.js'\nimport { addFiles } from './files.js'\nimport { addImports } from './imports.js'\nimport { addDatabasesAndCompat } from './databases/index.js'\nimport { addConfigNodes } from './configs.js'\nimport { addCallEdges } from './calls/index.js'\nimport { addInfra } from './infra/index.js'\nimport {\n drainExtractionErrors,\n writeExtractionErrors,\n drainDroppedExtracted,\n isRejectedLogEnabled,\n writeRejectedExtracted,\n type ExtractionError,\n type DroppedExtractedEdge,\n} from './errors.js'\nimport path from 'node:path'\nimport { retireExtractedEdgesByMissingFile } from './retire.js'\n\nexport interface ExtractResult {\n nodesAdded: number\n edgesAdded: number\n frontiersPromoted: number\n // ADR-065 — per-file extraction failures collected during the pass.\n // `extractionErrors` is the count; `errorEntries` is the drained list,\n // available for callers that want to surface per-file context. Both are\n // present on every pass (zero is observable as a positive signal).\n extractionErrors: number\n errorEntries: ExtractionError[]\n // #140 — count of EXTRACTED edges retired this pass because their\n // evidence.file no longer exists on disk. Zero on a clean pass; non-zero\n // means the snapshot was carrying ghosts from deleted source.\n ghostsRetired: number\n // ADR-066 — count of EXTRACTED candidates dropped at emit time because\n // their graded confidence fell below NEAT_EXTRACTED_PRECISION_FLOOR.\n // Always reported (zero is observable). Detail entries surface in\n // `droppedEntries` and route to rejected.ndjson when\n // NEAT_EXTRACTED_REJECTED_LOG=1.\n extractedDropped: number\n droppedEntries: DroppedExtractedEdge[]\n}\n\nexport interface ExtractOptions {\n // Post-extract policy trigger (ADR-043). Awaited after frontier promotion\n // so policies see the final post-pass graph state. Daemons wire this to\n // evaluateAllPolicies + PolicyViolationsLog.append.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n // Project tag for the extraction-complete event (ADR-051). Defaults to\n // DEFAULT_PROJECT when omitted.\n project?: string\n // ADR-065 — when set, drained extraction errors are appended to this\n // path as ndjson with `source: 'extract'`. Daemons / `neat init` /\n // `neat watch` wire this to `<projectDir>/neat-out/errors.ndjson`. When\n // omitted, errors are still drained and returned in the result, just\n // not persisted.\n errorsPath?: string\n}\n\nexport async function extractFromDirectory(\n graph: NeatGraph,\n scanPath: string,\n opts: ExtractOptions = {},\n): Promise<ExtractResult> {\n await ensureCompatLoaded()\n // Clear any stale entries from a prior pass (the producer-side sink is\n // process-local). Per ADR-065, every pass collects its own errors; we drain\n // again at the end to capture this pass's failures.\n drainExtractionErrors()\n\n const services = await discoverServices(scanPath)\n\n const phase1Nodes = addServiceNodes(graph, services)\n await addServiceAliases(graph, scanPath, services)\n const fileEnum = await addFiles(graph, services)\n const importGraph = await addImports(graph, services)\n const phase2 = await addDatabasesAndCompat(graph, services, scanPath)\n const phase3 = await addConfigNodes(graph, services, scanPath)\n const phase4 = await addCallEdges(graph, services)\n const phase5 = await addInfra(graph, scanPath, services)\n // #140 — drop EXTRACTED edges whose evidence.file no longer exists on disk.\n // Catches the deleted-file ghost case for the full-pass entry point\n // (init / daemon bootstrap). The edited-file case is handled per-mtime by\n // watch.ts's `retireEdgesByFile`. Service dirs are passed alongside scanPath\n // because CALLS-family producers store service-dir-relative paths while\n // configs / databases / infra store scanPath-relative.\n const ghostsRetired = retireExtractedEdgesByMissingFile(\n graph,\n scanPath,\n services.map((s) => s.dir),\n )\n const frontiersPromoted = promoteFrontierNodes(graph)\n\n // Post-extract policy trigger (ADR-043). Fires after frontier promotion so\n // policies see the post-pass graph (including any FRONTIER → OBSERVED edge\n // upgrades that just landed).\n if (opts.onPolicyTrigger) await opts.onPolicyTrigger(graph)\n\n // ADR-065 — drain the per-file extraction errors collected during the pass.\n // If a sidecar path was supplied, append the entries; otherwise return them\n // for the caller to surface.\n const errorEntries = drainExtractionErrors()\n if (opts.errorsPath && errorEntries.length > 0) {\n try {\n await writeExtractionErrors(errorEntries, opts.errorsPath)\n } catch (err) {\n console.warn(\n `[neat] failed to write extraction errors to ${opts.errorsPath}: ${(err as Error).message}`,\n )\n }\n }\n\n // ADR-066 — drain the precision-floor drops. Always returned; only\n // persisted when NEAT_EXTRACTED_REJECTED_LOG=1 (opt-in to keep the\n // default sidecar surface quiet).\n const droppedEntries = drainDroppedExtracted()\n if (\n isRejectedLogEnabled() &&\n opts.errorsPath &&\n droppedEntries.length > 0\n ) {\n // rejected.ndjson lives alongside errors.ndjson under neat-out/. Derive\n // from errorsPath rather than re-plumbing a new option.\n const rejectedPath = path.join(path.dirname(opts.errorsPath), 'rejected.ndjson')\n try {\n await writeRejectedExtracted(droppedEntries, rejectedPath)\n } catch (err) {\n console.warn(\n `[neat] failed to write rejected extracted edges to ${rejectedPath}: ${(err as Error).message}`,\n )\n }\n }\n\n const result: ExtractResult = {\n nodesAdded:\n phase1Nodes +\n fileEnum.nodesAdded +\n importGraph.nodesAdded +\n phase2.nodesAdded +\n phase3.nodesAdded +\n phase4.nodesAdded +\n phase5.nodesAdded,\n edgesAdded:\n fileEnum.edgesAdded +\n importGraph.edgesAdded +\n phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,\n frontiersPromoted,\n extractionErrors: errorEntries.length,\n errorEntries,\n ghostsRetired,\n extractedDropped: droppedEntries.length,\n droppedEntries,\n }\n\n // extraction-complete (ADR-051). fileCount is the number of services\n // discovered — the closest proxy we have for \"how much source did this\n // pass touch\" without a per-phase file accountant.\n emitNeatEvent({\n type: 'extraction-complete',\n project: opts.project ?? DEFAULT_PROJECT,\n payload: {\n project: opts.project ?? DEFAULT_PROJECT,\n fileCount: services.length,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n },\n })\n\n return result\n}\n","import { promises as fs, existsSync, readFileSync } from 'node:fs'\nimport path from 'node:path'\nimport * as sourceMapJs from 'source-map-js'\nimport type {\n DatabaseNode,\n ErrorEvent,\n FileNode,\n FrontierNode,\n GraphEdge,\n GraphNode,\n Policy,\n ServiceNode,\n StaleEvent,\n} from '@neat.is/types'\nimport type { PersistedGraph } from './persist.js'\nimport type { EvaluationContext as PolicyEvaluationContext } from './policy.js'\nimport { canPromoteFrontier } from './policy.js'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForObservedSignal,\n databaseId,\n extractedEdgeId,\n fileId,\n frontierId,\n inferredEdgeId,\n observedEdgeId,\n serviceId,\n type EdgeTypeValue,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport type { ParsedSpan } from './otel.js'\nimport { emitNeatEvent } from './events.js'\n\n// Maps OTel spans to graph signal:\n// * Cross-service span → upsert CALLS edge.\n// * Database span (db.system attr present) → upsert CONNECTS_TO edge to a\n// DatabaseNode resolved by host.\n// * Span with status.code === 2 → ErrorEvent appended to errors.ndjson.\n//\n// Contract anchors (see /docs/contracts.md):\n// * Rule 1 — Provenance: every edge here carries Provenance.X from @neat.is/types.\n// * Rule 2 — Coexistence: OBSERVED edges live alongside EXTRACTED ones with a\n// distinct id pattern (`${type}:OBSERVED:src->tgt`). Never write OBSERVED\n// under the EXTRACTED id; that erases the gap NEAT exists to surface.\n// * Rule 4 — Per-edge-type staleness (ADR-024): STALE_THRESHOLDS_BY_EDGE_TYPE\n// governs decay; never hardcode a flat 24h threshold.\n// * Rule 8 — No demo names: derive driver/engine identifiers from node\n// properties, not literals.\n\nexport interface IngestContext {\n graph: NeatGraph\n errorsPath: string\n // Absolute scan root the daemon is watching for this project. When set, a\n // runtime `code.filepath` is made service-root-relative against it before the\n // FileNode is keyed (file-awareness.md §4) — the service's absolute root is\n // `scanPath/<repoPath>`, which recovers `dist/foo.js` even for a single-\n // package service whose `repoPath` is empty (issue #430). Omitted by ad-hoc\n // callers and most tests, which rely on the repoPath-segment anchor instead.\n scanPath?: string\n // Project name for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT\n // when omitted — keeps single-project tests / scripts wire-compatible.\n project?: string\n now?: () => number\n // Set to false when the receiver already wrote the ErrorEvent synchronously\n // (production daemons via watch.ts wire this). When true or omitted, handleSpan\n // appends the ErrorEvent itself — the path used by ad-hoc scripts and tests\n // that don't go through buildOtelReceiver. ADR-033 §Error events.\n writeErrorEventInline?: boolean\n // Post-mutation policy trigger (ADR-043). Fires after handleSpan finishes\n // and the queue is drained. Daemons wire this to evaluateAllPolicies +\n // PolicyViolationsLog.append. Ad-hoc callers leave it undefined; their tests\n // don't need policy side effects.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n}\n\nconst HOUR_MS = 60 * 60 * 1000\nconst DAY_MS = 24 * HOUR_MS\n\n// Per-edge-type stale thresholds. HTTP CALLS at 24h is meaningless because\n// healthy traffic recurs in seconds; infra DEPENDS_ON is the opposite — a\n// docker-compose service can sit idle overnight without anything being wrong.\n// Override via NEAT_STALE_THRESHOLDS (JSON, ms-per-edge-type).\nconst DEFAULT_STALE_THRESHOLDS: Record<string, number> = {\n CALLS: HOUR_MS,\n CONNECTS_TO: 4 * HOUR_MS,\n PUBLISHES_TO: 4 * HOUR_MS,\n CONSUMES_FROM: 4 * HOUR_MS,\n DEPENDS_ON: DAY_MS,\n CONFIGURED_BY: DAY_MS,\n RUNS_ON: DAY_MS,\n}\n// Fallback for any edge type not in the map (forward compat — adding a new\n// EdgeType shouldn't break staleness sweeps).\nconst FALLBACK_STALE_THRESHOLD_MS = DAY_MS\n\nfunction loadStaleThresholdsFromEnv(): Record<string, number> {\n const raw = process.env.NEAT_STALE_THRESHOLDS\n if (!raw) return DEFAULT_STALE_THRESHOLDS\n try {\n const overrides = JSON.parse(raw) as Record<string, unknown>\n const merged = { ...DEFAULT_STALE_THRESHOLDS }\n for (const [k, v] of Object.entries(overrides)) {\n if (typeof v === 'number' && Number.isFinite(v) && v >= 0) merged[k] = v\n }\n return merged\n } catch (err) {\n console.warn(\n `[neat] NEAT_STALE_THRESHOLDS could not be parsed (${(err as Error).message}); using defaults`,\n )\n return DEFAULT_STALE_THRESHOLDS\n }\n}\n\nexport function thresholdForEdgeType(\n edgeType: string,\n overrides?: Record<string, number>,\n): number {\n const map = overrides ?? loadStaleThresholdsFromEnv()\n return map[edgeType] ?? FALLBACK_STALE_THRESHOLD_MS\n}\n\nfunction nowIso(ctx: IngestContext): string {\n return new Date(ctx.now ? ctx.now() : Date.now()).toISOString()\n}\n\n// One-time-per-session-per-project warning for spans whose resource omits\n// `service.name`. The OTel spec requires SDKs to set it; customised exporters\n// occasionally don't. Routing the span to `service:unidentified` keeps\n// diagnostic visibility intact (silent drop hides a real SDK misconfiguration);\n// the warning gives an operator one line of stderr per project to act on.\n// See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n// is missing.\nconst unidentifiedWarnedProjects = new Set<string>()\nfunction warnUnidentifiedSpan(project: string): void {\n if (unidentifiedWarnedProjects.has(project)) return\n unidentifiedWarnedProjects.add(project)\n console.warn(\n `[neatd] span lacked service.name; routed to 'unidentified' in project ${project}; check your OTel SDK config.`,\n )\n}\n\n// Test seam — production code never calls this. Tests that exercise the\n// once-per-session contract reset between cases so each assertion sees a\n// fresh warned-set.\nexport function resetUnidentifiedSpanWarnings(): void {\n unidentifiedWarnedProjects.clear()\n}\n\n// One-time-per-session-per-service audit for a compiled `dist/...js` call site\n// that carried no adjacent source map (file-awareness.md §4 + §6). Without a\n// map, ingest can't reconcile the observed dist file to the static `src/...ts`\n// the extractor parsed — the dist path is the honest answer, never a fabricated\n// src path. The leak this surfaces (issue #430) was hiding behind an absolute\n// path prefix; once the path is service-root-relative the mismatch is legible,\n// and this line tells the operator how to close it.\nconst noSourceMapWarnedServices = new Set<string>()\nfunction warnNoSourceMaps(serviceName: string): void {\n if (noSourceMapWarnedServices.has(serviceName)) return\n noSourceMapWarnedServices.add(serviceName)\n console.warn(\n `[neat] ${serviceName}: no .map files found under dist/; observed file edges will land on dist paths, not src. Set sourceMap: true in tsconfig to enable file-level reconciliation.`,\n )\n}\n\n// Test seam — mirrors resetUnidentifiedSpanWarnings for the once-per-service\n// audit above.\nexport function resetNoSourceMapWarnings(): void {\n noSourceMapWarnedServices.clear()\n}\n\nfunction pickAttr(span: ParsedSpan, ...keys: string[]): string | undefined {\n for (const k of keys) {\n const v = span.attributes[k]\n if (typeof v === 'string' && v.length > 0) return v\n }\n return undefined\n}\n\nfunction hostFromUrl(u: string | undefined): string | undefined {\n if (!u) return undefined\n try {\n return new URL(u).hostname\n } catch {\n return undefined\n }\n}\n\n// OTel HTTP/db semconv has gone through several names for \"the host on the\n// other end of this call.\" Try the modern ones first, fall back to the legacy\n// ones, then last resort parse out of a full URL.\nfunction pickAddress(span: ParsedSpan): string | undefined {\n return (\n pickAttr(span, 'server.address', 'net.peer.name', 'net.host.name') ??\n hostFromUrl(pickAttr(span, 'url.full', 'http.url'))\n )\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Call-site capture (file-awareness.md §4)\n//\n// The injected SpanProcessor sets `code.filepath` / `code.lineno` /\n// `code.function` on CLIENT/PRODUCER spans — the exact OTel attribute names,\n// written by the emit template (installers/templates.ts) and read here. The\n// two sites are cross-referenced so the names can't drift. When present, an\n// OBSERVED relationship originates from the file rather than the service.\n// SERVER spans and the callee side carry no call site and stay service-level;\n// evidence is never fabricated (§6).\nconst CODE_FILEPATH_ATTR = 'code.filepath'\nconst CODE_LINENO_ATTR = 'code.lineno'\nconst CODE_FUNCTION_ATTR = 'code.function'\n\nfunction toPosix(p: string): string {\n return p.split('\\\\').join('/')\n}\n\nfunction languageForExt(relPath: string): string | undefined {\n const dot = relPath.lastIndexOf('.')\n if (dot === -1) return undefined\n switch (relPath.slice(dot).toLowerCase()) {\n case '.py':\n return 'python'\n case '.ts':\n case '.tsx':\n return 'typescript'\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return 'javascript'\n default:\n return undefined\n }\n}\n\n// Join the runtime `code.filepath` against the service root so the OBSERVED\n// relPath lines up with the EXTRACTED service-relative path (file-awareness.md\n// §4 + §7). ServiceNode.repoPath is the scanPath-relative package dir; its\n// segments appear inside the absolute runtime path, so anchoring on it recovers\n// the package-relative tail. With no usable anchor, the real runtime path is\n// returned in a relative-looking form — honest, even if it doesn't align with a\n// static src path. Never fabricated.\nfunction relPathForRuntimeFile(\n filepath: string,\n serviceNode?: ServiceNode,\n scanPath?: string,\n): string | null {\n let p = toPosix(filepath).replace(/^file:\\/\\//, '')\n // When ingest knows the absolute scan root, the service's absolute root is\n // `scanPath/<repoPath>`. Stripping it directly recovers the service-relative\n // tail (`dist/foo.js`) even for a single-package service whose `repoPath` is\n // empty — the segment anchor below has nothing to grab in that case, so the\n // absolute path used to leak into the FileNode key (issue #430).\n if (scanPath && scanPath.length > 0) {\n const absRoot = toPosix(path.resolve(scanPath, serviceNode?.repoPath ?? ''))\n const anchor = absRoot.endsWith('/') ? absRoot : `${absRoot}/`\n if (p.startsWith(anchor)) return p.slice(anchor.length)\n }\n const root = serviceNode?.repoPath\n if (root && root !== '.' && root.length > 0) {\n const rootPosix = toPosix(root)\n const anchor = `/${rootPosix}/`\n const idx = p.lastIndexOf(anchor)\n if (idx !== -1) return p.slice(idx + anchor.length)\n const base = rootPosix.split('/').filter(Boolean).pop()\n if (base) {\n const baseAnchor = `/${base}/`\n const bidx = p.lastIndexOf(baseAnchor)\n if (bidx !== -1) return p.slice(bidx + baseAnchor.length)\n }\n }\n p = p.replace(/^[A-Za-z]:/, '').replace(/^\\/+/, '')\n return p.length > 0 ? p : null\n}\n\ninterface CallSite {\n relPath: string\n line?: number\n fn?: string\n // The service-relative dist path the call site was captured on, when ingest\n // resolved it through a source map to a different (source) `relPath`\n // (file-awareness.md §4). Surfaces as FileNode.originalPath. Absent when the\n // captured frame was already source-grained.\n originalRelPath?: string\n}\n\n// dist→src source-map resolution (file-awareness.md §4). A runtime call site in\n// a compiled `dist/...js` is resolved through a disk-adjacent `.map` to the\n// original `src/...ts`, so an OBSERVED edge lands on the source file an agent\n// can open. Same-host only — when the daemon's filesystem doesn't carry the map\n// (a service that ran on a different machine) the dist frame is kept, honestly,\n// never fabricated (§6). Each dist file is read from disk once: a present map\n// caches its consumer, an absent one caches `null`. Synchronous reads keep\n// callSiteFromSpan synchronous; the cost is amortised across a file's spans.\nconst sourceMapCache = new Map<\n string,\n { consumer: sourceMapJs.SourceMapConsumer; dir: string } | null\n>()\n\ninterface ResolvedSrc {\n filepath: string\n line?: number\n}\n\nfunction resolveDistToSrc(absFilepath: string, line?: number): ResolvedSrc | null {\n if (!absFilepath.endsWith('.js')) return null\n let entry = sourceMapCache.get(absFilepath)\n if (entry === undefined) {\n entry = null\n const mapPath = `${absFilepath}.map`\n try {\n if (existsSync(mapPath)) {\n const raw = JSON.parse(readFileSync(mapPath, 'utf8')) as unknown\n const consumer = new sourceMapJs.SourceMapConsumer(raw as never)\n entry = { consumer, dir: path.dirname(mapPath) }\n }\n } catch {\n entry = null\n }\n sourceMapCache.set(absFilepath, entry)\n }\n if (!entry) return null\n try {\n const pos = entry.consumer.originalPositionFor({\n line: line !== undefined && Number.isFinite(line) ? line : 1,\n column: 0,\n })\n if (!pos || !pos.source) return null\n const root = entry.consumer.sourceRoot ?? ''\n const resolved = path.resolve(entry.dir, root, pos.source)\n return { filepath: resolved, ...(pos.line ? { line: pos.line } : {}) }\n } catch {\n return null\n }\n}\n\n// Read the call-site attributes off a span. Returns null when the span carries\n// no `code.filepath` (SERVER spans, un-instrumented peers, callee side) so the\n// caller falls back to a service-level edge.\nfunction callSiteFromSpan(\n span: ParsedSpan,\n serviceNode?: ServiceNode,\n scanPath?: string,\n): CallSite | null {\n const filepath = span.attributes[CODE_FILEPATH_ATTR]\n if (typeof filepath !== 'string' || filepath.length === 0) return null\n const linenoRaw = span.attributes[CODE_LINENO_ATTR]\n let line =\n typeof linenoRaw === 'number' && Number.isFinite(linenoRaw) ? linenoRaw : undefined\n // Resolve a compiled dist frame to its source before computing the service-\n // relative path, so the FileNode lands on the original `src/...ts`.\n const abs = toPosix(filepath).replace(/^file:\\/\\//, '')\n const resolved = resolveDistToSrc(abs, line)\n let effectivePath = filepath\n let originalRelPath: string | undefined\n if (resolved) {\n originalRelPath = relPathForRuntimeFile(filepath, serviceNode, scanPath) ?? undefined\n effectivePath = resolved.filepath\n if (resolved.line !== undefined) line = resolved.line\n }\n const relPath = relPathForRuntimeFile(effectivePath, serviceNode, scanPath)\n if (!relPath) return null\n // A compiled `dist/...js` call site that didn't resolve through a map keeps\n // the (honest) dist path. Surface the absence once per service so the\n // operator can enable source maps and recover src-level reconciliation\n // (file-awareness.md §4 + §6, issue #430).\n if (!resolved && abs.endsWith('.js') && relPath.startsWith('dist/') && serviceNode?.name) {\n warnNoSourceMaps(serviceNode.name)\n }\n const fnRaw = span.attributes[CODE_FUNCTION_ATTR]\n const fn = typeof fnRaw === 'string' && fnRaw.length > 0 ? fnRaw : undefined\n return {\n relPath,\n ...(line !== undefined ? { line } : {}),\n ...(fn ? { fn } : {}),\n ...(originalRelPath && originalRelPath !== relPath ? { originalRelPath } : {}),\n }\n}\n\n// Ensure the FileNode for an observed call site and the owning service's\n// OBSERVED `CONTAINS` edge both exist, returning the FileNode id so the caller\n// can originate the relationship from it (file-awareness.md §1–2 + §4). The\n// CONTAINS edge carries no `lastObserved` — structural ownership doesn't go\n// STALE when traffic quiets (markStaleEdges skips edges without lastObserved),\n// and divergence detection skips CONTAINS so an OTel-only file node doesn't\n// surface as a missing-extracted finding.\nfunction ensureObservedFileNode(\n graph: NeatGraph,\n serviceName: string,\n serviceNodeId: string,\n callSite: CallSite,\n): string {\n const fileNodeId = fileId(serviceName, callSite.relPath)\n if (!graph.hasNode(fileNodeId)) {\n const language = languageForExt(callSite.relPath)\n const node: FileNode = {\n id: fileNodeId,\n type: NodeType.FileNode,\n service: serviceName,\n path: callSite.relPath,\n ...(language ? { language } : {}),\n ...(callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {}),\n discoveredVia: 'otel',\n }\n graph.addNode(fileNodeId, node)\n }\n const containsId = makeObservedEdgeId(EdgeType.CONTAINS, serviceNodeId, fileNodeId)\n if (!graph.hasEdge(containsId)) {\n const edge: GraphEdge = {\n id: containsId,\n source: serviceNodeId,\n target: fileNodeId,\n type: EdgeType.CONTAINS,\n provenance: Provenance.OBSERVED,\n }\n graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n }\n return fileNodeId\n}\n\n// Edge id helpers live in @neat.is/types/identity.ts (ADR-029). The local\n// signatures below preserve the (type, source, target) argument order ingest.ts\n// has used historically while delegating to the canonical wire-format helpers.\nfunction makeObservedEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n return observedEdgeId(source, target, type)\n}\n\nfunction makeInferredEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n return inferredEdgeId(source, target, type)\n}\n\nconst INFERRED_CONFIDENCE = 0.6\nconst STITCH_MAX_DEPTH = 2\n\n// OTLP-wire SpanKind values. The receiver decodes the raw wire integer onto\n// `ParsedSpan.kind` (otel.ts), and the wire enum is offset by one from the\n// `@opentelemetry/api` SpanKind the SDK uses in-process — UNSPECIFIED 0,\n// INTERNAL 1, SERVER 2, CLIENT 3, PRODUCER 4, CONSUMER 5. So we must NOT import\n// `@opentelemetry/api` here: its CLIENT is 2 (= wire SERVER) and PRODUCER is 3\n// (= wire CLIENT), which would gate the wrong kinds. Cross-referenced with the\n// wire fixtures in otel.test.ts (kind 2 = SERVER, kind 3 = CLIENT) and the\n// CLIENT call-site spans in ingest.test.ts (kind 3).\nconst WIRE_SPAN_KIND_CLIENT = 3\nconst WIRE_SPAN_KIND_PRODUCER = 4\n\n// An OBSERVED edge originates from the caller/producer side of a call. CLIENT\n// and PRODUCER spans are that side; INTERNAL / SERVER / CONSUMER are not — a\n// SERVER span is the callee, and its edge is minted from its parent CLIENT via\n// the parent-span fallback (the mirror image of CLIENT+SERVER, and of\n// PRODUCER+CONSUMER for queues). Without this gate every INTERNAL span that\n// happens to carry a peer address — e.g. a `tcp.connect` / `tls.connect` to an\n// AWS endpoint — mints a spurious service-level edge (issue #429), because no\n// §4 capture layer stamps `code.*` on INTERNAL spans.\n//\n// A span that reports no kind (undefined) or UNSPECIFIED (0) carries no\n// caller/callee signal, so it falls back to the historical unconditional\n// behavior — hand-built and legacy producers keep minting. The leak this gates\n// is always an explicitly-kinded INTERNAL span.\nfunction spanMintsObservedEdge(kind: number | undefined): boolean {\n if (kind === undefined || kind === 0) return true\n return kind === WIRE_SPAN_KIND_CLIENT || kind === WIRE_SPAN_KIND_PRODUCER\n}\n\n// Parent-span TTL cache (ADR-033). Address-based peer resolution (server.address /\n// net.peer.name / url.full) misses non-HTTP RPCs and any span with an opaque\n// peer. The cache stores each span's service keyed by `${traceId}:${spanId}` so\n// a child span whose address resolution fails can fall back to its parent's\n// service, identifying a cross-service CALLS edge from parent → current.\n//\n// Bounded size + TTL — out-of-order arrival (child before parent) drops the\n// child rather than buffering. We accept that loss because the cache is best-\n// effort: for every cross-service call, the CLIENT span on the caller side\n// covers the same edge via address-based resolution, so missing one direction\n// is recoverable.\nconst PARENT_SPAN_CACHE_SIZE = 10_000\nconst PARENT_SPAN_CACHE_TTL_MS = 5 * 60 * 1000\n\ninterface ParentSpanCacheEntry {\n service: string\n // Env discriminator from the parent span (ADR-074 §2). The parent-span\n // fallback in handleSpan uses this so the auto-created parent ServiceNode\n // lands on the same env-tagged id the OTel emitter advertised.\n env: string\n expiresAt: number\n}\n\nconst parentSpanCache = new Map<string, ParentSpanCacheEntry>()\n\nfunction parentSpanKey(traceId: string, spanId: string): string {\n return `${traceId}:${spanId}`\n}\n\nfunction cacheSpanService(span: ParsedSpan, now: number): void {\n if (!span.traceId || !span.spanId) return\n const key = parentSpanKey(span.traceId, span.spanId)\n // Map preserves insertion order, so deleting + re-inserting bumps an entry to\n // the back. Eviction is \"drop oldest\" once size exceeds the cap.\n parentSpanCache.delete(key)\n parentSpanCache.set(key, {\n service: span.service,\n env: span.env ?? 'unknown',\n expiresAt: now + PARENT_SPAN_CACHE_TTL_MS,\n })\n while (parentSpanCache.size > PARENT_SPAN_CACHE_SIZE) {\n const oldest = parentSpanCache.keys().next().value\n if (!oldest) break\n parentSpanCache.delete(oldest)\n }\n}\n\nfunction lookupParentSpan(\n traceId: string,\n parentSpanId: string,\n now: number,\n): { service: string; env: string } | null {\n const entry = parentSpanCache.get(parentSpanKey(traceId, parentSpanId))\n if (!entry) return null\n if (entry.expiresAt <= now) {\n parentSpanCache.delete(parentSpanKey(traceId, parentSpanId))\n return null\n }\n return { service: entry.service, env: entry.env }\n}\n\n// Test seam: lets unit tests start from a clean slate.\nexport function resetParentSpanCache(): void {\n parentSpanCache.clear()\n}\n\n// Peer host → ServiceNode id resolution. With env-dimension (ADR-074 §2),\n// the same `name` may live across multiple ServiceNodes — one per env, plus\n// the env-less form from static extraction. When `env` is known (the source\n// span's env), prefer a same-env match; fall back to the env-less node so\n// EXTRACTED edges from static analysis remain reachable until OBSERVED\n// traffic from the same env promotes them.\n//\n// Match passes:\n// 1. Exact id lookup for `(host, env)` — `serviceId(host, env)`.\n// 2. Exact id lookup for env-less `serviceId(host)`.\n// 3. Name/alias scan across every ServiceNode, preferring same-env then\n// env-less then any other env.\nfunction resolveServiceId(\n graph: NeatGraph,\n host: string,\n env: string,\n): string | null {\n const envTagged = serviceId(host, env)\n if (graph.hasNode(envTagged)) return envTagged\n const envLess = serviceId(host)\n if (envLess !== envTagged && graph.hasNode(envLess)) return envLess\n\n let sameEnv: string | null = null\n let envLessMatch: string | null = null\n let anyMatch: string | null = null\n graph.forEachNode((id, attrs) => {\n if (sameEnv) return\n const a = attrs as ServiceNode & { type?: string }\n if (a.type !== NodeType.ServiceNode) return\n const matchesByName = a.name === host\n const matchesByAlias = a.aliases ? a.aliases.includes(host) : false\n if (!matchesByName && !matchesByAlias) return\n const nodeEnv = a.env ?? 'unknown'\n if (nodeEnv === env) {\n sameEnv = id\n return\n }\n if (nodeEnv === 'unknown' && !envLessMatch) envLessMatch = id\n else if (!anyMatch) anyMatch = id\n })\n return sameEnv ?? envLessMatch ?? anyMatch\n}\n\nexport function frontierIdFor(host: string): string {\n return frontierId(host)\n}\n\n// Auto-create a minimal ServiceNode for span.service when no such node exists.\n// Used at the top of handleSpan so subsequent edge upserts always have endpoints\n// — without it, OBSERVED edges silently drop for any service the static\n// extractor hasn't reached yet (and never reaches at all in OTel-only setups).\n// `language: 'unknown'` is the contract's specified placeholder (ADR-033). When\n// static extraction later produces a ServiceNode at the same id, addServiceNodes\n// merges and flips discoveredVia to 'merged' rather than overwriting.\nfunction ensureServiceNode(\n graph: NeatGraph,\n serviceName: string,\n env: string,\n): string {\n const id = serviceId(serviceName, env)\n if (graph.hasNode(id)) return id\n const node: ServiceNode = {\n id,\n type: NodeType.ServiceNode,\n name: serviceName,\n language: 'unknown',\n discoveredVia: 'otel',\n ...(env !== 'unknown' ? { env } : {}),\n }\n graph.addNode(id, node)\n return id\n}\n\n// Same shape for unseen db.system + host pairs. Engine comes off the OTel\n// attribute as a string per Rule 8 — no hardcoded engine list. compatibleDrivers\n// is empty until static extraction merges in the matrix-derived drivers.\nfunction ensureDatabaseNode(graph: NeatGraph, host: string, engine: string): string {\n const id = databaseId(host)\n if (graph.hasNode(id)) return id\n const node: DatabaseNode = {\n id,\n type: NodeType.DatabaseNode,\n name: host,\n engine,\n engineVersion: 'unknown',\n compatibleDrivers: [],\n host,\n discoveredVia: 'otel',\n }\n graph.addNode(id, node)\n return id\n}\n\nfunction ensureFrontierNode(graph: NeatGraph, host: string, ts: string): string {\n const id = frontierIdFor(host)\n if (graph.hasNode(id)) {\n const existing = graph.getNodeAttributes(id) as FrontierNode\n graph.replaceNodeAttributes(id, { ...existing, lastObserved: ts })\n return id\n }\n const node: FrontierNode = {\n id,\n type: NodeType.FrontierNode,\n name: host,\n host,\n firstObserved: ts,\n lastObserved: ts,\n }\n graph.addNode(id, node)\n return id\n}\n\ninterface UpsertResult {\n edge: GraphEdge\n created: boolean\n}\n\nfunction upsertObservedEdge(\n graph: NeatGraph,\n type: EdgeTypeValue,\n source: string,\n target: string,\n ts: string,\n isError = false,\n evidence?: { file: string; line?: number },\n): UpsertResult | null {\n if (!graph.hasNode(source) || !graph.hasNode(target)) return null\n\n const id = makeObservedEdgeId(type, source, target)\n if (graph.hasEdge(id)) {\n const existing = graph.getEdgeAttributes(id) as GraphEdge\n const newSpanCount = (existing.signal?.spanCount ?? existing.callCount ?? 0) + 1\n const newErrorCount = (existing.signal?.errorCount ?? 0) + (isError ? 1 : 0)\n const newSignal = {\n spanCount: newSpanCount,\n errorCount: newErrorCount,\n lastObservedAgeMs: 0,\n }\n // ADR-066 §2 — confidence grades from the signal block. PROV_RANK stays;\n // the grade reflects volume + recency + error ratio within the OBSERVED\n // tier.\n const updated: GraphEdge = {\n ...existing,\n provenance: Provenance.OBSERVED,\n lastObserved: ts,\n callCount: newSpanCount,\n signal: newSignal,\n confidence: confidenceForObservedSignal(newSignal),\n }\n graph.replaceEdgeAttributes(id, updated)\n return { edge: updated, created: false }\n }\n\n const signal = {\n spanCount: 1,\n errorCount: isError ? 1 : 0,\n lastObservedAgeMs: 0,\n }\n const edge: GraphEdge = {\n id,\n source,\n target,\n type,\n provenance: Provenance.OBSERVED,\n confidence: confidenceForObservedSignal(signal),\n lastObserved: ts,\n callCount: 1,\n signal,\n // Call-site evidence from span code.* semconv (file-awareness.md §4 + §6).\n // Only set when code.filepath was present on the span — never fabricated.\n ...(evidence ? { evidence } : {}),\n }\n graph.addEdgeWithKey(id, source, target, edge)\n return { edge, created: true }\n}\n\n// When a span errors, the system is exercising its dependencies right now even\n// if some of them aren't auto-instrumented (pg 7.4.0 in the demo, see ADR-014).\n// Walk EXTRACTED edges out from the erroring service for a couple of hops and\n// promote them to INFERRED twins so traversal can prefer them over the bare\n// static edges without claiming OBSERVED-grade certainty.\nfunction stitchTrace(graph: NeatGraph, sourceServiceId: string, ts: string): void {\n if (!graph.hasNode(sourceServiceId)) return\n\n const visited = new Set<string>([sourceServiceId])\n const queue: { nodeId: string; depth: number }[] = [{ nodeId: sourceServiceId, depth: 0 }]\n\n while (queue.length > 0) {\n const { nodeId, depth } = queue.shift()!\n if (depth >= STITCH_MAX_DEPTH) continue\n\n const outbound = graph.outboundEdges(nodeId)\n for (const edgeId of outbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) continue\n\n // OBSERVED twin already covers this hop with ground truth — no inference\n // needed (ADR-034). Stomping it with INFERRED erases the gap NEAT exists\n // to surface; skipping it keeps the OBSERVED edge as the authoritative\n // record and avoids cluttering the graph with a redundant INFERRED twin.\n if (graph.hasEdge(observedEdgeId(edge.source, edge.target, edge.type))) continue\n\n upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts)\n\n if (!visited.has(edge.target)) {\n visited.add(edge.target)\n queue.push({ nodeId: edge.target, depth: depth + 1 })\n }\n }\n }\n}\n\nfunction upsertInferredEdge(\n graph: NeatGraph,\n type: EdgeTypeValue,\n source: string,\n target: string,\n ts: string,\n): void {\n const id = makeInferredEdgeId(type, source, target)\n if (graph.hasEdge(id)) {\n const existing = graph.getEdgeAttributes(id) as GraphEdge\n const updated: GraphEdge = { ...existing, lastObserved: ts }\n graph.replaceEdgeAttributes(id, updated)\n return\n }\n\n const edge: GraphEdge = {\n id,\n source,\n target,\n type,\n provenance: Provenance.INFERRED,\n confidence: INFERRED_CONFIDENCE,\n lastObserved: ts,\n }\n graph.addEdgeWithKey(id, source, target, edge)\n}\n\nasync function appendErrorEvent(ctx: IngestContext, ev: ErrorEvent): Promise<void> {\n await fs.mkdir(path.dirname(ctx.errorsPath), { recursive: true })\n await fs.appendFile(ctx.errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\n}\n\n// Build the minimal ErrorEvent the receiver writes synchronously before\n// replying (ADR-033 §Error events, amended). affectedNode resolves to the\n// originating service because graph state isn't available at this point —\n// the queued handleSpan path may reach a more precise target later, but the\n// durable record is what the receiver writes here.\n//\n// errorMessage reads from the exception event's `exception.message` (OTel\n// semconv) so the incident surface shows the actual thrown error string.\n// When the span carries no exception event the field falls back to the\n// literal 'unknown error' rather than `span.name` — OTel HTTP server\n// instrumentation routinely populates `span.name` with the HTTP method,\n// which produces incidents that read 'GET' or 'POST' instead of the\n// underlying failure. `span.status.message` is intentionally out of the\n// chain for the same reason.\n// Span attributes pass through verbatim so consumers can read source\n// attribution (`code.filepath`, `code.lineno`, `code.function`) and other\n// SDK-emitted context without ingest enumerating every key it cares about.\n// Coerce span attributes to a JSON-safe shape — bigint values from the\n// parsed span (long ids, high-cardinality counters) become strings so the\n// passthrough record can be serialised to the ErrorEvent shape and round-\n// tripped through ErrorEventSchema. All other types pass through verbatim.\nfunction sanitizeAttributes(\n attrs: ParsedSpan['attributes'],\n): Record<string, string | number | boolean | null | string[] | number[] | boolean[]> {\n const out: Record<string, string | number | boolean | null | string[] | number[] | boolean[]> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v === 'bigint') out[k] = v.toString()\n else out[k] = v as string | number | boolean | null | string[] | number[] | boolean[]\n }\n return out\n}\n\nexport function buildErrorEventForReceiver(span: ParsedSpan): ErrorEvent | null {\n if (span.statusCode !== 2) return null\n const ts = span.startTimeIso ?? new Date().toISOString()\n const attrs = sanitizeAttributes(span.attributes)\n return {\n id: `${span.traceId}:${span.spanId}`,\n timestamp: ts,\n service: span.service,\n traceId: span.traceId,\n spanId: span.spanId,\n errorMessage: span.exception?.message ?? 'unknown error',\n ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n ...(span.exception?.stacktrace\n ? { exceptionStacktrace: span.exception.stacktrace }\n : {}),\n ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n affectedNode: serviceId(span.service, span.env),\n }\n}\n\n// Synchronous file-write helper bound to a receiver. The receiver awaits this\n// before replying, so a write failure surfaces as 500 → OTel SDK retries.\nexport function makeErrorSpanWriter(\n errorsPath: string,\n): (span: ParsedSpan) => Promise<void> {\n return async (span) => {\n const ev = buildErrorEventForReceiver(span)\n if (!ev) return\n await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n await fs.appendFile(errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\n }\n}\n\nexport async function handleSpan(ctx: IngestContext, span: ParsedSpan): Promise<void> {\n // lastObserved derives from the span's own startTime per ADR-033 — replayed\n // traces and out-of-order spans get a timestamp that reflects when the call\n // actually fired, not when the receiver received it. Wall-clock is only the\n // fallback for spans whose startTimeUnixNano is missing or unparseable.\n const ts = span.startTimeIso ?? nowIso(ctx)\n const nowMs = ctx.now ? ctx.now() : Date.now()\n // Env discriminator from `deployment.environment(.name)` (ADR-074 §2).\n // Older ParsedSpan producers may omit it — fall back to the literal\n // `'unknown'` so the env-less wire format is preserved on auto-creation.\n const env = span.env ?? 'unknown'\n // Issue #374 — spans whose resource omits `service.name` route to\n // `service:unidentified` in the URL-resolved project (the parser already\n // substitutes the fallback). One warning per project per session names\n // the project so an operator can fix the SDK config without grepping.\n if (span.resourceServiceNamePresent === false) {\n warnUnidentifiedSpan(ctx.project ?? DEFAULT_PROJECT)\n }\n // Auto-create a minimal ServiceNode for unseen span.service so OBSERVED\n // edges land instead of silently dropping. Static extraction merges richer\n // fields when it later finds the same id (ADR-033). The node is env-tagged\n // when the span carries an env signal.\n const sourceId = ensureServiceNode(ctx.graph, span.service, env)\n const isError = span.statusCode === 2\n // Stash this span in the parent-span cache so any later child whose address\n // resolution misses can still resolve the cross-service edge via parentSpanId.\n cacheSpanService(span, nowMs)\n\n // File-first OBSERVED origin (file-awareness.md §4). When the injected\n // SpanProcessor captured a call site on this outbound (CLIENT/PRODUCER) span,\n // the relationship originates from the file; without one it stays\n // service-level. `observedSource()` creates the FileNode + CONTAINS lazily so\n // they only land when an edge actually does — and never for the inbound\n // (SERVER) parent-fallback side, which carries no call site.\n const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId) as ServiceNode\n const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath)\n const observedSource = (): string =>\n callSite ? ensureObservedFileNode(ctx.graph, span.service, sourceId, callSite) : sourceId\n // Evidence for the OBSERVED edge — populated from the span's code.* semconv\n // when the call site resolved (file-awareness.md §4 + §6). Never fabricated:\n // absent call site → undefined evidence.\n const callSiteEvidence: { file: string; line?: number } | undefined = callSite\n ? { file: callSite.relPath, ...(callSite.line !== undefined ? { line: callSite.line } : {}) }\n : undefined\n\n let affectedNode = sourceId\n\n // Only the caller/producer side of a call mints an OBSERVED edge directly\n // (issue #429). INTERNAL / SERVER / CONSUMER spans don't: a SERVER/CONSUMER\n // span is the callee, and its edge is minted from its parent via the\n // parent-span fallback below (left ungated). Gating here keeps INTERNAL\n // connection spans (`tcp.connect` / `tls.connect` with a peer address) from\n // minting spurious service-level edges.\n const mintsFromCallerSide = spanMintsObservedEdge(span.kind)\n\n if (span.dbSystem) {\n // Database span — try to resolve the DatabaseNode by host.\n const host = pickAddress(span)\n if (mintsFromCallerSide && host) {\n // Auto-create a minimal DatabaseNode when this host hasn't been seen.\n // Engine comes off the OTel attribute as a string per Rule 8.\n ensureDatabaseNode(ctx.graph, host, span.dbSystem)\n const targetId = databaseId(host)\n const result = upsertObservedEdge(\n ctx.graph,\n EdgeType.CONNECTS_TO,\n observedSource(),\n targetId,\n ts,\n isError,\n callSiteEvidence,\n )\n if (result) affectedNode = targetId\n }\n } else {\n // Possibly a cross-service call. Resolve the peer; if it matches a known\n // ServiceNode, record an OBSERVED CALLS edge to the typed target. If it\n // matches nothing — pod IP, ingress hostname, AWS PrivateLink endpoint —\n // create a FrontierNode placeholder and record an OBSERVED edge to that\n // FrontierNode so the call carries the same provenance + signal-block +\n // graded confidence as any other OBSERVED edge (ADR-068). The target ref\n // identifies the node-type; provenance describes how the edge was learned.\n // promoteFrontierNodes (run by the extract orchestrator) rewrites the\n // target ref once a later round resolves the host; the edge's provenance\n // stays OBSERVED across promotion.\n const host = pickAddress(span)\n let resolvedViaAddress = false\n if (mintsFromCallerSide && host && host !== span.service) {\n const targetId = resolveServiceId(ctx.graph, host, env)\n if (targetId && targetId !== sourceId) {\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n observedSource(),\n targetId,\n ts,\n isError,\n callSiteEvidence,\n )\n affectedNode = targetId\n resolvedViaAddress = true\n } else if (!targetId) {\n const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts)\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n observedSource(),\n frontierNodeId,\n ts,\n isError,\n callSiteEvidence,\n )\n affectedNode = frontierNodeId\n resolvedViaAddress = true\n }\n }\n\n // Parent-span fallback (ADR-033): when address-based resolution didn't\n // produce an edge and the span has a parentSpanId we've cached, the\n // parent's service identifies the caller. The current span is the server\n // side of the call, so the edge direction is parent.service → current.\n // The cached entry carries the parent span's env, so the auto-created\n // parent ServiceNode lands on the env-tagged id the parent advertised.\n if (!resolvedViaAddress && span.parentSpanId) {\n const parent = lookupParentSpan(span.traceId, span.parentSpanId, nowMs)\n if (parent && parent.service !== span.service) {\n const parentId = ensureServiceNode(ctx.graph, parent.service, parent.env)\n upsertObservedEdge(\n ctx.graph,\n EdgeType.CALLS,\n parentId,\n sourceId,\n ts,\n isError,\n )\n }\n }\n }\n\n if (span.statusCode === 2) {\n stitchTrace(ctx.graph, sourceId, ts)\n // The durable ErrorEvent write moved to the receiver so the file write\n // happens synchronously before the 200 reply (ADR-033 §Error events,\n // amended). watch.ts wires makeErrorSpanWriter into onErrorSpanSync.\n // handleSpan still runs the in-graph error effects (stitchTrace above);\n // it just doesn't append to errors.ndjson anymore. ctx.errorsPath stays\n // for the optional opt-in path below — daemon-less callers (CLI tests,\n // ad-hoc scripts) that skip the receiver hook still get a write here.\n if (ctx.writeErrorEventInline !== false) {\n const attrs = sanitizeAttributes(span.attributes)\n const ev: ErrorEvent = {\n id: `${span.traceId}:${span.spanId}`,\n timestamp: ts,\n service: span.service,\n traceId: span.traceId,\n spanId: span.spanId,\n errorMessage: span.exception?.message ?? 'unknown error',\n ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n ...(span.exception?.stacktrace\n ? { exceptionStacktrace: span.exception.stacktrace }\n : {}),\n ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n affectedNode,\n }\n await appendErrorEvent(ctx, ev)\n }\n }\n void affectedNode\n\n // Post-ingest policy trigger (ADR-043). The hook is awaited so failures\n // surface; daemons wrap it in a try/catch that logs without throwing.\n if (ctx.onPolicyTrigger) await ctx.onPolicyTrigger(ctx.graph)\n}\n\nexport { stitchTrace }\n\n// Promote any frontier:<host> placeholder whose host matches an alias on a\n// real ServiceNode: re-link inbound/outbound edges to the service, then drop\n// the placeholder. Returns the count of nodes promoted, for tests + logs.\n//\n// Called at the end of every extraction round. Static rounds are when new\n// aliases land (compose names, k8s metadata.name, Dockerfile labels), so\n// running it there picks up the case the issue describes: ingest fills in a\n// frontier when traffic arrives for an unknown host, and the next extraction\n// round resolves it.\n// Optional gate for block-action policies (ADR-044). When `policies` is\n// non-empty, each candidate FrontierNode runs through `canPromoteFrontier`\n// before its incident edges are rewired. Block-action policies that fire on\n// the frontier veto the promotion — the FrontierNode persists; the next\n// extract pass tries again.\nexport interface PromoteFrontierOptions {\n policies?: Policy[]\n policyCtx?: PolicyEvaluationContext\n}\n\nexport function promoteFrontierNodes(\n graph: NeatGraph,\n opts: PromoteFrontierOptions = {},\n): number {\n const aliasIndex = new Map<string, string>()\n graph.forEachNode((id, attrs) => {\n const a = attrs as ServiceNode & { type?: string }\n if (a.type !== NodeType.ServiceNode) return\n aliasIndex.set(a.name, id)\n if (a.aliases) {\n for (const alias of a.aliases) aliasIndex.set(alias, id)\n }\n })\n\n const toPromote: { frontierId: string; serviceId: string }[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as FrontierNode & { type?: string }\n if (a.type !== NodeType.FrontierNode) return\n const target = aliasIndex.get(a.host)\n if (!target) return\n if (target === id) return\n toPromote.push({ frontierId: id, serviceId: target })\n })\n\n let promoted = 0\n for (const { frontierId, serviceId } of toPromote) {\n if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {\n const gate = canPromoteFrontier(graph, frontierId, opts.policies, opts.policyCtx)\n if (!gate.allowed) {\n // Block-action policy fired on this frontier — skip the rewire and\n // leave the FrontierNode in place. Violations already surfaced via\n // the policy log on the same evaluation pass.\n continue\n }\n }\n rewireFrontierEdges(graph, frontierId, serviceId)\n graph.dropNode(frontierId)\n promoted++\n }\n return promoted\n}\n\nfunction rewireFrontierEdges(graph: NeatGraph, frontierId: string, serviceId: string): void {\n const inbound = [...graph.inboundEdges(frontierId)]\n const outbound = [...graph.outboundEdges(frontierId)]\n\n for (const edgeId of inbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n rebuildEdge(graph, edge, edge.source, serviceId, edgeId)\n }\n for (const edgeId of outbound) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n rebuildEdge(graph, edge, serviceId, edge.target, edgeId)\n }\n}\n\nfunction rebuildEdge(\n graph: NeatGraph,\n edge: GraphEdge,\n newSource: string,\n newTarget: string,\n oldEdgeId: string,\n): void {\n graph.dropEdge(oldEdgeId)\n // ADR-068 — promotion rewrites the target ref; provenance carries forward.\n // An OBSERVED edge to a FrontierNode promotes to an OBSERVED edge to the\n // matched typed node; an INFERRED edge stays INFERRED; etc.\n const newId =\n edge.provenance === Provenance.OBSERVED\n ? observedEdgeId(newSource, newTarget, edge.type)\n : edge.provenance === Provenance.INFERRED\n ? inferredEdgeId(newSource, newTarget, edge.type)\n : extractedEdgeId(newSource, newTarget, edge.type)\n\n if (graph.hasEdge(newId)) {\n const existing = graph.getEdgeAttributes(newId) as GraphEdge\n const merged: GraphEdge = {\n ...existing,\n callCount: (existing.callCount ?? 0) + (edge.callCount ?? 0),\n lastObserved: pickLater(existing.lastObserved, edge.lastObserved),\n }\n graph.replaceEdgeAttributes(newId, merged)\n return\n }\n\n const rebuilt: GraphEdge = {\n ...edge,\n id: newId,\n source: newSource,\n target: newTarget,\n }\n graph.addEdgeWithKey(newId, newSource, newTarget, rebuilt)\n}\n\nfunction pickLater(a: string | undefined, b: string | undefined): string | undefined {\n if (!a) return b\n if (!b) return a\n return new Date(a).getTime() >= new Date(b).getTime() ? a : b\n}\n\nexport function makeSpanHandler(ctx: IngestContext): (span: ParsedSpan) => Promise<void> {\n return (span) => handleSpan(ctx, span)\n}\n\nexport type { StaleEvent }\n\nexport interface MarkStaleOptions {\n // Per-edge-type override map. Defaults to DEFAULT_STALE_THRESHOLDS, merged\n // with NEAT_STALE_THRESHOLDS if the env var is set.\n thresholds?: Record<string, number>\n now?: number\n // ndjson path. When set, every OBSERVED → STALE transition appends one\n // line. Skipped if undefined — tests and embedded use cases don't need a\n // log.\n staleEventsPath?: string\n // Project tag for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT.\n project?: string\n}\n\n// Demote OBSERVED edges that haven't been seen in a while. Per-edge-type\n// thresholds: HTTP CALLS go stale fast; infra DEPENDS_ON is patient. Returns\n// the count of demotions and the events appended to the log.\nexport async function markStaleEdges(\n graph: NeatGraph,\n options: MarkStaleOptions = {},\n): Promise<{ count: number; events: StaleEvent[] }> {\n const thresholds = options.thresholds ?? loadStaleThresholdsFromEnv()\n const now = options.now ?? Date.now()\n const events: StaleEvent[] = []\n\n const project = options.project ?? DEFAULT_PROJECT\n graph.forEachEdge((id, attrs) => {\n const e = attrs as GraphEdge\n if (e.provenance !== Provenance.OBSERVED) return\n if (!e.lastObserved) return\n const threshold = thresholdForEdgeType(e.type, thresholds)\n const age = now - new Date(e.lastObserved).getTime()\n if (age > threshold) {\n const updated: GraphEdge = { ...e, provenance: Provenance.STALE, confidence: 0.3 }\n graph.replaceEdgeAttributes(id, updated)\n events.push({\n edgeId: id,\n source: e.source,\n target: e.target,\n edgeType: e.type,\n thresholdMs: threshold,\n ageMs: age,\n lastObserved: e.lastObserved,\n transitionedAt: new Date(now).toISOString(),\n })\n // Stale-transition fires through the bus (ADR-051). The graph\n // subscription in events.ts can't see the OBSERVED→STALE semantic on\n // its own — a provenance flip is just an attribute update from\n // graphology's view.\n emitNeatEvent({\n type: 'stale-transition',\n project,\n payload: {\n edgeId: id,\n from: Provenance.OBSERVED,\n to: Provenance.STALE,\n },\n })\n }\n })\n\n if (options.staleEventsPath && events.length > 0) {\n await appendStaleEvents(options.staleEventsPath, events)\n }\n\n return { count: events.length, events }\n}\n\nasync function appendStaleEvents(staleEventsPath: string, events: StaleEvent[]): Promise<void> {\n await fs.mkdir(path.dirname(staleEventsPath), { recursive: true })\n const lines = events.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n await fs.appendFile(staleEventsPath, lines, 'utf8')\n}\n\nexport async function readStaleEvents(staleEventsPath: string): Promise<StaleEvent[]> {\n try {\n const raw = await fs.readFile(staleEventsPath, 'utf8')\n return raw\n .split('\\n')\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as StaleEvent)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n}\n\nexport interface StalenessLoopOptions {\n thresholds?: Record<string, number>\n intervalMs?: number\n staleEventsPath?: string\n // Project tag for event-bus routing (ADR-051).\n project?: string\n // Post-stale-transition policy trigger (ADR-043). Fires after each tick of\n // markStaleEdges so policies see the new STALE state. Daemons wire this to\n // evaluateAllPolicies + PolicyViolationsLog.append.\n onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n}\n\nexport function startStalenessLoop(\n graph: NeatGraph,\n options: StalenessLoopOptions = {},\n): () => void {\n let stopped = false\n const intervalMs = options.intervalMs ?? 60_000\n const tick = (): void => {\n if (stopped) return\n void (async () => {\n try {\n await markStaleEdges(graph, {\n thresholds: options.thresholds,\n staleEventsPath: options.staleEventsPath,\n project: options.project,\n })\n if (options.onPolicyTrigger) await options.onPolicyTrigger(graph)\n } catch (err) {\n console.error('staleness tick failed', err)\n }\n })()\n }\n const interval = setInterval(tick, intervalMs)\n if (typeof interval.unref === 'function') interval.unref()\n return () => {\n stopped = true\n clearInterval(interval)\n }\n}\n\nexport async function readErrorEvents(errorsPath: string): Promise<ErrorEvent[]> {\n try {\n const raw = await fs.readFile(errorsPath, 'utf8')\n return raw\n .split('\\n')\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as ErrorEvent)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot merge (ADR-074 §1)\n//\n// `neat sync` (local) and `neat sync --to <url>` (remote) feed snapshots into\n// a live graph through this helper. It lives in ingest.ts because mutation\n// authority sits with ingest + extract per the lifecycle contract (ADR-030);\n// the merge is ingestion of an external snapshot, no different in shape from\n// the way handleSpan ingests an OTel span.\n//\n// The merge preserves EXTRACTED + OBSERVED coexistence per Rule 2 — each\n// provenance variant has its own edge id, so the incoming EXTRACTED edges\n// can't stomp the daemon's accumulated OBSERVED edges and vice versa. Rule of\n// thumb: incoming wins for nodes/edges the live graph hasn't seen yet;\n// everything already present keeps its current attributes.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface MergeSnapshotResult {\n nodesAdded: number\n edgesAdded: number\n}\n\nexport function mergeSnapshot(\n graph: NeatGraph,\n snapshot: PersistedGraph,\n): MergeSnapshotResult {\n const exported = snapshot.graph as {\n nodes?: Array<{ key: string; attributes?: GraphNode }>\n edges?: Array<{ key?: string; source: string; target: string; attributes?: GraphEdge }>\n }\n\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const node of exported.nodes ?? []) {\n if (graph.hasNode(node.key)) continue\n if (!node.attributes) continue\n graph.addNode(node.key, node.attributes)\n nodesAdded++\n }\n\n for (const edge of exported.edges ?? []) {\n const attrs = edge.attributes\n if (!attrs) continue\n const id = edge.key ?? attrs.id\n if (!id) continue\n if (graph.hasEdge(id)) continue\n // Skip when either endpoint is missing — can happen if the snapshot\n // names a node the live graph already evicted and the incoming nodes\n // array didn't include.\n if (!graph.hasNode(edge.source) || !graph.hasNode(edge.target)) continue\n graph.addEdgeWithKey(id, edge.source, edge.target, attrs)\n edgesAdded++\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n GraphEdge,\n GraphNode,\n Policy,\n PolicyAction,\n PolicyFile,\n PolicyRule,\n PolicySeverity,\n PolicyViolation,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n PolicyFileSchema,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n deprecatedApis,\n nodeEngineConstraints,\n packageConflicts,\n} from './compat.js'\nimport { emitNeatEvent } from './events.js'\nimport { getBlastRadius } from './traverse.js'\n\n// Policy evaluation engine (ADR-043). The entry point evaluateAllPolicies is\n// pure: same graph + same policies → same violations. Per-rule-type dispatch\n// via the policyEvaluators table. Adding a new rule type means one new\n// evaluator entry plus the schema entry in @neat.is/types/policy.ts.\n//\n// Deterministic violation ids per ADR-043: ${policy.id}:${context}. The\n// context is shape-specific (nodeId, edgeId, or composite). The\n// policy-violations.ndjson writer skips on duplicate ids.\n\nexport interface EvaluationContext {\n // Wall-clock provider. Tests pin this; production uses Date.now.\n now: () => number\n}\n\ninterface RuleEvaluatorArgs<T extends PolicyRule = PolicyRule> {\n graph: NeatGraph\n policy: Policy\n rule: T\n ctx: EvaluationContext\n}\n\ntype RuleEvaluator<T extends PolicyRule = PolicyRule> = (\n args: RuleEvaluatorArgs<T>,\n) => PolicyViolation[]\n\n// Severity-driven default action per ADR-044.\nconst DEFAULT_ACTION_BY_SEVERITY: Record<PolicySeverity, PolicyAction> = {\n info: 'log',\n warning: 'alert',\n error: 'alert',\n critical: 'block',\n}\n\nexport function resolveOnViolation(policy: Policy): PolicyAction {\n return policy.onViolation ?? DEFAULT_ACTION_BY_SEVERITY[policy.severity]\n}\n\nfunction makeViolation(\n policy: Policy,\n rule: PolicyRule,\n contextSuffix: string,\n message: string,\n subject: PolicyViolation['subject'],\n ctx: EvaluationContext,\n): PolicyViolation {\n return {\n id: `${policy.id}:${contextSuffix}`,\n policyId: policy.id,\n policyName: policy.name,\n severity: policy.severity,\n onViolation: resolveOnViolation(policy),\n ruleType: rule.type,\n subject,\n message,\n observedAt: new Date(ctx.now()).toISOString(),\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Per-rule-type evaluators\n// ──────────────────────────────────────────────────────────────────────────\n\nconst evaluateStructural: RuleEvaluator<Extract<PolicyRule, { type: 'structural' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== rule.fromNodeType) return\n let satisfied = false\n for (const edgeId of graph.outboundEdges(id)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== rule.edgeType) continue\n const target = graph.getNodeAttributes(e.target) as GraphNode\n // FrontierNodes are unresolved peers (ADR-068) — skip; the rule\n // counts edges that resolve to a real typed node only.\n if (target.type === NodeType.FrontierNode) continue\n if (target.type === rule.toNodeType) {\n satisfied = true\n break\n }\n }\n if (!satisfied) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.fromNodeType} ${id} has no ${rule.edgeType} edge to a ${rule.toNodeType}`,\n { nodeId: id },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateOwnership: RuleEvaluator<Extract<PolicyRule, { type: 'ownership' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode & Record<string, unknown>\n if (a.type !== rule.nodeType) return\n const value = a[rule.field]\n if (typeof value !== 'string' || value.length === 0) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.nodeType} ${id} is missing required field \"${rule.field}\"`,\n { nodeId: id },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateProvenance: RuleEvaluator<Extract<PolicyRule, { type: 'provenance' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const required = Array.isArray(rule.required) ? new Set(rule.required) : new Set([rule.required])\n const violations: PolicyViolation[] = []\n graph.forEachEdge((edgeId, attrs) => {\n const e = attrs as GraphEdge\n if (e.type !== rule.edgeType) return\n if (rule.targetNodeId && e.target !== rule.targetNodeId) return\n if (!required.has(e.provenance)) {\n const requiredList = [...required].join(' | ')\n violations.push(\n makeViolation(\n policy,\n rule,\n edgeId,\n `${rule.edgeType} edge ${edgeId} has provenance ${e.provenance}; required ${requiredList}`,\n { edgeId },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateBlastRadius: RuleEvaluator<Extract<PolicyRule, { type: 'blast-radius' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n const depth = rule.depth\n graph.forEachNode((id, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== rule.nodeType) return\n const result = depth !== undefined ? getBlastRadius(graph, id, depth) : getBlastRadius(graph, id)\n if (result.totalAffected > rule.maxAffected) {\n violations.push(\n makeViolation(\n policy,\n rule,\n id,\n `${rule.nodeType} ${id} has blast radius ${result.totalAffected} > ${rule.maxAffected}`,\n { nodeId: id, path: [id] },\n ctx,\n ),\n )\n }\n })\n return violations\n}\n\nconst evaluateCompatibility: RuleEvaluator<Extract<PolicyRule, { type: 'compatibility' }>> = ({\n graph,\n policy,\n rule,\n ctx,\n}) => {\n const violations: PolicyViolation[] = []\n // Iterate every ServiceNode and re-run the compat shapes the static\n // extractor runs at extract time. Catches OBSERVED-vs-EXTRACTED divergence:\n // a service whose dep manifest changed since the last extract gets re-flagged\n // here on every evaluation cycle.\n const wantsKind = (kind: NonNullable<typeof rule.kind>): boolean =>\n rule.kind === undefined || rule.kind === kind\n\n graph.forEachNode((svcId, attrs) => {\n const a = attrs as GraphNode\n if (a.type !== NodeType.ServiceNode) return\n const svc = a as ServiceNode\n const deps = svc.dependencies ?? {}\n\n if (wantsKind('driver-engine')) {\n // Walk every CONNECTS_TO edge from this service to a DatabaseNode,\n // then run the driver-engine compat for each (driver, declared, engine,\n // engineVersion) tuple.\n for (const edgeId of graph.outboundEdges(svcId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== EdgeType.CONNECTS_TO) continue\n const dbAttrs = graph.getNodeAttributes(e.target) as GraphNode\n // FrontierNodes are unresolved peers (ADR-068) — skip; compat\n // checking needs a typed DatabaseNode.\n if (dbAttrs.type === NodeType.FrontierNode) continue\n if (dbAttrs.type !== NodeType.DatabaseNode) continue\n const db = dbAttrs as { engine: string; engineVersion: string }\n for (const pair of compatPairs()) {\n if (pair.engine !== db.engine) continue\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(pair.driver, declared, db.engine, db.engineVersion)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:driver-engine:${pair.driver}@${declared}:${db.engine}@${db.engineVersion}`,\n result.reason,\n { nodeId: svcId, edgeId },\n ctx,\n ),\n )\n }\n }\n }\n }\n\n if (wantsKind('node-engine')) {\n const serviceNodeRange = svc.nodeEngine\n for (const constraint of nodeEngineConstraints()) {\n const declared = deps[constraint.package]\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeRange)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:node-engine:${constraint.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n\n if (wantsKind('package-conflict')) {\n for (const conflict of packageConflicts()) {\n const declared = deps[conflict.package]\n if (!declared) continue\n const requiredDeclared = deps[conflict.requires.name]\n const result = checkPackageConflict(conflict, declared, requiredDeclared)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:package-conflict:${conflict.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n\n if (wantsKind('deprecated-api')) {\n for (const dep of deprecatedApis()) {\n const declared = deps[dep.package]\n if (!declared) continue\n const result = checkDeprecatedApi(dep, declared)\n if (!result.compatible && result.reason) {\n violations.push(\n makeViolation(\n policy,\n rule,\n `${svcId}:deprecated-api:${dep.package}@${declared}`,\n result.reason,\n { nodeId: svcId },\n ctx,\n ),\n )\n }\n }\n }\n })\n\n return violations\n}\n\nconst policyEvaluators: { [K in PolicyRule['type']]: RuleEvaluator<Extract<PolicyRule, { type: K }>> } = {\n structural: evaluateStructural,\n ownership: evaluateOwnership,\n provenance: evaluateProvenance,\n 'blast-radius': evaluateBlastRadius,\n compatibility: evaluateCompatibility,\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public entry point\n// ──────────────────────────────────────────────────────────────────────────\n\n// Block-action gating for FrontierNode promotion (ADR-044 §block, MVP scope).\n// Runs the policy evaluator and returns the subset of block-action violations\n// that mention the candidate FrontierNode. Callers (ingest.ts\n// promoteFrontierNodes) check `allowed` before rewiring; when false, the\n// promotion is skipped and the violations surface through the standard\n// policy-violations.ndjson channel.\n//\n// Block scope is tightly bounded per the contract: FrontierNode promotion\n// only. Other gating points (deploy, codemod, OTel auto-create) need their\n// own ADRs before this function expands.\nexport function canPromoteFrontier(\n graph: NeatGraph,\n frontierId: string,\n policies: Policy[],\n ctx: EvaluationContext,\n): { allowed: boolean; violations: PolicyViolation[] } {\n if (policies.length === 0) return { allowed: true, violations: [] }\n const all = evaluateAllPolicies(graph, policies, ctx)\n const blocking = all.filter((v) => {\n if (v.onViolation !== 'block') return false\n return (\n v.subject.nodeId === frontierId ||\n v.subject.path?.includes(frontierId) === true\n )\n })\n return { allowed: blocking.length === 0, violations: blocking }\n}\n\nexport function evaluateAllPolicies(\n graph: NeatGraph,\n policies: Policy[],\n ctx: EvaluationContext,\n): PolicyViolation[] {\n const out: PolicyViolation[] = []\n for (const policy of policies) {\n const evaluator = policyEvaluators[policy.rule.type] as RuleEvaluator\n const violations = evaluator({ graph, policy, rule: policy.rule, ctx })\n for (const v of violations) out.push(v)\n }\n return out\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Loader\n// ──────────────────────────────────────────────────────────────────────────\n\n// Reads <projectRoot>/policy.json. Returns [] when the file doesn't exist —\n// a project without policies is a perfectly fine state. Failures to parse\n// throw with the Zod error so the daemon surfaces malformed files loudly\n// instead of silently dropping rules.\nexport async function loadPolicyFile(policyPath: string): Promise<Policy[]> {\n let raw: string\n try {\n raw = await fs.readFile(policyPath, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n const json = JSON.parse(raw) as unknown\n const file: PolicyFile = PolicyFileSchema.parse(json)\n return file.policies\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Append-only ndjson writer with id-based dedup\n// ──────────────────────────────────────────────────────────────────────────\n\n// Keeps an in-memory Set of seen violation ids so re-evaluation cycles don't\n// produce duplicate ndjson lines. The set hydrates from disk on first append\n// — startups that load an existing log don't lose dedup state.\nexport class PolicyViolationsLog {\n private readonly path: string\n private readonly project: string\n private seen: Set<string> | null = null\n\n constructor(logPath: string, project: string = DEFAULT_PROJECT) {\n this.path = logPath\n this.project = project\n }\n\n async append(v: PolicyViolation): Promise<boolean> {\n if (!this.seen) await this.hydrate()\n if (this.seen!.has(v.id)) return false\n this.seen!.add(v.id)\n await fs.mkdir(path.dirname(this.path), { recursive: true })\n await fs.appendFile(this.path, JSON.stringify(v) + '\\n', 'utf8')\n // Emit policy-violation only on first sighting (post-dedup) so SSE\n // consumers don't see the same violation again on every evaluation\n // cycle (ADR-051 #2).\n emitNeatEvent({\n type: 'policy-violation',\n project: this.project,\n payload: { violation: v },\n })\n return true\n }\n\n async readAll(): Promise<PolicyViolation[]> {\n try {\n const raw = await fs.readFile(this.path, 'utf8')\n return raw\n .split('\\n')\n .filter(Boolean)\n .map((line) => JSON.parse(line) as PolicyViolation)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n }\n\n private async hydrate(): Promise<void> {\n this.seen = new Set()\n const existing = await this.readAll()\n for (const v of existing) this.seen.add(v.id)\n }\n}\n","import { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport semver from 'semver'\nimport compatData from '../compat.json' with { type: 'json' }\n\nexport interface CompatibilityResult {\n compatible: boolean\n reason?: string\n minDriverVersion?: string\n}\n\nexport interface CompatPair {\n kind?: 'driver-engine'\n driver: string\n engine: string\n minDriverVersion: string\n // The driver constraint only kicks in once the engine is at this major or higher.\n // Older engines (e.g. PostgreSQL 13) accept the older driver fine.\n minEngineVersion?: string\n reason: string\n}\n\nexport interface NodeEngineConstraint {\n kind?: 'node-engine'\n package: string\n packageMinVersion?: string\n minNodeVersion: string\n reason: string\n}\n\nexport interface PackageConflict {\n kind?: 'package-conflict'\n package: string\n packageMinVersion?: string\n requires: { name: string; minVersion: string }\n reason: string\n}\n\nexport interface DeprecatedApi {\n kind?: 'deprecated-api'\n package: string\n packageMaxVersion?: string\n reason: string\n}\n\nexport interface CompatMatrix {\n pairs: CompatPair[]\n nodeEngineConstraints?: NodeEngineConstraint[]\n packageConflicts?: PackageConflict[]\n deprecatedApis?: DeprecatedApi[]\n}\n\nconst bundledMatrix = compatData as CompatMatrix\nlet mergedMatrix: CompatMatrix | null = null\nlet remoteLoadAttempted = false\n\nconst REMOTE_CACHE_DIR = path.join(os.homedir(), '.neat')\nconst REMOTE_CACHE_PATH = path.join(REMOTE_CACHE_DIR, 'compat-cache.json')\nconst REMOTE_TTL_MS = 24 * 60 * 60 * 1000\n\ninterface RemoteCacheFile {\n fetchedAt: string\n url: string\n matrix: CompatMatrix\n}\n\n// Engines like Postgres/MySQL only carry a major in the version field, so semver\n// won't always parse them cleanly. Compare as integers when both sides look like\n// majors; otherwise fall back to semver.coerce.\nfunction engineMeetsThreshold(engineVersion: string, threshold: string): boolean {\n const e = parseInt(engineVersion, 10)\n const t = parseInt(threshold, 10)\n if (Number.isFinite(e) && Number.isFinite(t)) return e >= t\n\n const ec = semver.coerce(engineVersion)\n const tc = semver.coerce(threshold)\n if (ec && tc) return semver.gte(ec, tc)\n\n return false\n}\n\nexport function checkCompatibility(\n driver: string,\n driverVersion: string,\n engine: string,\n engineVersion: string,\n): CompatibilityResult {\n const matrix = currentMatrix()\n const pair = matrix.pairs.find((p) => p.driver === driver && p.engine === engine)\n if (!pair) return { compatible: true }\n\n if (pair.minEngineVersion && !engineMeetsThreshold(engineVersion, pair.minEngineVersion)) {\n return { compatible: true }\n }\n\n const driverCoerced = semver.coerce(driverVersion)\n if (!driverCoerced) return { compatible: true }\n\n if (semver.lt(driverCoerced, pair.minDriverVersion)) {\n return {\n compatible: false,\n reason: pair.reason,\n minDriverVersion: pair.minDriverVersion,\n }\n }\n\n return { compatible: true }\n}\n\nexport interface NodeEngineCheck {\n compatible: boolean\n reason?: string\n requiredNodeVersion?: string\n}\n\n// True when `serviceNodeRange` (a service's `engines.node`) is guaranteed to\n// admit `requiredNodeVersion`. We use a permissive semver compare via `coerce`\n// — exact ranges like \">=20\" parse fine, exotic ones like \"^20 || ^22\" pass as\n// long as semver can resolve them. If the range can't be parsed at all, we\n// don't claim a conflict — under-flag rather than over-flag.\nfunction rangeAdmitsVersion(serviceNodeRange: string, requiredNodeVersion: string): boolean {\n try {\n const required = semver.coerce(requiredNodeVersion)\n if (!required) return true\n // Is every version that satisfies the service's range >= required? If yes,\n // the service guarantees the requirement; if not, there's at least one\n // admissible Node version that won't satisfy the dep — that's the\n // conflict.\n return semver.subset(serviceNodeRange, `>=${required.version}`, {\n includePrerelease: false,\n })\n } catch {\n return true\n }\n}\n\nexport function checkNodeEngineConstraint(\n constraint: NodeEngineConstraint,\n declaredPackageVersion: string | undefined,\n serviceNodeRange: string | undefined,\n): NodeEngineCheck {\n if (constraint.packageMinVersion && declaredPackageVersion) {\n const v = semver.coerce(declaredPackageVersion)\n if (v && semver.lt(v, constraint.packageMinVersion)) {\n return { compatible: true }\n }\n }\n if (!serviceNodeRange) {\n return { compatible: true }\n }\n if (rangeAdmitsVersion(serviceNodeRange, constraint.minNodeVersion)) {\n return { compatible: true }\n }\n return {\n compatible: false,\n reason: constraint.reason,\n requiredNodeVersion: constraint.minNodeVersion,\n }\n}\n\nexport interface PackageConflictCheck {\n compatible: boolean\n reason?: string\n requires?: { name: string; minVersion: string }\n foundVersion?: string\n}\n\nexport function checkPackageConflict(\n conflict: PackageConflict,\n declaredPackageVersion: string | undefined,\n declaredRequiredVersion: string | undefined,\n): PackageConflictCheck {\n if (!declaredPackageVersion) return { compatible: true }\n if (conflict.packageMinVersion) {\n const v = semver.coerce(declaredPackageVersion)\n if (v && semver.lt(v, conflict.packageMinVersion)) {\n return { compatible: true }\n }\n }\n if (!declaredRequiredVersion) {\n return {\n compatible: false,\n reason: conflict.reason,\n requires: conflict.requires,\n }\n }\n const requiredCoerced = semver.coerce(declaredRequiredVersion)\n if (!requiredCoerced) return { compatible: true }\n if (semver.lt(requiredCoerced, conflict.requires.minVersion)) {\n return {\n compatible: false,\n reason: conflict.reason,\n requires: conflict.requires,\n foundVersion: declaredRequiredVersion,\n }\n }\n return { compatible: true }\n}\n\nexport function checkDeprecatedApi(\n rule: DeprecatedApi,\n declaredVersion: string | undefined,\n): { compatible: boolean; reason?: string } {\n if (declaredVersion === undefined) return { compatible: true }\n if (rule.packageMaxVersion) {\n const v = semver.coerce(declaredVersion)\n const max = semver.coerce(rule.packageMaxVersion)\n if (v && max && semver.gt(v, max)) return { compatible: true }\n }\n return { compatible: false, reason: rule.reason }\n}\n\nfunction currentMatrix(): CompatMatrix {\n return mergedMatrix ?? bundledMatrix\n}\n\nfunction mergeMatrices(a: CompatMatrix, b: CompatMatrix): CompatMatrix {\n return {\n pairs: [...a.pairs, ...(b.pairs ?? [])],\n nodeEngineConstraints: [\n ...(a.nodeEngineConstraints ?? []),\n ...(b.nodeEngineConstraints ?? []),\n ],\n packageConflicts: [...(a.packageConflicts ?? []), ...(b.packageConflicts ?? [])],\n deprecatedApis: [...(a.deprecatedApis ?? []), ...(b.deprecatedApis ?? [])],\n }\n}\n\nasync function readRemoteCache(url: string): Promise<CompatMatrix | null> {\n try {\n const raw = await fs.readFile(REMOTE_CACHE_PATH, 'utf8')\n const parsed = JSON.parse(raw) as RemoteCacheFile\n if (parsed.url !== url) return null\n const age = Date.now() - new Date(parsed.fetchedAt).getTime()\n if (age > REMOTE_TTL_MS) return null\n return parsed.matrix\n } catch {\n return null\n }\n}\n\nasync function writeRemoteCache(url: string, matrix: CompatMatrix): Promise<void> {\n const file: RemoteCacheFile = {\n fetchedAt: new Date().toISOString(),\n url,\n matrix,\n }\n try {\n await fs.mkdir(REMOTE_CACHE_DIR, { recursive: true })\n await fs.writeFile(REMOTE_CACHE_PATH, JSON.stringify(file), 'utf8')\n } catch (err) {\n console.warn(`[neat] failed to cache compat matrix: ${(err as Error).message}`)\n }\n}\n\n// Loads the bundled matrix and, if `NEAT_COMPAT_URL` is set, merges in a\n// remote extension. Falls back to a fresh fetch when the on-disk cache is\n// stale (24h TTL) or missing. Returns the merged matrix; subsequent calls are\n// memoised.\n//\n// Async because the fetch happens lazily on first use. Extract phase 2 awaits\n// this before iterating pairs; everything else goes through the sync\n// `currentMatrix()` view, which is fine because by the time CLI / traversal\n// runs, extraction has already loaded.\nexport async function ensureCompatLoaded(): Promise<CompatMatrix> {\n if (mergedMatrix) return mergedMatrix\n if (remoteLoadAttempted) {\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n remoteLoadAttempted = true\n\n const url = process.env.NEAT_COMPAT_URL\n if (!url) {\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n\n const cached = await readRemoteCache(url)\n if (cached) {\n mergedMatrix = mergeMatrices(bundledMatrix, cached)\n return mergedMatrix\n }\n\n try {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)\n const remote = (await res.json()) as CompatMatrix\n await writeRemoteCache(url, remote)\n mergedMatrix = mergeMatrices(bundledMatrix, remote)\n return mergedMatrix\n } catch (err) {\n console.warn(\n `[neat] NEAT_COMPAT_URL fetch failed (${(err as Error).message}); using bundled matrix only`,\n )\n mergedMatrix = bundledMatrix\n return mergedMatrix\n }\n}\n\n// Reset the merged-matrix memo. Intended for tests so each test starts with a\n// freshly loaded matrix.\nexport function resetCompatMatrix(): void {\n mergedMatrix = null\n remoteLoadAttempted = false\n}\n\nexport function compatPairs(): readonly CompatPair[] {\n return currentMatrix().pairs\n}\n\nexport function nodeEngineConstraints(): readonly NodeEngineConstraint[] {\n return currentMatrix().nodeEngineConstraints ?? []\n}\n\nexport function packageConflicts(): readonly PackageConflict[] {\n return currentMatrix().packageConflicts ?? []\n}\n\nexport function deprecatedApis(): readonly DeprecatedApi[] {\n return currentMatrix().deprecatedApis ?? []\n}\n","{\n \"pairs\": [\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"pg\",\n \"engine\": \"postgresql\",\n \"minDriverVersion\": \"8.0.0\",\n \"minEngineVersion\": \"14\",\n \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; pg < 8.0.0 only speaks md5.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mysql2\",\n \"engine\": \"mysql\",\n \"minDriverVersion\": \"3.0.0\",\n \"minEngineVersion\": \"8\",\n \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql2 < 3.0.0 doesn't negotiate it.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mongoose\",\n \"engine\": \"mongodb\",\n \"minDriverVersion\": \"7.0.0\",\n \"minEngineVersion\": \"7\",\n \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that mongoose < 7.0.0 still emits.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"psycopg2\",\n \"engine\": \"postgresql\",\n \"minDriverVersion\": \"2.9.0\",\n \"minEngineVersion\": \"14\",\n \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; psycopg2 < 2.9.0 only speaks md5.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"pymongo\",\n \"engine\": \"mongodb\",\n \"minDriverVersion\": \"4.0.0\",\n \"minEngineVersion\": \"7\",\n \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that pymongo < 4.0.0 still emits.\"\n },\n {\n \"kind\": \"driver-engine\",\n \"driver\": \"mysql-connector-python\",\n \"engine\": \"mysql\",\n \"minDriverVersion\": \"8.0.0\",\n \"minEngineVersion\": \"8\",\n \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql-connector-python < 8.0.0 doesn't negotiate it.\"\n }\n ],\n \"nodeEngineConstraints\": [\n {\n \"kind\": \"node-engine\",\n \"package\": \"vitest\",\n \"packageMinVersion\": \"2.0.0\",\n \"minNodeVersion\": \"18.0.0\",\n \"reason\": \"vitest >= 2.0 drops Node 16 support; requires Node 18+.\"\n },\n {\n \"kind\": \"node-engine\",\n \"package\": \"next\",\n \"packageMinVersion\": \"14.0.0\",\n \"minNodeVersion\": \"18.17.0\",\n \"reason\": \"Next 14+ requires Node 18.17+ (uses APIs introduced in that minor).\"\n },\n {\n \"kind\": \"node-engine\",\n \"package\": \"@modelcontextprotocol/sdk\",\n \"packageMinVersion\": \"1.0.0\",\n \"minNodeVersion\": \"18.0.0\",\n \"reason\": \"@modelcontextprotocol/sdk >= 1 requires Node 18+ (web-streams polyfill removed).\"\n }\n ],\n \"packageConflicts\": [\n {\n \"kind\": \"package-conflict\",\n \"package\": \"@tanstack/react-query\",\n \"packageMinVersion\": \"5.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.0.0\"\n },\n \"reason\": \"@tanstack/react-query 5+ uses useSyncExternalStore — only available in React 18+.\"\n },\n {\n \"kind\": \"package-conflict\",\n \"package\": \"react-router-dom\",\n \"packageMinVersion\": \"7.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.0.0\"\n },\n \"reason\": \"react-router-dom 7+ requires React 18+.\"\n },\n {\n \"kind\": \"package-conflict\",\n \"package\": \"next\",\n \"packageMinVersion\": \"14.0.0\",\n \"requires\": {\n \"name\": \"react\",\n \"minVersion\": \"18.2.0\"\n },\n \"reason\": \"Next.js 14+ requires React 18.2+.\"\n }\n ],\n \"deprecatedApis\": [\n {\n \"kind\": \"deprecated-api\",\n \"package\": \"request\",\n \"packageMaxVersion\": \"2.88.2\",\n \"reason\": \"request is deprecated; use undici, node-fetch, or axios instead.\"\n },\n {\n \"kind\": \"deprecated-api\",\n \"package\": \"node-uuid\",\n \"reason\": \"node-uuid is deprecated; use the `uuid` package.\"\n }\n ]\n}\n","// Frontend-facing event bus (ADR-051). The single in-process EventEmitter\n// every producer (ingest / extract / watch / policy) emits through and the\n// only thing the SSE handler in streaming.ts subscribes to.\n//\n// Direct producer-to-handler coupling is a contract violation — every event\n// goes through `eventBus.emit('event', envelope)` so the SSE layer is the\n// only consumer that has to know the wire taxonomy.\n//\n// The taxonomy is locked at eight types (ADR-051 #2). Adding a ninth type\n// requires a successor ADR.\n\nimport { EventEmitter } from 'node:events'\nimport type { GraphEdge, GraphNode, PolicyViolation, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Locked event taxonomy. Eight values. Tests assert the array shape\n// directly, so adding here without updating the contract is a regression.\nexport const NEAT_EVENT_TYPES = [\n 'node-added',\n 'node-updated',\n 'node-removed',\n 'edge-added',\n 'edge-removed',\n 'extraction-complete',\n 'policy-violation',\n 'stale-transition',\n] as const\n\nexport type NeatEventType = (typeof NEAT_EVENT_TYPES)[number]\n\n// Per-type payload shapes. The wire layer (SSE) writes the payload as the\n// `data` field; producers use `emit*` helpers below for type safety.\nexport interface NodeAddedPayload {\n node: GraphNode\n}\nexport interface NodeUpdatedPayload {\n id: string\n changes: Partial<GraphNode>\n}\nexport interface NodeRemovedPayload {\n id: string\n}\nexport interface EdgeAddedPayload {\n edge: GraphEdge\n}\nexport interface EdgeRemovedPayload {\n id: string\n}\nexport interface ExtractionCompletePayload {\n project: string\n fileCount: number\n nodesAdded: number\n edgesAdded: number\n}\nexport interface PolicyViolationPayload {\n violation: PolicyViolation\n}\nexport interface StaleTransitionPayload {\n edgeId: string\n from: typeof Provenance.OBSERVED\n to: typeof Provenance.STALE\n}\n\nexport type NeatEventPayload = {\n 'node-added': NodeAddedPayload\n 'node-updated': NodeUpdatedPayload\n 'node-removed': NodeRemovedPayload\n 'edge-added': EdgeAddedPayload\n 'edge-removed': EdgeRemovedPayload\n 'extraction-complete': ExtractionCompletePayload\n 'policy-violation': PolicyViolationPayload\n 'stale-transition': StaleTransitionPayload\n}\n\n// What the bus carries internally. Project is metadata used by the SSE\n// handler to route between /events and /projects/:project/events; it never\n// lands in the wire payload.\nexport interface NeatEventEnvelope<T extends NeatEventType = NeatEventType> {\n type: T\n project: string\n payload: NeatEventPayload[T]\n}\n\n// Single event channel — listeners filter by `envelope.type` and\n// `envelope.project`. Using one channel keeps the contract surface narrow\n// and matches the SSE handler's needs (one subscription, fan out).\nexport const EVENT_BUS_CHANNEL = 'event'\n\nclass NeatEventBus extends EventEmitter {}\n\n// Singleton. Process-wide so producers in ingest / extract / watch / policy\n// can emit without threading a bus instance through every call site.\nexport const eventBus: NeatEventBus = new NeatEventBus()\n\n// EventEmitter defaults to 10 listeners; SSE clients add up quickly under a\n// browser refresh storm, so lift the cap.\neventBus.setMaxListeners(0)\n\nexport function emitNeatEvent<T extends NeatEventType>(envelope: NeatEventEnvelope<T>): void {\n eventBus.emit(EVENT_BUS_CHANNEL, envelope)\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Graph subscription — one place to wire graphology mutation events into\n// the bus so producers don't have to instrument every addNode/addEdge.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface AttachOptions {\n project: string\n}\n\n// Subscribes to a NeatGraph and re-emits node/edge add/remove + node/edge\n// attribute updates as bus envelopes scoped to `project`. Returns a detach\n// fn that removes every listener it installed.\n//\n// Stale-transition is NOT routed through here — a provenance flip is just an\n// attribute update from graphology's view, and we'd lose the OBSERVED→STALE\n// semantic. ingest.ts emits stale-transition itself.\nexport function attachGraphToEventBus(graph: NeatGraph, opts: AttachOptions): () => void {\n const { project } = opts\n\n const onNodeAdded = (payload: { key: string; attributes: GraphNode }): void => {\n emitNeatEvent({\n type: 'node-added',\n project,\n payload: { node: payload.attributes },\n })\n }\n const onNodeDropped = (payload: { key: string }): void => {\n emitNeatEvent({\n type: 'node-removed',\n project,\n payload: { id: payload.key },\n })\n }\n const onEdgeAdded = (payload: { key: string; attributes: GraphEdge }): void => {\n emitNeatEvent({\n type: 'edge-added',\n project,\n payload: { edge: payload.attributes },\n })\n }\n const onEdgeDropped = (payload: { key: string }): void => {\n emitNeatEvent({\n type: 'edge-removed',\n project,\n payload: { id: payload.key },\n })\n }\n const onNodeAttrsUpdated = (payload: { key: string; attributes: GraphNode }): void => {\n emitNeatEvent({\n type: 'node-updated',\n project,\n payload: { id: payload.key, changes: payload.attributes },\n })\n }\n\n graph.on('nodeAdded', onNodeAdded)\n graph.on('nodeDropped', onNodeDropped)\n graph.on('edgeAdded', onEdgeAdded)\n graph.on('edgeDropped', onEdgeDropped)\n graph.on('nodeAttributesUpdated', onNodeAttrsUpdated)\n\n return () => {\n graph.off('nodeAdded', onNodeAdded)\n graph.off('nodeDropped', onNodeDropped)\n graph.off('edgeAdded', onEdgeAdded)\n graph.off('edgeDropped', onEdgeDropped)\n graph.off('nodeAttributesUpdated', onNodeAttrsUpdated)\n }\n}\n","import type {\n BlastRadiusAffectedNode,\n BlastRadiusResult,\n DatabaseNode,\n ErrorEvent,\n GraphEdge,\n GraphNode,\n RootCauseResult,\n ServiceNode,\n TransitiveDependenciesResult,\n TransitiveDependency,\n} from '@neat.is/types'\nimport {\n BlastRadiusResultSchema,\n EdgeType,\n NodeType,\n PROV_RANK,\n RootCauseResultSchema,\n TransitiveDependenciesResultSchema,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n checkCompatibility,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n nodeEngineConstraints,\n packageConflicts,\n} from './compat.js'\n\n// Contract anchors (see /docs/contracts.md + docs/contracts/provenance.md):\n// * Rule 2 — Coexistence: walk by provenance priority, never collapse edges.\n// * Rule 3 — FrontierNodes terminate traversal — edges to/from FrontierNodes\n// are skipped, not merely deprioritized. If a node's only neighbour is a\n// FrontierNode, traversal stops there. ADR-068 makes node-type the gating\n// property, independent of edge provenance.\n// * Rule 5 — Validate results against RootCauseResultSchema /\n// BlastRadiusResultSchema before returning.\n// * Rule 8 — No demo-name hardcoding: driver/engine identifiers come from\n// node properties + compatPairs(), never literals.\n// * ADR-029 — PROV_RANK is the canonical provenance ranking, imported\n// from @neat.is/types so consumers (traversal, MCP, policies) all agree.\n\nconst ROOT_CAUSE_MAX_DEPTH = 5\nconst BLAST_RADIUS_DEFAULT_DEPTH = 10\n\nfunction isFrontierNode(graph: NeatGraph, nodeId: string): boolean {\n if (!graph.hasNode(nodeId)) return false\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n return attrs.type === NodeType.FrontierNode\n}\n\n// Resolve a node on the walk path to the ServiceNode that carries the compat\n// evidence (declared dependencies + node engine). A ServiceNode resolves to\n// itself; a FileNode resolves to its owning service via the inbound\n// `service ──CONTAINS──▶ file` edge (file-awareness.md §2) — in a file-first\n// graph the caller on the path is a FileNode, but the dependency declaration\n// lives on the service that owns it. Anything else has no service to resolve\n// to. Returns the resolved ServiceNode's id + attributes, or null.\nfunction resolveOwningService(\n graph: NeatGraph,\n nodeId: string,\n): { id: string; svc: ServiceNode } | null {\n if (!graph.hasNode(nodeId)) return null\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n if (attrs.type === NodeType.ServiceNode) {\n return { id: nodeId, svc: attrs as ServiceNode }\n }\n if (attrs.type === NodeType.FileNode) {\n for (const edgeId of graph.inboundEdges(nodeId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type !== EdgeType.CONTAINS) continue\n const owner = graph.getNodeAttributes(e.source) as GraphNode\n if (owner.type === NodeType.ServiceNode) {\n return { id: e.source, svc: owner as ServiceNode }\n }\n }\n }\n return null\n}\n\n// Multiple edges between the same pair coexist by provenance (EXTRACTED next to\n// OBSERVED next to INFERRED). Traversal walks the system as the graph \"sees it\n// best\", so for any neighbour pair we pick the highest-provenance edge.\n// Edges connecting to FrontierNodes are skipped at the node level (ADR-068):\n// FrontierNodes are unresolved peers, traversal terminates at them rather than\n// pretending the path continues into unknown territory.\nfunction bestEdgeBySource(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n const best = new Map<string, GraphEdge>()\n for (const id of edgeIds) {\n const e = graph.getEdgeAttributes(id) as GraphEdge\n if (isFrontierNode(graph, e.source)) continue\n const cur = best.get(e.source)\n if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {\n best.set(e.source, e)\n }\n }\n return best\n}\n\nfunction bestEdgeByTarget(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n const best = new Map<string, GraphEdge>()\n for (const id of edgeIds) {\n const e = graph.getEdgeAttributes(id) as GraphEdge\n if (isFrontierNode(graph, e.target)) continue\n const cur = best.get(e.target)\n if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {\n best.set(e.target, e)\n }\n }\n return best\n}\n\n// Per-edge confidence is provenance × volume × recency × cleanliness.\n// * provenance gives a ceiling: OBSERVED 1.0, INFERRED 0.7, EXTRACTED 0.5,\n// STALE 0.3.\n// * volume: log-scaled span count, saturating quickly so 1 span ≈ 0.55 and\n// ~1k spans ≈ 1.0.\n// * recency: 1.0 within an hour; decays toward 0.5 by 24h, toward 0.3 past.\n// * cleanliness: error rate above ~10% pulls the score down — a flapping\n// edge with thousands of spans shouldn't outrank a clean low-traffic one.\n// Bounded to [0, 1]. Walks of multiple edges multiply per-edge confidences.\nconst PROVENANCE_CEILING: Record<string, number> = {\n OBSERVED: 1.0,\n INFERRED: 0.7,\n EXTRACTED: 0.5,\n STALE: 0.3,\n}\n\nfunction volumeWeight(spanCount: number | undefined): number {\n if (!spanCount || spanCount <= 0) return 0.5\n // log10 saturating around ~1000 spans → ~1.0.\n const w = 0.5 + Math.log10(spanCount + 1) / 3\n return Math.min(1, w)\n}\n\nfunction recencyWeight(ageMs: number | undefined): number {\n if (ageMs === undefined) return 0.8\n const hour = 60 * 60 * 1000\n if (ageMs <= hour) return 1.0\n if (ageMs <= 24 * hour) {\n const t = (ageMs - hour) / (23 * hour)\n return 1.0 - 0.5 * t\n }\n return 0.3\n}\n\nfunction cleanlinessWeight(spanCount: number | undefined, errorCount: number | undefined): number {\n if (!spanCount || spanCount <= 0) return 1\n const rate = (errorCount ?? 0) / spanCount\n if (rate <= 0.01) return 1\n if (rate >= 0.5) return 0.3\n return 1 - rate * 1.4\n}\n\nexport function confidenceForEdge(edge: GraphEdge, now = Date.now()): number {\n const ceiling = PROVENANCE_CEILING[edge.provenance] ?? 0.5\n\n // No runtime signal yet → the provenance ceiling is all we have. This keeps\n // EXTRACTED-only graphs returning the same coarse 0.3/0.5/0.7/1.0 ladder\n // they always have, while letting OBSERVED edges with real OTel data move\n // off the ceiling once ingest starts populating signal counters.\n const spanCount = edge.signal?.spanCount ?? edge.callCount\n const ageMs = edge.signal?.lastObservedAgeMs ?? lastObservedAge(edge, now)\n if (spanCount === undefined && ageMs === undefined && edge.signal === undefined) {\n return ceiling\n }\n\n const v = volumeWeight(spanCount)\n const r = recencyWeight(ageMs)\n const c = cleanlinessWeight(spanCount, edge.signal?.errorCount)\n return Math.max(0, Math.min(1, ceiling * v * r * c))\n}\n\nfunction lastObservedAge(edge: GraphEdge, now: number): number | undefined {\n if (!edge.lastObserved) return undefined\n const t = Date.parse(edge.lastObserved)\n if (!Number.isFinite(t)) return undefined\n return Math.max(0, now - t)\n}\n\n// Path-level confidence is the *product* of per-edge confidences (ADR-036).\n// Each hop is independent evidence and uncertainty compounds — a 3-hop path\n// of edges at confidence 0.8 each gives 0.512, not 0.8. Multiplying punishes\n// long walks accordingly, which is the contract's intent: traversal should\n// surface the cumulative trust the graph actually has, not the weakest link\n// alone.\nfunction confidenceFromMix(edges: GraphEdge[], now = Date.now()): number {\n if (edges.length === 0) return 1.0\n let product = 1\n for (const e of edges) {\n product *= confidenceForEdge(e, now)\n }\n return Math.max(0, Math.min(1, product))\n}\n\ninterface Walk {\n path: string[]\n edges: GraphEdge[]\n}\n\n// DFS along incoming edges from start, depth-bounded. Returns the longest path\n// reachable, picking best-provenance edges per neighbour pair so the walk\n// reflects the system as the graph knows it most reliably.\nfunction longestIncomingWalk(graph: NeatGraph, start: string, maxDepth: number): Walk {\n let best: Walk = { path: [start], edges: [] }\n const visited = new Set<string>([start])\n\n function step(node: string, path: string[], edges: GraphEdge[]): void {\n if (path.length > best.path.length) {\n best = { path: [...path], edges: [...edges] }\n }\n if (path.length - 1 >= maxDepth) return\n\n const incoming = bestEdgeBySource(graph, graph.inboundEdges(node))\n for (const [srcId, edge] of incoming) {\n if (visited.has(srcId)) continue\n visited.add(srcId)\n path.push(srcId)\n edges.push(edge)\n step(srcId, path, edges)\n path.pop()\n edges.pop()\n visited.delete(srcId)\n }\n }\n\n step(start, [start], [])\n return best\n}\n\n// Per-shape match result. Each shape walks the same incoming `walk.path` but\n// looks for a different class of incompatibility. Adding a new shape (e.g. a\n// future ConfigNode \"missing required env var\" rule) is one entry in\n// `rootCauseShapes` plus its match function — no restructure to getRootCause.\ninterface RootCauseMatch {\n rootCauseNode: string\n rootCauseReason: string\n fixRecommendation?: string\n}\n\ntype RootCauseShape = (\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n) => RootCauseMatch | null\n\n// DatabaseNode origin → driver/engine compat (the original v0.1.x behavior,\n// preserved verbatim). The walk ignores non-ServiceNodes; the first upstream\n// service whose declared driver fails compat against the origin DB's\n// (engine, engineVersion) wins.\nfunction databaseRootCauseShape(\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n const targetDb = origin as DatabaseNode\n // Pairs that could possibly hit on this engine — narrowed once outside the\n // walk so we don't re-scan the matrix for every service we visit.\n const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine)\n if (candidatePairs.length === 0) return null\n\n for (const id of walk.path) {\n // The compat carrier is a service: a ServiceNode resolves to itself, a\n // FileNode on the path resolves to its owning service via CONTAINS\n // (file-awareness.md §2). In a file-first graph the caller on the walk is\n // the FileNode that holds the CALLS edge, but the declared driver lives on\n // the service that owns it.\n const owner = resolveOwningService(graph, id)\n if (!owner) continue\n const { id: serviceId, svc } = owner\n const deps = svc.dependencies ?? {}\n for (const pair of candidatePairs) {\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(\n pair.driver,\n declared,\n targetDb.engine,\n targetDb.engineVersion,\n )\n if (!result.compatible) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason ?? 'incompatible driver',\n ...(result.minDriverVersion\n ? {\n fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`,\n }\n : {}),\n }\n }\n }\n }\n return null\n}\n\n// ServiceNode origin → node-engine + package-conflict shapes from compat.ts.\n// The check is over each ServiceNode along the incoming walk (the origin\n// itself + any upstream callers): a node-engine constraint failing against\n// the service's `engines.node`, or a package-conflict where a declared dep\n// requires a peer at a higher version than the service has.\nfunction serviceRootCauseShape(\n graph: NeatGraph,\n _origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n for (const id of walk.path) {\n // ServiceNode → itself; FileNode → owning service via CONTAINS\n // (file-awareness.md §2). The compat evidence (declared deps, node engine)\n // lives on the service, even when the caller on the walk is a file.\n const owner = resolveOwningService(graph, id)\n if (!owner) continue\n const { id: serviceId, svc } = owner\n const deps = svc.dependencies ?? {}\n const serviceNodeEngine = svc.nodeEngine\n\n for (const constraint of nodeEngineConstraints()) {\n const declared = deps[constraint.package]\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n if (!result.compatible && result.reason) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason,\n ...(result.requiredNodeVersion\n ? {\n fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`,\n }\n : {}),\n }\n }\n }\n\n for (const conflict of packageConflicts()) {\n const declared = deps[conflict.package]\n if (!declared) continue\n const requiredDeclared = deps[conflict.requires.name]\n const result = checkPackageConflict(conflict, declared, requiredDeclared)\n if (!result.compatible && result.reason) {\n return {\n rootCauseNode: serviceId,\n rootCauseReason: result.reason,\n fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`,\n }\n }\n }\n }\n return null\n}\n\n// FileNode origin → resolve the file to its owning service (file-awareness.md\n// §2) and run the service shape. In a file-first graph an error can land on a\n// FileNode (the file that holds the failing CALLS edge); the incompatibility,\n// if any, is still a property of the service that owns the file's declared\n// dependencies. The owning service is folded into the origin's position so the\n// service shape scans it alongside the upstream walk.\nfunction fileRootCauseShape(\n graph: NeatGraph,\n origin: GraphNode,\n walk: Walk,\n): RootCauseMatch | null {\n const owner = resolveOwningService(graph, origin.id)\n if (!owner) return null\n return serviceRootCauseShape(graph, owner.svc, walk)\n}\n\n// Dispatch by origin node type per ADR-037. Origin types not present here\n// (InfraNode, ConfigNode, FrontierNode) cleanly return null — getRootCause\n// needs an explicit shape to know what an \"incompatibility\" looks like for\n// that origin, and those types don't have one yet.\nconst rootCauseShapes: Partial<Record<GraphNode['type'], RootCauseShape>> = {\n [NodeType.DatabaseNode]: databaseRootCauseShape,\n [NodeType.ServiceNode]: serviceRootCauseShape,\n [NodeType.FileNode]: fileRootCauseShape,\n}\n\nexport function getRootCause(\n graph: NeatGraph,\n errorNodeId: string,\n errorEvent?: ErrorEvent,\n): RootCauseResult | null {\n if (!graph.hasNode(errorNodeId)) return null\n const origin = graph.getNodeAttributes(errorNodeId) as GraphNode\n const shape = rootCauseShapes[origin.type]\n if (!shape) return null\n\n const walk = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH)\n const match = shape(graph, origin, walk)\n if (!match) return null\n\n const reason = errorEvent\n ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})`\n : match.rootCauseReason\n\n // Schema-validate before return (ADR-036, #139). A drift in the result\n // shape becomes a runtime throw at the call site rather than a silently\n // malformed payload reaching MCP / REST consumers.\n return RootCauseResultSchema.parse({\n rootCauseNode: match.rootCauseNode,\n rootCauseReason: reason,\n traversalPath: walk.path,\n edgeProvenances: walk.edges.map((e) => e.provenance),\n confidence: confidenceFromMix(walk.edges),\n fixRecommendation: match.fixRecommendation,\n })\n}\n\n// BFS along outgoing edges from origin. Records each reachable node with the\n// shortest distance back to origin and the provenance of the edge that brought\n// us to it. Best-provenance edge selection per pair mirrors getRootCause.\nexport function getBlastRadius(\n graph: NeatGraph,\n nodeId: string,\n maxDepth = BLAST_RADIUS_DEFAULT_DEPTH,\n): BlastRadiusResult {\n if (!graph.hasNode(nodeId)) {\n return BlastRadiusResultSchema.parse({ origin: nodeId, affectedNodes: [], totalAffected: 0 })\n }\n\n // Each frame carries its full predecessor chain so the affected-node payload\n // can surface `path` (origin → ... → nodeId) and `confidence` (cascaded over\n // every edge along that path). The BFS visits each reachable node once on\n // its shortest-distance path; later frames at greater distance are dropped.\n interface Frame {\n nodeId: string\n distance: number\n path: string[]\n pathEdges: GraphEdge[]\n }\n\n const seen = new Map<string, BlastRadiusAffectedNode>()\n const queue: Frame[] = [{ nodeId, distance: 0, path: [nodeId], pathEdges: [] }]\n const enqueued = new Set<string>([nodeId])\n\n while (queue.length > 0) {\n const frame = queue.shift()!\n if (frame.distance > 0 && frame.pathEdges.length > 0) {\n const lastEdge = frame.pathEdges[frame.pathEdges.length - 1]!\n seen.set(frame.nodeId, {\n nodeId: frame.nodeId,\n distance: frame.distance,\n edgeProvenance: lastEdge.provenance,\n path: frame.path,\n confidence: confidenceFromMix(frame.pathEdges),\n })\n }\n if (frame.distance >= maxDepth) continue\n\n const outgoing = bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n for (const [tgtId, edge] of outgoing) {\n if (enqueued.has(tgtId)) continue\n enqueued.add(tgtId)\n queue.push({\n nodeId: tgtId,\n distance: frame.distance + 1,\n path: [...frame.path, tgtId],\n pathEdges: [...frame.pathEdges, edge],\n })\n }\n }\n\n const affectedNodes = [...seen.values()].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n return BlastRadiusResultSchema.parse({\n origin: nodeId,\n affectedNodes,\n totalAffected: affectedNodes.length,\n })\n}\n\n// Default + max depth for transitive get_dependencies (issue #144). Default\n// 3 keeps the output legible at the agent layer; the contract caps the\n// caller-supplied value at 10 to prevent BFS blow-up on dense graphs.\nexport const TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH = 3\nexport const TRANSITIVE_DEPENDENCIES_MAX_DEPTH = 10\n\n// Transitive get_dependencies (ADR-039 / #144). BFS outbound from origin to\n// `depth` hops, returning a flat list with distance, edgeType, and provenance\n// per dependency. Origin is never in the list. Direct-only consumers pass\n// depth=1; the MCP get_dependencies tool defaults to 3.\n//\n// Reuses bestEdgeByTarget (FRONTIER filtered, PROV_RANK-best per pair) so\n// dedup behavior matches the rest of traversal. Result is schema-validated\n// before return per ADR-036 §Result schema validation.\nexport function getTransitiveDependencies(\n graph: NeatGraph,\n nodeId: string,\n depth: number = TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n): TransitiveDependenciesResult {\n if (!graph.hasNode(nodeId)) {\n return TransitiveDependenciesResultSchema.parse({\n origin: nodeId,\n depth,\n dependencies: [],\n total: 0,\n })\n }\n\n interface Frame {\n nodeId: string\n distance: number\n edge: GraphEdge | null\n }\n\n const seen = new Map<string, TransitiveDependency>()\n const queue: Frame[] = [{ nodeId, distance: 0, edge: null }]\n const enqueued = new Set<string>([nodeId])\n\n while (queue.length > 0) {\n const frame = queue.shift()!\n if (frame.distance > 0 && frame.edge) {\n seen.set(frame.nodeId, {\n nodeId: frame.nodeId,\n distance: frame.distance,\n edgeType: frame.edge.type,\n provenance: frame.edge.provenance,\n })\n }\n if (frame.distance >= depth) continue\n\n const outgoing = bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n for (const [tgtId, edge] of outgoing) {\n if (enqueued.has(tgtId)) continue\n enqueued.add(tgtId)\n queue.push({ nodeId: tgtId, distance: frame.distance + 1, edge })\n }\n }\n\n const dependencies = [...seen.values()].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n return TransitiveDependenciesResultSchema.parse({\n origin: nodeId,\n depth,\n dependencies,\n total: dependencies.length,\n })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport ignore, { type Ignore } from 'ignore'\nimport { minimatch } from 'minimatch'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n IGNORED_DIRS,\n exists,\n isPythonVenvDir,\n readJson,\n type DiscoveredService,\n type PackageJson,\n} from './shared.js'\nimport { discoverPythonService, pythonToPackage } from './python.js'\nimport { computeServiceOwner, loadCodeowners } from './owners.js'\nimport { recordExtractionError } from './errors.js'\n\nconst DEFAULT_SCAN_DEPTH = 5\n\ninterface RootPackageJson extends PackageJson {\n workspaces?: string[] | { packages?: string[] }\n}\n\nfunction parseScanDepth(): number {\n const raw = process.env.NEAT_SCAN_DEPTH\n if (!raw) return DEFAULT_SCAN_DEPTH\n const n = Number.parseInt(raw, 10)\n return Number.isFinite(n) && n >= 0 ? n : DEFAULT_SCAN_DEPTH\n}\n\nfunction workspaceGlobs(pkg: RootPackageJson): string[] | null {\n const ws = pkg.workspaces\n if (!ws) return null\n if (Array.isArray(ws)) return ws.length > 0 ? ws : null\n if (Array.isArray(ws.packages)) return ws.packages.length > 0 ? ws.packages : null\n return null\n}\n\nasync function loadGitignore(scanPath: string): Promise<Ignore | null> {\n const gitignorePath = path.join(scanPath, '.gitignore')\n if (!(await exists(gitignorePath))) return null\n const raw = await fs.readFile(gitignorePath, 'utf8')\n return ignore().add(raw)\n}\n\ninterface WalkOptions {\n maxDepth: number\n ig: Ignore | null\n}\n\nasync function walkDirs(\n start: string,\n scanPath: string,\n options: WalkOptions,\n visit: (dir: string) => Promise<void> | void,\n): Promise<void> {\n async function recurse(current: string, depth: number): Promise<void> {\n if (depth > options.maxDepth) return\n const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(current, entry.name)\n if (options.ig) {\n const rel = path.relative(scanPath, child).split(path.sep).join('/')\n // Trailing slash so `ignore` evaluates the entry as a directory; without\n // it, gitignore patterns like `dist/` won't match because the lib\n // distinguishes file vs. directory tests.\n if (rel && options.ig.ignores(rel + '/')) continue\n }\n // Issue #344 — `pyvenv.cfg` marks every directory that `python -m venv`\n // or `virtualenv` creates, regardless of what the wrapper dir is called.\n // The `IGNORED_DIRS` name list catches the common shapes (`.venv`,\n // `venv`, `.tox`); this catches the long-tail ones (`env-3.11`,\n // `.direnv`, ad-hoc names).\n if (await isPythonVenvDir(child)) continue\n await visit(child)\n await recurse(child, depth + 1)\n }\n }\n await recurse(start, 0)\n}\n\nasync function expandWorkspaceGlobs(\n scanPath: string,\n globs: string[],\n): Promise<string[]> {\n const found = new Set<string>()\n const scanDepth = parseScanDepth()\n\n for (const raw of globs) {\n const pattern = raw.replace(/^\\.\\//, '')\n\n if (!pattern.includes('*')) {\n const candidate = path.join(scanPath, pattern)\n if (await exists(path.join(candidate, 'package.json'))) found.add(candidate)\n continue\n }\n\n const segments = pattern.split('/')\n const staticSegments: string[] = []\n for (const seg of segments) {\n if (seg.includes('*')) break\n staticSegments.push(seg)\n }\n const start = path.join(scanPath, ...staticSegments)\n if (!(await exists(start))) continue\n\n const hasDoubleStar = pattern.includes('**')\n const walkDepth = hasDoubleStar\n ? scanDepth\n : Math.max(0, segments.length - staticSegments.length - 1)\n\n await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {\n const rel = path.relative(scanPath, dir).split(path.sep).join('/')\n if (minimatch(rel, pattern) && (await exists(path.join(dir, 'package.json')))) {\n found.add(dir)\n }\n })\n }\n\n return [...found]\n}\n\n// Framework detection from package.json deps (ADR-074 §3). Mirrors the\n// installer dispatch precedence so a project the installer recognises as\n// Remix records `framework: 'remix'` on its ServiceNode. The static\n// extractor sees only manifest data, so detection is dep-presence based —\n// it doesn't crack open config files. Detection precedence: Next → Remix\n// → SvelteKit → Nuxt → Astro → vanilla Node.\nfunction detectJsFramework(pkg: PackageJson): string | undefined {\n const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n if (deps['next'] !== undefined) return 'next'\n if (deps['remix'] !== undefined) return 'remix'\n for (const k of Object.keys(deps)) {\n if (k.startsWith('@remix-run/')) return 'remix'\n }\n if (deps['@sveltejs/kit'] !== undefined) return 'sveltekit'\n if (deps['nuxt'] !== undefined) return 'nuxt'\n if (deps['astro'] !== undefined) return 'astro'\n return undefined\n}\n\nasync function discoverNodeService(\n scanPath: string,\n dir: string,\n): Promise<DiscoveredService | null> {\n const pkgPath = path.join(dir, 'package.json')\n if (!(await exists(pkgPath))) return null\n let pkg: PackageJson\n try {\n pkg = await readJson<PackageJson>(pkgPath)\n } catch (err) {\n recordExtractionError('services', path.relative(scanPath, pkgPath), err)\n return null\n }\n if (!pkg.name) return null\n const framework = detectJsFramework(pkg)\n const node: ServiceNode = {\n id: serviceId(pkg.name),\n type: NodeType.ServiceNode,\n name: pkg.name,\n language: 'javascript',\n version: pkg.version,\n dependencies: pkg.dependencies ?? {},\n repoPath: path.relative(scanPath, dir),\n ...(pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {}),\n ...(framework ? { framework } : {}),\n }\n return { pkg, dir, node }\n}\n\nasync function discoverPyService(\n scanPath: string,\n dir: string,\n): Promise<DiscoveredService | null> {\n const py = await discoverPythonService(dir)\n if (!py) return null\n const pkg = pythonToPackage(py)\n const node: ServiceNode = {\n id: serviceId(py.name),\n type: NodeType.ServiceNode,\n name: py.name,\n language: 'python',\n version: py.version,\n dependencies: py.dependencies,\n repoPath: path.relative(scanPath, dir),\n }\n return { pkg, dir, node }\n}\n\n// Phase 1 — discover service directories under scanPath. A service is any\n// directory containing a JS/TS manifest (`package.json`) or a Python manifest\n// (`pyproject.toml` / `requirements.txt` / `setup.py`). JS wins on tie.\n//\n// If the root `package.json` declares `workspaces`, those globs are\n// authoritative — we don't fall back to a free recursive walk. Otherwise we\n// walk recursively, depth-bounded by `NEAT_SCAN_DEPTH` (default 5), skipping\n// `IGNORED_DIRS` and anything matched by the root `.gitignore`.\n//\n// Two manifests sharing a `name` collapse to one node per ADR-010; the\n// duplicate logs a warning naming both paths.\nexport async function discoverServices(scanPath: string): Promise<DiscoveredService[]> {\n const rootPkgPath = path.join(scanPath, 'package.json')\n let rootPkg: RootPackageJson | null = null\n if (await exists(rootPkgPath)) {\n try {\n rootPkg = await readJson<RootPackageJson>(rootPkgPath)\n } catch (err) {\n recordExtractionError(\n 'services workspaces',\n path.relative(scanPath, rootPkgPath),\n err,\n )\n }\n }\n const wsGlobs = rootPkg ? workspaceGlobs(rootPkg) : null\n\n const candidateDirs: string[] = []\n if (wsGlobs) {\n candidateDirs.push(...(await expandWorkspaceGlobs(scanPath, wsGlobs)))\n } else {\n if (rootPkg && rootPkg.name) candidateDirs.push(scanPath)\n const ig = await loadGitignore(scanPath)\n await walkDirs(\n scanPath,\n scanPath,\n { maxDepth: parseScanDepth(), ig },\n async (dir) => {\n if (await exists(path.join(dir, 'package.json'))) {\n candidateDirs.push(dir)\n } else if (\n (await exists(path.join(dir, 'pyproject.toml'))) ||\n (await exists(path.join(dir, 'requirements.txt'))) ||\n (await exists(path.join(dir, 'setup.py')))\n ) {\n candidateDirs.push(dir)\n }\n },\n )\n }\n\n candidateDirs.sort()\n\n const seen = new Map<string, string>()\n const out: DiscoveredService[] = []\n for (const dir of candidateDirs) {\n const service =\n (await discoverNodeService(scanPath, dir)) ??\n (await discoverPyService(scanPath, dir))\n if (!service) continue\n\n const existingDir = seen.get(service.node.name)\n if (existingDir !== undefined) {\n const a = path.relative(scanPath, existingDir) || '.'\n const b = path.relative(scanPath, dir) || '.'\n console.warn(\n `[neat] duplicate package name \"${service.node.name}\" — keeping ${a}, ignoring ${b}`,\n )\n continue\n }\n seen.set(service.node.name, dir)\n out.push(service)\n }\n\n // Owner extraction (ADR-054). CODEOWNERS first, package.json `author`\n // fallback, undefined otherwise. Read once per discovery pass; the file\n // is small and parsing it per-service would be wasteful.\n const codeowners = await loadCodeowners(scanPath)\n for (const service of out) {\n const owner = await computeServiceOwner(codeowners, service.node.repoPath, service.dir)\n if (owner !== undefined) service.node.owner = owner\n }\n\n return out\n}\n\nexport function addServiceNodes(graph: NeatGraph, services: DiscoveredService[]): number {\n let nodesAdded = 0\n for (const service of services) {\n if (!graph.hasNode(service.node.id)) {\n graph.addNode(service.node.id, { ...service.node, discoveredVia: 'static' })\n nodesAdded++\n continue\n }\n // OTel ingest may have auto-created a minimal node at this id. Merge per\n // ADR-033 / identity contract: static fields override OTel-derived fields,\n // and discoveredVia flips to 'merged' when both layers contributed.\n const existing = graph.getNodeAttributes(service.node.id) as ServiceNode\n const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n existing.discoveredVia === 'otel' ? 'merged' : 'static'\n graph.replaceNodeAttributes(service.node.id, {\n ...existing,\n ...service.node,\n discoveredVia: mergedDiscoveredVia,\n })\n }\n return nodesAdded\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\n\nexport interface PackageJson {\n name: string\n version?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n engines?: { node?: string }\n}\n\nexport interface DiscoveredService {\n pkg: PackageJson\n dir: string\n node: ServiceNode\n}\n\nexport const SERVICE_FILE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.py'])\nexport const CONFIG_FILE_EXTENSIONS = new Set(['.yaml', '.yml'])\nexport const IGNORED_DIRS = new Set([\n 'node_modules',\n '.git',\n '.turbo',\n 'dist',\n 'build',\n '.next',\n // Python virtualenv shapes (issue #344). Walking into a venv pulls in the\n // entire CPython stdlib + every installed package as if it were first-party\n // service code — 20k+ files, none of which the user wrote. The shape names\n // cover the three common venv tools (`venv` / `python -m venv`,\n // `virtualenv`) and the tox + PEP 582 conventions.\n '.venv',\n 'venv',\n '__pypackages__',\n '.tox',\n // `site-packages` shows up nested inside venvs that don't carry one of the\n // outer names (system Python on macOS, in-place pyenv layouts). Listing it\n // here means we stop the walk at the boundary even when the wrapper dir\n // wasn't recognisable.\n 'site-packages',\n])\n\n// Marker file `python -m venv` and `virtualenv` both drop at the venv root.\n// Used by the walkers to recognise venvs whose top-level directory doesn't\n// happen to match one of the canonical `IGNORED_DIRS` names (issue #344).\n// Cached per process to keep the recursion hot path off the fs after the\n// first walk; venv contents don't change inside one extract pass.\nconst PYVENV_MARKER_CACHE = new Map<string, boolean>()\n\nexport async function isPythonVenvDir(dir: string): Promise<boolean> {\n const cached = PYVENV_MARKER_CACHE.get(dir)\n if (cached !== undefined) return cached\n try {\n const stat = await fs.stat(path.join(dir, 'pyvenv.cfg'))\n const ok = stat.isFile()\n PYVENV_MARKER_CACHE.set(dir, ok)\n return ok\n } catch {\n PYVENV_MARKER_CACHE.set(dir, false)\n return false\n }\n}\n\nexport function isConfigFile(name: string): { match: boolean; fileType: string } {\n const ext = path.extname(name)\n if (CONFIG_FILE_EXTENSIONS.has(ext)) return { match: true, fileType: ext.slice(1) }\n // .env, .env.local, .env.production. Bare filename or any dotted-suffix\n // variant; folder names get filtered upstream by walking files only.\n // ADR-065 #4 filters .env.template / .env.example / .env.sample (and the\n // dotted-suffix variants) at the producer level — those are documentation,\n // not runtime config.\n if (name === '.env' || name.startsWith('.env.')) {\n if (isEnvTemplateFile(name)) return { match: false, fileType: '' }\n return { match: true, fileType: 'env' }\n }\n return { match: false, fileType: '' }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-065 precision-filter helpers. Pre-emit gates inside the producer pass.\n// Filtered candidates are never written to the graph (idempotency intact).\n// ─────────────────────────────────────────────────────────────────────────\n\n// ADR-065 #1 — test-scope exclusion. Returns true when the file path matches\n// any test-scope pattern. Path is normalised to forward slashes before\n// matching so callers can pass either form.\n//\n// Patterns:\n// - any segment named __tests__, __fixtures__, or integration-tests\n// - basename matches *.spec.{ts,tsx,js,jsx,mjs,cjs,py}\n// - basename matches *.test.{ts,tsx,js,jsx,mjs,cjs,py}\nexport function isTestPath(filePath: string): boolean {\n const normalised = filePath.replace(/\\\\/g, '/')\n const segments = normalised.split('/')\n for (const seg of segments) {\n if (seg === '__tests__' || seg === '__fixtures__' || seg === 'integration-tests') {\n return true\n }\n }\n const base = segments[segments.length - 1] ?? ''\n return /\\.(spec|test)\\.(?:tsx?|jsx?|mjs|cjs|py)$/i.test(base)\n}\n\n// ADR-065 #4 — `.env.template` exclusion. Matches:\n// .env.template / .env.example / .env.sample\n// .env.*.template / .env.*.example / .env.*.sample\n// These are docs/onboarding artifacts, not runtime config. ConfigNodes are\n// bound to runtime existence (ADR-016); templates fail that test.\nexport function isEnvTemplateFile(name: string): boolean {\n if (\n name === '.env.template' ||\n name === '.env.example' ||\n name === '.env.sample'\n ) {\n return true\n }\n // `.env.*.template` / `.env.*.example` / `.env.*.sample`\n return /^\\.env\\.[^.]+\\.(?:template|example|sample)$/i.test(name)\n}\n\n// ADR-065 #2 — comment-body exclusion. Replaces every JS/TS comment span in\n// the source with an equal-length run of spaces, preserving line/column for\n// downstream line-mapping. Strings that contain `//` sequences (URLs) are\n// preserved by tracking the string context as we scan.\n//\n// Not a full parser — good enough for the medusa-shape failures. The HTTP\n// extractor's AST walk already gets comment-awareness for free; this helper\n// is for the regex-based extractors (redis, kafka, aws, grpc).\nexport function maskCommentsInSource(src: string): string {\n const len = src.length\n const out: string[] = new Array(len)\n let i = 0\n // String context: ' \" ` (template) — open-quote char, 0 when not in a string.\n let inString: string | 0 = 0\n let escaped = false\n while (i < len) {\n const c = src[i]!\n if (inString !== 0) {\n out[i] = c\n if (escaped) {\n escaped = false\n } else if (c === '\\\\') {\n escaped = true\n } else if (c === inString) {\n inString = 0\n }\n i++\n continue\n }\n if (c === '/' && i + 1 < len) {\n const next = src[i + 1]!\n if (next === '/') {\n out[i] = ' '\n out[i + 1] = ' '\n let j = i + 2\n while (j < len && src[j] !== '\\n') {\n out[j] = ' '\n j++\n }\n i = j\n continue\n }\n if (next === '*') {\n out[i] = ' '\n out[i + 1] = ' '\n let j = i + 2\n while (j < len) {\n if (src[j] === '\\n') {\n out[j] = '\\n'\n j++\n continue\n }\n if (src[j] === '*' && j + 1 < len && src[j + 1] === '/') {\n out[j] = ' '\n out[j + 1] = ' '\n j += 2\n break\n }\n out[j] = ' '\n j++\n }\n i = j\n continue\n }\n }\n out[i] = c\n if (c === \"'\" || c === '\"' || c === '`') inString = c\n i++\n }\n return out.join('')\n}\n\n// ADR-065 #5 — exact hostname match for cross-service URL inference. Returns\n// true if `urlString` looks like an actual URL — has an explicit `scheme://`\n// or starts with a scheme-relative `//` — and its hostname matches `host`\n// exactly (case-insensitive). No `.includes()` containment, and no bare-string\n// matching: a literal like `'admin-bundler'` would otherwise parse as\n// `http://admin-bundler` and match the basename of every service directory,\n// which is how the v0.3.3 medusa pre-check produced 279 false positives.\n//\n// Accepts a `host` that may include a port (`api.example.com:8080`); in that\n// case the URL's hostname AND port must both match.\nconst URL_LIKE = /^(?:[a-z][a-z0-9+.-]*:)?\\/\\//i\n\nexport function urlMatchesHost(urlString: string, host: string): boolean {\n if (typeof urlString !== 'string' || urlString.length === 0) return false\n // Require the literal to look like a URL — scheme + `://` or scheme-relative\n // `//host`. Bare hostnames are rejected; they're the load-bearing source of\n // false positives.\n if (!URL_LIKE.test(urlString)) return false\n const [wantedHost, wantedPort] = host.split(':')\n let parsed: URL\n try {\n // For scheme-relative `//host/path`, prepend `http:` so URL accepts it.\n const candidate = urlString.startsWith('//') ? `http:${urlString}` : urlString\n parsed = new URL(candidate)\n } catch {\n return false\n }\n if (parsed.hostname.toLowerCase() !== (wantedHost ?? '').toLowerCase()) return false\n if (wantedPort && parsed.port !== wantedPort) return false\n return true\n}\n\n// Strip semver range prefixes (^, ~, >=, etc.) and bare \"v\" so the extracted\n// version is usable for compat checks. We don't try to resolve ranges to actual\n// installed versions — that's a published-lockfile concern, not extraction's job.\nexport function cleanVersion(raw: string | undefined): string | undefined {\n if (!raw) return undefined\n return raw.replace(/^[\\^~><=v\\s]+/, '').trim() || undefined\n}\n\nexport async function readJson<T>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8')\n return JSON.parse(raw) as T\n}\n\nexport async function readYaml<T>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8')\n return parseYaml(raw) as T\n}\n\nexport async function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// Thin re-export so existing callers (calls/, configs.ts, databases/, infra/)\n// keep their import path. Wire format lives in @neat.is/types/identity.ts per\n// ADR-029.\nexport { extractedEdgeId as makeEdgeId } from '@neat.is/types'\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport { exists, type PackageJson } from './shared.js'\n\n// Lines like `psycopg2==2.7.0`, `psycopg2 == 2.7.0`, `psycopg2[extras]==2.7`,\n// or `psycopg2~=2.7,<3`. We capture the package name and the first version\n// that follows an `==` operator. Anything else (range, no pin, no version) is\n// recorded with an empty version — the compat matrix's semver coercer treats\n// those as \"can't reason\" and under-flags rather than over-flags.\nconst REQUIREMENT_LINE = /^\\s*([A-Za-z0-9_.-]+)(?:\\[[^\\]]*\\])?\\s*(?:(==)\\s*([A-Za-z0-9_.+-]+))?/\n\nfunction parseRequirementsTxt(content: string): Record<string, string> {\n const out: Record<string, string> = {}\n for (const rawLine of content.split('\\n')) {\n const line = rawLine.split('#')[0]?.trim()\n if (!line) continue\n if (line.startsWith('-')) continue // -r requirements-dev.txt etc.\n const match = REQUIREMENT_LINE.exec(line)\n if (!match) continue\n const name = match[1]!.toLowerCase()\n const version = match[3] ?? ''\n out[name] = version\n }\n return out\n}\n\ninterface PyProjectFile {\n project?: {\n name?: string\n version?: string\n dependencies?: string[]\n }\n tool?: {\n poetry?: {\n name?: string\n version?: string\n dependencies?: Record<string, string | { version?: string }>\n }\n }\n}\n\nfunction depsFromPyProject(pyproject: PyProjectFile): Record<string, string> {\n const out: Record<string, string> = {}\n\n // PEP 621 — [project] dependencies = [\"psycopg2==2.7.0\", \"requests\"]\n for (const entry of pyproject.project?.dependencies ?? []) {\n const match = REQUIREMENT_LINE.exec(entry)\n if (!match) continue\n out[match[1]!.toLowerCase()] = match[3] ?? ''\n }\n\n // Poetry — [tool.poetry.dependencies] psycopg2 = \"2.7.0\"\n const poetryDeps = pyproject.tool?.poetry?.dependencies ?? {}\n for (const [name, value] of Object.entries(poetryDeps)) {\n if (name.toLowerCase() === 'python') continue\n const raw = typeof value === 'string' ? value : (value?.version ?? '')\n out[name.toLowerCase()] = raw.replace(/^[\\^~><=v\\s]+/, '')\n }\n return out\n}\n\nexport interface PythonService {\n name: string\n version?: string\n dependencies: Record<string, string>\n}\n\n// Detect a Python service by the conventional manifest files. We try\n// pyproject.toml first because it can name the package; fallback to the\n// directory name when only requirements.txt or setup.py is present.\nexport async function discoverPythonService(serviceDir: string): Promise<PythonService | null> {\n const pyprojectPath = path.join(serviceDir, 'pyproject.toml')\n const requirementsPath = path.join(serviceDir, 'requirements.txt')\n const setupPath = path.join(serviceDir, 'setup.py')\n\n const hasPyproject = await exists(pyprojectPath)\n const hasRequirements = await exists(requirementsPath)\n const hasSetup = await exists(setupPath)\n if (!hasPyproject && !hasRequirements && !hasSetup) return null\n\n let name = path.basename(serviceDir)\n let version: string | undefined\n const dependencies: Record<string, string> = {}\n\n if (hasPyproject) {\n const raw = await fs.readFile(pyprojectPath, 'utf8')\n const pyproject = parseToml(raw) as PyProjectFile\n name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name\n version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? undefined\n Object.assign(dependencies, depsFromPyProject(pyproject))\n }\n\n if (hasRequirements) {\n const raw = await fs.readFile(requirementsPath, 'utf8')\n Object.assign(dependencies, parseRequirementsTxt(raw))\n }\n\n return { name, version, dependencies }\n}\n\n// Build the same `pkg`-shaped shim the JS path uses so downstream phases\n// (databases, calls, etc.) can keep reading service.pkg.dependencies and\n// service.pkg.name without caring which language produced the service.\nexport function pythonToPackage(service: PythonService): PackageJson {\n return {\n name: service.name,\n version: service.version,\n dependencies: service.dependencies,\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { minimatch } from 'minimatch'\nimport { exists, readJson } from './shared.js'\n\nexport interface CodeownersRule {\n pattern: string\n owners: string\n}\n\nexport interface CodeownersFile {\n rules: CodeownersRule[]\n}\n\ninterface PackageJsonAuthor {\n author?: string | { name?: string }\n}\n\n// Read CODEOWNERS at <scanPath>/CODEOWNERS first, then <scanPath>/.github/CODEOWNERS.\n// Returns null when neither exists. ADR-054 #2.1.\nexport async function loadCodeowners(scanPath: string): Promise<CodeownersFile | null> {\n const candidates = [\n path.join(scanPath, 'CODEOWNERS'),\n path.join(scanPath, '.github', 'CODEOWNERS'),\n ]\n for (const file of candidates) {\n if (await exists(file)) {\n const raw = await fs.readFile(file, 'utf8')\n return parseCodeowners(raw)\n }\n }\n return null\n}\n\nfunction parseCodeowners(raw: string): CodeownersFile {\n const rules: CodeownersRule[] = []\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) continue\n const match = /^(\\S+)\\s+(.+)$/.exec(trimmed)\n if (!match) continue\n rules.push({ pattern: match[1]!, owners: match[2]!.trim() })\n }\n return { rules }\n}\n\n// First matching pattern wins; returns the literal RHS or null. ADR-054 #2.1.\n// Pattern matcher is minimal per ADR-054 #6 — handles `*`, `**`, and exact\n// paths; not a full gitignore-style parser.\nexport function matchOwner(file: CodeownersFile, repoPath: string): string | null {\n const normalized = repoPath.split(path.sep).join('/')\n for (const rule of file.rules) {\n if (matchesPattern(rule.pattern, normalized)) return rule.owners\n }\n return null\n}\n\nfunction matchesPattern(rawPattern: string, repoPath: string): boolean {\n let pattern = rawPattern.startsWith('/') ? rawPattern.slice(1) : rawPattern\n if (pattern === '*') return !repoPath.includes('/')\n if (pattern === '**' || pattern === '') return true\n // Trailing slash means \"everything in this directory\".\n if (pattern.endsWith('/')) pattern = pattern + '**'\n if (minimatch(repoPath, pattern, { dot: true })) return true\n // A pattern that names a directory should match files beneath it too.\n if (!pattern.includes('*') && minimatch(repoPath, pattern + '/**', { dot: true })) return true\n return false\n}\n\n// Read <serviceDir>/package.json and return the `author` field as a literal\n// string. Accepts either string form (\"Cem D <cem@example.com>\") or object\n// form ({ name: 'Cem D' }). Returns null when missing or unparseable.\n// ADR-054 #2.2.\nexport async function readPackageJsonAuthor(serviceDir: string): Promise<string | null> {\n const pkgPath = path.join(serviceDir, 'package.json')\n if (!(await exists(pkgPath))) return null\n try {\n const pkg = await readJson<PackageJsonAuthor>(pkgPath)\n if (!pkg.author) return null\n if (typeof pkg.author === 'string') return pkg.author\n if (typeof pkg.author === 'object' && typeof pkg.author.name === 'string') return pkg.author.name\n return null\n } catch {\n return null\n }\n}\n\n// Compute owner per ADR-054 priority: CODEOWNERS first, package.json `author`\n// fallback, undefined otherwise. Literal source value, no normalization (#3).\nexport async function computeServiceOwner(\n codeowners: CodeownersFile | null,\n repoPath: string | undefined,\n serviceDir: string,\n): Promise<string | undefined> {\n if (codeowners && repoPath !== undefined) {\n const owner = matchOwner(codeowners, repoPath)\n if (owner) return owner\n }\n const author = await readPackageJsonAuthor(serviceDir)\n return author ?? undefined\n}\n","// ADR-065 — loud failure mode for static extraction.\n//\n// Per-file extraction failures used to land as a single `console.warn` line\n// with no aggregate count and no on-disk record. The 2026-05-12 medusa\n// experiment ran `neat init` against ~90 files that all silently failed\n// extraction with \"Invalid argument\"; the snapshot shipped with those files\n// missing, the user had no signal it had happened, and the divergence query\n// couldn't surface gaps it didn't know it had.\n//\n// This module is the failure-mode plumbing: a process-local sink that every\n// producer appends to when a per-file parse fails, with helpers to drain the\n// sink to `<projectDir>/neat-out/errors.ndjson` and to surface the aggregate\n// count in init / watch banners.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface ExtractionError {\n // Producer name (e.g. \"http\", \"services\", \"infra docker-compose\"). Stable\n // human-readable identifier for logs and contract assertions.\n producer: string\n // Absolute or relative path of the file that failed. Stored verbatim from\n // the call site; no normalisation here.\n file: string\n // The error's `.message`. Stringified if the throw value wasn't an Error.\n error: string\n // Optional stack trace (captured at the call site). Useful for diagnosing\n // tree-sitter \"Invalid argument\" cases where the message alone is generic.\n stack?: string\n // ISO timestamp of when the error was recorded.\n ts: string\n // Discriminator for `errors.ndjson` consumers — separates extract failures\n // from OTel error events that share the same file (ADR-033).\n source: 'extract'\n}\n\nconst sink: ExtractionError[] = []\n\n// Record a per-file extraction failure. Preserves the visible warn line so\n// existing scripts/CI consumers still see a per-file message; appends to the\n// process-local sink so the aggregate count + sidecar write can fire later.\nexport function recordExtractionError(\n producer: string,\n file: string,\n err: unknown,\n): void {\n const e = err instanceof Error ? err : new Error(String(err))\n sink.push({\n producer,\n file,\n error: e.message,\n stack: e.stack,\n ts: new Date().toISOString(),\n source: 'extract',\n })\n // Visible warn preserved (pre-ADR-065 callers logged this). Banners\n // aggregate, but per-file context still useful for tail -f sessions.\n console.warn(`[neat] ${producer} skipped ${file}: ${e.message}`)\n}\n\n// Drain all queued errors. Idempotent — subsequent calls return an empty\n// array until new errors land. Callers (extractFromDirectory) drain at start\n// to clear stale state from prior runs, then drain again at end to collect\n// the pass's failures.\nexport function drainExtractionErrors(): ExtractionError[] {\n return sink.splice(0, sink.length)\n}\n\n// Read-only count of currently-queued errors. Used by callers that want the\n// count without consuming the sink (the banner case — we want the count for\n// display and the entries for `errors.ndjson`).\nexport function pendingExtractionErrors(): number {\n return sink.length\n}\n\n// Append the drained entries to `<projectDir>/neat-out/errors.ndjson`. The\n// file is shared with OTel error events (per ADR-033); the `source: 'extract'`\n// discriminator separates them for consumers. Creates the directory if\n// missing. Append-only — never rewritten.\nexport async function writeExtractionErrors(\n errors: ExtractionError[],\n errorsPath: string,\n): Promise<void> {\n if (errors.length === 0) return\n await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n const lines = errors.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n await fs.appendFile(errorsPath, lines, 'utf8')\n}\n\n// ADR-065 — `NEAT_STRICT_EXTRACTION=1` makes any per-file extraction failure\n// cause the calling command to exit non-zero. Default is forgiving (banner\n// only). The check is at the caller (cli.ts / server.ts / watch.ts) so the\n// extraction phase itself stays library-shaped.\nexport function isStrictExtractionEnabled(): boolean {\n const raw = process.env.NEAT_STRICT_EXTRACTION\n return raw === '1' || raw === 'true'\n}\n\n// Format the unconditional summary banner. Zero errors is a positive signal\n// (\"0 files skipped\") so callers print this even on clean runs.\nexport function formatExtractionBanner(count: number): string {\n if (count === 1) return `[neat] 1 file skipped due to parse errors`\n return `[neat] ${count} files skipped due to parse errors`\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-066 — precision-floor drop accounting.\n//\n// EXTRACTED candidates whose graded confidence falls below\n// NEAT_EXTRACTED_PRECISION_FLOOR (default 0.7) are computed but never added\n// to the graph. The drop count surfaces on the extraction banner;\n// NEAT_EXTRACTED_REJECTED_LOG=1 routes the per-candidate detail to\n// `<projectDir>/neat-out/rejected.ndjson`. The default keeps the sidecar\n// surface quiet.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface DroppedExtractedEdge {\n source: string\n target: string\n type: string\n confidence: number\n confidenceKind: string\n evidence: { file: string; line?: number; snippet?: string }\n}\n\nconst droppedSink: DroppedExtractedEdge[] = []\n\nexport function noteExtractedDropped(edge: DroppedExtractedEdge): void {\n droppedSink.push(edge)\n}\n\nexport function drainDroppedExtracted(): DroppedExtractedEdge[] {\n return droppedSink.splice(0, droppedSink.length)\n}\n\nexport function pendingDroppedExtracted(): number {\n return droppedSink.length\n}\n\nexport function isRejectedLogEnabled(): boolean {\n const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG\n return raw === '1' || raw === 'true'\n}\n\nexport async function writeRejectedExtracted(\n drops: DroppedExtractedEdge[],\n rejectedPath: string,\n): Promise<void> {\n if (drops.length === 0) return\n await fs.mkdir(path.dirname(rejectedPath), { recursive: true })\n const lines = drops.map((d) => JSON.stringify({ ...d, ts: new Date().toISOString() })).join('\\n') + '\\n'\n await fs.appendFile(rejectedPath, lines, 'utf8')\n}\n\nexport function formatPrecisionFloorBanner(count: number): string {\n if (count === 1) return `[neat] 1 extracted edge dropped below precision floor`\n return `[neat] ${count} extracted edges dropped below precision floor`\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport { parseAllDocuments } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { recordExtractionError } from './errors.js'\nimport {\n CONFIG_FILE_EXTENSIONS,\n IGNORED_DIRS,\n exists,\n isPythonVenvDir,\n readYaml,\n type DiscoveredService,\n} from './shared.js'\n\n// Populate ServiceNode.aliases from sources that the OTel layer is likely to\n// see in span attributes:\n//\n// - docker-compose service names (compose-DNS).\n// - Dockerfile LABEL values that name the service.\n// - k8s metadata.name (and the cluster-DNS variants) for Service /\n// Deployment / StatefulSet whose name matches a known service.\n//\n// resolveServiceId in ingest.ts checks aliases before falling back to a\n// FRONTIER placeholder; promoteFrontierNodes uses them to retire stale\n// placeholders once they map to a real service.\n\ninterface ComposeService {\n container_name?: string\n hostname?: string\n networks?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\ninterface K8sDoc {\n kind?: string\n metadata?: {\n name?: string\n namespace?: string\n labels?: Record<string, string>\n }\n spec?: {\n selector?: {\n app?: string\n matchLabels?: Record<string, string>\n }\n }\n}\n\nconst K8S_KINDS_WITH_HOSTNAMES = new Set([\n 'Service',\n 'Deployment',\n 'StatefulSet',\n 'DaemonSet',\n])\n\nfunction addAliases(graph: NeatGraph, serviceId: string, candidates: Iterable<string>): void {\n if (!graph.hasNode(serviceId)) return\n const node = graph.getNodeAttributes(serviceId) as ServiceNode & { type?: string }\n if (node.type !== NodeType.ServiceNode) return\n const set = new Set(node.aliases ?? [])\n for (const c of candidates) {\n if (!c) continue\n if (c === node.name) continue\n set.add(c)\n }\n if (set.size === 0) return\n const updated: ServiceNode = { ...node, aliases: [...set].sort() }\n graph.replaceNodeAttributes(serviceId, updated)\n}\n\nfunction indexServicesByName(services: DiscoveredService[]): Map<string, string> {\n const map = new Map<string, string>()\n for (const s of services) {\n map.set(s.node.name, s.node.id)\n map.set(path.basename(s.dir), s.node.id)\n }\n return map\n}\n\nasync function collectComposeAliases(\n graph: NeatGraph,\n scanPath: string,\n serviceIndex: Map<string, string>,\n): Promise<void> {\n let composePath: string | null = null\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(scanPath, name)\n if (await exists(abs)) {\n composePath = abs\n break\n }\n }\n if (!composePath) return\n\n let compose: ComposeFile\n try {\n compose = await readYaml<ComposeFile>(composePath)\n } catch (err) {\n recordExtractionError(\n 'aliases compose',\n path.relative(scanPath, composePath),\n err,\n )\n return\n }\n if (!compose?.services) return\n\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const serviceId = serviceIndex.get(composeName)\n if (!serviceId) continue\n const aliases = new Set<string>([composeName])\n if (svc.container_name) aliases.add(svc.container_name)\n if (svc.hostname) aliases.add(svc.hostname)\n addAliases(graph, serviceId, aliases)\n }\n}\n\nconst LABEL_KEYS = new Set([\n 'service',\n 'service.name',\n 'app',\n 'app.name',\n 'com.docker.compose.service',\n 'org.opencontainers.image.title',\n])\n\nfunction parseDockerfileLabels(content: string): string[] {\n const out: string[] = []\n // Support `LABEL key=value`, `LABEL key=\"value with spaces\"`, and the\n // multi-pair form `LABEL k1=v1 k2=v2`. We don't try to honour line\n // continuations — the common single-line form is enough.\n const lineRegex = /^\\s*label\\s+(.+)$/i\n for (const raw of content.split('\\n')) {\n const m = lineRegex.exec(raw)\n if (!m) continue\n const rest = m[1]!\n const pairRegex = /([\\w.-]+)\\s*=\\s*(\"([^\"]*)\"|'([^']*)'|([^\\s]+))/g\n let pair: RegExpExecArray | null\n while ((pair = pairRegex.exec(rest)) !== null) {\n const key = pair[1]!.toLowerCase()\n if (!LABEL_KEYS.has(key)) continue\n const value = pair[3] ?? pair[4] ?? pair[5] ?? ''\n if (value) out.push(value)\n }\n }\n return out\n}\n\nasync function collectDockerfileAliases(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<void> {\n for (const service of services) {\n const dockerfilePath = path.join(service.dir, 'Dockerfile')\n if (!(await exists(dockerfilePath))) continue\n let content: string\n try {\n content = await fs.readFile(dockerfilePath, 'utf8')\n } catch (err) {\n recordExtractionError('aliases dockerfile', dockerfilePath, err)\n continue\n }\n const aliases = parseDockerfileLabels(content)\n if (aliases.length > 0) addAliases(graph, service.node.id, aliases)\n }\n}\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkYamlFiles(child, depth + 1, max)))\n } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\nfunction k8sHostnames(name: string, namespace: string | undefined): string[] {\n const ns = namespace ?? 'default'\n return [\n name,\n `${name}.${ns}`,\n `${name}.${ns}.svc`,\n `${name}.${ns}.svc.cluster.local`,\n ]\n}\n\nfunction k8sServiceTarget(\n doc: K8sDoc,\n byName: Map<string, string>,\n): string | null {\n // For `Service` resources, the target is whatever app the spec selects, not\n // necessarily the Service's own metadata.name. We prefer that mapping; if no\n // selector, fall back to the metadata.name match.\n const selector = doc.spec?.selector\n const selectorApp = selector?.app ?? selector?.matchLabels?.app\n if (selectorApp && byName.has(selectorApp)) return byName.get(selectorApp)!\n\n const labelApp = doc.metadata?.labels?.app\n if (labelApp && byName.has(labelApp)) return byName.get(labelApp)!\n\n const metaName = doc.metadata?.name\n if (metaName && byName.has(metaName)) return byName.get(metaName)!\n\n return null\n}\n\nasync function collectK8sAliases(\n graph: NeatGraph,\n scanPath: string,\n serviceIndex: Map<string, string>,\n): Promise<void> {\n const files = await walkYamlFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n let docs: K8sDoc[]\n try {\n docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n } catch {\n continue\n }\n for (const doc of docs) {\n if (!doc?.kind || !doc.metadata?.name) continue\n if (!K8S_KINDS_WITH_HOSTNAMES.has(doc.kind)) continue\n const target = k8sServiceTarget(doc, serviceIndex)\n if (!target) continue\n addAliases(graph, target, k8sHostnames(doc.metadata.name, doc.metadata.namespace))\n }\n }\n}\n\nexport async function addServiceAliases(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<void> {\n const byName = indexServicesByName(services)\n await collectComposeAliases(graph, scanPath, byName)\n await collectDockerfileAliases(graph, services)\n await collectK8sAliases(graph, scanPath, byName)\n}\n","import type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { ensureFileNode, walkSourceFiles, toPosix } from './calls/shared.js'\nimport path from 'node:path'\n\n// Phase 1 — unconditional file enumeration (ADR-092, file-awareness.md §1).\n// Walks every source file matching SERVICE_FILE_EXTENSIONS within each service\n// and emits a FileNode + service ──CONTAINS──▶ file edge, regardless of whether\n// any call pattern fires from the file later.\nexport async function addFiles(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const filePaths = await walkSourceFiles(service.dir)\n for (const filePath of filePaths) {\n const relPath = toPosix(path.relative(service.dir, filePath))\n const { nodesAdded: n, edgesAdded: e } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relPath,\n )\n nodesAdded += n\n edgesAdded += e\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { EdgeEvidence, ExtractedConfidenceKind, FileNode, GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForExtracted,\n extractedEdgeId,\n fileId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { IGNORED_DIRS, SERVICE_FILE_EXTENSIONS, isPythonVenvDir } from '../shared.js'\n\nexport interface SourceFile {\n path: string\n content: string\n}\n\nexport interface ExternalEndpoint {\n // Stable id of the InfraNode this evidence implies. Format\n // `infra:<kind>:<name>` so the orchestrator can dedupe across services.\n infraId: string\n // Display name on the InfraNode (e.g., \"orders\" for kafka-topic:orders).\n name: string\n kind: string\n edgeType: 'CALLS' | 'PUBLISHES_TO' | 'CONSUMES_FROM'\n evidence: EdgeEvidence\n // Confidence grade per ADR-066 — set by the per-shape detector. The\n // orchestrator (calls/index.ts) writes this onto the EXTRACTED edge and\n // applies the precision floor before adding the edge to the graph.\n confidenceKind: ExtractedConfidenceKind\n}\n\nexport async function walkSourceFiles(dir: string): Promise<string[]> {\n const out: string[] = []\n async function walk(current: string): Promise<void> {\n const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n const full = path.join(current, entry.name)\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n if (await isPythonVenvDir(full)) continue\n await walk(full)\n } else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(full)\n }\n }\n }\n await walk(dir)\n return out\n}\n\nexport async function loadSourceFiles(dir: string): Promise<SourceFile[]> {\n const paths = await walkSourceFiles(dir)\n const out: SourceFile[] = []\n for (const p of paths) {\n try {\n const content = await fs.readFile(p, 'utf8')\n out.push({ path: p, content })\n } catch {\n // unreadable, skip\n }\n }\n return out\n}\n\n// Locate the line of the first occurrence of `needle` in `text`, 1-indexed.\n// Falls back to line 1 if the needle isn't found verbatim — better to point at\n// the file than to drop the evidence entirely.\nexport function lineOf(text: string, needle: string): number {\n const idx = text.indexOf(needle)\n if (idx < 0) return 1\n return text.slice(0, idx).split('\\n').length\n}\n\nexport function snippet(text: string, line: number): string {\n const lines = text.split('\\n')\n return (lines[line - 1] ?? '').trim()\n}\n\n// Forward-slash a path so a FileNode id is byte-stable across platforms (the\n// `relPath` segment of `file:<service>:<relPath>` must not vary by OS).\nexport function toPosix(p: string): string {\n return p.split('\\\\').join('/')\n}\n\n// Extension → language tag for a FileNode. Returns undefined for extensions we\n// don't name rather than guessing — evidence is never fabricated (§6).\nexport function languageForPath(relPath: string): string | undefined {\n switch (path.extname(relPath).toLowerCase()) {\n case '.py':\n return 'python'\n case '.ts':\n case '.tsx':\n return 'typescript'\n case '.js':\n case '.jsx':\n case '.mjs':\n case '.cjs':\n return 'javascript'\n default:\n return undefined\n }\n}\n\n// File-first emission (file-awareness.md §1–2). Ensure the FileNode for\n// `relPath` and the owning `service ──CONTAINS──▶ file` edge both exist, then\n// return the FileNode id so the caller can originate a relationship from it.\n// `relPath` must already be service-relative and forward-slashed (use toPosix).\n// CONTAINS is structural ownership — graded at the 'structural' tier like\n// CONFIGURED_BY, never a flat value. Idempotent: re-running extraction over an\n// unchanged file is a no-op.\nexport function ensureFileNode(\n graph: NeatGraph,\n serviceName: string,\n serviceNodeId: string,\n relPath: string,\n): { fileNodeId: string; nodesAdded: number; edgesAdded: number } {\n let nodesAdded = 0\n let edgesAdded = 0\n const fileNodeId = fileId(serviceName, relPath)\n if (!graph.hasNode(fileNodeId)) {\n const language = languageForPath(relPath)\n const node: FileNode = {\n id: fileNodeId,\n type: NodeType.FileNode,\n service: serviceName,\n path: relPath,\n ...(language ? { language } : {}),\n discoveredVia: 'static',\n }\n graph.addNode(fileNodeId, node)\n nodesAdded++\n }\n const containsId = extractedEdgeId(serviceNodeId, fileNodeId, EdgeType.CONTAINS)\n if (!graph.hasEdge(containsId)) {\n const edge: GraphEdge = {\n id: containsId,\n source: serviceNodeId,\n target: fileNodeId,\n type: EdgeType.CONTAINS,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: relPath },\n }\n graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n edgesAdded++\n }\n return { fileNodeId, nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport Python from 'tree-sitter-python'\nimport type { GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n Provenance,\n confidenceForExtracted,\n extractedEdgeId,\n fileId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, toPosix } from './calls/shared.js'\n\n// Phase 2 — import graph extraction (ADR-092, file-awareness.md §10). Walks\n// every source file's AST for import / require statements and emits IMPORTS\n// edges between FileNodes within the same service. Cross-service and\n// unresolvable specifiers are silent skips — Phase 3's CALLS producers cover\n// the cross-service case where an external-call pattern matches.\n\n// Same chunked-parse approach as calls/shared.ts — tree-sitter's bare string\n// path throws \"Invalid argument\" once the source clears ~32K code units. The\n// callback form streams the source in bounded slices instead.\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n return parser.parse((index: number) =>\n index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n )\n}\n\nfunction makeJsParser(): Parser {\n const p = new Parser()\n p.setLanguage(JavaScript)\n return p\n}\n\nfunction makePyParser(): Parser {\n const p = new Parser()\n p.setLanguage(Python)\n return p\n}\n\n// ── string-literal text ────────────────────────────────────────────────────\n\n// The interior text of a string literal node, stripped of quote characters.\n// tree-sitter-javascript wraps the content in a `string_fragment` child;\n// fall back to slicing the raw text when that shape isn't present (e.g. an\n// empty string literal has no fragment child at all).\nfunction stringLiteralText(node: Parser.SyntaxNode): string | null {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i)\n if (child?.type === 'string_fragment') return child.text\n }\n const raw = node.text\n if (raw.length >= 2) return raw.slice(1, -1)\n return raw.length === 0 ? null : ''\n}\n\nfunction clipSnippet(text: string): string {\n const oneLine = text.split('\\n')[0] ?? text\n return oneLine.length > 120 ? oneLine.slice(0, 120) : oneLine\n}\n\n// ── JS / TS import collection ──────────────────────────────────────────────\n\ninterface RawImport {\n specifier: string\n line: number // 1-indexed\n snippet: string\n}\n\n// Walks the AST for `import ... from 'spec'` / `import 'spec'` (ES modules)\n// and `require('spec')` (CommonJS). Doesn't recurse into import_statement —\n// its only string child is the source specifier, never a nested import.\nfunction collectJsImports(node: Parser.SyntaxNode, out: RawImport[]): void {\n if (node.type === 'import_statement') {\n const source = node.childForFieldName('source')\n if (source) {\n const specifier = stringLiteralText(source)\n if (specifier) {\n out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n }\n }\n return\n }\n\n if (node.type === 'call_expression') {\n const fn = node.childForFieldName('function')\n if (fn?.type === 'identifier' && fn.text === 'require') {\n const args = node.childForFieldName('arguments')\n const firstArg = args?.namedChild(0)\n if (firstArg?.type === 'string') {\n const specifier = stringLiteralText(firstArg)\n if (specifier) {\n out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n }\n }\n }\n }\n\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i)\n if (child) collectJsImports(child, out)\n }\n}\n\n// ── Python import collection ───────────────────────────────────────────────\n\ninterface RawPyImport {\n modulePath: string // dotted path with the leading dots stripped, e.g. 'utils.auth'\n level: number // count of leading dots; 0 = absolute import\n line: number\n snippet: string\n}\n\n// Walks the AST for `from X import ...` / `from .X import ...`. Bare `import\n// X` statements name modules without resolving to a single file (`import\n// os.path` doesn't tell us which file in `os` got used), so Phase 2 limits\n// itself to the `from`-form per the resolution rules in the contract.\nfunction collectPyImports(node: Parser.SyntaxNode, out: RawPyImport[]): void {\n if (node.type === 'import_from_statement') {\n let level = 0\n let modulePath = ''\n let pastFrom = false\n\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i)\n if (!child) continue\n if (!pastFrom) {\n if (child.type === 'from') pastFrom = true\n continue\n }\n if (child.type === 'import') break\n\n if (child.type === 'relative_import') {\n for (let j = 0; j < child.childCount; j++) {\n const rc = child.child(j)\n if (!rc) continue\n // tree-sitter-python groups every leading dot into a single\n // import_prefix node — `..` parses as one import_prefix with two\n // `.` children, not two import_prefix nodes. Count the `.` tokens,\n // not the prefix nodes, or multi-dot imports under-count `level`\n // and resolve onto the wrong (sometimes self) target (#457).\n if (rc.type === 'import_prefix') {\n for (let k = 0; k < rc.childCount; k++) {\n if (rc.child(k)?.type === '.') level++\n }\n } else if (rc.type === 'dotted_name') modulePath = rc.text\n }\n break\n }\n if (child.type === 'dotted_name') {\n modulePath = child.text\n break\n }\n }\n\n if (level > 0 || modulePath) {\n out.push({ modulePath, level, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n }\n }\n\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i)\n if (child) collectPyImports(child, out)\n }\n}\n\n// ── filesystem resolution helpers ──────────────────────────────────────────\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// An import that escapes the service directory (`../../other-service/x`)\n// isn't an intra-service edge — Phase 2 is scoped to within-service module\n// dependencies (file-awareness.md §10).\nfunction isWithinServiceDir(candidate: string, serviceDir: string): boolean {\n const rel = path.relative(serviceDir, candidate)\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel)\n}\n\nconst JS_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nconst JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`)\n\n// Try `base`, `base.<ext>`, and `base/index.<ext>` in TypeScript-resolution\n// order. Returns the service-relative posix path of the first hit.\nasync function firstExistingCandidate(\n base: string,\n serviceDir: string,\n): Promise<string | null> {\n for (const ext of JS_EXTENSIONS) {\n const candidate = base + ext\n if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n return toPosix(path.relative(serviceDir, candidate))\n }\n }\n for (const indexFile of JS_INDEX_FILES) {\n const candidate = path.join(base, indexFile)\n if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n return toPosix(path.relative(serviceDir, candidate))\n }\n }\n return null\n}\n\ninterface TsPathConfig {\n paths: Record<string, string[]>\n baseDir: string // absolute directory compilerOptions.baseUrl resolves against\n}\n\n// `tsconfig.json` at the service root. The contract names scanPath as a\n// fallback location too, but every discovered service already carries its own\n// root — the scanPath fallback only matters for configs that live above the\n// service tree, which the resolver doesn't have a path back to from here.\nasync function loadTsPathConfig(serviceDir: string): Promise<TsPathConfig | null> {\n const tsconfigPath = path.join(serviceDir, 'tsconfig.json')\n let raw: string\n try {\n raw = await fs.readFile(tsconfigPath, 'utf8')\n } catch {\n return null\n }\n try {\n const parsed = JSON.parse(raw) as {\n compilerOptions?: { paths?: Record<string, string[]>; baseUrl?: string }\n }\n const paths = parsed.compilerOptions?.paths\n if (!paths || Object.keys(paths).length === 0) return null\n const baseUrl = parsed.compilerOptions?.baseUrl\n return { paths, baseDir: baseUrl ? path.resolve(serviceDir, baseUrl) : serviceDir }\n } catch (err) {\n recordExtractionError('import alias resolution', tsconfigPath, err)\n return null\n }\n}\n\n// Resolve a bare specifier against `compilerOptions.paths`. Matches the first\n// alias whose pattern fits — exact (`@db`) or wildcard (`@db/*`) — and tries\n// each mapped target in declaration order. No match anywhere → null, the\n// silent-skip the contract calls for.\nasync function resolveTsAlias(\n specifier: string,\n config: TsPathConfig,\n serviceDir: string,\n): Promise<string | null> {\n for (const [pattern, targets] of Object.entries(config.paths)) {\n let suffix: string | null = null\n if (pattern === specifier) {\n suffix = ''\n } else if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -1) // keep the trailing '/'\n if (specifier.startsWith(prefix)) suffix = specifier.slice(prefix.length)\n }\n if (suffix === null) continue\n\n for (const target of targets) {\n const targetBase = target.endsWith('/*') ? target.slice(0, -2) : target.replace(/\\*$/, '')\n const resolvedBase = path.resolve(config.baseDir, targetBase, suffix)\n const hit = await firstExistingCandidate(resolvedBase, serviceDir)\n if (hit) return hit\n // The candidate may already carry its own extension (`@db/mongo.ts`).\n if (isWithinServiceDir(resolvedBase, serviceDir) && (await fileExists(resolvedBase))) {\n return toPosix(path.relative(serviceDir, resolvedBase))\n }\n }\n }\n return null\n}\n\n// Resolves a JS/TS module specifier to a service-relative posix path, or\n// null when it names something outside the service (node_modules, Node\n// builtins, an alias with no tsconfig match, an escaping relative path).\nasync function resolveJsImport(\n specifier: string,\n importerDir: string,\n serviceDir: string,\n tsPaths: TsPathConfig | null,\n): Promise<string | null> {\n if (!specifier) return null\n\n if (specifier.startsWith('./') || specifier.startsWith('../')) {\n const base = path.resolve(importerDir, specifier)\n const ext = path.extname(specifier)\n\n if (ext) {\n // `./foo.js` written against a `.ts` source — the TypeScript ESM\n // convention of naming the post-build extension in source. Try the\n // TS sibling before the literal path.\n if (ext === '.js' || ext === '.jsx') {\n const tsExt = ext === '.jsx' ? '.tsx' : '.ts'\n const tsSibling = base.slice(0, -ext.length) + tsExt\n if (isWithinServiceDir(tsSibling, serviceDir) && (await fileExists(tsSibling))) {\n return toPosix(path.relative(serviceDir, tsSibling))\n }\n }\n if (isWithinServiceDir(base, serviceDir) && (await fileExists(base))) {\n return toPosix(path.relative(serviceDir, base))\n }\n return null\n }\n\n return firstExistingCandidate(base, serviceDir)\n }\n\n // Bare specifier — only a registered TS path alias can make this\n // intra-service. Anything else is node_modules / a Node builtin.\n if (tsPaths) return resolveTsAlias(specifier, tsPaths, serviceDir)\n return null\n}\n\n// Resolves a Python `from`-import to a service-relative posix path.\n// Relative imports (level > 0) walk up from the importing module's directory;\n// absolute imports match against the service source tree directly.\nasync function resolvePyImport(\n imp: RawPyImport,\n importerPath: string,\n serviceDir: string,\n): Promise<string | null> {\n if (!imp.modulePath) return null // bare `from . import x` names a package, not a file\n\n const relPath = imp.modulePath.split('.').join('/')\n let baseDir: string\n if (imp.level > 0) {\n baseDir = path.dirname(importerPath)\n for (let i = 1; i < imp.level; i++) baseDir = path.dirname(baseDir)\n } else {\n baseDir = serviceDir\n }\n\n const candidates = [path.join(baseDir, `${relPath}.py`), path.join(baseDir, relPath, '__init__.py')]\n for (const candidate of candidates) {\n if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n return toPosix(path.relative(serviceDir, candidate))\n }\n }\n return null\n}\n\n// ── edge emission ──────────────────────────────────────────────────────────\n\nfunction emitImportEdge(\n graph: NeatGraph,\n serviceName: string,\n importerFileId: string,\n importerRelPath: string,\n importeeRelPath: string,\n line: number,\n snippet: string,\n): number {\n const importeeFileId = fileId(serviceName, importeeRelPath)\n // Phase 1 enumerates every source file unconditionally; a resolved path\n // that isn't a FileNode is outside SERVICE_FILE_EXTENSIONS or otherwise\n // wasn't walked — not an intra-service module edge.\n if (!graph.hasNode(importeeFileId)) return 0\n\n const edgeId = extractedEdgeId(importerFileId, importeeFileId, EdgeType.IMPORTS)\n if (graph.hasEdge(edgeId)) return 0\n\n const edge: GraphEdge = {\n id: edgeId,\n source: importerFileId,\n target: importeeFileId,\n type: EdgeType.IMPORTS,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: importerRelPath, line, snippet },\n }\n graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge)\n return 1\n}\n\n// ── producer ───────────────────────────────────────────────────────────────\n\nexport async function addImports(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n const jsParser = makeJsParser()\n const pyParser = makePyParser()\n let edgesAdded = 0\n\n for (const service of services) {\n const tsPaths = await loadTsPathConfig(service.dir)\n const files = await loadSourceFiles(service.dir)\n\n for (const file of files) {\n // ADR-065 §1 — test-scope exclusion. The file stays a FileNode (Phase 1);\n // only its outbound module edges are filtered (file-awareness.md §10).\n if (isTestPath(file.path)) continue\n\n const relFile = toPosix(path.relative(service.dir, file.path))\n const importerFileId = fileId(service.pkg.name, relFile)\n const isPython = path.extname(file.path) === '.py'\n\n if (isPython) {\n let pyImports: RawPyImport[] = []\n try {\n const tree = parseSource(pyParser, file.content)\n collectPyImports(tree.rootNode, pyImports)\n } catch (err) {\n recordExtractionError('import extraction', file.path, err)\n continue\n }\n for (const imp of pyImports) {\n const resolved = await resolvePyImport(imp, file.path, service.dir)\n if (!resolved) continue\n edgesAdded += emitImportEdge(\n graph,\n service.pkg.name,\n importerFileId,\n relFile,\n resolved,\n imp.line,\n imp.snippet,\n )\n }\n continue\n }\n\n let jsImports: RawImport[] = []\n try {\n const tree = parseSource(jsParser, file.content)\n collectJsImports(tree.rootNode, jsImports)\n } catch (err) {\n recordExtractionError('import extraction', file.path, err)\n continue\n }\n for (const imp of jsImports) {\n const resolved = await resolveJsImport(imp.specifier, path.dirname(file.path), service.dir, tsPaths)\n if (!resolved) continue\n edgesAdded += emitImportEdge(\n graph,\n service.pkg.name,\n importerFileId,\n relFile,\n resolved,\n imp.line,\n imp.snippet,\n )\n }\n }\n }\n\n return { nodesAdded: 0, edgesAdded }\n}\n","import path from 'node:path'\nimport type {\n CompatibleDriver,\n DatabaseNode,\n GraphEdge,\n GraphNode,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n databaseId,\n confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n checkNodeEngineConstraint,\n checkPackageConflict,\n compatPairs,\n deprecatedApis,\n nodeEngineConstraints,\n packageConflicts,\n} from '../../compat.js'\nimport { cleanVersion, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { ensureFileNode, toPosix } from '../calls/shared.js'\nimport { dbConfigYamlParser } from './db-config-yaml.js'\nimport { dotenvParser } from './dotenv.js'\nimport { prismaParser } from './prisma.js'\nimport { drizzleParser } from './drizzle.js'\nimport { knexParser } from './knex.js'\nimport { ormconfigParser } from './ormconfig.js'\nimport { typeormParser } from './typeorm.js'\nimport { sequelizeParser } from './sequelize.js'\nimport { dockerComposeParser } from './docker-compose.js'\nimport type { DbConfig } from './shared.js'\n\nexport type { DbConfig } from './shared.js'\n\nexport interface DbParser {\n name: string\n parse(serviceDir: string): Promise<DbConfig[]>\n}\n\n// Registry — order is for tie-breaking only (first wins on identical host).\n// db-config.yaml stays first so the canonical demo behaviour matches today's\n// extraction byte-for-byte.\nexport const DB_PARSERS: DbParser[] = [\n dbConfigYamlParser,\n dotenvParser,\n prismaParser,\n drizzleParser,\n knexParser,\n ormconfigParser,\n typeormParser,\n sequelizeParser,\n dockerComposeParser,\n]\n\nfunction compatibleDriversFor(engine: string): CompatibleDriver[] {\n return compatPairs()\n .filter((p) => p.engine === engine)\n .map((p) => ({ name: p.driver, minVersion: p.minDriverVersion }))\n}\n\nfunction toDatabaseNode(config: DbConfig): DatabaseNode {\n return {\n id: databaseId(config.host),\n type: NodeType.DatabaseNode,\n name: config.database || config.host,\n engine: config.engine,\n engineVersion: config.engineVersion,\n compatibleDrivers: compatibleDriversFor(config.engine),\n host: config.host,\n port: config.port,\n }\n}\n\nexport function attachIncompatibilities(\n service: DiscoveredService,\n configs: DbConfig[],\n): void {\n const deps = { ...(service.pkg.dependencies ?? {}), ...(service.pkg.devDependencies ?? {}) }\n const incompatibilities: NonNullable<ServiceNode['incompatibilities']> = []\n const seen = new Set<string>()\n\n // 1. driver-engine — original behaviour. Per (db config, configured driver\n // pair) check that the declared driver version meets the engine threshold.\n for (const config of configs) {\n for (const pair of compatPairs()) {\n if (pair.engine !== config.engine) continue\n const declaredVersion = cleanVersion(deps[pair.driver])\n if (!declaredVersion) continue\n const result = checkCompatibility(\n pair.driver,\n declaredVersion,\n config.engine,\n config.engineVersion,\n )\n if (!result.compatible && result.reason) {\n const key = `driver-engine|${pair.driver}@${declaredVersion}|${config.engine}@${config.engineVersion}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'driver-engine',\n driver: pair.driver,\n driverVersion: declaredVersion,\n engine: config.engine,\n engineVersion: config.engineVersion,\n reason: result.reason,\n })\n }\n }\n }\n\n // 2. node-engine — service's `engines.node` vs each declared dep that has a\n // matrix-recorded minimum.\n const serviceNodeEngine = service.node.nodeEngine ?? service.pkg.engines?.node\n for (const constraint of nodeEngineConstraints()) {\n const declared = cleanVersion(deps[constraint.package])\n if (!declared) continue\n const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n if (!result.compatible && result.reason) {\n const key = `node-engine|${constraint.package}@${declared}|${serviceNodeEngine ?? ''}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'node-engine',\n package: constraint.package,\n packageVersion: declared,\n requiredNodeVersion: result.requiredNodeVersion ?? constraint.minNodeVersion,\n ...(serviceNodeEngine ? { declaredNodeEngine: serviceNodeEngine } : {}),\n reason: result.reason,\n })\n }\n }\n\n // 3. package-conflict — pair like react-query 5+ requiring react 18+.\n for (const conflict of packageConflicts()) {\n const declared = cleanVersion(deps[conflict.package])\n if (!declared) continue\n const requiredVersion = cleanVersion(deps[conflict.requires.name])\n const result = checkPackageConflict(conflict, declared, requiredVersion)\n if (!result.compatible && result.reason) {\n const key = `package-conflict|${conflict.package}@${declared}|${conflict.requires.name}@${requiredVersion ?? 'missing'}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'package-conflict',\n package: conflict.package,\n packageVersion: declared,\n requires: conflict.requires,\n ...(requiredVersion ? { foundVersion: requiredVersion } : {}),\n reason: result.reason,\n })\n }\n }\n\n // 4. deprecated-api — flag presence of a known-deprecated package.\n for (const rule of deprecatedApis()) {\n const declared = cleanVersion(deps[rule.package])\n if (declared === undefined) continue\n const result = checkDeprecatedApi(rule, declared)\n if (!result.compatible && result.reason) {\n const key = `deprecated-api|${rule.package}@${declared}`\n if (seen.has(key)) continue\n seen.add(key)\n incompatibilities.push({\n kind: 'deprecated-api',\n package: rule.package,\n packageVersion: declared,\n reason: result.reason,\n })\n }\n }\n\n if (incompatibilities.length > 0) service.node.incompatibilities = incompatibilities\n}\n\n// Phase 2 — for each service, run every parser and merge their DbConfigs by\n// host. Each unique host produces one DatabaseNode + CONNECTS_TO edge from the\n// service. The parser registry decides priority on tie; the demo's\n// db-config.yaml stays first so its `engineVersion: 15` continues to win.\nexport async function addDatabasesAndCompat(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const merged = new Map<string, DbConfig>()\n for (const parser of DB_PARSERS) {\n let configs: DbConfig[]\n try {\n configs = await parser.parse(service.dir)\n } catch (err) {\n console.warn(\n `[neat] ${parser.name} parser failed on ${service.node.name}: ${(err as Error).message}`,\n )\n continue\n }\n for (const config of configs) {\n if (!config.host) continue\n if (!merged.has(config.host)) merged.set(config.host, config)\n }\n }\n\n const allConfigs = [...merged.values()]\n for (const config of allConfigs) {\n const dbNode = toDatabaseNode(config)\n if (!graph.hasNode(dbNode.id)) {\n graph.addNode(dbNode.id, { ...dbNode, discoveredVia: 'static' })\n nodesAdded++\n } else {\n // OTel ingest may have auto-created a minimal node at this id. Merge\n // per ADR-033: static fields override OTel-derived fields, discoveredVia\n // flips to 'merged' when both layers contributed.\n const existing = graph.getNodeAttributes(dbNode.id) as DatabaseNode\n const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n existing.discoveredVia === 'otel' ? 'merged' : 'static'\n graph.replaceNodeAttributes(dbNode.id, {\n ...existing,\n ...dbNode,\n discoveredVia: mergedDiscoveredVia,\n })\n }\n // file-awareness §1 — the connection is declared in a config file; that\n // file is the relationship origin. ensureFileNode creates the FileNode +\n // CONTAINS edge so the CONNECTS_TO lands file-grained, not service-level.\n const relConfigFile = toPosix(path.relative(service.dir, config.sourceFile))\n const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relConfigFile,\n )\n nodesAdded += fn\n edgesAdded += fe\n const evidenceFile = toPosix(path.relative(scanPath, config.sourceFile))\n const edge: GraphEdge = {\n id: makeEdgeId(fileNodeId, dbNode.id, EdgeType.CONNECTS_TO),\n source: fileNodeId,\n target: dbNode.id,\n type: EdgeType.CONNECTS_TO,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: evidenceFile },\n }\n if (!graph.hasEdge(edge.id)) {\n graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n // Run all kinds of incompat checks even for services with no db connection\n // — node-engine / package-conflict / deprecated-api don't depend on db.\n attachIncompatibilities(service, allConfigs)\n if (graph.hasNode(service.node.id)) {\n // Merge with whatever's on the node already (aliases from γ #75 land\n // before this phase), so the writeback doesn't drop fields populated by\n // earlier passes.\n const current = graph.getNodeAttributes(service.node.id) as ServiceNode\n const updated: ServiceNode = {\n ...current,\n ...(service.node as ServiceNode),\n ...(current.aliases ? { aliases: current.aliases } : {}),\n }\n // attachIncompatibilities only sets the field when there's something to\n // flag. On a re-extract (`neat watch`, `POST /graph/scan`), a stale\n // entry on `current` would otherwise survive the spread and leave the\n // graph reporting a problem the new manifest no longer has.\n if (!service.node.incompatibilities || service.node.incompatibilities.length === 0) {\n delete (updated as { incompatibilities?: unknown }).incompatibilities\n }\n graph.replaceNodeAttributes(service.node.id, updated as unknown as GraphNode)\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport type { DbConfig } from './shared.js'\n\ninterface DbConfigYaml {\n host: string\n port?: number\n database: string\n engine: string\n engineVersion?: string | number\n}\n\n// The original db-config.yaml format, kept as a parser so the demo continues\n// to work. Engine + version are explicit here, so this is the one source that\n// can produce a real engineVersion without inference.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const yamlPath = path.join(serviceDir, 'db-config.yaml')\n if (!(await exists(yamlPath))) return []\n const raw = await readYaml<DbConfigYaml>(yamlPath)\n return [\n {\n host: raw.host,\n port: raw.port,\n database: raw.database,\n engine: raw.engine,\n engineVersion: raw.engineVersion !== undefined ? String(raw.engineVersion) : 'unknown',\n sourceFile: yamlPath,\n },\n ]\n}\n\nexport const dbConfigYamlParser = { name: 'db-config.yaml', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { isConfigFile } from '../shared.js'\nimport { parseConnectionString, type DbConfig } from './shared.js'\n\nconst CONNECTION_KEYS = new Set([\n 'DATABASE_URL',\n 'DB_URL',\n 'POSTGRES_URL',\n 'POSTGRESQL_URL',\n 'MYSQL_URL',\n 'MONGODB_URI',\n 'MONGO_URL',\n 'MONGO_URI',\n 'REDIS_URL',\n])\n\n// Per ADR-016, .env contents do not land in any snapshot. We read them here\n// only to derive a transient DbConfig — the value never reaches a ConfigNode.\nfunction parseDotenvLine(line: string): { key: string; value: string } | null {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('#')) return null\n const eq = trimmed.indexOf('=')\n if (eq < 0) return null\n const key = trimmed.slice(0, eq).trim()\n let value = trimmed.slice(eq + 1).trim()\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1)\n }\n return { key, value }\n}\n\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const entries = await fs.readdir(serviceDir, { withFileTypes: true }).catch(() => [])\n const configs: DbConfig[] = []\n const seen = new Set<string>()\n\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const match = isConfigFile(entry.name)\n if (!match.match || match.fileType !== 'env') continue\n\n const filePath = path.join(serviceDir, entry.name)\n const content = await fs.readFile(filePath, 'utf8')\n for (const line of content.split('\\n')) {\n const parsed = parseDotenvLine(line)\n if (!parsed) continue\n if (!CONNECTION_KEYS.has(parsed.key.toUpperCase())) continue\n const config = parseConnectionString(parsed.value)\n if (!config) continue\n const key = `${config.engine}://${config.host}:${config.port ?? ''}/${config.database}`\n if (seen.has(key)) continue\n seen.add(key)\n configs.push({ ...config, sourceFile: filePath })\n }\n }\n return configs\n}\n\nexport const dotenvParser = { name: '.env', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface DbConfig {\n host: string\n port?: number\n database: string\n engine: string\n engineVersion: string // \"unknown\" when not statically determinable\n // Absolute path to the file the parser read this config from. Required —\n // ghost-edge cleanup keys CONNECTS_TO retirement on `evidence.file` per\n // ADR-032 / #140. Parsers that synthesize a DbConfig from a partial\n // source still set this to the file the partial came from.\n sourceFile: string\n}\n\n// Map a connection-string scheme to the engine name our compat matrix uses.\n// Schemes like \"postgres+asyncpg\" are normalised by stripping the dialect\n// suffix; anything we don't recognise returns null so the parser can decline.\nexport function schemeToEngine(scheme: string): string | null {\n const s = scheme.toLowerCase().split('+')[0]\n switch (s) {\n case 'postgres':\n case 'postgresql':\n return 'postgresql'\n case 'mysql':\n case 'mariadb':\n return 'mysql'\n case 'mongodb':\n case 'mongodb+srv':\n return 'mongodb'\n case 'redis':\n case 'rediss':\n return 'redis'\n case 'sqlite':\n return 'sqlite'\n default:\n return null\n }\n}\n\n// Returns the inner DbConfig fields without sourceFile — every caller spreads\n// the parser's own file path on top. Type makes that contract explicit.\nexport type ParsedConnectionConfig = Omit<DbConfig, 'sourceFile'>\n\nexport function parseConnectionString(url: string): ParsedConnectionConfig | null {\n const m = url.match(\n /^(?<scheme>[a-z][a-z+]*):\\/\\/(?:[^@/]+(?::[^@]*)?@)?(?<host>[^:/?]+)(?::(?<port>\\d+))?(?:\\/(?<db>[^?#]*))?/i,\n )\n if (!m || !m.groups) return null\n const engine = schemeToEngine(m.groups.scheme!)\n if (!engine) return null\n return {\n host: m.groups.host!,\n port: m.groups.port ? Number(m.groups.port) : undefined,\n database: m.groups.db ?? '',\n engine,\n engineVersion: 'unknown',\n }\n}\n\nexport async function readIfExists(filePath: string): Promise<string | null> {\n try {\n return await fs.readFile(filePath, 'utf8')\n } catch {\n return null\n }\n}\n\nexport async function findFirst(\n serviceDir: string,\n candidates: string[],\n): Promise<string | null> {\n for (const rel of candidates) {\n const abs = path.join(serviceDir, rel)\n const content = await readIfExists(abs)\n if (content !== null) return abs\n }\n return null\n}\n\n// Engine name from a docker-compose `image:` value like \"postgres:15-alpine\"\n// or \"mysql/mysql-server:8.0\". Returns the engine + version when both are\n// resolvable, or null if the image isn't one we recognise.\nexport function engineFromImage(\n image: string,\n): { engine: string; engineVersion: string } | null {\n const lower = image.toLowerCase()\n const colon = lower.lastIndexOf(':')\n const repo = colon >= 0 ? lower.slice(0, colon) : lower\n const tag = colon >= 0 ? lower.slice(colon + 1) : 'latest'\n const last = repo.split('/').pop() ?? repo\n let engine: string | null = null\n if (last.startsWith('postgres')) engine = 'postgresql'\n else if (last.startsWith('mysql') || last.startsWith('mariadb')) engine = 'mysql'\n else if (last.startsWith('mongo')) engine = 'mongodb'\n else if (last.startsWith('redis')) engine = 'redis'\n else if (last.startsWith('sqlite')) engine = 'sqlite'\n if (!engine) return null\n // Strip everything after the major version digit run; \"15-alpine\" -> \"15\".\n const versionMatch = tag.match(/^(\\d+(?:\\.\\d+){0,2})/)\n return {\n engine,\n engineVersion: versionMatch ? versionMatch[1]! : 'unknown',\n }\n}\n","import path from 'node:path'\nimport { readIfExists, parseConnectionString, schemeToEngine, type DbConfig } from './shared.js'\n\n// Prisma's schema file declares datasources of the form:\n//\n// datasource db {\n// provider = \"postgresql\"\n// url = env(\"DATABASE_URL\")\n// }\n//\n// We match the provider directly. URLs come in via env() so we can't resolve\n// them statically; host/database fall back to placeholders so the DatabaseNode\n// id remains deterministic per service.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const schemaPath = path.join(serviceDir, 'prisma', 'schema.prisma')\n const content = await readIfExists(schemaPath)\n if (!content) return []\n\n const block = content.match(/datasource\\s+\\w+\\s*\\{([^}]*)\\}/s)\n if (!block) return []\n const body = block[1] ?? ''\n\n const providerMatch = body.match(/provider\\s*=\\s*\"([^\"]+)\"/)\n if (!providerMatch) return []\n const engine = schemeToEngine(providerMatch[1]!)\n if (!engine) return []\n\n const urlMatch = body.match(/url\\s*=\\s*\"([^\"]+)\"/)\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: schemaPath }]\n }\n\n return [\n {\n host: `${engine}-prisma`,\n database: '',\n engine,\n engineVersion: 'unknown',\n sourceFile: schemaPath,\n },\n ]\n}\n\nexport const prismaParser = { name: 'prisma', parse }\n","import { findFirst, readIfExists, parseConnectionString, schemeToEngine, type DbConfig } from './shared.js'\n\nconst DIALECT_TO_ENGINE: Record<string, string> = {\n postgresql: 'postgresql',\n postgres: 'postgresql',\n pg: 'postgresql',\n mysql: 'mysql',\n mysql2: 'mysql',\n sqlite: 'sqlite',\n 'better-sqlite': 'sqlite',\n}\n\n// Drizzle's drizzle.config.{ts,js,mjs} declares a `dialect` plus credentials.\n// We can't safely eval the file, but the relevant bits are simple key/value\n// expressions — regex-extracted to stay sandbox-clean and dep-free.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'drizzle.config.ts',\n 'drizzle.config.js',\n 'drizzle.config.mjs',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const dialectMatch = content.match(/dialect\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (!dialectMatch) return []\n const engine =\n DIALECT_TO_ENGINE[dialectMatch[1]!.toLowerCase()] ?? schemeToEngine(dialectMatch[1]!)\n if (!engine) return []\n\n const urlMatch = content.match(\n /(?:url|connectionString)\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n )\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: filePath }]\n }\n const hostMatch = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (hostMatch) {\n const portMatch = content.match(/port\\s*:\\s*(\\d+)/)\n const dbMatch = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n return [\n {\n host: hostMatch[1]!,\n port: portMatch ? Number(portMatch[1]) : undefined,\n database: dbMatch?.[1] ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n }\n return [\n { host: `${engine}-drizzle`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath },\n ]\n}\n\nexport const drizzleParser = { name: 'drizzle', parse }\n","import { findFirst, readIfExists, parseConnectionString, type DbConfig } from './shared.js'\n\nconst CLIENT_TO_ENGINE: Record<string, string> = {\n pg: 'postgresql',\n postgres: 'postgresql',\n postgresql: 'postgresql',\n mysql: 'mysql',\n mysql2: 'mysql',\n sqlite3: 'sqlite',\n 'better-sqlite3': 'sqlite',\n}\n\n// knexfile.{js,ts} declares a client (one of pg/mysql/sqlite/...) plus a\n// connection string or host/port object. We pick whichever shape is in the\n// file and ignore environment-driven values we can't resolve statically.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'knexfile.js',\n 'knexfile.ts',\n 'knexfile.cjs',\n 'knexfile.mjs',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const clientMatch = content.match(/client\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n if (!clientMatch) return []\n const engine = CLIENT_TO_ENGINE[clientMatch[1]!.toLowerCase()]\n if (!engine) return []\n\n const urlMatch = content.match(\n /connection\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n )\n if (urlMatch) {\n const config = parseConnectionString(urlMatch[1]!)\n if (config) return [{ ...config, sourceFile: filePath }]\n }\n\n const host = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n if (host) {\n const port = content.match(/port\\s*:\\s*(\\d+)/)?.[1]\n const database = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n return [\n {\n host,\n port: port ? Number(port) : undefined,\n database,\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n }\n\n return [{ host: `${engine}-knex`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath }]\n}\n\nexport const knexParser = { name: 'knex', parse }\n","import path from 'node:path'\nimport { exists, readJson, readYaml } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface OrmConfigEntry {\n type?: string\n host?: string\n port?: number\n database?: string\n}\n\n// ormconfig.{json,yaml,yml} — TypeORM's legacy config file. Single object or\n// an array of named connections; we walk both.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n for (const candidate of ['ormconfig.json', 'ormconfig.yaml', 'ormconfig.yml']) {\n const abs = path.join(serviceDir, candidate)\n if (!(await exists(abs))) continue\n const raw = candidate.endsWith('.json')\n ? await readJson<OrmConfigEntry | OrmConfigEntry[]>(abs)\n : await readYaml<OrmConfigEntry | OrmConfigEntry[]>(abs)\n const entries = Array.isArray(raw) ? raw : [raw]\n\n const out: DbConfig[] = []\n for (const entry of entries) {\n if (!entry?.type || !entry.host) continue\n const engine = schemeToEngine(entry.type)\n if (!engine) continue\n out.push({\n host: entry.host,\n port: entry.port,\n database: entry.database ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: abs,\n })\n }\n if (out.length > 0) return out\n }\n return []\n}\n\nexport const ormconfigParser = { name: 'ormconfig', parse }\n","import { findFirst, readIfExists, schemeToEngine, type DbConfig } from './shared.js'\n\n// TypeORM's modern shape: `new DataSource({ type: 'postgres', host, port, ... })`\n// in a data-source.ts (or .js). We regex for the type/host/port/database keys\n// in the first DataSource literal we find.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const filePath = await findFirst(serviceDir, [\n 'data-source.ts',\n 'data-source.js',\n 'src/data-source.ts',\n 'src/data-source.js',\n ])\n if (!filePath) return []\n const content = await readIfExists(filePath)\n if (!content) return []\n\n const block = content.match(/new\\s+DataSource\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)/)\n const body = block ? block[1]! : content\n\n const typeMatch = body.match(/type\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n const host = body.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n if (!typeMatch || !host) return []\n\n const engine = schemeToEngine(typeMatch[1]!)\n if (!engine) return []\n\n const port = body.match(/port\\s*:\\s*(\\d+)/)?.[1]\n const database = body.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n\n return [\n {\n host,\n port: port ? Number(port) : undefined,\n database,\n engine,\n engineVersion: 'unknown',\n sourceFile: filePath,\n },\n ]\n}\n\nexport const typeormParser = { name: 'typeorm', parse }\n","import path from 'node:path'\nimport { exists, readJson } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface SequelizeConfigEntry {\n dialect?: string\n host?: string\n port?: number\n database?: string\n}\n\ntype SequelizeConfig = Record<string, SequelizeConfigEntry>\n\n// Sequelize stores per-environment configs under config/config.json. We read\n// every named environment so a service that declares production + staging\n// surfaces both DB targets.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n const configPath = path.join(serviceDir, 'config', 'config.json')\n if (!(await exists(configPath))) return []\n const raw = await readJson<SequelizeConfig>(configPath)\n\n const out: DbConfig[] = []\n const seen = new Set<string>()\n for (const entry of Object.values(raw)) {\n if (!entry?.dialect || !entry.host) continue\n const engine = schemeToEngine(entry.dialect)\n if (!engine) continue\n const key = `${engine}://${entry.host}:${entry.port ?? ''}/${entry.database ?? ''}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push({\n host: entry.host,\n port: entry.port,\n database: entry.database ?? '',\n engine,\n engineVersion: 'unknown',\n sourceFile: configPath,\n })\n }\n return out\n}\n\nexport const sequelizeParser = { name: 'sequelize', parse }\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport { engineFromImage, type DbConfig } from './shared.js'\n\ninterface ComposeService {\n image?: string\n ports?: (string | number)[]\n environment?: Record<string, string> | string[]\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\nfunction portFromService(svc: ComposeService): number | undefined {\n for (const raw of svc.ports ?? []) {\n const str = String(raw)\n // \"5432:5432\", \"5432\", or \"host:5432\" → take the trailing port.\n const last = str.split(':').pop()\n const n = Number(last)\n if (Number.isFinite(n) && n > 0) return n\n }\n return undefined\n}\n\nfunction databaseFromEnv(svc: ComposeService): string {\n const env = svc.environment\n const get = (key: string): string | undefined => {\n if (!env) return undefined\n if (Array.isArray(env)) {\n for (const line of env) {\n const [k, v] = line.split('=')\n if (k === key) return v\n }\n return undefined\n }\n return env[key]\n }\n return get('POSTGRES_DB') ?? get('MYSQL_DATABASE') ?? get('MONGO_INITDB_DATABASE') ?? ''\n}\n\n// Service-local docker-compose.yml — every service whose image we recognise\n// becomes a candidate DB. The compose service name doubles as the host since\n// that's how peer services on the same compose network reach it.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(serviceDir, name)\n if (!(await exists(abs))) continue\n const raw = await readYaml<ComposeFile>(abs)\n if (!raw?.services) return []\n\n const out: DbConfig[] = []\n for (const [serviceName, svc] of Object.entries(raw.services)) {\n if (!svc.image) continue\n const meta = engineFromImage(svc.image)\n if (!meta) continue\n out.push({\n host: serviceName,\n port: portFromService(svc),\n database: databaseFromEnv(svc),\n engine: meta.engine,\n engineVersion: meta.engineVersion,\n sourceFile: abs,\n })\n }\n return out\n }\n return []\n}\n\nexport const dockerComposeParser = { name: 'docker-compose', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ConfigNode, GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n configId,\n confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n IGNORED_DIRS,\n isConfigFile,\n isPythonVenvDir,\n makeEdgeId,\n type DiscoveredService,\n} from './shared.js'\nimport { ensureFileNode, toPosix } from './calls/shared.js'\n\n// Walk a service directory and collect every config file path\n// (yaml/yml + .env-shaped). We deliberately stop at file paths here so nothing\n// in this module reads file contents — .env files routinely carry secrets\n// (ADR-016).\nexport async function walkConfigFiles(dir: string): Promise<string[]> {\n const out: string[] = []\n async function walk(current: string): Promise<void> {\n const entries = await fs.readdir(current, { withFileTypes: true })\n for (const entry of entries) {\n const full = path.join(current, entry.name)\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n if (await isPythonVenvDir(full)) continue\n await walk(full)\n } else if (entry.isFile() && isConfigFile(entry.name).match) {\n out.push(full)\n }\n }\n }\n await walk(dir)\n return out\n}\n\n// Phase 3 — turn each config file into a ConfigNode with a CONFIGURED_BY edge\n// from its owning service.\nexport async function addConfigNodes(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n for (const service of services) {\n const configFiles = await walkConfigFiles(service.dir)\n for (const file of configFiles) {\n const relPath = path.relative(scanPath, file)\n const node: ConfigNode = {\n id: configId(relPath),\n type: NodeType.ConfigNode,\n name: path.basename(file),\n path: relPath,\n fileType: isConfigFile(path.basename(file)).fileType,\n }\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n // file-awareness §1 — the config file IS the relationship origin.\n // ensureFileNode creates the FileNode + CONTAINS edge so CONFIGURED_BY\n // lands file-grained rather than service-level.\n const relToService = toPosix(path.relative(service.dir, file))\n const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relToService,\n )\n nodesAdded += fn\n edgesAdded += fe\n const edge: GraphEdge = {\n id: makeEdgeId(fileNodeId, node.id, EdgeType.CONFIGURED_BY),\n source: fileNodeId,\n target: node.id,\n type: EdgeType.CONFIGURED_BY,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: relPath.split(path.sep).join('/') },\n }\n if (!graph.hasEdge(edge.id)) {\n graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n","import type { GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n EdgeType,\n NodeType,\n Provenance,\n confidenceForExtracted,\n passesExtractedFloor,\n} from '@neat.is/types'\nimport { noteExtractedDropped } from '../errors.js'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n isTestPath,\n makeEdgeId,\n maskCommentsInSource,\n type DiscoveredService,\n} from '../shared.js'\nimport { addHttpCallEdges } from './http.js'\nimport { ensureFileNode, loadSourceFiles, toPosix, type ExternalEndpoint } from './shared.js'\nimport { kafkaEndpointsFromFile } from './kafka.js'\nimport { redisEndpointsFromFile } from './redis.js'\nimport { awsEndpointsFromFile } from './aws.js'\nimport { grpcEndpointsFromFile } from './grpc.js'\n\nexport interface CallExtractResult {\n nodesAdded: number\n edgesAdded: number\n}\n\nfunction edgeTypeFromEndpoint(ep: ExternalEndpoint): (typeof EdgeType)[keyof typeof EdgeType] {\n switch (ep.edgeType) {\n case 'PUBLISHES_TO':\n return EdgeType.PUBLISHES_TO\n case 'CONSUMES_FROM':\n return EdgeType.CONSUMES_FROM\n default:\n return EdgeType.CALLS\n }\n}\n\nfunction isAwsKind(kind: string): boolean {\n return (\n kind.startsWith('aws-') ||\n kind.startsWith('s3') ||\n kind.startsWith('dynamodb')\n )\n}\n\nasync function addExternalEndpointEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<CallExtractResult> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const files = await loadSourceFiles(service.dir)\n const endpoints: ExternalEndpoint[] = []\n for (const file of files) {\n // ADR-065 #1 — test-scope exclusion. Tests stay registered as\n // service-internal (via the file walk earlier); only outbound\n // endpoint inference from them is filtered.\n if (isTestPath(file.path)) continue\n // ADR-065 #2 — comment-body exclusion. The regex-based extractors\n // (redis / kafka / aws / grpc) scan raw file.content; URLs inside\n // JSDoc / line / block comments leaked through to the graph in the\n // v0.3.0 medusa run. Mask comments while preserving line/column for\n // evidence line-mapping.\n const masked = maskCommentsInSource(file.content)\n const maskedFile = { path: file.path, content: masked }\n endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir))\n endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir))\n }\n if (endpoints.length === 0) continue\n\n const seenEdges = new Set<string>()\n for (const ep of endpoints) {\n if (!graph.hasNode(ep.infraId)) {\n const node: InfraNode = {\n id: ep.infraId,\n type: NodeType.InfraNode,\n name: ep.name,\n // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,\n // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the\n // bucket / table kinds from aws.ts.\n provider: isAwsKind(ep.kind) ? 'aws' : 'self',\n kind: ep.kind,\n }\n graph.addNode(node.id, node)\n nodesAdded++\n }\n\n const edgeType = edgeTypeFromEndpoint(ep)\n const confidence = confidenceForExtracted(ep.confidenceKind)\n // File-first (file-awareness.md §1): the endpoint relationship originates\n // from the file the call site lives in, with the owning service\n // ──CONTAINS──▶ file edge alongside it (§2). File-node existence is\n // independent of edge-target precision (ADR-089 amendment) — a matched\n // call site is a parsed fact, so the FileNode + CONTAINS materialize\n // regardless of how confident we are about the resolved target.\n const relFile = toPosix(ep.evidence.file)\n const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relFile,\n )\n nodesAdded += n\n edgesAdded += e\n // Precision floor (ADR-066 §3). Only the file→target edge is gated:\n // sub-threshold candidates are recorded as drops (banner accounting) and\n // never added to the graph; the file and its call site still surface.\n if (!passesExtractedFloor(confidence)) {\n noteExtractedDropped({\n source: fileNodeId,\n target: ep.infraId,\n type: edgeType,\n confidence,\n confidenceKind: ep.confidenceKind,\n evidence: ep.evidence,\n })\n continue\n }\n const edgeId = makeEdgeId(fileNodeId, ep.infraId, edgeType)\n if (seenEdges.has(edgeId)) continue\n seenEdges.add(edgeId)\n if (!graph.hasEdge(edgeId)) {\n const edge: GraphEdge = {\n id: edgeId,\n source: fileNodeId,\n target: ep.infraId,\n type: edgeType,\n provenance: Provenance.EXTRACTED,\n confidence,\n evidence: ep.evidence,\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n\nexport async function addCallEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<CallExtractResult> {\n const http = await addHttpCallEdges(graph, services)\n const ext = await addExternalEndpointEdges(graph, services)\n return {\n nodesAdded: http.nodesAdded + ext.nodesAdded,\n edgesAdded: http.edgesAdded + ext.edgesAdded,\n }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport Python from 'tree-sitter-python'\nimport type { GraphEdge } from '@neat.is/types'\nimport {\n EdgeType,\n Provenance,\n confidenceForExtracted,\n passesExtractedFloor,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n isTestPath,\n makeEdgeId,\n urlMatchesHost,\n type DiscoveredService,\n} from '../shared.js'\nimport { recordExtractionError, noteExtractedDropped } from '../errors.js'\nimport { ensureFileNode, loadSourceFiles, snippet, toPosix } from './shared.js'\n\n// JS uses `string_fragment` for the textual interior of a template/string;\n// Python uses `string_content` inside a `string` node. Either way we want the\n// raw textual content (no quotes), so we accept both.\nconst STRING_LITERAL_NODE_TYPES = new Set(['string_fragment', 'string_content'])\n\n// ADR-065 #3 — JSX external-link exclusion. Tags whose URL-attr strings are\n// user-clickable hyperlinks, not service-to-service calls.\nconst JSX_EXTERNAL_LINK_TAGS = new Set(['a', 'Link', 'NavLink', 'ExternalLink', 'Anchor'])\n\n// Walk upward from a string-literal node to detect whether it sits inside a\n// JSX attribute on an external-link element. Returns true if the literal\n// should be filtered.\nfunction isInsideJsxExternalLink(node: Parser.SyntaxNode): boolean {\n let cursor: Parser.SyntaxNode | null = node.parent\n // Step out of the string wrapper if needed (parent is `string` /\n // `template_string`).\n while (cursor) {\n if (cursor.type === 'jsx_attribute') {\n // The element that owns this attribute. jsx_attribute lives inside\n // jsx_opening_element / jsx_self_closing_element.\n let owner: Parser.SyntaxNode | null = cursor.parent\n while (owner && owner.type !== 'jsx_opening_element' && owner.type !== 'jsx_self_closing_element') {\n owner = owner.parent\n }\n if (!owner) return false\n // First named child of an opening/self-closing element is the tag name\n // (`identifier` or `member_expression`).\n const tagNode = owner.namedChild(0)\n const tagName = tagNode?.text ?? ''\n // For `<Foo.Bar>` we just want the rightmost ident; pick after the\n // last dot.\n const right = tagName.includes('.') ? tagName.split('.').pop()! : tagName\n return JSX_EXTERNAL_LINK_TAGS.has(right)\n }\n cursor = cursor.parent\n }\n return false\n}\n\n// Collect (literal text, ast-node) pairs so the JSX-context check has the\n// node available. Comment tokens have no string_fragment / string_content\n// children in tree-sitter — JSDoc text lives inside `comment` nodes — so\n// comment-body exclusion comes for free with this AST walk (ADR-065 #2).\nfunction collectStringLiterals(\n node: Parser.SyntaxNode,\n out: { text: string; node: Parser.SyntaxNode }[],\n): void {\n if (STRING_LITERAL_NODE_TYPES.has(node.type)) out.push({ text: node.text, node })\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i)\n if (child) collectStringLiterals(child, out)\n }\n}\n\n// A matched outbound call: the host the URL literal names and the 1-indexed\n// line it sits on. File-first extraction (file-awareness.md §1) originates a\n// CALLS edge from the file the call site lives in, so the position travels with\n// the host rather than being recovered after the fact.\nexport interface HttpCallSite {\n host: string\n line: number\n}\n\n// tree-sitter's node binding copies a string handed to `parser.parse` into a\n// fixed scratch buffer of ~32K code units and throws a bare \"Invalid argument\"\n// once the source is larger — it never names the size as the cause. NEAT's own\n// `cli.ts`, `ingest.ts`, and `installers/javascript.ts` all clear 40K, so the\n// http-call extractor was quietly skipping the three most interesting files in\n// the repo while dogfooding NEAT-on-NEAT. The callback form sidesteps the\n// buffer entirely: tree-sitter pulls the text in chunks we keep well under the\n// limit, so a file of any length parses. Chunking is by `.length` (UTF-16 code\n// units), which is exactly what the buffer counts.\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n return parser.parse((index: number) =>\n index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n )\n}\n\nexport function callsFromSource(\n source: string,\n parser: Parser,\n knownHosts: Set<string>,\n): HttpCallSite[] {\n const tree = parseSource(parser, source)\n const literals: { text: string; node: Parser.SyntaxNode }[] = []\n collectStringLiterals(tree.rootNode, literals)\n const out: HttpCallSite[] = []\n for (const lit of literals) {\n // ADR-065 #3 — JSX external-link exclusion. URL strings on <a>, <Link>,\n // <NavLink>, <ExternalLink>, <Anchor> are user-clickable hyperlinks, not\n // service calls.\n if (isInsideJsxExternalLink(lit.node)) continue\n for (const host of knownHosts) {\n // ADR-065 #5 — exact hostname match (not substring containment).\n // `medusa.cloud` no longer matches `@medusajs/medusa`.\n if (urlMatchesHost(lit.text, host)) {\n out.push({ host, line: lit.node.startPosition.row + 1 })\n }\n }\n }\n return out\n}\n\nfunction makeJsParser(): Parser {\n const p = new Parser()\n p.setLanguage(JavaScript)\n return p\n}\n\nfunction makePyParser(): Parser {\n const p = new Parser()\n p.setLanguage(Python)\n return p\n}\n\n// HTTP CALLS via URL hostname match. Parser is picked per file extension:\n// .py uses tree-sitter-python; everything else uses tree-sitter-javascript.\n//\n// File-first (file-awareness.md §1): each matched call site originates a\n// `file:<svc>:<relPath> ──CALLS──▶ target` edge plus the owning service's\n// CONTAINS edge, rather than collapsing every call in a service to one\n// service-level edge.\n//\n// File-node existence is independent of edge-target precision (file-awareness.md\n// §1, ADR-089 amendment). A matched call site is a parsed fact — the file and\n// its `service ──CONTAINS──▶ file` edge are certain regardless of how confident\n// we are about *what* it calls. So the FileNode + CONTAINS materialize for every\n// matched site; only the file→target CALLS edge is subject to the precision\n// floor. A hostname-shape match (0.2) below the floor surfaces the file and its\n// call site without claiming the resolved target, rather than vanishing whole.\nexport async function addHttpCallEdges(\n graph: NeatGraph,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n const jsParser = makeJsParser()\n const pyParser = makePyParser()\n\n const knownHosts = new Set<string>()\n const hostToNodeId = new Map<string, string>()\n for (const service of services) {\n knownHosts.add(path.basename(service.dir))\n knownHosts.add(service.pkg.name)\n hostToNodeId.set(path.basename(service.dir), service.node.id)\n hostToNodeId.set(service.pkg.name, service.node.id)\n }\n\n let nodesAdded = 0\n let edgesAdded = 0\n for (const service of services) {\n const files = await loadSourceFiles(service.dir)\n // File grain: one file→target CALLS per (file, target) pair, even when a\n // file names the same host on several lines (function-level is deferred).\n const seen = new Set<string>()\n for (const file of files) {\n // ADR-065 #1 — test-scope exclusion.\n if (isTestPath(file.path)) continue\n const parser = path.extname(file.path) === '.py' ? pyParser : jsParser\n let sites: HttpCallSite[]\n try {\n sites = callsFromSource(file.content, parser, knownHosts)\n } catch (err) {\n recordExtractionError('http call extraction', file.path, err)\n continue\n }\n if (sites.length === 0) continue\n const relFile = toPosix(path.relative(service.dir, file.path))\n for (const site of sites) {\n const targetId = hostToNodeId.get(site.host)\n if (!targetId || targetId === service.node.id) continue\n const dedupKey = `${relFile}|${targetId}`\n if (seen.has(dedupKey)) continue\n seen.add(dedupKey)\n // URL-string match against a registered service hostname is the\n // hostname-shape tier per ADR-066 — structurally tight (urlMatchesHost\n // requires scheme + exact hostname) but no framework-aware recognizer\n // confirms the call. Drops below the default precision floor (0.7).\n const confidence = confidenceForExtracted('hostname-shape-match')\n const ev = {\n file: relFile,\n line: site.line,\n snippet: snippet(file.content, site.line),\n }\n // The matched call site is a parsed fact: materialize the FileNode and\n // its `service ──CONTAINS──▶ file` edge regardless of target precision\n // (file-awareness.md §1, ADR-089 amendment). The file surfaces even\n // when the resolved target sits below the floor.\n const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relFile,\n )\n nodesAdded += n\n edgesAdded += e\n // The file→target CALLS edge alone is subject to the precision floor.\n // A sub-floor target is recorded as a drop (banner accounting) and not\n // claimed as a resolved edge — the file and its call site still stand.\n if (!passesExtractedFloor(confidence)) {\n noteExtractedDropped({\n source: fileNodeId,\n target: targetId,\n type: EdgeType.CALLS,\n confidence,\n confidenceKind: 'hostname-shape-match',\n evidence: ev,\n })\n continue\n }\n const edgeId = makeEdgeId(fileNodeId, targetId, EdgeType.CALLS)\n if (!graph.hasEdge(edgeId)) {\n const edge: GraphEdge = {\n id: edgeId,\n source: fileNodeId,\n target: targetId,\n type: EdgeType.CALLS,\n provenance: Provenance.EXTRACTED,\n confidence,\n evidence: ev,\n }\n graph.addEdgeWithKey(edgeId, fileNodeId, targetId, edge)\n edgesAdded++\n }\n }\n }\n }\n return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Match `producer.send({ topic: \"orders\" ... })` and `producer.send({\n// topic: 'orders' })` plus the two-arg form `producer.send(\"orders\", ...)`.\n// Kafka client libraries vary; these two forms cover kafkajs + node-rdkafka\n// well enough for static extraction. Same shape covers consumer.subscribe.\nconst PRODUCER_TOPIC_RE =\n /(?:producer|kafkaProducer)[\\s\\S]{0,40}?\\.send\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst CONSUMER_TOPIC_RE =\n /(?:consumer|kafkaConsumer)[\\s\\S]{0,40}?\\.(?:subscribe|run)\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic[s]?\\s*:\\s*(?:\\[\\s*)?['\"`]([^'\"`]+)['\"`]/g\n\nfunction findAll(re: RegExp, text: string): { topic: string; index: number }[] {\n re.lastIndex = 0\n const out: { topic: string; index: number }[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n out.push({ topic: m[1]!, index: m.index })\n }\n return out\n}\n\nexport function kafkaEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const make = (topic: string, edgeType: 'PUBLISHES_TO' | 'CONSUMES_FROM'): void => {\n const key = `${edgeType}|${topic}`\n if (seen.has(key)) return\n seen.add(key)\n const line = lineOf(file.content, topic)\n out.push({\n infraId: infraId('kafka-topic', topic),\n name: topic,\n kind: 'kafka-topic',\n edgeType,\n // `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})` —\n // framework-aware (kafkajs / node-rdkafka shape). Verified-call-site\n // tier (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n\n for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, 'PUBLISHES_TO')\n for (const { topic } of findAll(CONSUMER_TOPIC_RE, file.content)) make(topic, 'CONSUMES_FROM')\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Redis URLs in source — `redis://host[:port]` or `rediss://...`. We only\n// catch literal strings; env-driven URLs go through the database parsers\n// (.env, ormconfig, etc.) and don't need a CALLS edge.\nconst REDIS_URL_RE = /redis(?:s)?:\\/\\/(?:[^@'\"`\\s]+@)?([^:/'\"`\\s]+)(?::(\\d+))?/g\n\nexport function redisEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n REDIS_URL_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = REDIS_URL_RE.exec(file.content)) !== null) {\n const host = m[1]!\n if (seen.has(host)) continue\n seen.add(host)\n const line = lineOf(file.content, host)\n out.push({\n infraId: infraId('redis', host),\n name: host,\n kind: 'redis',\n edgeType: 'CALLS',\n // `redis://host` URL literal — the scheme is structural support, but no\n // call expression is verified to wire it through. URL-with-structural-\n // support tier (ADR-066).\n confidenceKind: 'url-with-structural-support',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// AWS SDK v3 calls. We catch S3 (`Bucket: \"x\"` near a `S3Client`-using\n// PutObjectCommand / GetObjectCommand / DeleteObjectCommand) and DynamoDB\n// (`TableName: \"x\"` near GetCommand / PutCommand / DynamoDBClient). The\n// pattern is intentionally permissive: a literal Bucket/TableName near an\n// SDK constant is good enough evidence; misses are fine because non-static\n// resources can't be catalogued anyway.\nconst S3_BUCKET_RE = /Bucket\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst DYNAMO_TABLE_RE = /TableName\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\n\nfunction hasMarker(text: string, markers: string[]): boolean {\n return markers.some((m) => text.includes(m))\n}\n\nfunction findAll(re: RegExp, text: string): { name: string; index: number }[] {\n re.lastIndex = 0\n const out: { name: string; index: number }[] = []\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n out.push({ name: m[1]!, index: m.index })\n }\n return out\n}\n\nexport function awsEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const make = (kind: string, name: string): void => {\n const key = `${kind}|${name}`\n if (seen.has(key)) return\n seen.add(key)\n const line = lineOf(file.content, name)\n out.push({\n infraId: infraId(kind, name),\n name,\n kind,\n edgeType: 'CALLS',\n // SDK marker (S3Client, GetCommand, etc.) plus a Bucket/TableName\n // literal — framework-aware recognizer, verified-call-site tier\n // (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n\n if (hasMarker(file.content, ['S3Client', 'PutObjectCommand', 'GetObjectCommand', 'DeleteObjectCommand'])) {\n for (const { name } of findAll(S3_BUCKET_RE, file.content)) make('s3-bucket', name)\n }\n if (\n hasMarker(file.content, [\n 'DynamoDBClient',\n 'DynamoDBDocumentClient',\n 'GetCommand',\n 'PutCommand',\n 'QueryCommand',\n 'UpdateCommand',\n 'DeleteCommand',\n ])\n ) {\n for (const { name } of findAll(DYNAMO_TABLE_RE, file.content)) make('dynamodb-table', name)\n }\n return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Client-construction in JS/TS:\n//\n// const client = new orders_proto.OrderService(...)\n// const client = new OrdersClient('orders.internal:50051', ...)\n// const client = new S3Client({ region: 'us-east-1' })\n//\n// The same `new <Name>Client(...)` shape is used by gRPC client stubs, AWS\n// SDK v3 service clients, and a long tail of other SDKs. v0.3.0 mapped every\n// `*Client(...)` to `infra:grpc-service:*`, which was true for the demo and\n// false for every AWS service medusa imported.\n//\n// Per ADR-065 / #238, classification is import-aware:\n// 1. file imports `@aws-sdk/client-<suffix>` and `<Name>` lowercases to the\n// same alphanumeric tail (`S3Client` ↔ `client-s3`,\n// `CognitoIdentityProviderClient` ↔ `client-cognito-identity-provider`)\n// → kind `aws-<suffix>` (e.g. `infra:aws-s3:S3`).\n// 2. file imports `@grpc/grpc-js` or any `*_grpc_pb` generated stub\n// → kind `grpc-service` (the legitimate gRPC path; demo unchanged).\n// 3. otherwise → kind `service` (the safe default — accurate but\n// uninformative, the v0.3.0 grpc lie is removed).\nconst GRPC_CLIENT_RE = /new\\s+([A-Z][A-Za-z0-9_]*)Client\\s*\\(\\s*['\"`]?([^,'\"`)]+)?/g\nconst AWS_SDK_IMPORT_RE =\n /(?:from\\s+['\"`]|require\\(\\s*['\"`])@aws-sdk\\/client-([a-z0-9-]+)['\"`]/g\nconst GRPC_IMPORT_RE =\n /(?:from\\s+['\"`]|require\\(\\s*['\"`])@grpc\\/grpc-js['\"`]|_grpc_pb['\"`]/\n\nfunction isLikelyAddress(value: string | undefined): boolean {\n if (!value) return false\n // Reject code expressions: object literals, anything with whitespace.\n // process.env.X contains dots and would otherwise pass the dot check.\n if (/\\s/.test(value) || value.startsWith('{')) return false\n return /:\\d{2,5}$/.test(value) || value.includes('.')\n}\n\nfunction normaliseForMatch(s: string): string {\n return s.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n\ninterface ImportContext {\n awsSdkSuffixes: Map<string, string> // normalised → raw suffix (e.g. 's3' → 's3')\n hasGrpcImport: boolean\n}\n\nfunction readImports(content: string): ImportContext {\n const awsSdkSuffixes = new Map<string, string>()\n AWS_SDK_IMPORT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = AWS_SDK_IMPORT_RE.exec(content)) !== null) {\n const raw = m[1]!\n awsSdkSuffixes.set(normaliseForMatch(raw), raw)\n }\n return {\n awsSdkSuffixes,\n hasGrpcImport: GRPC_IMPORT_RE.test(content),\n }\n}\n\nfunction classifyClient(\n symbol: string,\n ctx: ImportContext,\n): { kind: string } | null {\n const key = normaliseForMatch(symbol)\n const awsRaw = ctx.awsSdkSuffixes.get(key)\n if (awsRaw) return { kind: `aws-${awsRaw}` }\n if (ctx.hasGrpcImport) return { kind: 'grpc-service' }\n // ADR-065 #5-adjacent — a bare `new <Name>Client()` with no AWS or gRPC\n // import context is ambiguous; could be an in-process client object\n // (`new QueryClient()` from @tanstack/react-query, `new PrismaClient()`,\n // a domain Client class, etc.). Refuse to emit an edge rather than guess\n // a `service` kind that produces false positives. v0.3.3 medusa run had\n // a QueryClient false positive before this guard.\n return null\n}\n\nexport function grpcEndpointsFromFile(\n file: SourceFile,\n serviceDir: string,\n): ExternalEndpoint[] {\n const out: ExternalEndpoint[] = []\n const seen = new Set<string>()\n const ctx = readImports(file.content)\n GRPC_CLIENT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = GRPC_CLIENT_RE.exec(file.content)) !== null) {\n const symbol = m[1]!\n const addr = m[2]?.trim()\n const name = isLikelyAddress(addr) ? addr! : symbol\n if (seen.has(name)) continue\n const classified = classifyClient(symbol, ctx)\n if (!classified) continue\n seen.add(name)\n const { kind } = classified\n const line = lineOf(file.content, m[0])\n out.push({\n infraId: infraId(kind, name),\n name,\n kind,\n edgeType: 'CALLS',\n // `new <Name>Client(...)` with @aws-sdk/* or @grpc/grpc-js import\n // context — import-aware classification per #238. Verified-call-site\n // tier (ADR-066).\n confidenceKind: 'verified-call-site',\n evidence: {\n file: path.relative(serviceDir, file.path),\n line,\n snippet: snippet(file.content, line),\n },\n })\n }\n return out\n}\n","import type { NeatGraph } from '../../graph.js'\nimport { type DiscoveredService } from '../shared.js'\nimport { addComposeInfra } from './docker-compose.js'\nimport { addDockerfileRuntimes } from './dockerfile.js'\nimport { addTerraformResources } from './terraform.js'\nimport { addK8sResources } from './k8s.js'\n\nexport interface InfraExtractResult {\n nodesAdded: number\n edgesAdded: number\n}\n\n// Phase 5 — infrastructure. Runs after services so RUNS_ON edges have a\n// ServiceNode to anchor on. Each sub-source contributes its own nodes/edges\n// independently; nothing here mutates ServiceNodes themselves.\nexport async function addInfra(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<InfraExtractResult> {\n const compose = await addComposeInfra(graph, scanPath, services)\n const dockerfile = await addDockerfileRuntimes(graph, services, scanPath)\n const terraform = await addTerraformResources(graph, scanPath)\n const k8s = await addK8sResources(graph, scanPath)\n\n return {\n nodesAdded:\n compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,\n edgesAdded:\n compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded,\n }\n}\n","import path from 'node:path'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, readYaml, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { classifyImage, makeInfraNode } from './shared.js'\n\ninterface ComposeService {\n image?: string\n build?: string | { context?: string }\n depends_on?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n services?: Record<string, ComposeService>\n}\n\nfunction dependsOnList(value: ComposeService['depends_on']): string[] {\n if (!value) return []\n if (Array.isArray(value)) return value\n return Object.keys(value)\n}\n\nfunction serviceNameToServiceNode(\n name: string,\n services: DiscoveredService[],\n): string | null {\n for (const s of services) {\n if (s.node.name === name || path.basename(s.dir) === name) return s.node.id\n }\n return null\n}\n\n// Project-level docker-compose.yml describes deployment topology. Each compose\n// service that is *not* one of the discovered ServiceNodes becomes an\n// InfraNode (databases, brokers, caches). depends_on lists become DEPENDS_ON\n// edges from the dependent to its dependency, regardless of whether the\n// endpoint is a ServiceNode or InfraNode — the edge itself is the deployment\n// fact, not the role.\nexport async function addComposeInfra(\n graph: NeatGraph,\n scanPath: string,\n services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n let composePath: string | null = null\n for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n const abs = path.join(scanPath, name)\n if (await exists(abs)) {\n composePath = abs\n break\n }\n }\n if (!composePath) return { nodesAdded, edgesAdded }\n\n let compose: ComposeFile\n try {\n compose = await readYaml<ComposeFile>(composePath)\n } catch (err) {\n recordExtractionError(\n 'infra docker-compose',\n path.relative(scanPath, composePath),\n err,\n )\n return { nodesAdded, edgesAdded }\n }\n if (!compose?.services) return { nodesAdded, edgesAdded }\n const evidenceFile = path.relative(scanPath, composePath).split(path.sep).join('/')\n\n const composeNameToNodeId = new Map<string, string>()\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const matchedServiceId = serviceNameToServiceNode(composeName, services)\n if (matchedServiceId) {\n composeNameToNodeId.set(composeName, matchedServiceId)\n continue\n }\n const kind = svc.image ? classifyImage(svc.image) : 'container'\n const node = makeInfraNode(kind, composeName)\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n composeNameToNodeId.set(composeName, node.id)\n }\n\n for (const [composeName, svc] of Object.entries(compose.services)) {\n const sourceId = composeNameToNodeId.get(composeName)\n if (!sourceId) continue\n for (const dep of dependsOnList(svc.depends_on)) {\n const targetId = composeNameToNodeId.get(dep)\n if (!targetId) continue\n const edgeId = makeEdgeId(sourceId, targetId, EdgeType.DEPENDS_ON)\n if (graph.hasEdge(edgeId)) continue\n // depends_on declaration from docker-compose.yml — structural deployment\n // fact, structural tier per ADR-066.\n const edge: GraphEdge = {\n id: edgeId,\n source: sourceId,\n target: targetId,\n type: EdgeType.DEPENDS_ON,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: { file: evidenceFile },\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import type { InfraNode } from '@neat.is/types'\nimport { NodeType, infraId } from '@neat.is/types'\n\n// ADR-010 reserves the `infra:` prefix; the kind segment lets traversal and\n// MCP tools sub-type without inventing a new top-level NodeType per source.\nexport function makeInfraNode(\n kind: string,\n name: string,\n provider = 'self',\n extras?: { region?: string },\n): InfraNode {\n return {\n id: infraId(kind, name),\n type: NodeType.InfraNode,\n name,\n provider,\n kind,\n ...(extras?.region ? { region: extras.region } : {}),\n }\n}\n\n// Stable kind for an image string like \"postgres:15-alpine\" or \"mysql:8\".\n// The image name itself ends up in the InfraNode `name` field; this function\n// only classifies what the image *is*, so callers can group similar runtimes.\nexport function classifyImage(image: string): string {\n const lower = image.toLowerCase()\n const repo = lower.split(':')[0]!\n const last = repo.split('/').pop() ?? repo\n if (last.startsWith('postgres')) return 'postgres'\n if (last.startsWith('mysql') || last.startsWith('mariadb')) return 'mysql'\n if (last.startsWith('mongo')) return 'mongodb'\n if (last.startsWith('redis')) return 'redis'\n if (last.startsWith('rabbitmq')) return 'rabbitmq'\n if (last.startsWith('kafka') || last.includes('kafka')) return 'kafka'\n if (last.startsWith('memcached')) return 'memcached'\n return 'container'\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { makeInfraNode } from './shared.js'\nimport { ensureFileNode, toPosix } from '../calls/shared.js'\n\n// Pull the first non-`scratch` `FROM` line out of a Dockerfile, ignoring\n// multi-stage `as` aliases. Returns the image including tag (e.g. `node:20`,\n// `python:3.11-slim`). Multi-stage builds report the *runtime* image — the\n// last FROM that isn't aliasing a previous stage.\nfunction runtimeImage(content: string): string | null {\n const lines = content.split('\\n')\n let last: string | null = null\n for (const raw of lines) {\n const line = raw.trim()\n if (!line || line.startsWith('#')) continue\n if (!/^from\\s+/i.test(line)) continue\n const tokens = line.split(/\\s+/)\n const image = tokens[1]\n if (!image || image.toLowerCase() === 'scratch') continue\n last = image\n }\n return last\n}\n\n// For each ServiceNode that has a Dockerfile in its dir, emit a\n// `infra:container-image:<image>` InfraNode and a RUNS_ON edge from the\n// service to the image.\nexport async function addDockerfileRuntimes(\n graph: NeatGraph,\n services: DiscoveredService[],\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n let edgesAdded = 0\n\n for (const service of services) {\n const dockerfilePath = path.join(service.dir, 'Dockerfile')\n if (!(await exists(dockerfilePath))) continue\n let content: string\n try {\n content = await fs.readFile(dockerfilePath, 'utf8')\n } catch (err) {\n recordExtractionError(\n 'infra dockerfile',\n path.relative(scanPath, dockerfilePath),\n err,\n )\n continue\n }\n const image = runtimeImage(content)\n if (!image) continue\n\n const node = makeInfraNode('container-image', image)\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n\n // file-awareness §1 — the Dockerfile IS the file that declares the runtime;\n // anchor the RUNS_ON edge on a FileNode for it, not on the service.\n const relDockerfile = toPosix(path.relative(service.dir, dockerfilePath))\n const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n graph,\n service.pkg.name,\n service.node.id,\n relDockerfile,\n )\n nodesAdded += fn\n edgesAdded += fe\n const edgeId = makeEdgeId(fileNodeId, node.id, EdgeType.RUNS_ON)\n if (!graph.hasEdge(edgeId)) {\n const edge: GraphEdge = {\n id: edgeId,\n source: fileNodeId,\n target: node.id,\n type: EdgeType.RUNS_ON,\n provenance: Provenance.EXTRACTED,\n confidence: confidenceForExtracted('structural'),\n evidence: {\n file: toPosix(path.relative(scanPath, dockerfilePath)),\n },\n }\n graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n edgesAdded++\n }\n }\n\n return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { NeatGraph } from '../../graph.js'\nimport { IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { makeInfraNode } from './shared.js'\n\n// Light pass: catalogue `resource \"aws_*\" \"name\"` blocks in any *.tf file.\n// We don't interpret references — a real Terraform backend would resolve\n// those — but the resource-type/name pair is enough to register the node so\n// later cross-references can hang off it.\nconst RESOURCE_RE = /resource\\s+\"(aws_[A-Za-z0-9_]+)\"\\s+\"([A-Za-z0-9_-]+)\"/g\n\nasync function walkTfFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name) || entry.name === '.terraform') continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkTfFiles(child, depth + 1, max)))\n } else if (entry.isFile() && entry.name.endsWith('.tf')) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\nexport async function addTerraformResources(\n graph: NeatGraph,\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n const files = await walkTfFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n RESOURCE_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = RESOURCE_RE.exec(content)) !== null) {\n const kind = m[1]!\n const name = m[2]!\n const node = makeInfraNode(kind, name, 'aws')\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded: 0 }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseAllDocuments } from 'yaml'\nimport type { NeatGraph } from '../../graph.js'\nimport { CONFIG_FILE_EXTENSIONS, IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { makeInfraNode } from './shared.js'\n\ninterface K8sDoc {\n kind?: string\n metadata?: { name?: string; namespace?: string }\n}\n\nconst K8S_KIND_TO_INFRA_KIND: Record<string, string> = {\n Service: 'k8s-service',\n Deployment: 'k8s-deployment',\n StatefulSet: 'k8s-statefulset',\n DaemonSet: 'k8s-daemonset',\n CronJob: 'k8s-cronjob',\n Job: 'k8s-job',\n Ingress: 'k8s-ingress',\n}\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n if (depth > max) return []\n const out: string[] = []\n const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (IGNORED_DIRS.has(entry.name)) continue\n const child = path.join(start, entry.name)\n if (await isPythonVenvDir(child)) continue\n out.push(...(await walkYamlFiles(child, depth + 1, max)))\n } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(path.join(start, entry.name))\n }\n }\n return out\n}\n\n// Multi-document YAML with kind/metadata.name. We keep the matching simple:\n// any file whose first doc looks k8s-shaped. The match is on `kind` only —\n// random YAML configs (db-config.yaml, etc.) are usually flat objects with no\n// `kind` field, so they're ignored without false positives.\nexport async function addK8sResources(\n graph: NeatGraph,\n scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n let nodesAdded = 0\n const files = await walkYamlFiles(scanPath)\n for (const file of files) {\n const content = await fs.readFile(file, 'utf8')\n let docs: K8sDoc[]\n try {\n docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n } catch {\n continue\n }\n for (const doc of docs) {\n if (!doc?.kind || !doc.metadata?.name) continue\n const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind]\n if (!infraKind) continue\n const namespaced = doc.metadata.namespace\n ? `${doc.metadata.namespace}/${doc.metadata.name}`\n : doc.metadata.name\n const node = makeInfraNode(infraKind, namespaced, 'kubernetes')\n if (!graph.hasNode(node.id)) {\n graph.addNode(node.id, node)\n nodesAdded++\n }\n }\n }\n return { nodesAdded, edgesAdded: 0 }\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\n\n// Drop any FileNode left with no edges. A FileNode exists to originate a\n// relationship (file-awareness.md §1); once its CALLS / CONTAINS edges are\n// retired and no OBSERVED traffic remains, the bare node carries nothing and\n// goes too. Called after edge retirement so the snapshot stays consistent with\n// what's on disk. Returns the count dropped.\nfunction dropOrphanedFileNodes(graph: NeatGraph): number {\n const orphans: string[] = []\n graph.forEachNode((id, attrs) => {\n if ((attrs as GraphNode).type !== NodeType.FileNode) return\n if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {\n orphans.push(id)\n }\n })\n for (const id of orphans) graph.dropNode(id)\n return orphans.length\n}\n\n// Drop every EXTRACTED edge whose evidence.file matches the given path, then\n// sweep any FileNode the retirement left orphaned. Called from watch.ts before\n// re-running an extract phase, so the producer's idempotent re-write recreates\n// only the edges that still apply. Edges from the deleted code stay deleted.\n// See docs/contracts/static-extraction.md §Ghost-edge cleanup. Mutation\n// authority lives under extract/* per ADR-030, so the dropEdge call must happen\n// here, not in watch.ts. The returned count is edges dropped (FileNode cleanup\n// is a structural side effect, not a ghost-edge count).\nexport function retireEdgesByFile(graph: NeatGraph, file: string): number {\n const normalized = file.split('\\\\').join('/')\n const toDrop: string[] = []\n graph.forEachEdge((id, attrs) => {\n const edge = attrs as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) return\n if (!edge.evidence?.file) return\n if (edge.evidence.file === normalized) toDrop.push(id)\n })\n for (const id of toDrop) graph.dropEdge(id)\n dropOrphanedFileNodes(graph)\n return toDrop.length\n}\n\n// #140 — full-pass cleanup. Walk every EXTRACTED edge in the graph; if its\n// `evidence.file` cannot be resolved on disk against the scan root or any\n// discovered service directory, drop it. extractFromDirectory calls this at\n// the end of every pass so a daemon bootstrap (or a re-init after the\n// operator deleted some source) gets a snapshot consistent with what's\n// actually on disk.\n//\n// Handles the deleted-file half of the ghost-edge bug. The edited-file half\n// (file still exists, producer no longer emits the edge) is handled by\n// watch.ts's per-file `retireEdgesByFile` on the mtime trigger.\n//\n// Path resolution is tolerant: producers in this tree are inconsistent about\n// whether `evidence.file` is scanPath-relative (configs, databases, infra)\n// or service-dir-relative (calls/*). We try every candidate base before\n// concluding the file is gone — the cost is one extra `existsSync` per\n// service dir per ghost candidate, which is cheap.\nexport function retireExtractedEdgesByMissingFile(\n graph: NeatGraph,\n scanPath: string,\n serviceDirs: readonly string[] = [],\n): number {\n const toDrop: string[] = []\n const bases = [scanPath, ...serviceDirs]\n graph.forEachEdge((id, attrs) => {\n const edge = attrs as GraphEdge\n if (edge.provenance !== Provenance.EXTRACTED) return\n const evidenceFile = edge.evidence?.file\n if (!evidenceFile) return\n if (path.isAbsolute(evidenceFile)) {\n if (!existsSync(evidenceFile)) toDrop.push(id)\n return\n }\n // Tolerant: the file is \"present\" if any base resolves it.\n const found = bases.some((base) => existsSync(path.join(base, evidenceFile)))\n if (!found) toDrop.push(id)\n })\n for (const id of toDrop) graph.dropEdge(id)\n dropOrphanedFileNodes(graph)\n return toDrop.length\n}\n","// computeDivergences — the thesis surface, derived (ADR-060).\n//\n// Walks the live graph and surfaces the five locked divergence shapes:\n// missing-observed, missing-extracted, version-mismatch, host-mismatch,\n// and compat-violation. Pure: no I/O, no mutation, no async. The function\n// operates on a NeatGraph reference and returns a fresh DivergenceResult\n// each call — there is no persistence (binding rule 2).\n//\n// Mutation authority (ADR-030 / contract #3) is locked to ingest.ts and\n// extract/*; this module reads only. The contract test\n// `packages/core/test/audits/contracts.test.ts` enforces it.\n\nimport type {\n CompatRuleRef,\n Divergence,\n DivergenceResult,\n DivergenceType,\n GraphEdge,\n GraphNode,\n ServiceNode,\n} from '@neat.is/types'\nimport {\n DivergenceResultSchema,\n EdgeType,\n NodeType,\n parseEdgeId,\n Provenance,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n checkCompatibility,\n checkDeprecatedApi,\n compatPairs,\n deprecatedApis,\n} from './compat.js'\nimport { confidenceForEdge } from './traverse.js'\n\nexport interface DivergenceQueryOpts {\n // Filter the result to a subset of divergence types. Undefined keeps all\n // five. Empty set returns nothing.\n type?: ReadonlySet<DivergenceType>\n // Drop divergences below this confidence threshold. Undefined keeps all.\n minConfidence?: number\n // Scope to divergences that involve this node (as source or target).\n node?: string\n}\n\n// (source, target, type) → which provenance variants are present. Each\n// bucket is the unit the missing-observed / missing-extracted detectors\n// operate over.\ninterface EdgeBucket {\n source: string\n target: string\n type: GraphEdge['type']\n extracted?: GraphEdge\n observed?: GraphEdge\n inferred?: GraphEdge\n stale?: GraphEdge\n}\n\nfunction bucketKey(source: string, target: string, type: string): string {\n return `${type}|${source}|${target}`\n}\n\nfunction bucketEdges(graph: NeatGraph): Map<string, EdgeBucket> {\n const buckets = new Map<string, EdgeBucket>()\n graph.forEachEdge((id, attrs) => {\n const e = attrs as GraphEdge\n const parsed = parseEdgeId(id)\n // parseEdgeId can fall through to EXTRACTED for unknown shapes — fall\n // back to the edge's own provenance when the id doesn't parse cleanly.\n const provenance = parsed?.provenance ?? e.provenance\n const key = bucketKey(e.source, e.target, e.type)\n const cur =\n buckets.get(key) ?? { source: e.source, target: e.target, type: e.type }\n switch (provenance) {\n case Provenance.EXTRACTED:\n cur.extracted = e\n break\n case Provenance.OBSERVED:\n cur.observed = e\n break\n case Provenance.INFERRED:\n cur.inferred = e\n break\n default:\n // STALE rides on what used to be an OBSERVED edge — the id format\n // stays OBSERVED per identity.ts, so this branch is mostly defensive.\n if (e.provenance === Provenance.STALE) cur.stale = e\n }\n buckets.set(key, cur)\n })\n return buckets\n}\n\nfunction nodeIsFrontier(graph: NeatGraph, nodeId: string): boolean {\n if (!graph.hasNode(nodeId)) return false\n const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n return attrs.type === NodeType.FrontierNode\n}\n\nfunction clampConfidence(n: number): number {\n if (!Number.isFinite(n)) return 0\n return Math.max(0, Math.min(1, n))\n}\n\nfunction reasonForMissingObserved(source: string, target: string, type: string): string {\n return `Code declares ${source} → ${target} (${type}) but no production traffic has been observed for this edge.`\n}\n\nfunction reasonForMissingExtracted(source: string, target: string, type: string): string {\n return `Production observed ${source} → ${target} (${type}) but static analysis did not surface this edge.`\n}\n\nconst RECOMMENDATION_MISSING_OBSERVED =\n 'Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.'\nconst RECOMMENDATION_MISSING_EXTRACTED =\n 'Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.'\nconst RECOMMENDATION_HOST_MISMATCH =\n 'Check environment-specific config overrides — the runtime host differs from what static configuration declares.'\n\n// ADR-066 §4 — reweight against graded confidence.\n//\n// `missing-extracted` (OBSERVED-led) cascades from the OBSERVED edge's\n// graded confidence (signal-block grade per ADR-066 §2). `missing-observed`\n// weights by the EXTRACTED edge's graded confidence (per-extractor grade\n// per ADR-066 §1). Sub-floor EXTRACTED candidates never enter the graph\n// (precision floor, §3) so what surfaces here is backed by structural or\n// verified-call-site evidence.\n//\n// Falls back to confidenceForEdge for legacy edges loaded from a pre-v0.3.4\n// snapshot that don't carry a stored `confidence` field.\nfunction gradedConfidence(edge: GraphEdge): number {\n if (typeof edge.confidence === 'number') return clampConfidence(edge.confidence)\n return clampConfidence(confidenceForEdge(edge))\n}\n\nfunction detectMissingDivergences(\n graph: NeatGraph,\n bucket: EdgeBucket,\n): Divergence[] {\n const out: Divergence[] = []\n\n // CONTAINS is structural ownership (service → file), not a declared-vs-\n // observed relationship — comparing its tiers would surface an OTel-only\n // file node as a spurious missing-extracted finding (file-awareness.md §2).\n // Divergence compares CALLS-family edges at the shared grain (§7).\n if (bucket.type === EdgeType.CONTAINS) return out\n\n if (bucket.extracted && !bucket.observed) {\n // Skip when the would-be target is a FrontierNode — those represent\n // unresolved span peers, not real entities we expect OBSERVED traffic\n // to. The coexistence contract is between EXTRACTED and OBSERVED on\n // real nodes; FRONTIER is unknown territory.\n if (!nodeIsFrontier(graph, bucket.target)) {\n // ADR-066 §4 — weight by the EXTRACTED edge's graded confidence.\n // Substring/hostname-shape candidates already dropped at the precision\n // floor; what remains is structural or verified-call-site evidence.\n out.push({\n type: 'missing-observed',\n source: bucket.source,\n target: bucket.target,\n edgeType: bucket.type,\n extracted: bucket.extracted,\n confidence: gradedConfidence(bucket.extracted),\n reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),\n recommendation: RECOMMENDATION_MISSING_OBSERVED,\n })\n }\n }\n\n if (bucket.observed && !bucket.extracted) {\n // ADR-066 §4 — cascade from the OBSERVED edge's graded confidence.\n // OBSERVED-led finding; the headline divergence type.\n out.push({\n type: 'missing-extracted',\n source: bucket.source,\n target: bucket.target,\n edgeType: bucket.type,\n observed: bucket.observed,\n confidence: gradedConfidence(bucket.observed),\n reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),\n recommendation: RECOMMENDATION_MISSING_EXTRACTED,\n })\n }\n\n return out\n}\n\n// Returns the declared host of the service's static DB target, when\n// recoverable. ServiceNode.dbConnectionTarget is the static-extraction\n// surface for \"this service connects to X\" — `X` is host[:port] or a\n// docker-compose-style service name. Empty / undefined means we have no\n// EXTRACTED host to compare against and host-mismatch can't fire.\nfunction declaredHostFor(svc: ServiceNode): string | null {\n const raw = svc.dbConnectionTarget?.trim()\n if (!raw) return null\n // Strip a trailing port if present so it lines up with DatabaseNode.host\n // (ADR-028 §6 — DatabaseNode id excludes port).\n const colon = raw.lastIndexOf(':')\n if (colon === -1) return raw\n const port = raw.slice(colon + 1)\n if (/^\\d+$/.test(port)) return raw.slice(0, colon)\n return raw\n}\n\nfunction hasExtractedConfiguredBy(graph: NeatGraph, svcId: string): boolean {\n for (const edgeId of graph.outboundEdges(svcId)) {\n const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (e.type === EdgeType.CONFIGURED_BY && e.provenance === Provenance.EXTRACTED) {\n return true\n }\n }\n return false\n}\n\nfunction detectHostMismatch(\n graph: NeatGraph,\n svcId: string,\n svc: ServiceNode,\n): Divergence[] {\n const declaredHost = declaredHostFor(svc)\n if (!declaredHost) return []\n if (!hasExtractedConfiguredBy(graph, svcId)) return []\n\n const out: Divergence[] = []\n for (const edgeId of graph.outboundEdges(svcId)) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.type !== EdgeType.CONNECTS_TO) continue\n if (edge.provenance !== Provenance.OBSERVED) continue\n const target = graph.getNodeAttributes(edge.target) as GraphNode\n if (target.type !== NodeType.DatabaseNode) continue\n const observedHost = target.host?.trim()\n if (!observedHost) continue\n if (observedHost === declaredHost) continue\n\n out.push({\n type: 'host-mismatch',\n source: svcId,\n target: edge.target,\n extractedHost: declaredHost,\n observedHost,\n confidence: clampConfidence(confidenceForEdge(edge)),\n reason: `Config declares ${svcId} connects to ${declaredHost}; production connects to ${observedHost}.`,\n recommendation: RECOMMENDATION_HOST_MISMATCH,\n })\n }\n return out\n}\n\nfunction detectCompatDivergences(\n graph: NeatGraph,\n svcId: string,\n svc: ServiceNode,\n): Divergence[] {\n const out: Divergence[] = []\n const deps = svc.dependencies ?? {}\n\n for (const edgeId of graph.outboundEdges(svcId)) {\n const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n if (edge.type !== EdgeType.CONNECTS_TO) continue\n if (edge.provenance !== Provenance.OBSERVED) continue\n const target = graph.getNodeAttributes(edge.target) as GraphNode\n if (target.type !== NodeType.DatabaseNode) continue\n\n // Driver-engine compat. Definitive — when a rule fires it's a\n // version-mismatch with confidence 1.0.\n for (const pair of compatPairs()) {\n if (pair.engine !== target.engine) continue\n const declared = deps[pair.driver]\n if (!declared) continue\n const result = checkCompatibility(\n pair.driver,\n declared,\n target.engine,\n target.engineVersion,\n )\n if (!result.compatible && result.reason) {\n out.push({\n type: 'version-mismatch',\n source: svcId,\n target: edge.target,\n extractedVersion: declared,\n observedVersion: target.engineVersion,\n compatibility: 'incompatible',\n confidence: 1.0,\n reason: result.reason,\n recommendation: result.minDriverVersion\n ? `Upgrade ${pair.driver} to >= ${result.minDriverVersion}.`\n : `Update the ${pair.driver} driver to a version compatible with ${target.engine} ${target.engineVersion}.`,\n })\n }\n }\n\n // Deprecated-api compat. Broader than version-mismatch — surfaces as\n // compat-violation. Driver-engine rules above already covered the\n // \"version is too low\" shape; deprecated covers \"version is too high\n // / no longer supported.\"\n for (const rule of deprecatedApis()) {\n const declared = deps[rule.package]\n if (!declared) continue\n const result = checkDeprecatedApi(rule, declared)\n if (!result.compatible && result.reason) {\n const ruleRef: CompatRuleRef = {\n kind: rule.kind ?? 'deprecated-api',\n reason: result.reason,\n package: rule.package,\n }\n out.push({\n type: 'compat-violation',\n source: svcId,\n target: edge.target,\n rule: ruleRef,\n observed: edge,\n confidence: 1.0,\n reason: result.reason,\n recommendation: `Replace deprecated ${rule.package}@${declared} with a supported version.`,\n })\n }\n }\n }\n return out\n}\n\nfunction involvesNode(d: Divergence, nodeId: string): boolean {\n return d.source === nodeId || d.target === nodeId\n}\n\nexport function computeDivergences(\n graph: NeatGraph,\n opts: DivergenceQueryOpts = {},\n): DivergenceResult {\n const all: Divergence[] = []\n\n // Pass 1 — bucket every edge and emit missing-observed / missing-extracted.\n const buckets = bucketEdges(graph)\n for (const bucket of buckets.values()) {\n for (const d of detectMissingDivergences(graph, bucket)) all.push(d)\n }\n\n // Pass 2 — per-service host + compat rules.\n graph.forEachNode((nodeId, attrs) => {\n const n = attrs as GraphNode\n if (n.type !== NodeType.ServiceNode) return\n const svc = n as ServiceNode\n for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d)\n for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d)\n })\n\n // Filter + sort. Higher confidence first; within the same confidence,\n // stable on (type, source, target) so callers see deterministic output.\n let filtered = all\n if (opts.type) {\n const allowed = opts.type\n filtered = filtered.filter((d) => allowed.has(d.type))\n }\n if (opts.minConfidence !== undefined) {\n const threshold = opts.minConfidence\n filtered = filtered.filter((d) => d.confidence >= threshold)\n }\n if (opts.node) {\n const target = opts.node\n filtered = filtered.filter((d) => involvesNode(d, target))\n }\n\n // ADR-066 §4 / §5 — confidence desc; missing-extracted leads\n // missing-observed at equal confidence (OBSERVED-led tiebreaker); then\n // stable on (type, source, target).\n const TYPE_LEADERSHIP: Record<DivergenceType, number> = {\n 'missing-extracted': 0,\n 'missing-observed': 1,\n 'version-mismatch': 2,\n 'host-mismatch': 3,\n 'compat-violation': 4,\n }\n filtered.sort((a, b) => {\n if (b.confidence !== a.confidence) return b.confidence - a.confidence\n const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type]\n if (lead !== 0) return lead\n if (a.type !== b.type) return a.type.localeCompare(b.type)\n if (a.source !== b.source) return a.source.localeCompare(b.source)\n return a.target.localeCompare(b.target)\n })\n\n return DivergenceResultSchema.parse({\n divergences: filtered,\n totalAffected: filtered.length,\n computedAt: new Date().toISOString(),\n })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { Provenance, observedEdgeId } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport const SCHEMA_VERSION = 4\n\nexport interface PersistedGraph {\n schemaVersion: number\n exportedAt: string\n graph: ReturnType<NeatGraph['export']>\n}\n\n// v1 → v2: ServiceNode shed `pgDriverVersion` (ADR-019). Compat traversal reads\n// `dependencies[driver]` instead. Strip the field from any v1 snapshot rather\n// than hard-failing — a stale snapshot on disk shouldn't cost a re-extract.\nfunction migrateV1ToV2(payload: PersistedGraph): PersistedGraph {\n const nodes = (payload.graph as { nodes?: Array<{ attributes?: Record<string, unknown> }> })\n .nodes\n if (Array.isArray(nodes)) {\n for (const node of nodes) {\n if (node.attributes && 'pgDriverVersion' in node.attributes) {\n delete node.attributes.pgDriverVersion\n }\n }\n }\n return { ...payload, schemaVersion: 2 }\n}\n\n// v2 → v3: Provenance enum shrinks to four values (ADR-068). Any edge whose\n// provenance still carries the pre-v0.3.5 'FRONTIER' literal is rewritten to\n// Provenance.OBSERVED on load. The target ref is unchanged — FrontierNodes\n// remain placeholders for unresolved peers; only how the edge was labelled\n// changes. If the edge id still carries the legacy provenance segment, it\n// is re-keyed to the OBSERVED wire format so consumers that parse the id\n// (traversal, divergence query, MCP) see the same shape downstream.\n//\n// The 'FRONTIER' string literal here is the only place in the codebase that\n// recognises the legacy value; the Rule 1 contract scan exempts persist.ts\n// for exactly this reason.\n// v3 → v4: ServiceNode identity gains an optional env discriminator\n// (ADR-074 §2). The v4 wire format reads as a superset of v3 — the\n// env-less `service:<name>` form is preserved as the env=`'unknown'`\n// node and the v3 → v4 migration is a version-only bump.\n//\n// Edges and node ids that pre-date the env discriminator remain valid v4\n// ids; no rewrite is needed. Idempotent — re-running on a v4 snapshot\n// produces an identical payload.\nfunction migrateV3ToV4(payload: PersistedGraph): PersistedGraph {\n return { ...payload, schemaVersion: 4 }\n}\n\nfunction migrateV2ToV3(payload: PersistedGraph): PersistedGraph {\n const edges = (payload.graph as {\n edges?: Array<{\n key?: string\n attributes?: Record<string, unknown>\n }>\n }).edges\n if (Array.isArray(edges)) {\n for (const edge of edges) {\n const attrs = edge.attributes\n // 'FRONTIER' is the pre-v0.3.5 literal — read-only here, never written\n // by current producers. The rewrite swaps to Provenance.OBSERVED.\n if (!attrs || attrs.provenance !== 'FRONTIER') continue\n attrs.provenance = Provenance.OBSERVED\n const type = typeof attrs.type === 'string' ? attrs.type : undefined\n const source = typeof attrs.source === 'string' ? attrs.source : undefined\n const target = typeof attrs.target === 'string' ? attrs.target : undefined\n if (type && source && target) {\n const newId = observedEdgeId(source, target, type)\n attrs.id = newId\n if (edge.key) edge.key = newId\n }\n }\n }\n return { ...payload, schemaVersion: 3 }\n}\n\nasync function ensureDir(filePath: string): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true })\n}\n\nexport async function saveGraphToDisk(graph: NeatGraph, outPath: string): Promise<void> {\n await ensureDir(outPath)\n const payload: PersistedGraph = {\n schemaVersion: SCHEMA_VERSION,\n exportedAt: new Date().toISOString(),\n graph: graph.export(),\n }\n // Atomic write: drop into <name>.tmp first, then rename. A crash mid-write\n // leaves the previous snapshot intact instead of a half-truncated file.\n const tmp = `${outPath}.tmp`\n await fs.writeFile(tmp, JSON.stringify(payload), 'utf8')\n await fs.rename(tmp, outPath)\n}\n\nexport async function loadGraphFromDisk(graph: NeatGraph, outPath: string): Promise<void> {\n let raw: string\n try {\n raw = await fs.readFile(outPath, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return\n throw err\n }\n let payload = JSON.parse(raw) as PersistedGraph\n if (payload.schemaVersion === 1) {\n payload = migrateV1ToV2(payload)\n }\n if (payload.schemaVersion === 2) {\n payload = migrateV2ToV3(payload)\n }\n if (payload.schemaVersion === 3) {\n payload = migrateV3ToV4(payload)\n }\n if (payload.schemaVersion !== SCHEMA_VERSION) {\n throw new Error(\n `persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`,\n )\n }\n graph.clear()\n graph.import(payload.graph)\n}\n\n// Periodic save + best-effort save on SIGTERM/SIGINT. Returns a cleanup that\n// clears the interval and unhooks the signal handlers — important for tests so\n// they don't keep the process alive.\nexport function startPersistLoop(\n graph: NeatGraph,\n outPath: string,\n intervalMs = 60_000,\n): () => void {\n let stopped = false\n\n const tick = async (): Promise<void> => {\n if (stopped) return\n try {\n await saveGraphToDisk(graph, outPath)\n } catch (err) {\n console.error('persist: periodic save failed', err)\n }\n }\n\n const interval = setInterval(() => {\n void tick()\n }, intervalMs)\n\n const onSignal = (signal: NodeJS.Signals): void => {\n void (async () => {\n try {\n await saveGraphToDisk(graph, outPath)\n } catch (err) {\n console.error(`persist: ${signal} save failed`, err)\n } finally {\n process.exit(0)\n }\n })()\n }\n\n process.on('SIGTERM', onSignal)\n process.on('SIGINT', onSignal)\n\n return () => {\n stopped = true\n clearInterval(interval)\n process.off('SIGTERM', onSignal)\n process.off('SIGINT', onSignal)\n }\n}\n\n// Snapshot merge (ADR-074 §1) lives in ingest.ts — that's the mutation-\n// authority boundary per the lifecycle contract (Rule 3 / ADR-030). The\n// merge is a form of ingestion: an external snapshot lands on the live graph\n// the same way an OTel span does, preserving the EXTRACTED + OBSERVED\n// coexistence contract along the way.\n","/**\n * `.gitignore` automation for the init flow (ADR-073 §6).\n *\n * Init writes a snapshot under `<projectDir>/neat-out/`. Un-ignored, that\n * directory leaks the snapshot into git history within one commit. The\n * helper here ensures `neat-out/` is present in `<projectDir>/.gitignore` —\n * appending to an existing file with a NEAT comment header, creating the\n * file when absent, no-oping when the line is already there.\n *\n * Idempotency rule: an exact-match line (`neat-out/` or `neat-out`, with\n * any surrounding whitespace) counts as already-present. No duplicate\n * line is written on a re-run.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport const NEAT_OUT_LINE = 'neat-out/'\nconst NEAT_HEADER = '# NEAT — machine-local snapshots and events'\n\nexport interface EnsureNeatOutResult {\n // 'added' when the line was appended to an existing .gitignore.\n // 'created' when the file did not exist and was created with a single line.\n // 'unchanged' when the line was already present.\n action: 'added' | 'created' | 'unchanged'\n // Absolute path to the .gitignore file, regardless of action.\n file: string\n}\n\nfunction isNeatOutLine(line: string): boolean {\n const trimmed = line.trim()\n return trimmed === 'neat-out/' || trimmed === 'neat-out'\n}\n\nexport async function ensureNeatOutIgnored(projectDir: string): Promise<EnsureNeatOutResult> {\n const file = path.join(projectDir, '.gitignore')\n let existing: string | null = null\n try {\n existing = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n\n if (existing === null) {\n await fs.writeFile(file, `${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`, 'utf8')\n return { action: 'created', file }\n }\n\n for (const line of existing.split(/\\r?\\n/)) {\n if (isNeatOutLine(line)) return { action: 'unchanged', file }\n }\n\n // Append with a leading newline if the file doesn't already end in one,\n // so the comment header sits on its own line.\n const needsLeadingNewline = existing.length > 0 && !existing.endsWith('\\n')\n const appended = `${needsLeadingNewline ? '\\n' : ''}\\n${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`\n await fs.writeFile(file, existing + appended, 'utf8')\n return { action: 'added', file }\n}\n","/**\n * Value-forward CLI summary (issue #305, ADR-073 §5).\n *\n * Replaces the per-type node/edge counts that ended `neat init` with a\n * findings-first block — compat violations, top divergences, services\n * that never produced an OBSERVED edge, and the OTel env-vars block the\n * operator pastes into their deploy platform. Per-type counts move behind\n * `--verbose`.\n *\n * The renderer is a pure string builder so tests can assert against its\n * output without spawning the CLI.\n */\n\nimport type { Divergence, GraphEdge, GraphNode, ServiceNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport interface SummaryInput {\n graph: NeatGraph\n divergences: Divergence[]\n // True → render the per-type counts after the value-forward block.\n verbose: boolean\n}\n\n// Static placeholder. The orchestrator and `neat deploy` print the same\n// block; `neat deploy` substitutes the actual token + host. This shape\n// lives in one place so the wire format stays in step.\nexport function renderOtelEnvBlock(): string {\n return [\n 'for prod OTel routing, set these in your deploy platform\\'s env:',\n ' OTEL_EXPORTER_OTLP_ENDPOINT=https://<your-neat-host>:4318',\n ' OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer <NEAT_AUTH_TOKEN>',\n ].join('\\n')\n}\n\nfunction findIncompatServices(nodes: GraphNode[]): ServiceNode[] {\n return nodes.filter(\n (n): n is ServiceNode =>\n n.type === NodeType.ServiceNode &&\n Array.isArray((n as ServiceNode).incompatibilities) &&\n ((n as ServiceNode).incompatibilities ?? []).length > 0,\n )\n}\n\n// Services that show up in the EXTRACTED graph but have no OBSERVED edge\n// pointing at or out of them. The thesis says: when the OBSERVED layer is\n// silent on a service, the gap is a load-bearing signal for the operator.\nfunction servicesWithoutObserved(nodes: GraphNode[], edges: GraphEdge[]): ServiceNode[] {\n const seen = new Set<string>()\n for (const e of edges) {\n if (e.provenance === Provenance.OBSERVED) {\n seen.add(e.source)\n seen.add(e.target)\n }\n }\n return nodes.filter(\n (n): n is ServiceNode => n.type === NodeType.ServiceNode && !seen.has(n.id),\n )\n}\n\nfunction formatDivergence(d: Divergence): string {\n // Short, scannable, one-line-per-finding. The reason field already carries\n // the load-bearing detail; the recommendation rides on a second indent.\n const conf = d.confidence.toFixed(2)\n return ` [${conf}] ${d.type} ${d.source} → ${d.target} — ${d.reason}`\n}\n\nexport function renderValueForwardSummary(input: SummaryInput): string {\n const { graph, divergences, verbose } = input\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => nodes.push(attrs))\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n const lines: string[] = []\n lines.push('=== neat: findings ===')\n lines.push('')\n\n // ── Compat violations (driver/engine mismatches) ───────────────────────\n const incompatServices = findIncompatServices(nodes)\n const totalIncompats = incompatServices.reduce(\n (acc, s) => acc + (s.incompatibilities?.length ?? 0),\n 0,\n )\n lines.push(`compat violations: ${totalIncompats}`)\n for (const svc of incompatServices) {\n for (const inc of svc.incompatibilities ?? []) {\n const detail = formatIncompat(inc)\n lines.push(` ${svc.name}: ${detail}`)\n }\n }\n lines.push('')\n\n // ── Top divergences (top 3 by confidence desc) ─────────────────────────\n const top = [...divergences].sort((a, b) => b.confidence - a.confidence).slice(0, 3)\n lines.push(`top divergences: ${divergences.length} total${top.length > 0 ? ', top 3:' : ''}`)\n for (const d of top) lines.push(formatDivergence(d))\n lines.push('')\n\n // ── Services missing OBSERVED coverage ─────────────────────────────────\n const noObserved = servicesWithoutObserved(nodes, edges)\n if (noObserved.length > 0) {\n lines.push(`services without OBSERVED coverage: ${noObserved.length}`)\n for (const svc of noObserved) lines.push(` ${svc.name}`)\n lines.push(' → run your services with the generated otel-init to populate OBSERVED edges.')\n lines.push('')\n }\n\n // ── OTel env-vars block (static; `neat deploy` substitutes real values)\n lines.push(renderOtelEnvBlock())\n lines.push('')\n\n // ── --verbose: per-type node/edge counts ──────────────────────────────\n if (verbose) {\n const byNode = new Map<string, number>()\n for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n const byEdge = new Map<string, number>()\n for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n lines.push('=== graph (verbose) ===')\n lines.push(`total: ${graph.order} nodes, ${graph.size} edges`)\n lines.push('nodes:')\n for (const [t, c] of [...byNode.entries()].sort()) lines.push(` ${t}: ${c}`)\n lines.push('edges:')\n for (const [t, c] of [...byEdge.entries()].sort()) lines.push(` ${t}: ${c}`)\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\nfunction formatIncompat(inc: NonNullable<ServiceNode['incompatibilities']>[number]): string {\n if (inc.kind === 'node-engine') {\n const range = inc.declaredNodeEngine ? ` (engines.node=\"${inc.declaredNodeEngine}\")` : ''\n return `${inc.package}@${inc.packageVersion ?? '?'} requires Node ${inc.requiredNodeVersion}${range} — ${inc.reason}`\n }\n if (inc.kind === 'package-conflict') {\n const found = inc.foundVersion ? `@${inc.foundVersion}` : ' (missing)'\n return `${inc.package}@${inc.packageVersion ?? '?'} requires ${inc.requires.name}>=${inc.requires.minVersion}; found ${inc.requires.name}${found} — ${inc.reason}`\n }\n if (inc.kind === 'deprecated-api') {\n return `${inc.package}@${inc.packageVersion ?? '?'} is deprecated — ${inc.reason}`\n }\n return `${inc.driver}@${inc.driverVersion} vs ${inc.engine} ${inc.engineVersion} — ${inc.reason}`\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport type { FastifyInstance } from 'fastify'\nimport type { NeatGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\nimport { ensureCompatLoaded } from './compat.js'\nimport { discoverServices, addServiceNodes } from './extract/services.js'\nimport { addServiceAliases } from './extract/aliases.js'\nimport { addImports } from './extract/imports.js'\nimport { addDatabasesAndCompat } from './extract/databases/index.js'\nimport { addConfigNodes } from './extract/configs.js'\nimport { addCallEdges } from './extract/calls/index.js'\nimport { addInfra } from './extract/infra/index.js'\nimport { retireEdgesByFile } from './extract/retire.js'\nimport {\n makeErrorSpanWriter,\n makeSpanHandler,\n promoteFrontierNodes,\n startStalenessLoop,\n} from './ingest.js'\nimport {\n evaluateAllPolicies,\n loadPolicyFile,\n PolicyViolationsLog,\n} from './policy.js'\nimport type { Policy } from '@neat.is/types'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildSearchIndex, type SearchIndex } from './search.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { Projects, pathsForProject } from './projects.js'\nimport { attachGraphToEventBus, emitNeatEvent } from './events.js'\n\nexport type ExtractPhase =\n | 'services'\n | 'aliases'\n | 'imports'\n | 'databases'\n | 'configs'\n | 'calls'\n | 'infra'\n\nconst ALL_PHASES: ExtractPhase[] = [\n 'services',\n 'aliases',\n 'imports',\n 'databases',\n 'configs',\n 'calls',\n 'infra',\n]\n\n// Map a changed path to the phases that need re-running. Anything not matched\n// here falls back to a full re-extract — better an extra ~50ms of work than a\n// missed update because the path didn't fit a regex.\n//\n// Mapping:\n// package.json / requirements.txt / pyproject.toml → services + aliases + databases\n// (deps drive compat; aliases pull from manifest fields)\n// .env / *.env.* / prisma / knex / ormconfig → databases + configs\n// docker-compose / Dockerfile / *.tf / k8s yaml → infra + aliases\n// (compose labels and Dockerfile labels feed alias discovery)\n// *.js / *.ts / *.tsx / *.py / *.jsx / *.mjs / *.cjs → imports + calls\n// (a source edit can shift both its IMPORTS and CALLS edges; the shared\n// evidence.file retirement mechanism — static-extraction.md §Ghost-edge\n// cleanup — drops the stale ones from either producer before re-running)\n// *.yaml / *.yml that isn't compose → databases + configs (ORM yaml fallbacks)\nexport function classifyChange(relPath: string): Set<ExtractPhase> {\n const phases = new Set<ExtractPhase>()\n const base = path.basename(relPath).toLowerCase()\n const segments = relPath.split(path.sep).map((s) => s.toLowerCase())\n\n if (\n base === 'package.json' ||\n base === 'requirements.txt' ||\n base === 'pyproject.toml' ||\n base === 'setup.py'\n ) {\n phases.add('services')\n phases.add('aliases')\n phases.add('databases')\n }\n\n if (\n base === '.env' ||\n base.startsWith('.env.') ||\n base === 'schema.prisma' ||\n /^knexfile\\.(?:js|ts|cjs|mjs)$/.test(base) ||\n /^ormconfig\\.(?:js|ts|json|ya?ml)$/.test(base)\n ) {\n phases.add('databases')\n phases.add('configs')\n }\n\n if (\n base === 'dockerfile' ||\n /^docker-compose.*\\.ya?ml$/.test(base) ||\n base.endsWith('.tf') ||\n segments.includes('k8s') ||\n segments.includes('kustomize') ||\n segments.includes('manifests')\n ) {\n phases.add('infra')\n phases.add('aliases')\n }\n\n if (/\\.(?:js|jsx|mjs|cjs|ts|tsx|py)$/.test(base)) {\n phases.add('imports')\n phases.add('calls')\n }\n\n if (/\\.ya?ml$/.test(base) && !/^docker-compose.*\\.ya?ml$/.test(base)) {\n // Generic yaml — could be an ORM file, k8s manifest, or random config.\n // Cheap to run databases + configs; if it was infra, the dir-name check\n // above already added that phase.\n phases.add('databases')\n phases.add('configs')\n }\n\n return phases\n}\n\ninterface RunPhasesResult {\n phases: ExtractPhase[]\n nodesAdded: number\n edgesAdded: number\n frontiersPromoted: number\n durationMs: number\n}\n\nexport async function runExtractPhases(\n graph: NeatGraph,\n scanPath: string,\n phases: Set<ExtractPhase>,\n // Project tag passed through for the runtime event bus (ADR-051) — not\n // required for extraction logic itself but threaded for parity with\n // extractFromDirectory's project option.\n project: string = DEFAULT_PROJECT,\n): Promise<RunPhasesResult> {\n void project\n const started = Date.now()\n await ensureCompatLoaded()\n // Discovery is cheap and every phase needs the same DiscoveredService list,\n // so we always re-walk. If the user moved a service directory, this is also\n // the path that picks it up.\n const services = await discoverServices(scanPath)\n\n let nodesAdded = 0\n let edgesAdded = 0\n\n if (phases.has('services')) {\n nodesAdded += addServiceNodes(graph, services)\n }\n if (phases.has('aliases')) {\n await addServiceAliases(graph, scanPath, services)\n }\n if (phases.has('imports')) {\n const r = await addImports(graph, services)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('databases')) {\n const r = await addDatabasesAndCompat(graph, services, scanPath)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('configs')) {\n const r = await addConfigNodes(graph, services, scanPath)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('calls')) {\n const r = await addCallEdges(graph, services)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n if (phases.has('infra')) {\n const r = await addInfra(graph, scanPath, services)\n nodesAdded += r.nodesAdded\n edgesAdded += r.edgesAdded\n }\n const frontiersPromoted = promoteFrontierNodes(graph)\n\n return {\n phases: ALL_PHASES.filter((p) => phases.has(p)),\n nodesAdded,\n edgesAdded,\n frontiersPromoted,\n durationMs: Date.now() - started,\n }\n}\n\nexport interface WatchOptions {\n scanPath: string\n outPath: string\n errorsPath: string\n staleEventsPath: string\n embeddingsCachePath?: string\n // Project name this watch instance owns. Defaults to `default` for the\n // single-project workflow that's been the only one until #83.\n project?: string\n host?: string\n port?: number\n otelPort?: number\n otelGrpc?: boolean\n otelGrpcPort?: number\n debounceMs?: number\n}\n\nexport interface WatchHandle {\n api: FastifyInstance\n stop: () => Promise<void>\n}\n\n// Anymatch-compatible ignore set passed to chokidar (#233). The earlier\n// implementation passed a function alone, which forced chokidar to descend\n// into every subdirectory before testing the path. On macOS with kqueue\n// (chokidar 4 dropped fsevents in favour of kqueue), each subdir under the\n// scan root opens a watch handle; nested `node_modules` blew through the\n// per-process kqueue cap with EMFILE before the function-based ignore ever\n// fired. Globs let chokidar prune at descent time — the dirs are never\n// opened in the first place.\nconst IGNORED_WATCH_GLOBS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/.turbo/**',\n '**/.next/**',\n '**/neat-out/**',\n // Python venv shapes (issue #344). chokidar opens one watch handle per\n // descended dir; a CPython venv carries 20k+ files and trivially blows\n // through the macOS kqueue cap before extraction even runs.\n '**/.venv/**',\n '**/venv/**',\n '**/__pypackages__/**',\n '**/.tox/**',\n '**/site-packages/**',\n '**/.DS_Store',\n]\n\n// Backstop regex set — covers anything chokidar surfaces post-descent that\n// the globs missed (e.g. a path containing one of these segments at an\n// unexpected depth). Same shape as before; the globs are the load-bearing\n// pruning, this is defence in depth.\nconst IGNORED_WATCH_PATHS = [\n /(?:^|[\\\\/])node_modules[\\\\/]/,\n /(?:^|[\\\\/])\\.git[\\\\/]/,\n /(?:^|[\\\\/])dist[\\\\/]/,\n /(?:^|[\\\\/])build[\\\\/]/,\n /(?:^|[\\\\/])\\.turbo[\\\\/]/,\n /(?:^|[\\\\/])\\.next[\\\\/]/,\n /(?:^|[\\\\/])neat-out[\\\\/]/,\n /(?:^|[\\\\/])\\.venv[\\\\/]/,\n /(?:^|[\\\\/])venv[\\\\/]/,\n /(?:^|[\\\\/])__pypackages__[\\\\/]/,\n /(?:^|[\\\\/])\\.tox[\\\\/]/,\n /(?:^|[\\\\/])site-packages[\\\\/]/,\n /[\\\\/]?\\.DS_Store$/,\n]\n\nfunction shouldIgnore(absPath: string): boolean {\n return IGNORED_WATCH_PATHS.some((re) => re.test(absPath))\n}\n\n// Roughly the number of immediate, non-ignored subdirectories in the scan\n// root above which `neat watch` should fall back to polling on darwin. kqueue\n// opens one handle per watched dir; macOS's per-process file-descriptor cap\n// is typically 256 (soft) / unlimited (hard) but raising the hard cap doesn't\n// help with the kqueue-specific limits. Empirically anything north of ~500\n// non-ignored dirs starts to flirt with EMFILE. Threshold sits comfortably\n// under that.\nconst DARWIN_POLLING_DIR_THRESHOLD = 400\n\n// Fast non-recursive count: walk top-level entries only, descending one\n// level into non-ignored subdirs to capture the medusa-shaped case where\n// `packages/*` itself looks small but each contains a heavy `node_modules`.\n// Returns early once it crosses the threshold so we don't waste time on huge\n// repos.\nfunction countWatchableDirs(scanPath: string, limit: number): number {\n let count = 0\n const visit = (dir: string, depth: number): void => {\n if (count >= limit) return\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n for (const e of entries) {\n if (count >= limit) return\n if (!e.isDirectory()) continue\n if (IGNORED_WATCH_PATHS.some((re) => re.test(path.join(dir, e.name) + path.sep))) continue\n count++\n // One level deeper — enough to surface nested `node_modules` shapes\n // without traversing the whole tree.\n if (depth < 2) visit(path.join(dir, e.name), depth + 1)\n }\n }\n visit(scanPath, 0)\n return count\n}\n\n// Darwin heuristic (#233). Forces chokidar onto polling when the scan root\n// is large enough that kqueue would EMFILE. Override via NEAT_WATCH_POLLING:\n// - \"1\" / \"true\" → force polling regardless of platform/threshold\n// - \"0\" / \"false\" → never poll (matches pre-#233 behaviour)\n// - unset → auto-detect on darwin\nfunction shouldUsePolling(scanPath: string): boolean {\n const env = process.env.NEAT_WATCH_POLLING\n if (env === '1' || env === 'true') return true\n if (env === '0' || env === 'false') return false\n if (process.platform !== 'darwin') return false\n return countWatchableDirs(scanPath, DARWIN_POLLING_DIR_THRESHOLD) >= DARWIN_POLLING_DIR_THRESHOLD\n}\n\nexport async function startWatch(\n graph: NeatGraph,\n opts: WatchOptions,\n): Promise<WatchHandle> {\n const debounceMs = opts.debounceMs ?? 1000\n const projectName = opts.project ?? DEFAULT_PROJECT\n\n await loadGraphFromDisk(graph, opts.outPath)\n\n // Wire graph mutations into the event bus (ADR-051) before extract begins\n // so the initial pass also produces node/edge events. Detached on stop().\n const detachEventBus = attachGraphToEventBus(graph, { project: projectName })\n\n // Load policies + open the violations log once at startup. policy.json\n // lives at the project root per ADR-042 §File location; absent file is\n // a perfectly fine state (loadPolicyFile returns []). Reload-on-change\n // is queued for v0.2.5 — the kickoff doc tracks it.\n const policyFilePath = path.join(opts.scanPath, 'policy.json')\n const policyViolationsPath = path.join(path.dirname(opts.outPath), 'policy-violations.ndjson')\n let policies: Policy[] = []\n try {\n policies = await loadPolicyFile(policyFilePath)\n if (policies.length > 0) {\n console.log(`policies: loaded ${policies.length} from ${policyFilePath}`)\n }\n } catch (err) {\n console.warn(`policies: failed to load ${policyFilePath} — ${(err as Error).message}`)\n }\n const policyLog = new PolicyViolationsLog(policyViolationsPath, projectName)\n\n // Single shared trigger callback wired into post-ingest, post-extract, and\n // post-stale per ADR-043. Failures append to console.warn but don't kill\n // the daemon — a malformed evaluator shouldn't take down ingest.\n const onPolicyTrigger = async (g: NeatGraph): Promise<void> => {\n if (policies.length === 0) return\n try {\n const violations = evaluateAllPolicies(g, policies, { now: () => Date.now() })\n for (const v of violations) await policyLog.append(v)\n } catch (err) {\n console.warn(`policies: evaluation failed — ${(err as Error).message}`)\n }\n }\n\n // The post-extract trigger fires from extractFromDirectory via opts.\n // For the initial extract here we run it inline so violations land on\n // startup before the receiver opens. Subsequent watch-driven re-extract\n // passes go through runExtractPhases which doesn't take the hook directly\n // — we run it after each flush() instead.\n const initial = await runExtractPhases(\n graph,\n opts.scanPath,\n new Set(ALL_PHASES),\n projectName,\n )\n console.log(\n `extract: ${initial.nodesAdded} new nodes, ${initial.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n // extraction-complete for the initial pass (ADR-051). runExtractPhases\n // doesn't emit on its own — the event lives at the watch / orchestrator\n // boundary so the daemon can swap in its own emission shape.\n emitNeatEvent({\n type: 'extraction-complete',\n project: projectName,\n payload: {\n project: projectName,\n fileCount: 0,\n nodesAdded: initial.nodesAdded,\n edgesAdded: initial.edgesAdded,\n },\n })\n await onPolicyTrigger(graph)\n\n const stopPersist = startPersistLoop(graph, opts.outPath)\n const stopStaleness = startStalenessLoop(graph, {\n staleEventsPath: opts.staleEventsPath,\n project: projectName,\n onPolicyTrigger,\n })\n\n // ADR-073 §3/§4 + issue #341 — `neat watch` follows the same bind discipline\n // as the daemon: an explicit host wins; otherwise loopback-only without a\n // token (laptop dev), public bind once `NEAT_AUTH_TOKEN` is set. buildApi\n // mounts the bearer gate from the same env, so a token-protected watch\n // returns 401 to unauthenticated callers exactly as `neatd` does.\n const auth = readAuthEnv()\n const host = opts.host ?? (auth.authToken ? '0.0.0.0' : '127.0.0.1')\n assertBindAuthority(host, auth.authToken)\n const port = opts.port ?? 8080\n const otelPort = opts.otelPort ?? 4318\n\n const cachePath =\n opts.embeddingsCachePath ?? path.join(path.dirname(opts.outPath), 'embeddings.json')\n let searchIndex: SearchIndex | undefined\n try {\n searchIndex = await buildSearchIndex(graph, { cachePath })\n console.log(`semantic_search: ${searchIndex.provider} provider`)\n } catch (err) {\n console.warn(\n `semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n }\n\n const registry = new Projects()\n registry.set(projectName, {\n graph,\n scanPath: opts.scanPath,\n paths: {\n // Paths are derived from the explicit options the watch caller passes\n // — pathsForProject is only used to fill in the embeddings/snapshot\n // fields so the registry shape is complete.\n ...pathsForProject(projectName, path.dirname(opts.outPath)),\n snapshotPath: opts.outPath,\n errorsPath: opts.errorsPath,\n staleEventsPath: opts.staleEventsPath,\n },\n searchIndex,\n })\n\n const api = await buildApi({ projects: registry })\n await api.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` scan path: ${opts.scanPath} (watching for changes)`)\n console.log(` snapshot path: ${opts.outPath}`)\n console.log(` errors log: ${opts.errorsPath}`)\n\n // The receiver writes ErrorEvents synchronously before reply (durability).\n // makeSpanHandler runs on the async queue and skips the inline write\n // because the receiver already handled it. Ad-hoc callers that bypass the\n // receiver (CLI tests, fixtures) leave writeErrorEventInline at its default\n // and get the in-handleSpan write. ADR-033 §Error events.\n const onSpan = makeSpanHandler({\n graph,\n errorsPath: opts.errorsPath,\n scanPath: opts.scanPath,\n project: projectName,\n writeErrorEventInline: false,\n onPolicyTrigger,\n })\n const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath)\n const otelHttp = await buildOtelReceiver({ onSpan, onErrorSpanSync })\n await otelHttp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n let grpcReceiver: { stop: () => Promise<void> } | null = null\n if (opts.otelGrpc) {\n const grpcPort = opts.otelGrpcPort ?? 4317\n // gRPC handler keeps the inline ErrorEvent write — the gRPC receiver\n // awaits onSpan synchronously (otel-grpc.ts), so the same durability\n // guarantee is met without a separate sync hook. Non-blocking gRPC\n // ingest is out of scope for the v0.2.2 batch.\n const onSpanGrpc = makeSpanHandler({\n graph,\n errorsPath: opts.errorsPath,\n scanPath: opts.scanPath,\n project: projectName,\n onPolicyTrigger,\n })\n const r = await startOtelGrpcReceiver({ onSpan: onSpanGrpc, host, port: grpcPort })\n console.log(`neat-core OTLP/gRPC receiver on ${r.address}`)\n grpcReceiver = r\n }\n\n // Coalesce bursts of changes into a single re-extract. chokidar fires one\n // event per affected path; an editor save can produce 3+ events on the same\n // file in <50ms.\n const pending = new Set<ExtractPhase>()\n const pendingPaths = new Set<string>()\n let timer: NodeJS.Timeout | null = null\n let inflight: Promise<void> | null = null\n\n const flush = async (): Promise<void> => {\n if (pending.size === 0) return\n const phases = new Set(pending)\n const paths = new Set(pendingPaths)\n pending.clear()\n pendingPaths.clear()\n try {\n // Drop EXTRACTED edges keyed to changed paths first, so the producer's\n // idempotent re-extract recreates only the edges that still apply.\n // Without this, edges from deleted code would survive forever\n // (docs/contracts/static-extraction.md §Ghost-edge cleanup).\n let retired = 0\n for (const p of paths) retired += retireEdgesByFile(graph, p)\n const result = await runExtractPhases(graph, opts.scanPath, phases, projectName)\n console.log(\n `[watch] re-extract phases=${result.phases.join(',')} retired=${retired} +${result.nodesAdded}n/+${result.edgesAdded}e in ${result.durationMs}ms`,\n )\n // extraction-complete after every re-extract pass (ADR-051). fileCount\n // is the number of paths that drove the pass — closest signal we have\n // for \"how much source moved\" without per-phase accounting.\n emitNeatEvent({\n type: 'extraction-complete',\n project: projectName,\n payload: {\n project: projectName,\n fileCount: paths.size,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n },\n })\n if (searchIndex) {\n try {\n await searchIndex.refresh(graph)\n } catch (err) {\n console.warn('[watch] semantic_search refresh failed', err)\n }\n }\n // Post-extract policy trigger (ADR-043). The runExtractPhases call\n // doesn't take the hook directly — it runs through promoteFrontierNodes\n // for FRONTIER → OBSERVED upgrades but doesn't load policies itself.\n // Firing the evaluator here keeps the trigger surface symmetric across\n // ingest / extract / stale paths.\n await onPolicyTrigger(graph)\n } catch (err) {\n console.error('[watch] re-extract failed', err)\n }\n }\n\n const schedule = (): void => {\n if (timer) clearTimeout(timer)\n timer = setTimeout(() => {\n timer = null\n // Serialise re-extracts so two flushes can't interleave on the graph.\n inflight = (inflight ?? Promise.resolve()).then(flush)\n }, debounceMs)\n }\n\n const onPath = (absPath: string): void => {\n if (shouldIgnore(absPath)) return\n const rel = path.relative(opts.scanPath, absPath)\n if (!rel || rel.startsWith('..')) return\n pendingPaths.add(rel.split(path.sep).join('/'))\n const phases = classifyChange(rel)\n if (phases.size === 0) {\n // Unknown file kind — fall back to full re-extract rather than silently\n // miss it. Cheaper than the user wondering why their change didn't show.\n for (const p of ALL_PHASES) pending.add(p)\n } else {\n for (const p of phases) pending.add(p)\n }\n schedule()\n }\n\n const usePolling = shouldUsePolling(opts.scanPath)\n if (usePolling) {\n const reason =\n process.env.NEAT_WATCH_POLLING === '1' || process.env.NEAT_WATCH_POLLING === 'true'\n ? 'NEAT_WATCH_POLLING env override'\n : 'darwin heuristic — large scan root, kqueue cap risk'\n console.log(`[${projectName}] watch: usePolling=true (${reason})`)\n }\n const watcher: FSWatcher = chokidar.watch(opts.scanPath, {\n ignoreInitial: true,\n // Glob array prunes at descent time (#233) so chokidar never opens a\n // kqueue handle for `node_modules` and friends. The function backstop\n // catches any path that slipped through and matches the regex set.\n ignored: [...IGNORED_WATCH_GLOBS, (p: string) => shouldIgnore(p)],\n persistent: true,\n usePolling,\n awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },\n })\n watcher.on('add', onPath)\n watcher.on('change', onPath)\n watcher.on('unlink', onPath)\n watcher.on('addDir', onPath)\n watcher.on('unlinkDir', onPath)\n\n let stopped = false\n const stop = async (): Promise<void> => {\n if (stopped) return\n stopped = true\n if (timer) clearTimeout(timer)\n timer = null\n if (inflight) {\n try {\n await inflight\n } catch {\n // surfaced already in flush()\n }\n }\n await watcher.close()\n stopStaleness()\n stopPersist()\n detachEventBus()\n await api.close()\n await otelHttp.close()\n if (grpcReceiver) await grpcReceiver.stop()\n }\n\n return { api, stop }\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n} from 'fastify'\nimport cors from '@fastify/cors'\nimport type {\n ErrorEvent,\n GraphEdge,\n GraphNode,\n Policy,\n PolicyViolation,\n} from '@neat.is/types'\nimport { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } from '@neat.is/types'\nimport type { DivergenceType } from '@neat.is/types'\nimport {\n applyExtension,\n describeProjectInstrumentation,\n dryRunExtension,\n listUninstrumented,\n lookupInstrumentation,\n rollbackExtension,\n} from './extend/index.js'\nimport { computeDivergences } from './divergences.js'\nimport {\n evaluateAllPolicies,\n loadPolicyFile,\n PolicyViolationsLog,\n} from './policy.js'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { readErrorEvents, readStaleEvents } from './ingest.js'\nimport {\n getBlastRadius,\n getRootCause,\n getTransitiveDependencies,\n TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n TRANSITIVE_DEPENDENCIES_MAX_DEPTH,\n} from './traverse.js'\nimport { computeGraphDiff, loadSnapshotForDiff } from './diff.js'\nimport { mergeSnapshot } from './ingest.js'\nimport { SCHEMA_VERSION, type PersistedGraph } from './persist.js'\nimport type { SearchIndex } from './search.js'\nimport type { Projects, ProjectContext } from './projects.js'\nimport { Projects as ProjectsClass, pathsForProject } from './projects.js'\nimport { getProject as getRegistryProject, listProjects as listRegistryProjects } from './registry.js'\nimport { handleSse } from './streaming.js'\nimport { mountBearerAuth, readAuthEnv } from './auth.js'\n\nexport interface BuildApiOptions {\n // Multi-project shape. Optional — when absent we synthesise a single-\n // project registry from the legacy fields below so existing callers\n // (mainly tests) keep working unchanged.\n projects?: Projects\n startedAt?: number\n\n // Legacy single-project shape. Mapped to project=`default` if `projects`\n // isn't provided.\n graph?: NeatGraph\n scanPath?: string\n errorsPath?: string\n staleEventsPath?: string\n searchIndex?: SearchIndex\n\n // ADR-073 §3 — bearer token required on `/api/*` and `/events`. Undefined\n // leaves the middleware off (loopback-only callers; the bind-authority\n // gate in startDaemon refuses to bind publicly without one).\n authToken?: string\n // ADR-073 §3 — when the operator runs behind a reverse proxy that already\n // authenticates the request, the daemon-side check is bypassed.\n trustProxy?: boolean\n // ADR-073 §3 amendment — public-read mode. When `true`, GET / HEAD / OPTIONS\n // bypass the bearer check; writes still require it. OTLP ingest is gated\n // independently and is unaffected by this flag.\n publicRead?: boolean\n // Issue #340 — per-project bootstrap status. When provided, project-scoped\n // routes for projects still extracting return 503 with `{ready: false}`\n // instead of 404.\n bootstrap?: {\n status: (name: string) => 'bootstrapping' | 'active' | 'broken' | undefined\n list: () => Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken'; elapsedMs: number }>\n }\n}\n\ninterface SerializedGraph {\n nodes: GraphNode[]\n edges: GraphEdge[]\n}\n\nfunction serializeGraph(graph: NeatGraph): SerializedGraph {\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => {\n nodes.push(attrs)\n })\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => {\n edges.push(attrs)\n })\n return { nodes, edges }\n}\n\nfunction projectFromReq(req: FastifyRequest): string {\n // `:project` is optional in the URL — the request hits either\n // /projects/:project/X or /X (which means default). Coerce the missing\n // param to DEFAULT_PROJECT here so handlers don't repeat the fallback.\n const params = req.params as { project?: string }\n return params.project ?? DEFAULT_PROJECT\n}\n\nfunction resolveProject(\n registry: Projects,\n req: FastifyRequest,\n reply: FastifyReply,\n bootstrap?: BuildApiOptions['bootstrap'],\n): ProjectContext | null {\n const name = projectFromReq(req)\n const ctx = registry.get(name)\n if (!ctx) {\n // Issue #340 — registered but still bootstrapping: surface 503 so the\n // probe consumer knows the project is real and incoming, not missing.\n const phase = bootstrap?.status(name)\n if (phase === 'bootstrapping') {\n void reply.code(503).send({ ready: false, project: name, status: 'bootstrapping' })\n return null\n }\n if (phase === 'broken') {\n void reply.code(503).send({ ready: false, project: name, status: 'broken' })\n return null\n }\n void reply.code(404).send({ error: 'project not found', project: name })\n return null\n }\n return ctx\n}\n\nfunction buildLegacyRegistry(opts: BuildApiOptions): Projects {\n if (opts.projects) return opts.projects\n if (!opts.graph) {\n throw new Error('buildApi: either `projects` or `graph` must be provided')\n }\n const registry = new ProjectsClass()\n // pathsForProject only matters here for the snapshot/embeddings paths\n // routes never read; the ingest paths come from explicit options below.\n const paths = pathsForProject(DEFAULT_PROJECT, '')\n registry.set(DEFAULT_PROJECT, {\n graph: opts.graph,\n scanPath: opts.scanPath,\n paths: {\n snapshotPath: paths.snapshotPath,\n errorsPath: opts.errorsPath ?? paths.errorsPath,\n staleEventsPath: opts.staleEventsPath ?? paths.staleEventsPath,\n embeddingsCachePath: paths.embeddingsCachePath,\n policyViolationsPath: paths.policyViolationsPath,\n },\n searchIndex: opts.searchIndex,\n })\n return registry\n}\n\ninterface RouteContext {\n registry: Projects\n startedAt: number\n // Where the routes are getting mounted. `'root'` is the legacy unprefixed\n // mount that historically resolved every request to the `default` project;\n // `'project'` is the `/projects/:project` plugin scope where the project\n // segment is always present. The /health handler branches on this so the\n // root mount can answer daemon-wide while the scoped mount stays\n // per-project (issue #343).\n scope: 'root' | 'project'\n // Legacy callers passed `errorsPath`/`staleEventsPath` explicitly and\n // expected absent values to disable the read. Track that intent so the\n // /incidents handlers don't accidentally read a phantom file.\n errorsPathFor: (ctx: ProjectContext) => string | undefined\n staleEventsPathFor: (ctx: ProjectContext) => string | undefined\n // policy.json lives at the project root (per ADR-042 §File location), not\n // under neat-out/. Routes that read it map a project context to the path.\n policyFilePathFor: (ctx: ProjectContext) => string | undefined\n // Issue #340 — flips per-project routes from 404 to 503 while a slot is\n // still extracting.\n bootstrap?: BuildApiOptions['bootstrap']\n}\n\n// Registers every project-scoped route on `scope`. Called twice from\n// buildApi: once on the root app (so /graph etc. land at default), once\n// inside a `register(_, { prefix: '/projects/:project' })` plugin so the\n// same handlers run when the URL names a project explicitly.\nfunction registerRoutes(scope: FastifyInstance, ctx: RouteContext): void {\n const { registry, startedAt, errorsPathFor, staleEventsPathFor } = ctx\n\n // SSE event stream (ADR-051 #1). Dual-mounted: hits /events for default\n // project and /projects/:project/events when scoped. The handler keeps\n // the connection open and writes one frame per bus envelope whose\n // `project` matches.\n scope.get<{ Params: { project?: string } }>('/events', (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n handleSse(req, reply, { project: proj.name })\n })\n\n // Per-project /health stays scoped. The unscoped `/health` at the root\n // mount is handled by the daemon-wide handler below (issue #343) —\n // daemon-wide readiness mustn't pivot on whether the `default` project\n // exists. The scoped variant carries the bootstrap-aware shape from\n // issue #340.\n if (ctx.scope === 'project') {\n scope.get<{ Params: { project?: string } }>('/health', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const uptimeMs = Date.now() - startedAt\n return {\n ok: true,\n project: proj.name,\n uptimeMs,\n // Legacy fields kept additively. The web shell's StatusBar reads\n // nodeCount / edgeCount; ADR-061's HealthResponseSchema validates\n // the canonical triple and lets the extras pass through.\n uptime: Math.floor(uptimeMs / 1000),\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n lastUpdated: new Date().toISOString(),\n }\n })\n }\n\n scope.get<{ Params: { project?: string } }>('/graph', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n return serializeGraph(proj.graph)\n })\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/node/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n return { node: proj.graph.getNodeAttributes(id) as GraphNode }\n },\n )\n\n scope.get<{ Params: { project?: string; id: string } }>(\n '/graph/edges/:id',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { id } = req.params\n if (!proj.graph.hasNode(id)) {\n return reply.code(404).send({ error: 'node not found', id })\n }\n const inbound = proj.graph\n .inboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n const outbound = proj.graph\n .outboundEdges(id)\n .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n return { inbound, outbound }\n },\n )\n\n // Transitive dependencies (issue #144). BFS outbound to depth N, returning\n // a flat list with distance + edgeType + provenance per dependency.\n // Default depth 3, max 10. The MCP get_dependencies tool calls this.\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { depth?: string }\n }>('/graph/dependencies/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const depth = req.query.depth ? Number(req.query.depth) : TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH\n if (!Number.isFinite(depth) || depth < 1 || depth > TRANSITIVE_DEPENDENCIES_MAX_DEPTH) {\n return reply.code(400).send({\n error: `depth must be an integer in [1, ${TRANSITIVE_DEPENDENCIES_MAX_DEPTH}]`,\n })\n }\n return getTransitiveDependencies(proj.graph, nodeId, depth)\n })\n\n // Divergence query — the thesis surface (ADR-060). Read-only, derived,\n // dual-mounted via registerRoutes. Query params filter the result set;\n // body shape is DivergenceResult.\n scope.get<{\n Params: { project?: string }\n Querystring: { type?: string; minConfidence?: string; node?: string }\n }>('/graph/divergences', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n let typeFilter: Set<DivergenceType> | undefined\n if (req.query.type) {\n const candidates = req.query.type\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0)\n const parsed: DivergenceType[] = []\n for (const c of candidates) {\n const r = DivergenceTypeSchema.safeParse(c)\n if (!r.success) {\n return reply.code(400).send({\n error: `unknown divergence type \"${c}\"`,\n allowed: DivergenceTypeSchema.options,\n })\n }\n parsed.push(r.data)\n }\n typeFilter = new Set(parsed)\n }\n let minConfidence: number | undefined\n if (req.query.minConfidence !== undefined) {\n const n = Number(req.query.minConfidence)\n if (!Number.isFinite(n) || n < 0 || n > 1) {\n return reply.code(400).send({\n error: 'minConfidence must be a number in [0, 1]',\n })\n }\n minConfidence = n\n }\n return computeDivergences(proj.graph, {\n ...(typeFilter ? { type: typeFilter } : {}),\n ...(minConfidence !== undefined ? { minConfidence } : {}),\n ...(req.query.node ? { node: req.query.node } : {}),\n })\n })\n\n // ADR-061 envelope rule: list endpoints return { count, total, events }.\n // `total` is the size of the underlying collection; `count` is the size of\n // the slice we're handing back. The web shell counts on both.\n scope.get<{\n Params: { project?: string }\n Querystring: { limit?: string }\n }>('/incidents', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const epath = errorsPathFor(proj)\n if (!epath) return { count: 0, total: 0, events: [] }\n const events = await readErrorEvents(epath)\n const total = events.length\n const limit = req.query.limit ? Number(req.query.limit) : 50\n const safeLimit =\n Number.isFinite(limit) && limit > 0 ? Math.min(limit, 200) : 50\n const sliced = events.slice(0, safeLimit)\n return { count: sliced.length, total, events: sliced }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { limit?: string; edgeType?: string }\n }>('/stale-events', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const spath = staleEventsPathFor(proj)\n if (!spath) return { count: 0, total: 0, events: [] }\n const events = await readStaleEvents(spath)\n const filtered = req.query.edgeType\n ? events.filter((e) => e.edgeType === req.query.edgeType)\n : events\n const ordered = [...filtered].reverse()\n const total = ordered.length\n const limit = req.query.limit ? Number(req.query.limit) : 50\n const sliced = ordered.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 50)\n return { count: sliced.length, total, events: sliced }\n })\n\n scope.get<{ Params: { project?: string; nodeId: string } }>(\n '/incidents/:nodeId',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const epath = errorsPathFor(proj)\n if (!epath) return { count: 0, total: 0, events: [] }\n const events = await readErrorEvents(epath)\n const filtered = events.filter(\n (e) =>\n e.affectedNode === nodeId || e.service === nodeId.replace(/^service:/, ''),\n )\n return { count: filtered.length, total: filtered.length, events: filtered }\n },\n )\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { errorId?: string }\n }>('/graph/root-cause/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n let errorEvent: ErrorEvent | undefined\n const epath = errorsPathFor(proj)\n if (req.query.errorId && epath) {\n const events = await readErrorEvents(epath)\n errorEvent = events.find((e) => e.id === req.query.errorId)\n if (!errorEvent) {\n return reply\n .code(404)\n .send({ error: 'error event not found', id: req.query.errorId })\n }\n }\n const result = getRootCause(proj.graph, nodeId, errorEvent)\n if (!result) return reply.code(404).send({ error: 'no root cause found', id: nodeId })\n return result\n })\n\n scope.get<{\n Params: { project?: string; nodeId: string }\n Querystring: { depth?: string }\n }>('/graph/blast-radius/:nodeId', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { nodeId } = req.params\n if (!proj.graph.hasNode(nodeId)) {\n return reply.code(404).send({ error: 'node not found', id: nodeId })\n }\n const depth = req.query.depth ? Number(req.query.depth) : undefined\n if (depth !== undefined && (!Number.isFinite(depth) || depth < 0)) {\n return reply.code(400).send({ error: 'depth must be a non-negative number' })\n }\n return getBlastRadius(proj.graph, nodeId, depth)\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { q?: string; limit?: string }\n }>('/search', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const raw = (req.query.q ?? '').trim()\n if (!raw) return reply.code(400).send({ error: 'query parameter `q` is required' })\n const limit = req.query.limit ? Number(req.query.limit) : undefined\n const safeLimit =\n limit !== undefined && Number.isFinite(limit) && limit > 0 ? limit : undefined\n if (proj.searchIndex) {\n const result = await proj.searchIndex.search(raw, safeLimit)\n return {\n query: result.query,\n provider: result.provider,\n matches: result.matches.map((m) => ({ ...m.node, score: m.score })),\n }\n }\n const q = raw.toLowerCase()\n const matches: (GraphNode & { score: number })[] = []\n proj.graph.forEachNode((id, attrs) => {\n const name = (attrs as { name?: string }).name ?? ''\n if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n matches.push({ ...(attrs as GraphNode), score: 1 })\n }\n })\n return {\n query: q,\n provider: 'substring' as const,\n matches: matches.slice(0, safeLimit),\n }\n })\n\n scope.get<{ Params: { project?: string }; Querystring: { against?: string } }>(\n '/graph/diff',\n async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const against = req.query.against\n if (!against) {\n return reply.code(400).send({ error: 'query parameter `against` is required' })\n }\n try {\n const snapshot = await loadSnapshotForDiff(against)\n return computeGraphDiff(proj.graph, snapshot)\n } catch (err) {\n return reply\n .code(400)\n .send({ error: 'failed to load snapshot', against, detail: (err as Error).message })\n }\n },\n )\n\n // Snapshot push (ADR-074 §1). `neat sync` POSTs a snapshot here; we merge\n // it into the live graph through `mergeSnapshot`, which preserves any\n // accumulated OBSERVED edges per the Rule 2 coexistence contract. Body\n // shape is the same JSON `persist.ts` writes to disk. Dual-mounted at\n // `/snapshot` and `/projects/:project/snapshot` via registerRoutes.\n scope.post<{\n Params: { project?: string }\n Body: { snapshot?: PersistedGraph }\n }>('/snapshot', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const body = req.body\n if (!body || typeof body !== 'object' || !body.snapshot) {\n return reply\n .code(400)\n .send({ error: 'request body must be { snapshot: <persisted-graph> }' })\n }\n const snap = body.snapshot\n if (typeof snap.schemaVersion !== 'number' || snap.schemaVersion !== SCHEMA_VERSION) {\n return reply.code(400).send({\n error: `unsupported snapshot schemaVersion ${snap.schemaVersion} (expected ${SCHEMA_VERSION})`,\n })\n }\n try {\n const result = mergeSnapshot(proj.graph, snap)\n return {\n project: proj.name,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n }\n } catch (err) {\n return reply.code(400).send({\n error: 'snapshot merge failed',\n details: (err as Error).message,\n })\n }\n })\n\n scope.post<{ Params: { project?: string } }>('/graph/scan', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply\n .code(409)\n .send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const result = await extractFromDirectory(proj.graph, proj.scanPath)\n return {\n project: proj.name,\n scanned: proj.scanPath,\n nodesAdded: result.nodesAdded,\n edgesAdded: result.edgesAdded,\n nodeCount: proj.graph.order,\n edgeCount: proj.graph.size,\n }\n })\n\n // Policy surface (ADR-045 / contract #18). /policies returns the parsed\n // policy.json; /policies/violations is the persistent log; /policies/check\n // is dry-run evaluation. All dual-mounted via registerRoutes.\n scope.get<{ Params: { project?: string } }>('/policies', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const policyPath = ctx.policyFilePathFor(proj)\n if (!policyPath) {\n // No policy file configured for this project — return the empty file\n // shape so consumers don't have to special-case \"no policies yet.\"\n return { version: 1, policies: [] }\n }\n try {\n const policies = await loadPolicyFile(policyPath)\n return { version: 1, policies }\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { severity?: string; policyId?: string }\n }>('/policies/violations', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const log = new PolicyViolationsLog(proj.paths.policyViolationsPath)\n let violations = await log.readAll()\n if (req.query.severity) {\n const sev = PolicySeveritySchema.safeParse(req.query.severity)\n if (!sev.success) {\n return reply.code(400).send({\n error: 'invalid severity',\n details: sev.error.format(),\n })\n }\n violations = violations.filter((v) => v.severity === sev.data)\n }\n if (req.query.policyId) {\n violations = violations.filter((v) => v.policyId === req.query.policyId)\n }\n return { violations }\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { hypotheticalAction?: unknown }\n }>('/policies/check', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const parsed = PoliciesCheckBodySchema.safeParse(req.body ?? {})\n if (!parsed.success) {\n return reply.code(400).send({\n error: 'invalid /policies/check body',\n details: parsed.error.format(),\n })\n }\n\n const policyPath = ctx.policyFilePathFor(proj)\n let policies: Policy[] = []\n if (policyPath) {\n try {\n policies = await loadPolicyFile(policyPath)\n } catch (err) {\n return reply.code(400).send({\n error: 'policy.json failed to parse',\n details: (err as Error).message,\n })\n }\n }\n\n // No hypothetical → return current violations against the live graph.\n // With a hypothetical → simulate the action against a deep-copy graph\n // (avoids mutation authority concerns), evaluate, return the delta.\n const evalCtx = { now: () => Date.now() }\n if (!parsed.data.hypotheticalAction) {\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return { allowed: blocking.length === 0, violations }\n }\n\n // For now the dry-run simulation re-uses evaluateAllPolicies on the\n // current graph. Full hypothetical simulation (e.g. \"what if I added\n // this OBSERVED edge?\") is the v0.2.4-δ scope; #117 ships the surface,\n // #118 fills in the action shapes' simulation logic.\n const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n const blocking = violations.filter((v) => v.onViolation === 'block')\n return {\n allowed: blocking.length === 0,\n hypotheticalAction: parsed.data.hypotheticalAction,\n violations,\n } as { allowed: boolean; hypotheticalAction: unknown; violations: PolicyViolation[] }\n })\n\n // ── /extend — surgical instrumentation tools (ADR-081, ADR-086) ─────────\n // Six routes. Three read-only (list-uninstrumented, lookup, describe),\n // three operative (apply, dry-run, rollback). File-scope restricted per\n // the extend-skill contract: only instrumentation/otel-init files and\n // package.json. Dual-mounted via registerRoutes.\n\n scope.get<{ Params: { project?: string } }>('/extend/list-uninstrumented', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n }\n try {\n const results = await listUninstrumented({ project: proj.name, scanPath: proj.scanPath })\n return { libraries: results }\n } catch (err) {\n return reply.code(500).send({ error: (err as Error).message })\n }\n })\n\n scope.get<{\n Params: { project?: string }\n Querystring: { library?: string; version?: string }\n }>('/extend/lookup', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n const { library, version } = req.query\n if (!library) {\n return reply.code(400).send({ error: 'query parameter `library` is required' })\n }\n const result = lookupInstrumentation(library, version)\n if (!result) {\n return reply.code(404).send({ error: 'library not found in registry', library })\n }\n return result\n })\n\n scope.get<{ Params: { project?: string } }>('/extend/describe', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n }\n try {\n const state = await describeProjectInstrumentation({ project: proj.name, scanPath: proj.scanPath })\n return state\n } catch (err) {\n return reply.code(500).send({ error: (err as Error).message })\n }\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { library?: string; instrumentation_package?: string; version?: string; registration_snippet?: string }\n }>('/extend/apply', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const { library, instrumentation_package, version, registration_snippet } = req.body ?? {}\n if (!library || !instrumentation_package || !version || !registration_snippet) {\n return reply.code(400).send({ error: 'body must include library, instrumentation_package, version, registration_snippet' })\n }\n try {\n const result = await applyExtension(\n { project: proj.name, scanPath: proj.scanPath },\n { library, instrumentation_package, version, registration_snippet },\n )\n return result\n } catch (err) {\n return reply.code(500).send({ error: (err as Error).message })\n }\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { library?: string; instrumentation_package?: string; version?: string; registration_snippet?: string }\n }>('/extend/dry-run', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const { library, instrumentation_package, version, registration_snippet } = req.body ?? {}\n if (!library || !instrumentation_package || !version || !registration_snippet) {\n return reply.code(400).send({ error: 'body must include library, instrumentation_package, version, registration_snippet' })\n }\n try {\n const result = await dryRunExtension(\n { project: proj.name, scanPath: proj.scanPath },\n { library, instrumentation_package, version, registration_snippet },\n )\n return result\n } catch (err) {\n return reply.code(500).send({ error: (err as Error).message })\n }\n })\n\n scope.post<{\n Params: { project?: string }\n Body: { library?: string }\n }>('/extend/rollback', async (req, reply) => {\n const proj = resolveProject(registry, req, reply, ctx.bootstrap)\n if (!proj) return\n if (!proj.scanPath) {\n return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n }\n const { library } = req.body ?? {}\n if (!library) {\n return reply.code(400).send({ error: 'body must include library' })\n }\n try {\n const result = await rollbackExtension(\n { project: proj.name, scanPath: proj.scanPath },\n { library },\n )\n return result\n } catch (err) {\n return reply.code(500).send({ error: (err as Error).message })\n }\n })\n}\n\nexport async function buildApi(opts: BuildApiOptions): Promise<FastifyInstance> {\n const app = Fastify({ logger: false })\n await app.register(cors, { origin: true })\n\n // ADR-073 §3/§4 — `buildApi` owns auth enforcement so every listener that\n // serves the REST surface gets the same gate, whoever builds it. When a\n // caller doesn't pass auth options explicitly, they resolve from the\n // environment (`NEAT_AUTH_TOKEN` / `NEAT_AUTH_PROXY` / `NEAT_PUBLIC_READ`)\n // through the single `readAuthEnv` reader. A caller that does pass them\n // wins, so the daemon and `serve` keep their explicit wiring; a caller that\n // omits them — `neat watch` — inherits the same token rather than serving\n // open by omission. The bind-host loopback refusal stays with the binding\n // caller via `assertBindAuthority`, which reads the same env.\n const env = readAuthEnv()\n const authToken = opts.authToken ?? env.authToken\n const trustProxy = opts.trustProxy ?? env.trustProxy\n const publicRead = opts.publicRead ?? env.publicRead\n\n // ADR-073 §3 — bearer middleware sits ahead of every route handler. No-op\n // when the resolved token is undefined; loopback-only callers (the laptop\n // dev path) hit that branch. `publicRead` opens GET / HEAD / OPTIONS to\n // anonymous callers while keeping writes gated.\n mountBearerAuth(app, {\n token: authToken,\n trustProxy,\n publicRead,\n })\n\n // ADR-073 §3 amendment — `/api/config` is always unauthenticated. The web\n // shell hits it before any bearer-carrying request to learn which mode the\n // daemon is in. Exposes exactly two booleans — `publicRead` and\n // `authProxy` — and nothing else; no project list, no version, no env.\n app.get('/api/config', async () => ({\n publicRead: publicRead === true,\n authProxy: trustProxy === true,\n }))\n\n const startedAt = opts.startedAt ?? Date.now()\n const registry = buildLegacyRegistry(opts)\n\n const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== undefined\n const legacyStaleExplicit = !opts.projects && opts.staleEventsPath !== undefined\n\n const errorsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyErrorsExplicit ? opts.errorsPath : undefined\n }\n return proj.paths.errorsPath\n }\n const staleEventsPathFor = (proj: ProjectContext): string | undefined => {\n if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n return legacyStaleExplicit ? opts.staleEventsPath : undefined\n }\n return proj.paths.staleEventsPath\n }\n\n // policy.json lives at the project's scanPath root per ADR-042. Without a\n // scanPath we have nowhere to read it from — those projects show as\n // \"no policies configured\" via the empty-file response.\n const policyFilePathFor = (proj: ProjectContext): string | undefined => {\n if (!proj.scanPath) return undefined\n return `${proj.scanPath}/policy.json`\n }\n\n const routeCtx: RouteContext = {\n registry,\n startedAt,\n scope: 'root',\n errorsPathFor,\n staleEventsPathFor,\n policyFilePathFor,\n bootstrap: opts.bootstrap,\n }\n\n // Daemon-wide /health (issue #343). Per ADR-049 the daemon is the unit of\n // readiness; the response answers \"is this process up and what's it\n // currently serving?\" without depending on a `default` project. Probes —\n // orchestrator, kubelet readiness, systemd, supervisors — read this.\n //\n // The `projects` array surfaces every slot the daemon knows about. When\n // the bootstrap tracker is wired (issue #340), the per-entry `status`\n // and `elapsedMs` come from there so the orchestrator's wait loop can\n // tell `bootstrapping` apart from `active` without per-project probes.\n app.get('/health', async () => {\n const uptimeMs = Date.now() - startedAt\n const bootstrapList = opts.bootstrap?.list() ?? []\n const byName = new Map(bootstrapList.map((p) => [p.name, p]))\n const names = new Set<string>([\n ...registry.list(),\n ...bootstrapList.map((p) => p.name),\n ])\n const projects = [...names].sort().map((name) => {\n const proj = registry.get(name)\n const tracked = byName.get(name)\n return {\n name,\n nodeCount: proj?.graph.order ?? 0,\n edgeCount: proj?.graph.size ?? 0,\n ...(tracked ? { status: tracked.status, elapsedMs: tracked.elapsedMs } : {}),\n }\n })\n return {\n ok: true,\n uptimeMs,\n projects,\n }\n })\n\n // Multi-project switcher (ADR-051 #4). Direct passthrough of the\n // machine-level registry from registry.ts (ADR-048) — distinct from the\n // dual-mount routing in ADR-026, which exposes per-project endpoints.\n // Returns Array<{ name, path, status, registeredAt, lastSeenAt?, languages }>.\n app.get('/projects', async (_req, reply) => {\n try {\n return await listRegistryProjects()\n } catch (err) {\n return reply.code(500).send({\n error: 'failed to read project registry',\n details: (err as Error).message,\n })\n }\n })\n\n // Singular project lookup (ADR-061 #7). Distinct route from the\n // `/projects/:project/...` dual-mount prefix because Fastify matches on\n // the full path; the trailing-segment-less request lands here.\n app.get<{ Params: { project: string } }>('/projects/:project', async (req, reply) => {\n try {\n const entry = await getRegistryProject(req.params.project)\n if (!entry) {\n return reply\n .code(404)\n .send({ error: 'project not found', project: req.params.project })\n }\n return { project: entry }\n } catch (err) {\n return reply.code(500).send({\n error: 'failed to read project registry',\n details: (err as Error).message,\n })\n }\n })\n\n // Default mount: /graph, /incidents, etc. resolve to project=default.\n // `/health` at this scope is the daemon-wide handler registered above,\n // not the per-project one (issue #343).\n registerRoutes(app, routeCtx)\n\n // Project-scoped mount: same handlers, URL params include `:project`,\n // and `/health` answers per project.\n await app.register(\n async (scope) => {\n registerRoutes(scope, { ...routeCtx, scope: 'project' })\n },\n { prefix: '/projects/:project' },\n )\n\n return app\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { resolve as registryResolve, list as registryList } from '@neat.is/instrumentation-registry'\nimport {\n detectPackageManager,\n runPackageManagerInstall,\n} from '../installers/package-manager.js'\n\nexport interface ExtendContext {\n project: string\n scanPath: string\n}\n\nexport interface LibraryCoverageResult {\n library: string\n coverage: 'bundled' | 'first-party' | 'third-party' | 'http-only' | 'gap'\n installedVersion?: string\n instrumentation_package?: string\n package_version?: string\n registration?: string\n notes?: string\n}\n\nexport interface ProjectInstrumentationState {\n hookFiles: string[]\n envNeat: boolean\n installedDeps: Record<string, string>\n}\n\nexport interface ExtensionApplyResult {\n library: string\n filesTouched: string[]\n depsAdded: string[]\n installOutput: string\n alreadyApplied: boolean\n}\n\nexport interface ExtensionDiff {\n library: string\n filesTouched: string[]\n depsToAdd: string[]\n packageJsonPatch: object\n templatePatch: string\n}\n\ninterface PackageJson {\n name?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n [key: string]: unknown\n}\n\ninterface ExtendLogEntry {\n timestamp: string\n project: string\n library: string\n instrumentation_package: string\n version: string\n registration_snippet: string\n filesTouched: string[]\n depsAdded: string[]\n installOutput: string\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\nasync function readPackageJson(scanPath: string): Promise<PackageJson> {\n const pkgPath = path.join(scanPath, 'package.json')\n const raw = await fs.readFile(pkgPath, 'utf8')\n return JSON.parse(raw) as PackageJson\n}\n\nasync function findHookFiles(scanPath: string): Promise<string[]> {\n const entries = await fs.readdir(scanPath)\n return entries\n .filter(\n (e) =>\n (e.startsWith('instrumentation') || e.startsWith('otel-init')) &&\n /\\.(ts|js)$/.test(e),\n )\n .sort()\n}\n\nfunction extendLogPath(): string {\n return process.env.NEAT_EXTEND_LOG ?? path.join(os.homedir(), '.neat', 'extend-log.ndjson')\n}\n\nasync function appendExtendLog(entry: ExtendLogEntry): Promise<void> {\n const logPath = extendLogPath()\n await fs.mkdir(path.dirname(logPath), { recursive: true })\n await fs.appendFile(logPath, JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n// Insert `snippet` into `fileContent` at the instrumentation array.\n// Tries __INSTRUMENTATION_BLOCK__ first, then last instrumentations.push(,\n// then before new NodeSDK(. Returns null if no insertion point is found.\nfunction splicedContent(fileContent: string, snippet: string): string | null {\n if (fileContent.includes('__INSTRUMENTATION_BLOCK__')) {\n return fileContent.replace('__INSTRUMENTATION_BLOCK__', `${snippet}\\n__INSTRUMENTATION_BLOCK__`)\n }\n\n const lines = fileContent.split('\\n')\n\n let lastPushIdx = -1\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].includes('instrumentations.push(')) lastPushIdx = i\n }\n if (lastPushIdx >= 0) {\n lines.splice(lastPushIdx + 1, 0, snippet)\n return lines.join('\\n')\n }\n\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].includes('new NodeSDK(')) {\n lines.splice(i, 0, snippet)\n return lines.join('\\n')\n }\n }\n\n return null\n}\n\nexport async function listUninstrumented(ctx: ExtendContext): Promise<LibraryCoverageResult[]> {\n const pkg = await readPackageJson(ctx.scanPath)\n const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n\n const results: LibraryCoverageResult[] = []\n for (const [library, installedVersion] of Object.entries(allDeps)) {\n const entry = registryResolve(library, installedVersion)\n if (!entry) continue\n if (entry.coverage === 'bundled' || entry.coverage === 'http-only') continue\n results.push({\n library,\n coverage: entry.coverage,\n installedVersion,\n instrumentation_package: entry.instrumentation_package,\n package_version: entry.package_version,\n registration: entry.registration,\n notes: entry.notes,\n })\n }\n return results\n}\n\nexport function lookupInstrumentation(\n library: string,\n installedVersion?: string,\n): LibraryCoverageResult | null {\n const entry = registryResolve(library, installedVersion)\n if (!entry) return null\n return {\n library: entry.library,\n coverage: entry.coverage,\n instrumentation_package: entry.instrumentation_package,\n package_version: entry.package_version,\n registration: entry.registration,\n notes: entry.notes,\n }\n}\n\nexport async function describeProjectInstrumentation(\n ctx: ExtendContext,\n): Promise<ProjectInstrumentationState> {\n const hookFiles = await findHookFiles(ctx.scanPath)\n const envNeat = await fileExists(path.join(ctx.scanPath, '.env.neat'))\n\n const registryInstrPackages = new Set<string>(\n registryList()\n .map((e) => e.instrumentation_package)\n .filter((p): p is string => !!p),\n )\n\n const pkg = await readPackageJson(ctx.scanPath)\n const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n\n const installedDeps: Record<string, string> = {}\n for (const [key, version] of Object.entries(allDeps)) {\n if (key.startsWith('@opentelemetry/') || registryInstrPackages.has(key)) {\n installedDeps[key] = version\n }\n }\n\n return { hookFiles, envNeat, installedDeps }\n}\n\nexport async function applyExtension(\n ctx: ExtendContext,\n args: {\n library: string\n instrumentation_package: string\n version: string\n registration_snippet: string\n },\n options?: {\n runInstall?: typeof runPackageManagerInstall\n },\n): Promise<ExtensionApplyResult> {\n const hookFiles = await findHookFiles(ctx.scanPath)\n\n if (hookFiles.length === 0) {\n throw new Error(\n `No instrumentation hook files found in ${ctx.scanPath}. Run \\`neat init\\` first.`,\n )\n }\n\n // Idempotency check: scan all hook files for the snippet\n for (const file of hookFiles) {\n const content = await fs.readFile(path.join(ctx.scanPath, file), 'utf8')\n if (content.includes(args.registration_snippet)) {\n return { library: args.library, filesTouched: [], depsAdded: [], installOutput: '', alreadyApplied: true }\n }\n }\n\n const primaryFile = hookFiles[0]!\n const primaryPath = path.join(ctx.scanPath, primaryFile)\n const filesTouched: string[] = []\n const depsAdded: string[] = []\n\n // 1. Add dep to package.json if not already present\n const pkgPath = path.join(ctx.scanPath, 'package.json')\n const pkg = await readPackageJson(ctx.scanPath)\n if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {\n pkg.dependencies = { ...(pkg.dependencies ?? {}), [args.instrumentation_package]: args.version }\n await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\\n', 'utf8')\n filesTouched.push('package.json')\n depsAdded.push(`${args.instrumentation_package}@${args.version}`)\n }\n\n // 2. Splice registration snippet into hook file\n const hookContent = await fs.readFile(primaryPath, 'utf8')\n const patched = splicedContent(hookContent, args.registration_snippet)\n if (!patched) {\n throw new Error(\n `Could not find instrumentation insertion point in ${primaryFile}. ` +\n 'Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.',\n )\n }\n await fs.writeFile(primaryPath, patched, 'utf8')\n filesTouched.push(primaryFile)\n\n // 3. Run package manager install\n const cmd = await detectPackageManager(ctx.scanPath)\n const installer = options?.runInstall ?? runPackageManagerInstall\n const install = await installer(cmd)\n const installOutput =\n install.exitCode === 0\n ? `${cmd.pm} install succeeded`\n : install.stderr || `${cmd.pm} install failed (exit ${install.exitCode})`\n\n // 4. Log the apply\n await appendExtendLog({\n timestamp: new Date().toISOString(),\n project: ctx.project,\n library: args.library,\n instrumentation_package: args.instrumentation_package,\n version: args.version,\n registration_snippet: args.registration_snippet,\n filesTouched,\n depsAdded,\n installOutput,\n })\n\n return { library: args.library, filesTouched, depsAdded, installOutput, alreadyApplied: false }\n}\n\nexport async function dryRunExtension(\n ctx: ExtendContext,\n args: {\n library: string\n instrumentation_package: string\n version: string\n registration_snippet: string\n },\n): Promise<ExtensionDiff> {\n const hookFiles = await findHookFiles(ctx.scanPath)\n\n if (hookFiles.length === 0) {\n return {\n library: args.library,\n filesTouched: [],\n depsToAdd: [],\n packageJsonPatch: {},\n templatePatch: \"No hook files found. Run 'neat init' first.\",\n }\n }\n\n for (const file of hookFiles) {\n const content = await fs.readFile(path.join(ctx.scanPath, file), 'utf8')\n if (content.includes(args.registration_snippet)) {\n return {\n library: args.library,\n filesTouched: [],\n depsToAdd: [],\n packageJsonPatch: {},\n templatePatch: 'Already applied — no changes would be made.',\n }\n }\n }\n\n const primaryFile = hookFiles[0]!\n const filesTouched: string[] = []\n const depsToAdd: string[] = []\n let packageJsonPatch: object = {}\n let templatePatch = ''\n\n const pkg = await readPackageJson(ctx.scanPath)\n if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {\n packageJsonPatch = { dependencies: { [args.instrumentation_package]: args.version } }\n depsToAdd.push(`${args.instrumentation_package}@${args.version}`)\n filesTouched.push('package.json')\n }\n\n const hookContent = await fs.readFile(path.join(ctx.scanPath, primaryFile), 'utf8')\n const patched = splicedContent(hookContent, args.registration_snippet)\n if (patched) {\n filesTouched.push(primaryFile)\n templatePatch = `+ ${args.registration_snippet}`\n } else {\n templatePatch = 'Could not find insertion point in hook file.'\n }\n\n return { library: args.library, filesTouched, depsToAdd, packageJsonPatch, templatePatch }\n}\n\nexport async function rollbackExtension(\n ctx: ExtendContext,\n args: { library: string },\n): Promise<{ undone: boolean; message: string }> {\n const logPath = extendLogPath()\n\n if (!(await fileExists(logPath))) {\n return { undone: false, message: 'no apply found for library' }\n }\n\n const raw = await fs.readFile(logPath, 'utf8')\n const entries: ExtendLogEntry[] = raw\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => JSON.parse(line) as ExtendLogEntry)\n\n const match = [...entries]\n .reverse()\n .find((e) => e.project === ctx.project && e.library === args.library)\n\n if (!match) {\n return { undone: false, message: 'no apply found for library' }\n }\n\n // Remove dep from package.json\n const pkgPath = path.join(ctx.scanPath, 'package.json')\n if (await fileExists(pkgPath)) {\n const pkg = await readPackageJson(ctx.scanPath)\n if (pkg.dependencies?.[match.instrumentation_package]) {\n const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies\n pkg.dependencies = rest\n await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\\n', 'utf8')\n }\n }\n\n // Remove the registration snippet from hook files (no re-install — user owns the lockfile)\n const hookFiles = await findHookFiles(ctx.scanPath)\n for (const file of hookFiles) {\n const filePath = path.join(ctx.scanPath, file)\n const content = await fs.readFile(filePath, 'utf8')\n if (content.includes(match.registration_snippet)) {\n const filtered = content\n .split('\\n')\n .filter((line) => !line.includes(match.registration_snippet))\n .join('\\n')\n await fs.writeFile(filePath, filtered, 'utf8')\n break\n }\n }\n\n return {\n undone: true,\n message: `rolled back ${match.library} (${match.instrumentation_package})`,\n }\n}\n","/**\n * Package-manager detection + install invocation.\n *\n * Issue #381 — the apply phase adds dependencies to package.json but\n * relies on the operator to run `npm install` afterwards. The v0.4.5\n * smoke surfaced this as a hard regression on Brief: the installer\n * adds `@opentelemetry/sdk-node` (and `@prisma/instrumentation` when\n * Prisma is in deps) and the next `npm run dev` fails with\n * `Cannot find module '@opentelemetry/sdk-node'` before the OTel SDK\n * even gets a chance to load.\n *\n * ADR-046's \"lockfiles never touched\" rule is about NEAT not directly\n * editing lockfile contents; letting the user's own package manager\n * update them as a side effect of `<pm> install` is consistent with\n * that contract. The clarification is documented in\n * docs/contracts/sdk-install.md.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\n\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm'\n\nexport interface PackageManagerCommand {\n pm: PackageManager\n // The directory the install command runs in. Monorepo workspaces install\n // from the lockfile root, not the per-package directory, so detection\n // walks up from `serviceDir` and reports the lockfile-owning parent.\n cwd: string\n // The argv passed to spawn(). Each entry is one positional token. Selected\n // to keep install output quiet on the happy path; failures still print\n // because stderr is streamed verbatim.\n args: string[]\n}\n\n// Lockfile basename → package manager + the install args we run for it.\n// Priority order — first match wins when multiple lockfiles coexist (rare,\n// but `package-lock.json` alongside `pnpm-lock.yaml` happens during a\n// migration). Bun leads because a project that opted into Bun deliberately\n// rejects npm; pnpm and yarn follow for similar reasons; npm is the default\n// when nothing else applies.\nconst LOCKFILE_PRIORITY: ReadonlyArray<{\n lockfile: string\n pm: PackageManager\n args: string[]\n}> = [\n { lockfile: 'bun.lockb', pm: 'bun', args: ['install', '--no-summary'] },\n { lockfile: 'pnpm-lock.yaml', pm: 'pnpm', args: ['install', '--no-summary'] },\n { lockfile: 'yarn.lock', pm: 'yarn', args: ['install', '--silent'] },\n {\n lockfile: 'package-lock.json',\n pm: 'npm',\n args: ['install', '--no-audit', '--no-fund', '--prefer-offline'],\n },\n]\n\n// Default when no lockfile is present anywhere in the ancestor chain — a\n// fresh project the operator hasn't installed yet. npm is the safe pick:\n// it's available on every Node install and produces a `package-lock.json`\n// the user can later swap out for pnpm/yarn/bun without losing fidelity.\nconst NPM_FALLBACK_ARGS = ['install', '--no-audit', '--no-fund', '--prefer-offline']\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.access(p)\n return true\n } catch {\n return false\n }\n}\n\n// Resolve the package-manager command for a service directory. Walks up from\n// `serviceDir` looking for a lockfile — the first ancestor that has one\n// owns the install. Monorepos (npm/pnpm/yarn workspaces, Bun workspaces)\n// land their lockfile at the workspace root, so this returns the root cwd\n// even when `serviceDir` is a per-package subdir.\n//\n// No lockfile anywhere → npm at the service dir. A fresh `create-next-app`\n// run sits in this bucket (no install yet, no lockfile to read).\nexport async function detectPackageManager(\n serviceDir: string,\n): Promise<PackageManagerCommand> {\n let dir = path.resolve(serviceDir)\n const stops = new Set<string>()\n for (let i = 0; i < 64; i++) {\n if (stops.has(dir)) break\n stops.add(dir)\n for (const candidate of LOCKFILE_PRIORITY) {\n const lockPath = path.join(dir, candidate.lockfile)\n if (await exists(lockPath)) {\n return { pm: candidate.pm, cwd: dir, args: [...candidate.args] }\n }\n }\n const parent = path.dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n return { pm: 'npm', cwd: path.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] }\n}\n\nexport interface PackageManagerInvocation {\n pm: PackageManager\n cwd: string\n args: string[]\n // 0 → success; non-zero → install failed. Reported in the orchestrator\n // summary so the operator can act before the daemon goes hunting for\n // spans that never arrive.\n exitCode: number\n // Stderr captured from the child process, trimmed. Empty on success.\n // Surfaces the underlying failure cause without dumping the entire\n // install log into the summary.\n stderr: string\n}\n\n// Run the install command and resolve with the outcome. Stdout is dropped\n// (`<pm> install --silent`-style flags already keep it short); stderr is\n// captured so a failure can be relayed up to the orchestrator's summary.\nexport async function runPackageManagerInstall(\n cmd: PackageManagerCommand,\n): Promise<PackageManagerInvocation> {\n return new Promise((resolve) => {\n const child = spawn(cmd.pm, cmd.args, {\n cwd: cmd.cwd,\n // Inherit PATH + HOME so the user's installed managers resolve.\n env: process.env,\n // `false` keeps the parent in control of cleanup if the orchestrator\n // exits before install finishes. Cross-platform-safe.\n shell: false,\n stdio: ['ignore', 'ignore', 'pipe'],\n })\n let stderr = ''\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8')\n })\n child.on('error', (err) => {\n resolve({\n pm: cmd.pm,\n cwd: cmd.cwd,\n args: cmd.args,\n exitCode: 127,\n stderr: stderr + `\\n${err.message}`,\n })\n })\n child.on('close', (code) => {\n resolve({\n pm: cmd.pm,\n cwd: cmd.cwd,\n args: cmd.args,\n exitCode: code ?? 1,\n stderr: stderr.trim(),\n })\n })\n })\n}\n","import { promises as fs } from 'node:fs'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Diff a snapshot on disk (or fetched over HTTP) against the live in-memory\n// graph. The \"base\" is the snapshot you supplied; the \"current\" is whatever\n// the server has loaded right now. Symmetric in shape, but consumers usually\n// want to read it as \"what changed since base.\"\n//\n// The shape mirrors the issue's spec (#77):\n// { added: { nodes, edges }, removed: { nodes, edges },\n// changed: { nodes: [{id, before, after}], edges: [{id, before, after}] } }\n//\n// Both timestamps are echoed back so the caller doesn't have to track them\n// separately.\n\ninterface PersistedNodeEntry {\n key?: string\n attributes?: Record<string, unknown>\n}\n\ninterface PersistedEdgeEntry {\n key?: string\n source?: string\n target?: string\n attributes?: Record<string, unknown>\n}\n\nexport interface PersistedSnapshot {\n schemaVersion?: number\n exportedAt?: string\n graph?: {\n nodes?: PersistedNodeEntry[]\n edges?: PersistedEdgeEntry[]\n }\n}\n\nexport interface GraphDiff {\n base: { exportedAt?: string }\n current: { exportedAt: string }\n added: { nodes: GraphNode[]; edges: GraphEdge[] }\n removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n changed: {\n nodes: { id: string; before: GraphNode; after: GraphNode }[]\n edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n }\n}\n\nexport async function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot> {\n if (/^https?:\\/\\//i.test(target)) {\n const res = await fetch(target)\n if (!res.ok) {\n throw new Error(`fetch ${target} failed: ${res.status} ${res.statusText}`)\n }\n return (await res.json()) as PersistedSnapshot\n }\n const raw = await fs.readFile(target, 'utf8')\n return JSON.parse(raw) as PersistedSnapshot\n}\n\nfunction indexEntries<T>(\n entries: { key?: string; attributes?: Record<string, unknown> }[] | undefined,\n): Map<string, T> {\n const m = new Map<string, T>()\n if (!entries) return m\n for (const entry of entries) {\n const id = (entry.attributes?.id as string | undefined) ?? entry.key\n if (!id) continue\n m.set(id, entry.attributes as T)\n }\n return m\n}\n\nexport function computeGraphDiff(\n liveGraph: NeatGraph,\n baseSnapshot: PersistedSnapshot,\n currentExportedAt: string = new Date().toISOString(),\n): GraphDiff {\n const baseNodes = indexEntries<GraphNode>(baseSnapshot.graph?.nodes)\n const baseEdges = indexEntries<GraphEdge>(baseSnapshot.graph?.edges)\n\n const liveNodes = new Map<string, GraphNode>()\n liveGraph.forEachNode((id, attrs) => liveNodes.set(id, attrs as GraphNode))\n const liveEdges = new Map<string, GraphEdge>()\n liveGraph.forEachEdge((id, attrs) => liveEdges.set(id, attrs as GraphEdge))\n\n const result: GraphDiff = {\n base: { exportedAt: baseSnapshot.exportedAt },\n current: { exportedAt: currentExportedAt },\n added: { nodes: [], edges: [] },\n removed: { nodes: [], edges: [] },\n changed: { nodes: [], edges: [] },\n }\n\n for (const [id, after] of liveNodes) {\n const before = baseNodes.get(id)\n if (!before) {\n result.added.nodes.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.nodes.push({ id, before, after })\n }\n }\n for (const [id, before] of baseNodes) {\n if (!liveNodes.has(id)) result.removed.nodes.push(before)\n }\n for (const [id, after] of liveEdges) {\n const before = baseEdges.get(id)\n if (!before) {\n result.added.edges.push(after)\n } else if (!shallowEqual(before, after)) {\n result.changed.edges.push({ id, before, after })\n }\n }\n for (const [id, before] of baseEdges) {\n if (!liveEdges.has(id)) result.removed.edges.push(before)\n }\n\n return result\n}\n\n// Stable JSON comparison. Snapshot order isn't guaranteed, so canonicalising\n// keys before stringify keeps the comparison robust against re-ordered fields.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n return canonicalJson(a) === canonicalJson(b)\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(value, (_key, v) => {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n return Object.keys(v as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = (v as Record<string, unknown>)[k]\n return acc\n }, {})\n }\n return v\n })\n}\n","// Project registry — owns the per-project state that lives alongside the\n// graph map: snapshot/error/stale paths, scan path, optional search index.\n//\n// Routes use it via `resolve(project)`. Server / watch construct it once at\n// boot and pass it to buildApi. Tests can mock it with a small literal.\n\nimport path from 'node:path'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport type { SearchIndex } from './search.js'\n\nexport interface ProjectPaths {\n snapshotPath: string\n errorsPath: string\n staleEventsPath: string\n embeddingsCachePath: string\n // Policy-violations log per ADR-041 § Append-only ndjson sidecars. Lives\n // in the same neat-out directory as the other ndjson sidecars; daemons\n // wire PolicyViolationsLog to it.\n policyViolationsPath: string\n}\n\n// Default project keeps the legacy filenames so existing M5 / β / γ users\n// see no behaviour change. Named projects fan out by name (ADR-026).\nexport function pathsForProject(project: string, baseDir: string): ProjectPaths {\n if (project === DEFAULT_PROJECT) {\n return {\n snapshotPath: path.join(baseDir, 'graph.json'),\n errorsPath: path.join(baseDir, 'errors.ndjson'),\n staleEventsPath: path.join(baseDir, 'stale-events.ndjson'),\n embeddingsCachePath: path.join(baseDir, 'embeddings.json'),\n policyViolationsPath: path.join(baseDir, 'policy-violations.ndjson'),\n }\n }\n return {\n snapshotPath: path.join(baseDir, `${project}.json`),\n errorsPath: path.join(baseDir, `errors.${project}.ndjson`),\n staleEventsPath: path.join(baseDir, `stale-events.${project}.ndjson`),\n embeddingsCachePath: path.join(baseDir, `embeddings.${project}.json`),\n policyViolationsPath: path.join(baseDir, `policy-violations.${project}.ndjson`),\n }\n}\n\nexport interface ProjectContext {\n name: string\n graph: NeatGraph\n scanPath?: string\n paths: ProjectPaths\n searchIndex?: SearchIndex\n}\n\nexport class Projects {\n private contexts = new Map<string, ProjectContext>()\n\n upsert(ctx: ProjectContext): void {\n this.contexts.set(ctx.name, ctx)\n }\n\n set(\n name: string,\n init: Omit<ProjectContext, 'name' | 'graph'> & { graph?: NeatGraph },\n ): ProjectContext {\n const ctx: ProjectContext = {\n name,\n graph: init.graph ?? getGraph(name),\n scanPath: init.scanPath,\n paths: init.paths,\n searchIndex: init.searchIndex,\n }\n this.contexts.set(name, ctx)\n return ctx\n }\n\n get(name: string): ProjectContext | undefined {\n return this.contexts.get(name)\n }\n\n has(name: string): boolean {\n return this.contexts.has(name)\n }\n\n list(): string[] {\n return [...this.contexts.keys()].sort()\n }\n\n attachSearchIndex(name: string, index: SearchIndex | undefined): void {\n const ctx = this.contexts.get(name)\n if (ctx) ctx.searchIndex = index\n }\n}\n\n// Parses NEAT_PROJECTS=a,b,c; trims whitespace, drops empty entries.\n// `default` is implicit (always loaded), so callers usually filter it out\n// before iterating extra projects.\nexport function parseExtraProjects(raw: string | undefined): string[] {\n if (!raw) return []\n return raw\n .split(',')\n .map((p) => p.trim())\n .filter((p) => p.length > 0 && p !== DEFAULT_PROJECT)\n}\n","/**\n * Machine-level project registry (ADR-048).\n *\n * One file: `~/.neat/projects.json`. Per-user, machine-local. Not synced.\n * `registry.ts` is the only module that opens it. Everything else — `init`,\n * `daemon`, `cli` — calls into the helpers below.\n *\n * Two safety properties matter:\n * 1. Atomic writes. We tmp + fsync + rename so the daemon never sees a torn\n * file when init races against it.\n * 2. Cross-process exclusion. We hold an exclusive lock on\n * `~/.neat/projects.json.lock` for the read-modify-write window. Two\n * concurrent `neat init` runs cannot both win and overwrite each other.\n *\n * The lock is a file we exclusively-create (`O_EXCL`), hold while we mutate,\n * and unlink on the way out. Crude but cross-platform; matches what\n * `proper-lockfile` does internally without pulling the dep in.\n */\n\nimport { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport {\n RegistryFileSchema,\n type RegistryEntry,\n type RegistryFile,\n type RegistryStatus,\n} from '@neat.is/types'\n\nconst LOCK_TIMEOUT_MS = 5_000\nconst LOCK_RETRY_MS = 50\n\n// Resolve `~/.neat/` per call so tests can override `HOME` / `NEAT_HOME`\n// before each run without module-load order mattering.\nfunction neatHome(): string {\n const override = process.env.NEAT_HOME\n if (override && override.length > 0) return path.resolve(override)\n return path.join(os.homedir(), '.neat')\n}\n\nexport function registryPath(): string {\n return path.join(neatHome(), 'projects.json')\n}\n\nexport function registryLockPath(): string {\n return path.join(neatHome(), 'projects.json.lock')\n}\n\n// The daemon writes its PID here on startup (daemon.ts). It's the authoritative\n// \"is a neat daemon running\" signal — more reliable than matching the lock's\n// own PID, since the daemon holds the registry lock only for brief read-modify-\n// write windows and an init that contends usually catches an orphaned lock\n// rather than the daemon mid-write.\nfunction daemonPidPath(): string {\n return path.join(neatHome(), 'neatd.pid')\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #432 — distinguish a live daemon from a genuinely stale lock.\n//\n// `neat init` used to hang the full timeout on any contended lock and then\n// print one remediation: \"remove the file by hand.\" That advice is actively\n// dangerous when a neat daemon is alive — the daemon grabs the lock for its\n// own registry writes, so hand-removing it races the daemon and corrupts the\n// registry for the live process. The lock now carries the holder PID, and the\n// timeout (or first contention with a live daemon) resolves to a message that\n// names who holds it and what's safe to do.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type LockHolder =\n | { kind: 'daemon'; pid: number }\n | { kind: 'command'; pid: number }\n | { kind: 'stale' }\n\n// Probes the holder-resolution logic depends on, broken out so tests can drive\n// each branch without a real daemon or live PIDs.\nexport interface LockHolderProbe {\n // POSIX liveness via `process.kill(pid, 0)`: true if the process exists\n // (including EPERM — alive but owned by another user), false if it's gone.\n isPidAlive(pid: number): boolean\n // PID recorded in `~/.neat/neatd.pid`, or undefined if there's no pidfile.\n daemonPidFromFile(): Promise<number | undefined>\n // Whether the daemon's always-open `/health` endpoint answers. Confirms a\n // live neatd.pid is actually our daemon and not a reused PID.\n daemonResponds(): Promise<boolean>\n}\n\nfunction isPidAliveDefault(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err) {\n // ESRCH → no such process (dead). EPERM → exists but owned by another user\n // (alive). Treat anything else as not-alive: we'd rather under-claim a live\n // holder than wrongly block on a lock we can't verify.\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nasync function readPidFile(file: string): Promise<number | undefined> {\n try {\n const raw = await fs.readFile(file, 'utf8')\n const pid = Number.parseInt(raw.trim(), 10)\n return Number.isInteger(pid) && pid > 0 ? pid : undefined\n } catch {\n return undefined\n }\n}\n\nconst defaultLockHolderProbe: LockHolderProbe = {\n isPidAlive: isPidAliveDefault,\n daemonPidFromFile: () => readPidFile(daemonPidPath()),\n async daemonResponds(): Promise<boolean> {\n const base = process.env.NEAT_API_URL ?? 'http://localhost:8080'\n try {\n // `/health` stays unauthenticated in every mode (auth.ts), so a reachable\n // daemon answers it even with a bearer token set. Any HTTP response — not\n // just 2xx — means a daemon owns the port. A short timeout keeps the\n // fail-fast path well under a second.\n await fetch(`${base}/health`, { signal: AbortSignal.timeout(750) })\n return true\n } catch {\n return false\n }\n },\n}\n\n// Read the PID a lock holder recorded when it created the lock. Undefined for a\n// legacy empty lock, an unreadable file, or a lock unlinked out from under us.\nasync function readLockPid(lockPath: string): Promise<number | undefined> {\n return readPidFile(lockPath)\n}\n\n// Decide who holds (or orphaned) the lock. A live daemon dominates: while neatd\n// is alive, hand-removing the lock is never safe, so we surface the daemon\n// message even when the lock itself is an empty orphan. We never classify our\n// own process as the blocking daemon — a daemon serializing two of its own\n// registry writes contends with itself briefly and should just retry.\nexport async function classifyLockHolder(\n lockPath: string,\n probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<LockHolder> {\n const lockPid = await readLockPid(lockPath)\n const daemonPid = await probe.daemonPidFromFile()\n if (\n daemonPid !== undefined &&\n daemonPid !== process.pid &&\n probe.isPidAlive(daemonPid) &&\n // The lock already names the daemon, or the daemon answers on its port.\n // Either confirms a live daemon is in the picture (the second guards\n // against a stale pidfile whose PID got reused).\n (daemonPid === lockPid || (await probe.daemonResponds()))\n ) {\n return { kind: 'daemon', pid: daemonPid }\n }\n if (lockPid !== undefined && lockPid !== process.pid && probe.isPidAlive(lockPid)) {\n return { kind: 'command', pid: lockPid }\n }\n return { kind: 'stale' }\n}\n\nexport function lockHolderMessage(holder: LockHolder, lockPath: string, timeoutMs: number): string {\n switch (holder.kind) {\n case 'daemon':\n return (\n `The neat daemon (pid ${holder.pid}) is holding the registry lock. ` +\n 'Register this project through the daemon, or stop neatd and re-run `neat init`.'\n )\n case 'command':\n return (\n `Another neat command (pid ${holder.pid}) is holding the registry lock. ` +\n \"Wait for it to finish, or check `ps` if you're not sure what's running.\"\n )\n case 'stale':\n return (\n `neat registry: timed out after ${timeoutMs}ms waiting for ${lockPath}. ` +\n 'Another neat process is holding the lock; if no such process exists, remove the file by hand.'\n )\n }\n}\n\n/**\n * Path normalisation per ADR-048 #7. Two `init` calls from different relative\n * paths to the same dir must collapse to one entry. `path.resolve` handles\n * relative-to-cwd; we pass it through `fs.realpath` when the dir exists so\n * symlinked paths land on the same canonical entry too.\n */\nexport async function normalizeProjectPath(input: string): Promise<string> {\n const resolved = path.resolve(input)\n try {\n return await fs.realpath(resolved)\n } catch {\n return resolved\n }\n}\n\n/**\n * tmp + fsync + rename. The fsync on the data fd guarantees the bytes are on\n * disk before rename swaps the inode; rename itself is atomic on POSIX.\n *\n * Exported so the init flow and test harnesses can use the same helper.\n */\nexport async function writeAtomically(target: string, contents: string): Promise<void> {\n await fs.mkdir(path.dirname(target), { recursive: true })\n const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`\n const fd = await fs.open(tmp, 'w')\n try {\n await fd.writeFile(contents, 'utf8')\n await fd.sync()\n } finally {\n await fd.close()\n }\n await fs.rename(tmp, target)\n}\n\nasync function acquireLock(\n lockPath: string,\n timeoutMs: number = LOCK_TIMEOUT_MS,\n probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<void> {\n const deadline = Date.now() + timeoutMs\n await fs.mkdir(path.dirname(lockPath), { recursive: true })\n let probedHolder = false\n while (true) {\n try {\n const fd = await fs.open(lockPath, 'wx')\n try {\n // Stamp the lock with our PID so a contender can name who holds it and\n // tell a live holder apart from a stale file. Best-effort: an empty\n // lock still excludes correctly, it just can't be diagnosed.\n await fd.writeFile(`${process.pid}\\n`, 'utf8')\n } finally {\n await fd.close()\n }\n return\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code !== 'EEXIST') throw err\n // A live daemon holds the registry continuously enough that spinning the\n // full timeout is pointless — surface the routed remediation on the first\n // contention. Peer commands and stale locks fall through to the retry:\n // peers clear on their own, and a stale lock wants the timeout's guidance.\n if (!probedHolder) {\n probedHolder = true\n const holder = await classifyLockHolder(lockPath, probe)\n if (holder.kind === 'daemon') throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n }\n if (Date.now() >= deadline) {\n const holder = await classifyLockHolder(lockPath, probe)\n throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n }\n await new Promise((r) => setTimeout(r, LOCK_RETRY_MS))\n }\n }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {})\n}\n\nasync function withLock<T>(fn: () => Promise<T>): Promise<T> {\n const lock = registryLockPath()\n await acquireLock(lock)\n try {\n return await fn()\n } finally {\n await releaseLock(lock)\n }\n}\n\n/**\n * Read the registry from disk. Returns an empty registry if the file does\n * not exist yet — first run, never registered anything.\n *\n * Throws on parse / schema errors. The contract is single-source-of-truth;\n * a corrupt file is louder than a silent reset.\n */\nexport async function readRegistry(): Promise<RegistryFile> {\n const file = registryPath()\n let raw: string\n try {\n raw = await fs.readFile(file, 'utf8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { version: 1, projects: [] }\n }\n throw err\n }\n const parsed = JSON.parse(raw)\n return RegistryFileSchema.parse(parsed)\n}\n\nasync function writeRegistry(reg: RegistryFile): Promise<void> {\n // Re-parse before writing to surface schema drift introduced by callers\n // mutating the in-memory object directly.\n const validated = RegistryFileSchema.parse(reg)\n await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + '\\n')\n}\n\nexport interface AddProjectOptions {\n name: string\n path: string\n languages?: string[]\n status?: RegistryStatus\n}\n\nexport class ProjectNameCollisionError extends Error {\n readonly projectName: string\n constructor(name: string) {\n super(`neat registry: a project named \"${name}\" is already registered`)\n this.name = 'ProjectNameCollisionError'\n this.projectName = name\n }\n}\n\n/**\n * Register a project, or update its `lastSeenAt` if the same path is already\n * registered under the same name (idempotent re-init).\n *\n * Hard error on name collision against a different path — ADR-046 #7. The\n * caller can recover by passing `--project <new-name>`.\n */\nexport async function addProject(opts: AddProjectOptions): Promise<RegistryEntry> {\n const resolvedPath = await normalizeProjectPath(opts.path)\n return withLock(async () => {\n const reg = await readRegistry()\n const byName = reg.projects.find((p) => p.name === opts.name)\n const byPath = reg.projects.find((p) => p.path === resolvedPath)\n\n if (byName && byName.path !== resolvedPath) {\n throw new ProjectNameCollisionError(opts.name)\n }\n\n const now = new Date().toISOString()\n\n if (byName && byName.path === resolvedPath) {\n // Idempotent re-register: same name, same path. Refresh languages /\n // status if the caller passed new ones.\n byName.lastSeenAt = now\n if (opts.languages) byName.languages = opts.languages\n if (opts.status) byName.status = opts.status\n await writeRegistry(reg)\n return byName\n }\n\n if (byPath && byPath.name !== opts.name) {\n // Same dir already registered under a different name. Treat as a\n // collision so the user is forced to decide which name wins.\n throw new ProjectNameCollisionError(byPath.name)\n }\n\n const entry: RegistryEntry = {\n name: opts.name,\n path: resolvedPath,\n registeredAt: now,\n languages: opts.languages ?? [],\n status: opts.status ?? 'active',\n }\n reg.projects.push(entry)\n await writeRegistry(reg)\n return entry\n })\n}\n\nexport async function getProject(name: string): Promise<RegistryEntry | undefined> {\n const reg = await readRegistry()\n return reg.projects.find((p) => p.name === name)\n}\n\nexport async function listProjects(): Promise<RegistryEntry[]> {\n const reg = await readRegistry()\n return reg.projects\n}\n\nexport async function setStatus(name: string, status: RegistryStatus): Promise<RegistryEntry> {\n return withLock(async () => {\n const reg = await readRegistry()\n const entry = reg.projects.find((p) => p.name === name)\n if (!entry) throw new Error(`neat registry: no project named \"${name}\"`)\n entry.status = status\n await writeRegistry(reg)\n return entry\n })\n}\n\nexport async function touchLastSeen(name: string, at: string = new Date().toISOString()): Promise<void> {\n await withLock(async () => {\n const reg = await readRegistry()\n const entry = reg.projects.find((p) => p.name === name)\n if (!entry) return\n entry.lastSeenAt = at\n await writeRegistry(reg)\n })\n}\n\n/**\n * Remove the registry entry for `name`. Per ADR-048 #6: this only removes the\n * registry row. It does **not** touch `neat-out/`, `policy.json`, or any user\n * file in the project directory. SDK-install rollback is a separate flow\n * (`neat-rollback.patch`) that the caller opts in to.\n */\nexport async function removeProject(name: string): Promise<RegistryEntry | undefined> {\n return withLock(async () => {\n const reg = await readRegistry()\n const idx = reg.projects.findIndex((p) => p.name === name)\n if (idx < 0) return undefined\n const [removed] = reg.projects.splice(idx, 1)\n await writeRegistry(reg)\n return removed\n })\n}\n\n","// SSE handler for the frontend-facing event stream (ADR-051 #1).\n// Subscribes to the bus in events.ts, filters by project, writes\n// `event: <type>\\ndata: <json>\\n\\n` frames to the client.\n//\n// Backpressure: per-connection queue cap of 1000 outstanding writes; once\n// hit, the connection is dropped with `event: error data: { reason:\n// 'backpressure' }` per ADR-051 #8. Heartbeat: comment line every 30s\n// keeps proxies from idle-timing out (ADR-051 #3).\n\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport {\n EVENT_BUS_CHANNEL,\n eventBus,\n type NeatEventEnvelope,\n} from './events.js'\n\nexport const SSE_HEARTBEAT_MS = 30_000\nexport const SSE_BACKPRESSURE_CAP = 1000\n\nexport interface HandleSseOptions {\n project: string\n heartbeatMs?: number\n backpressureCap?: number\n}\n\nexport function handleSse(\n req: FastifyRequest,\n reply: FastifyReply,\n opts: HandleSseOptions,\n): void {\n const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS\n const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP\n\n reply.raw.setHeader('Content-Type', 'text/event-stream')\n reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n reply.raw.setHeader('Connection', 'keep-alive')\n reply.raw.setHeader('X-Accel-Buffering', 'no')\n reply.raw.flushHeaders?.()\n\n let pending = 0\n let dropped = false\n\n const closeConnection = (): void => {\n if (dropped) return\n dropped = true\n eventBus.off(EVENT_BUS_CHANNEL, listener)\n clearInterval(heartbeat)\n if (!reply.raw.writableEnded) reply.raw.end()\n }\n\n const writeFrame = (frame: string): void => {\n if (dropped) return\n if (pending >= backpressureCap) {\n // Past the cap — emit one final error frame and drop. Don't try to\n // gracefully drain; a slow consumer that's already 1000 frames behind\n // is not going to catch up.\n const errFrame = `event: error\\ndata: ${JSON.stringify({ reason: 'backpressure' })}\\n\\n`\n reply.raw.write(errFrame)\n closeConnection()\n return\n }\n pending++\n reply.raw.write(frame, () => {\n pending = Math.max(0, pending - 1)\n })\n }\n\n const listener = (envelope: NeatEventEnvelope): void => {\n if (envelope.project !== opts.project) return\n writeFrame(`event: ${envelope.type}\\ndata: ${JSON.stringify(envelope.payload)}\\n\\n`)\n }\n\n eventBus.on(EVENT_BUS_CHANNEL, listener)\n\n const heartbeat = setInterval(() => {\n if (dropped) return\n reply.raw.write(':heartbeat\\n\\n')\n }, heartbeatMs)\n if (typeof heartbeat.unref === 'function') heartbeat.unref()\n\n req.raw.on('close', closeConnection)\n reply.raw.on('close', closeConnection)\n reply.raw.on('error', closeConnection)\n}\n","// semantic_search — embedding-based node retrieval with a three-tier\n// fallback chain. The chain is settled in ADR-025; this file is the\n// implementation. Public API:\n//\n// buildSearchIndex(graph, opts) → SearchIndex\n// SearchIndex.search(query, limit) → { provider, matches }\n// SearchIndex.refresh(graph) → re-embeds new/changed nodes,\n// drops vanished ones\n//\n// The `/search` route in api.ts holds a single SearchIndex, refreshing it\n// after any extraction. MCP's `semantic_search` tool reads the same shape.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { createHash } from 'node:crypto'\nimport type { GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport interface ScoredNode {\n node: GraphNode\n score: number\n}\n\nexport interface SearchResponse {\n query: string\n provider: 'ollama' | 'transformers' | 'substring'\n matches: ScoredNode[]\n}\n\nexport interface SearchIndex {\n readonly provider: SearchResponse['provider']\n search(query: string, limit?: number): Promise<SearchResponse>\n refresh(graph: NeatGraph): Promise<void>\n}\n\ninterface Embedder {\n provider: 'ollama' | 'transformers'\n model: string\n dim: number\n embed(texts: string[]): Promise<Float32Array[]>\n}\n\nconst DEFAULT_LIMIT = 10\nconst NOMIC_DIM = 768\nconst MINI_LM_DIM = 384\n\n// FrontierNodes are noise by design (placeholders that should disappear).\n// Embedding them would just clutter results.\nfunction shouldEmbed(node: GraphNode): boolean {\n return node.type !== 'FrontierNode'\n}\n\n// Deterministic per-node text. Stable keys let the cache hit across\n// extractions when nothing material changed.\nexport function embedText(node: GraphNode): string {\n const parts: string[] = [node.id]\n const name = (node as { name?: string }).name\n if (name) parts.push(name)\n switch (node.type) {\n case 'ServiceNode': {\n const lang = (node as { language?: string }).language\n if (lang) parts.push(`language=${lang}`)\n break\n }\n case 'DatabaseNode': {\n const eng = (node as { engine?: string }).engine\n const ver = (node as { engineVersion?: string }).engineVersion\n if (eng) parts.push(`engine=${eng}`)\n if (ver) parts.push(`engineVersion=${ver}`)\n break\n }\n case 'InfraNode': {\n const kind = (node as { kind?: string }).kind\n if (kind) parts.push(`kind=${kind}`)\n break\n }\n case 'ConfigNode': {\n const filePath = (node as { path?: string }).path\n if (filePath) parts.push(`path=${filePath}`)\n break\n }\n default:\n break\n }\n return parts.join(' ')\n}\n\nfunction attrsHash(node: GraphNode): string {\n return createHash('sha1').update(embedText(node)).digest('hex').slice(0, 16)\n}\n\nexport function cosine(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) return 0\n let dot = 0\n let na = 0\n let nb = 0\n for (let i = 0; i < a.length; i++) {\n const ai = a[i] ?? 0\n const bi = b[i] ?? 0\n dot += ai * bi\n na += ai * ai\n nb += bi * bi\n }\n if (na === 0 || nb === 0) return 0\n return dot / (Math.sqrt(na) * Math.sqrt(nb))\n}\n\n// ---------------------------------------------------------------- Embedders\n\nfunction ollamaHost(): string | null {\n return process.env.OLLAMA_HOST ?? null\n}\n\nasync function ollamaReachable(host: string): Promise<boolean> {\n try {\n const res = await fetch(`${host.replace(/\\/$/, '')}/api/tags`, {\n signal: AbortSignal.timeout(500),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nfunction makeOllamaEmbedder(host: string, model = 'nomic-embed-text'): Embedder {\n const root = host.replace(/\\/$/, '')\n return {\n provider: 'ollama',\n model,\n dim: NOMIC_DIM,\n async embed(texts: string[]): Promise<Float32Array[]> {\n const out: Float32Array[] = []\n // Ollama's /api/embeddings is one-text-per-request. ≤10K nodes × ~30ms\n // each is fine for a one-shot index build; if it ever isn't, the API\n // also accepts batched input on /api/embed (newer routes).\n for (const text of texts) {\n const res = await fetch(`${root}/api/embeddings`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ model, prompt: text }),\n })\n if (!res.ok) {\n throw new Error(`ollama embeddings: ${res.status} ${res.statusText}`)\n }\n const data = (await res.json()) as { embedding: number[] }\n out.push(Float32Array.from(data.embedding))\n }\n return out\n },\n }\n}\n\ninterface XenovaPipeline {\n (text: string | string[], options?: { pooling?: string; normalize?: boolean }): Promise<{\n data: Float32Array\n }>\n}\n\nasync function makeTransformersEmbedder(): Promise<Embedder | null> {\n let pipelineFn: ((task: string, model: string) => Promise<XenovaPipeline>) | null = null\n try {\n // Lazy require so server.ts boot doesn't pay the WASM init cost when\n // Ollama is available. The package is heavy — only load it on demand.\n // The package is optional so its types may not be installed in every\n // environment. Use a dynamic specifier so tsc keeps the import dynamic\n // and doesn't try to resolve types at build time.\n const specifier = '@xenova/transformers'\n const mod = (await import(specifier)) as unknown as {\n pipeline: (task: string, model: string) => Promise<XenovaPipeline>\n }\n pipelineFn = mod.pipeline\n } catch {\n return null\n }\n if (!pipelineFn) return null\n const model = 'Xenova/all-MiniLM-L6-v2'\n const extractor = await pipelineFn('feature-extraction', model)\n return {\n provider: 'transformers',\n model,\n dim: MINI_LM_DIM,\n async embed(texts: string[]): Promise<Float32Array[]> {\n const out: Float32Array[] = []\n for (const text of texts) {\n // Mean-pooled, L2-normalized → cosine reduces to dot product but\n // we keep the explicit cosine() for clarity.\n const result = await extractor(text, { pooling: 'mean', normalize: true })\n out.push(Float32Array.from(result.data))\n }\n return out\n },\n }\n}\n\n// Picks the highest-tier embedder available. Returns null when only\n// substring is available (caller decides what to build).\nexport async function pickEmbedder(): Promise<Embedder | null> {\n const host = ollamaHost()\n if (host && (await ollamaReachable(host))) {\n return makeOllamaEmbedder(host)\n }\n return makeTransformersEmbedder()\n}\n\n// ------------------------------------------------------------------ Cache\n\ninterface CacheEntry {\n nodeId: string\n attrsHash: string\n vector: number[]\n}\n\ninterface CacheFile {\n version: 1\n provider: 'ollama' | 'transformers'\n model: string\n dim: number\n entries: CacheEntry[]\n}\n\nasync function readCache(cachePath: string): Promise<CacheFile | null> {\n try {\n const raw = await fs.readFile(cachePath, 'utf8')\n const parsed = JSON.parse(raw) as CacheFile\n if (parsed.version !== 1) return null\n return parsed\n } catch {\n return null\n }\n}\n\nasync function writeCache(cachePath: string, cache: CacheFile): Promise<void> {\n await fs.mkdir(path.dirname(cachePath), { recursive: true })\n await fs.writeFile(cachePath, JSON.stringify(cache))\n}\n\n// ----------------------------------------------------------------- Indexes\n\nclass VectorIndex implements SearchIndex {\n readonly provider: 'ollama' | 'transformers'\n private vectors = new Map<string, { node: GraphNode; vector: Float32Array; hash: string }>()\n\n constructor(\n private embedder: Embedder,\n private cachePath: string | null,\n ) {\n this.provider = embedder.provider\n }\n\n async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n const trimmed = query.trim()\n if (!trimmed || this.vectors.size === 0) {\n return { query: trimmed, provider: this.provider, matches: [] }\n }\n const embedded = await this.embedder.embed([trimmed])\n const qv = embedded[0]\n if (!qv) {\n return { query: trimmed, provider: this.provider, matches: [] }\n }\n const scored: ScoredNode[] = []\n for (const { node, vector } of this.vectors.values()) {\n const score = cosine(qv, vector)\n scored.push({ node, score })\n }\n scored.sort((a, b) => b.score - a.score)\n return { query: trimmed, provider: this.provider, matches: scored.slice(0, limit) }\n }\n\n async refresh(graph: NeatGraph): Promise<void> {\n const present = new Set<string>()\n const toEmbed: { id: string; node: GraphNode; hash: string; text: string }[] = []\n\n graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n if (!shouldEmbed(node)) return\n present.add(id)\n const hash = attrsHash(node)\n const cached = this.vectors.get(id)\n if (cached && cached.hash === hash) {\n cached.node = node\n return\n }\n toEmbed.push({ id, node, hash, text: embedText(node) })\n })\n\n // Drop vanished nodes\n for (const id of [...this.vectors.keys()]) {\n if (!present.has(id)) this.vectors.delete(id)\n }\n\n if (toEmbed.length > 0) {\n const vectors = await this.embedder.embed(toEmbed.map((e) => e.text))\n toEmbed.forEach((entry, i) => {\n const v = vectors[i]\n if (!v) return\n this.vectors.set(entry.id, { node: entry.node, vector: v, hash: entry.hash })\n })\n }\n\n if (this.cachePath) {\n const entries: CacheEntry[] = []\n for (const [id, { vector, hash }] of this.vectors) {\n entries.push({ nodeId: id, attrsHash: hash, vector: Array.from(vector) })\n }\n await writeCache(this.cachePath, {\n version: 1,\n provider: this.embedder.provider,\n model: this.embedder.model,\n dim: this.embedder.dim,\n entries,\n })\n }\n }\n\n // Hydrate the in-memory map from a previously-written cache. Validates\n // shape against the current embedder; mismatch → empty start.\n loadFromCache(cache: CacheFile, graph: NeatGraph): void {\n if (\n cache.provider !== this.embedder.provider ||\n cache.model !== this.embedder.model ||\n cache.dim !== this.embedder.dim\n ) {\n return\n }\n const present = new Map<string, GraphNode>()\n graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n if (shouldEmbed(node)) present.set(id, node)\n })\n for (const entry of cache.entries) {\n const node = present.get(entry.nodeId)\n if (!node) continue\n // Skip cache entries whose attrs no longer match — they'll be\n // re-embedded by the next refresh().\n if (attrsHash(node) !== entry.attrsHash) continue\n if (entry.vector.length !== this.embedder.dim) continue\n this.vectors.set(entry.nodeId, {\n node,\n hash: entry.attrsHash,\n vector: Float32Array.from(entry.vector),\n })\n }\n }\n}\n\nclass SubstringIndex implements SearchIndex {\n readonly provider = 'substring' as const\n private graph: NeatGraph | null = null\n\n async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n const q = query.trim().toLowerCase()\n const out: ScoredNode[] = []\n if (!q || !this.graph) {\n return { query: q, provider: 'substring', matches: [] }\n }\n this.graph.forEachNode((id, attrs) => {\n const node = attrs as GraphNode\n const name = (node as { name?: string }).name ?? ''\n if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n out.push({ node, score: 1 })\n }\n })\n return { query: q, provider: 'substring', matches: out.slice(0, limit) }\n }\n\n async refresh(graph: NeatGraph): Promise<void> {\n this.graph = graph\n }\n}\n\n// ------------------------------------------------------------ Public factory\n\nexport interface BuildSearchIndexOptions {\n // Where to read/write the embedding cache. Falls back to in-memory only\n // if not provided. Pass `null` to explicitly disable caching.\n cachePath?: string | null\n // Override the embedder selection. Useful for tests (substring-only mode\n // skips the Ollama probe + the Transformers.js download).\n forceProvider?: 'ollama' | 'transformers' | 'substring'\n // Pre-built embedder (test injection). Wins over forceProvider.\n embedder?: Embedder\n}\n\nexport async function buildSearchIndex(\n graph: NeatGraph,\n options: BuildSearchIndexOptions = {},\n): Promise<SearchIndex> {\n let embedder: Embedder | null = null\n if (options.embedder) {\n embedder = options.embedder\n } else if (options.forceProvider !== 'substring') {\n embedder = await pickEmbedder()\n if (options.forceProvider === 'ollama' && embedder?.provider !== 'ollama') {\n embedder = null\n }\n if (options.forceProvider === 'transformers' && embedder?.provider !== 'transformers') {\n embedder = null\n }\n }\n\n if (!embedder) {\n const idx = new SubstringIndex()\n await idx.refresh(graph)\n return idx\n }\n\n const cachePath = options.cachePath === undefined ? null : options.cachePath\n const idx = new VectorIndex(embedder, cachePath)\n if (cachePath) {\n const cache = await readCache(cachePath)\n if (cache) idx.loadFromCache(cache, graph)\n }\n await idx.refresh(graph)\n return idx\n}\n","/**\n * `neat deploy` substrate detection + artifact generation (ADR-073 §2).\n *\n * Three substrates, detected in order:\n *\n * 1. Docker + `docker compose` present → emit `docker-compose.neat.yml`.\n * 2. Bare machine with `systemctl` available → emit `neat.service`.\n * 3. Fallback → print a `docker run` snippet to stdout.\n *\n * Every branch generates a fresh `NEAT_AUTH_TOKEN` (32 bytes, base64url),\n * prints it once, and never embeds it in the on-disk artifact — the file\n * names the env-var, the operator stores the value out of band.\n *\n * Every branch also prints the OTel env-vars block the operator pastes into\n * their application services' deploy platform.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport { randomBytes } from 'node:crypto'\n\nexport type Substrate = 'docker-compose' | 'systemd' | 'docker-run'\n\nexport interface DetectOptions {\n cwd?: string\n // Detection is shellable-out by injected probes; tests pass these to avoid\n // depending on the local docker / systemctl installation.\n hasDocker?: () => Promise<boolean>\n hasSystemd?: () => Promise<boolean>\n}\n\nexport interface DeployArtifact {\n substrate: Substrate\n // Path written to disk; undefined for the docker-run fallback (stdout-only).\n artifactPath?: string\n // The newly generated bearer token. Printed once by the caller, never\n // re-read from disk.\n token: string\n // The body of the artifact. Always returned so callers (and tests) can\n // inspect what was written without re-reading the file.\n contents: string\n // The shell command the operator runs to bring NEAT up on this substrate.\n startCommand: string\n}\n\nexport function generateToken(): string {\n // 32 bytes → 43-byte base64url (no padding). Plenty of entropy; URL-safe\n // so the operator can paste it into env-var dashboards that escape `=`.\n return randomBytes(32).toString('base64url')\n}\n\nasync function probeBinary(binary: string, arg: string): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(binary, [arg], { stdio: 'ignore' })\n const timer = setTimeout(() => {\n child.kill('SIGKILL')\n resolve(false)\n }, 2000)\n child.once('error', () => {\n clearTimeout(timer)\n resolve(false)\n })\n child.once('exit', (code) => {\n clearTimeout(timer)\n resolve(code === 0)\n })\n })\n}\n\nexport async function detectSubstrate(opts: DetectOptions = {}): Promise<Substrate> {\n const hasDocker = opts.hasDocker ?? (() => probeBinary('docker', 'version'))\n const hasSystemd = opts.hasSystemd ?? (() => probeBinary('systemctl', '--version'))\n if (await hasDocker()) return 'docker-compose'\n if (await hasSystemd()) return 'systemd'\n return 'docker-run'\n}\n\nconst IMAGE = 'ghcr.io/neat-technologies/neat:latest'\n\nexport function emitDockerCompose(cwd: string): string {\n // Compose v3 — declares the three documented ports + a data volume. The\n // operator's deploy platform supplies `NEAT_AUTH_TOKEN`; the file names\n // the var with no default, so a missing env stops the container from\n // coming up rather than running unauthenticated.\n return [\n 'services:',\n ' neat:',\n ` image: ${IMAGE}`,\n ' restart: unless-stopped',\n ' environment:',\n ' NEAT_AUTH_TOKEN: ${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}',\n ' ports:',\n ' - \"8080:8080\"',\n ' - \"4318:4318\"',\n ' - \"6328:6328\"',\n ' volumes:',\n ` - ${cwd}:/workspace`,\n ' - ./neat-data:/neat-out',\n '',\n ].join('\\n')\n}\n\nexport function emitSystemdUnit(cwd: string): string {\n // Token lives in /etc/neat/neatd.env (NEAT_AUTH_TOKEN=...) so it's readable\n // only by root and the service user. The unit itself stays version-\n // controllable without leaking the secret.\n return [\n '# NEAT_AUTH_TOKEN is read from /etc/neat/neatd.env at startup.',\n '# Put `NEAT_AUTH_TOKEN=<value>` in that file with mode 0640 root:root.',\n '[Unit]',\n 'Description=NEAT daemon',\n 'After=network-online.target',\n 'Wants=network-online.target',\n '',\n '[Service]',\n 'Type=simple',\n 'ExecStart=/usr/local/bin/neatd start --foreground',\n `WorkingDirectory=${cwd}`,\n 'EnvironmentFile=/etc/neat/neatd.env',\n 'Restart=always',\n 'RestartSec=5',\n '',\n '[Install]',\n 'WantedBy=multi-user.target',\n '',\n ].join('\\n')\n}\n\nexport function emitDockerRunSnippet(): string {\n // Single-line `docker run` for substrates we can't detect. Operator pastes\n // their own token in; the variable name keeps the bearer-token-must-be-set\n // shape consistent across all three branches.\n return [\n '#!/usr/bin/env bash',\n 'set -euo pipefail',\n '',\n '# Generate a fresh token once, then store it where your secrets live.',\n ': \"${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}\"',\n '',\n `docker run -d --name neat \\\\`,\n ' -e NEAT_AUTH_TOKEN=\"$NEAT_AUTH_TOKEN\" \\\\',\n ' -p 8080:8080 -p 4318:4318 -p 6328:6328 \\\\',\n ' -v \"$PWD\":/workspace -v /var/lib/neat:/neat-out \\\\',\n ` ${IMAGE}`,\n '',\n ].join('\\n')\n}\n\nexport interface RenderDeployBlockOptions {\n substrate: Substrate\n // Host the operator's services will reach NEAT at. Defaults to a\n // placeholder so the operator notices and fills it in.\n host?: string\n}\n\n// The OTel env-vars block the operator pastes into their deploy platform.\n// Format matches the orchestrator summary so the two never drift.\nexport function renderOtelEnvBlock(token: string, host: string = '<host>'): string {\n return [\n `OTEL_EXPORTER_OTLP_ENDPOINT=https://${host}:4318`,\n `OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer ${token}`,\n 'OTEL_SERVICE_NAME=<service>',\n ].join('\\n')\n}\n\nexport async function runDeploy(opts: DetectOptions = {}): Promise<DeployArtifact> {\n const cwd = opts.cwd ?? process.cwd()\n const substrate = await detectSubstrate(opts)\n const token = generateToken()\n\n switch (substrate) {\n case 'docker-compose': {\n const artifactPath = path.join(cwd, 'docker-compose.neat.yml')\n const contents = emitDockerCompose(cwd)\n await fs.writeFile(artifactPath, contents, 'utf8')\n return {\n substrate,\n artifactPath,\n token,\n contents,\n startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${path.basename(artifactPath)} up -d`,\n }\n }\n case 'systemd': {\n const artifactPath = path.join(cwd, 'neat.service')\n const contents = emitSystemdUnit(cwd)\n await fs.writeFile(artifactPath, contents, 'utf8')\n return {\n substrate,\n artifactPath,\n token,\n contents,\n startCommand: [\n `sudo install -m 0640 -o root -g root <(echo NEAT_AUTH_TOKEN=${token}) /etc/neat/neatd.env`,\n `sudo install -m 0644 neat.service /etc/systemd/system/neat.service`,\n 'sudo systemctl daemon-reload && sudo systemctl enable --now neat',\n ].join(' && '),\n }\n }\n case 'docker-run':\n default: {\n const contents = emitDockerRunSnippet()\n // No on-disk artifact for the fallback — operator copies the snippet.\n return {\n substrate: 'docker-run',\n token,\n contents,\n startCommand: `NEAT_AUTH_TOKEN=${token} bash <(cat <<'EOF'\\n${contents}EOF\\n)`,\n }\n }\n }\n}\n","/**\n * Installer registry. v0.2.5 step 2 ships the scaffolding; the JavaScript\n * installer (step 3) and Python installer (step 4) populate `INSTALLERS`.\n */\n\nimport type { Installer, InstallPlan } from './shared.js'\nimport { javascriptInstaller } from './javascript.js'\nimport { pythonInstaller } from './python.js'\nexport { isEmptyPlan } from './shared.js'\nexport { javascriptInstaller } from './javascript.js'\nexport { pythonInstaller } from './python.js'\nexport type {\n ApplyOutcome,\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n GeneratedFile,\n Installer,\n InstallPlan,\n} from './shared.js'\n\n// Lockfile basenames installers must never write to (ADR-047 — \"lockfiles\n// never touched\"). Used by the patch renderer's safety check below.\nexport const FORBIDDEN_LOCKFILES: ReadonlySet<string> = new Set([\n 'package-lock.json',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'poetry.lock',\n 'Pipfile.lock',\n 'Gemfile.lock',\n 'Cargo.lock',\n 'go.sum',\n])\n\n// Order is priority — first match wins per service. JavaScript leads because\n// it's the most common shape in the projects NEAT targets; Python follows.\nexport const INSTALLERS: Installer[] = [javascriptInstaller, pythonInstaller]\n\n/**\n * Resolve the first installer that claims a given service directory. Returns\n * `null` if none match.\n *\n * Per language, the first matching installer wins. Order in `INSTALLERS`\n * defines that priority — declarations are explicit, not alphabetical.\n */\nexport async function pickInstaller(serviceDir: string): Promise<Installer | null> {\n for (const inst of INSTALLERS) {\n if (await inst.detect(serviceDir)) return inst\n }\n return null\n}\n\nexport interface PatchSection {\n installer: string\n plan: InstallPlan\n}\n\n/**\n * Render install plans into a single review-friendly text patch. The format\n * is intentionally human-shaped, not unified-diff: agents and humans both\n * read this. Determinism — same input, byte-identical output — is the\n * load-bearing property (ADR-047 #6).\n */\nexport function renderPatch(sections: PatchSection[]): string {\n if (sections.length === 0) {\n return [\n '# neat install plan',\n '',\n 'No SDK installers matched the discovered services. Two reasons this',\n 'normally happens:',\n ' - the project uses a language NEAT does not yet instrument',\n ' (Java / Ruby / .NET / Go / Rust are out of MVP scope per ADR-047);',\n ' - the SDK is already installed, so the installer returned an empty',\n ' plan.',\n '',\n 'You can re-run `neat init --apply` later to pick up new services.',\n '',\n ].join('\\n')\n }\n\n const lines: string[] = ['# neat install plan', '']\n for (const section of sections) {\n const { installer, plan } = section\n lines.push(`## ${installer} (${plan.language}) — ${plan.serviceDir}`)\n lines.push('')\n\n if (plan.libOnly) {\n lines.push('### skipped — no resolvable entry point (lib-only)')\n lines.push('')\n continue\n }\n\n if (plan.entryFile) {\n lines.push(`entry: ${plan.entryFile}`)\n lines.push('')\n }\n\n if (plan.dependencyEdits.length > 0) {\n lines.push('### dependencies')\n // Group by manifest file so each section names the path the apply phase\n // will write, satisfying the dry-run/apply path-parity contract\n // (ADR-069 §8).\n const byFile = new Map<string, typeof plan.dependencyEdits>()\n for (const dep of plan.dependencyEdits) {\n // Hard-fail rather than render a patch that could mislead the user\n // into thinking NEAT touches lockfiles.\n const base = dep.file.split(/[\\\\/]/).pop() ?? dep.file\n if (FORBIDDEN_LOCKFILES.has(base)) {\n throw new Error(\n `installer \"${installer}\" produced a dependency edit against a lockfile (${dep.file}); ` +\n `lockfiles must never be touched (ADR-047).`,\n )\n }\n const existing = byFile.get(dep.file) ?? []\n existing.push(dep)\n byFile.set(dep.file, existing)\n }\n for (const [file, deps] of byFile) {\n lines.push(`--- ${file}`)\n for (const dep of deps) {\n lines.push(`+ \"${dep.name}\": \"${dep.version}\"`)\n }\n }\n lines.push('')\n }\n\n if (plan.generatedFiles && plan.generatedFiles.length > 0) {\n lines.push('### generated files')\n for (const gen of plan.generatedFiles) {\n lines.push(`--- (new file) ${gen.file}`)\n for (const ln of gen.contents.split(/\\r?\\n/)) {\n lines.push(`+ ${ln}`)\n }\n }\n lines.push('')\n }\n\n if (plan.entrypointEdits.length > 0) {\n lines.push('### entry-point injection')\n for (const e of plan.entrypointEdits) {\n lines.push(`--- ${e.file}`)\n lines.push(`+ ${e.after}`)\n lines.push(` ${e.before}`)\n }\n lines.push('')\n }\n\n if (plan.envEdits.length > 0) {\n lines.push('### env (written to <package-dir>/.env.neat)')\n for (const env of plan.envEdits) {\n lines.push(`- ${env.key}=${env.value}`)\n }\n lines.push('')\n }\n\n // ADR-073 §1 — surface the next.config edit in the dry-run patch so the\n // operator can review the framework-flag change before it lands.\n if (plan.nextConfigEdit) {\n lines.push('### next.config (framework flag)')\n lines.push(`--- ${plan.nextConfigEdit.file}`)\n lines.push(`+ experimental: { instrumentationHook: true }, // ${plan.nextConfigEdit.reason}`)\n lines.push('')\n }\n }\n return lines.join('\\n')\n}\n","/**\n * Node / TypeScript SDK installer (ADR-047 + ADR-069).\n *\n * Detects services by the presence of a `package.json` carrying a `name`\n * field — same shape `extract/services.ts` uses to decide what counts as a\n * Node service. The plan adds four OTel-adjacent packages to `dependencies`\n * (api, sdk-node, auto-instrumentations-node, dotenv), writes a generated\n * `otel-init.{js,ts}` adjacent to the resolved entry, and injects the\n * require/import as the first non-shebang line of that entry. Per-package\n * `.env.neat` carries `OTEL_SERVICE_NAME` (scope-preserved) so dashboards\n * joining OBSERVED spans against the EXTRACTED graph use the same key.\n *\n * Lockfiles are never touched (ADR-047 §4). The apply phase writes only to\n * package.json, otel-init.{js,ts}, and .env.neat (ADR-069 §7). After\n * `--apply`, init prints \"run npm install\" so the user owns the lockfile\n * commit.\n *\n * Idempotency (ADR-069 §6): the generated otel-init's presence is the\n * primary signal that a package is instrumented end-to-end — when it\n * exists, the apply phase logs `already instrumented` and skips the file\n * write and the entry-point injection together. Existing `.env.neat` files\n * are preserved (never overwritten).\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport semver from 'semver'\nimport type {\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n GeneratedFile,\n Installer,\n InstallPlan,\n PlanOptions,\n} from './shared.js'\nimport {\n ASTRO_MIDDLEWARE_JS,\n ASTRO_MIDDLEWARE_TS,\n ASTRO_OTEL_INIT_JS,\n ASTRO_OTEL_INIT_TS,\n NEXT_INSTRUMENTATION_HEADER,\n NEXT_INSTRUMENTATION_JS,\n NEXT_INSTRUMENTATION_NODE_JS,\n NEXT_INSTRUMENTATION_NODE_TS,\n NEXT_INSTRUMENTATION_TS,\n NUXT_OTEL_INIT_JS,\n NUXT_OTEL_INIT_TS,\n NUXT_OTEL_PLUGIN_JS,\n NUXT_OTEL_PLUGIN_TS,\n OTEL_INIT_CJS,\n OTEL_INIT_ESM,\n OTEL_INIT_HEADER,\n OTEL_INIT_STAMP,\n OTEL_INIT_TS,\n REMIX_OTEL_SERVER_JS,\n REMIX_OTEL_SERVER_TS,\n SVELTEKIT_HOOKS_SERVER_JS,\n SVELTEKIT_HOOKS_SERVER_TS,\n SVELTEKIT_OTEL_INIT_JS,\n SVELTEKIT_OTEL_INIT_TS,\n renderEnvNeat,\n renderFrameworkOtelInit,\n renderNextInstrumentationNode,\n renderNodeOtelInit,\n} from './templates.js'\nimport { resolve as _resolveRegistry } from '@neat.is/instrumentation-registry' // #391 uses _resolveRegistry for version-reconciled instrumentation advice\n\n// ADR-069 §5 — three OTel packages land in `dependencies`. `dotenv` was a\n// fourth from v0.3.6 through v0.4.3; the generated `otel-init` templates\n// no longer load `.env.neat` from disk (issue #369), so it's gone from the\n// dep set.\nconst SDK_PACKAGES = [\n { name: '@opentelemetry/api', version: '^1.9.0' },\n { name: '@opentelemetry/sdk-node', version: '^0.57.0' },\n { name: '@opentelemetry/auto-instrumentations-node', version: '^0.55.0' },\n] as const\n\n// Issue #376 — non-bundled instrumentations. The auto-instrumentations-node\n// set covers HTTP, fetch, and the common DB drivers via the wire protocol,\n// but libraries that bypass those wires (Prisma's Rust query engine talks\n// to its own engine binary; LangChain wraps model calls in its own SDK)\n// need their own instrumentation package registered explicitly. The detected\n// entries here compose into the generated otel-init's `instrumentations`\n// array — one `instrumentations.push(...)` line per entry — and join the\n// package.json dep set so the registration line resolves at runtime.\n//\n// v0.4.5 scope is Prisma alone (first library that meaningfully widens\n// NEAT's OBSERVED coverage on real codebases). The function's interface is\n// stable so the v0.5.0 instrumentation registry (ADR-080) can return more\n// entries without revisiting the template.\ninterface NonBundledInstrumentation {\n pkg: string\n version: string\n registration: string\n}\n\n// Pull the leading integer out of a semver range. `^6.2.0`, `~6.2.0`, `6.x`,\n// `>=6.0.0 <7` all return 6. Anything we can't parse (workspace:*, file:…,\n// undefined) returns 0 so the caller falls through to the pre-Prisma-6 path.\nexport function getMajor(versionRange: string | undefined): number {\n if (!versionRange) return 0\n const match = versionRange.match(/(\\d+)/)\n return match ? parseInt(match[1], 10) : 0\n}\n\nexport function detectNonBundledInstrumentations(\n pkg: PackageJsonShape,\n): NonBundledInstrumentation[] {\n const deps = allDeps(pkg)\n const out: NonBundledInstrumentation[] = []\n if ('@prisma/client' in deps) {\n // Issue #381 — `@prisma/instrumentation@^5` doesn't speak Prisma 6's\n // tracing-helper API. Connecting the client throws\n // `this.getGlobalTracingHelper(...).dispatchEngineSpans is not a function`\n // before any user query lands. Mirror the Prisma major so the\n // instrumentation package matches the client surface.\n const prismaMajor = getMajor(deps['@prisma/client'])\n const prismaInstrVersion = prismaMajor >= 6 ? '^6.0.0' : '^5.0.0'\n out.push({\n pkg: '@prisma/instrumentation',\n version: prismaInstrVersion,\n registration:\n \"instrumentations.push(new (require('@prisma/instrumentation').PrismaInstrumentation)())\",\n })\n }\n return out\n}\n\nconst OTEL_ENV: EnvEdit = {\n // ADR-069 §4 — endpoint moves into the per-package .env.neat (written\n // by the apply phase). The envEdits surface stays for the dry-run\n // patch render: it documents the key/value the user can inspect in the\n // generated .env.neat.\n file: null,\n key: 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT',\n value: 'http://localhost:4318/projects/<project>/v1/traces',\n}\n\ninterface PackageJsonShape {\n name?: string\n type?: string\n main?: string\n bin?: string | Record<string, string>\n scripts?: Record<string, string>\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n}\n\n// v0.4.4 — `OTEL_SERVICE_NAME` regains its proper semantic role: the\n// ServiceNode id inside the project's graph, not the project name. v0.4.1\n// papered over the missing routing key by writing the project basename here;\n// the project-scoped OTLP URL (issue #367) means the URL carries the routing\n// key and the env var goes back to naming the ServiceNode.\nfunction serviceNodeName(pkg: PackageJsonShape, serviceDir: string): string {\n return pkg.name ?? path.basename(serviceDir)\n}\n\n// The URL routing key. When the orchestrator threads a project through we use\n// it verbatim; ad-hoc / test usage falls back to the package's own name so\n// the generated file is still well-formed.\nfunction projectToken(\n pkg: PackageJsonShape,\n serviceDir: string,\n project: string | undefined,\n): string {\n if (project && project.length > 0) return project\n return pkg.name ?? path.basename(serviceDir)\n}\n\n// Issue #370 — runtime-kind detection. The installer historically treated\n// every JavaScript package as a Node service; Brief's frontend workspace\n// showed that wrong assumption write `instrumentation-node/register` into a\n// Vite browser bundle and an Expo React Native entry, where the Node SDK\n// can't execute. Detection runs after framework dispatch (Next / Remix /\n// SvelteKit / Nuxt / Astro all render server-side, so they classify as\n// `node`); only the framework-less packages reach the bucket here.\ntype RuntimeKind = 'node' | 'browser-bundle' | 'react-native' | 'bun' | 'deno' | 'cloudflare-workers' | 'electron'\n\nasync function readJsonFile(p: string): Promise<unknown> {\n try {\n const raw = await fs.readFile(p, 'utf8')\n return JSON.parse(raw) as unknown\n } catch {\n return null\n }\n}\n\nasync function detectRuntimeKind(\n pkgRoot: string,\n pkg: PackageJsonShape,\n): Promise<RuntimeKind> {\n const deps = allDeps(pkg)\n if ('react-native' in deps || 'expo' in deps) return 'react-native'\n // Expo apps sometimes carry the SDK only as a transitive dep but always\n // ship an `app.json` carrying an `expo` block — that's the canonical Expo\n // signal.\n const appJson = await readJsonFile(path.join(pkgRoot, 'app.json'))\n if (appJson && typeof appJson === 'object' && 'expo' in (appJson as Record<string, unknown>)) {\n return 'react-native'\n }\n if (\n (await exists(path.join(pkgRoot, 'vite.config.js'))) ||\n (await exists(path.join(pkgRoot, 'vite.config.ts'))) ||\n (await exists(path.join(pkgRoot, 'vite.config.mjs'))) ||\n 'vite' in deps\n ) {\n return 'browser-bundle'\n }\n // Issues #389 #390 — out-of-scope runtime detection for BYO-OTel escape hatch.\n // Order: wrangler.toml first (Workers projects may also carry package.json),\n // then bun.lockb (Bun projects often have package.json too), then Deno signals.\n if (await exists(path.join(pkgRoot, 'wrangler.toml'))) return 'cloudflare-workers'\n if (await exists(path.join(pkgRoot, 'bun.lockb'))) return 'bun'\n if (\n (await exists(path.join(pkgRoot, 'deno.json'))) ||\n (await exists(path.join(pkgRoot, 'deno.lock')))\n ) {\n return 'deno'\n }\n const engines = (pkg as { engines?: Record<string, unknown> }).engines ?? {}\n if ('electron' in engines) return 'electron'\n return 'node'\n}\n\n// Issue #368 — `OTel deps in package.json` is no longer the signal for\n// `already-instrumented`. The hook file is. Each `plan<Framework>` reads its\n// canonical hook path off disk via `await exists(...)` before queueing the\n// generated-file write, so deps-present-but-hook-absent correctly buckets\n// the package as `instrumented` (the installer writes the hook), not\n// `already-instrumented`. The next-deps-no-hook fixture in the contract\n// suite locks this against regression.\n\nasync function readPackageJson(serviceDir: string): Promise<PackageJsonShape | null> {\n try {\n const raw = await fs.readFile(path.join(serviceDir, 'package.json'), 'utf8')\n return JSON.parse(raw) as PackageJsonShape\n } catch {\n return null\n }\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.stat(p)\n return true\n } catch {\n return false\n }\n}\n\n// Read a file's contents, or null when it doesn't exist. Used by the\n// otel-init migration check (file-awareness.md §4) so a single read decides\n// between write / migrate / preserve.\nasync function readFileMaybe(p: string): Promise<string | null> {\n try {\n return await fs.readFile(p, 'utf8')\n } catch {\n return null\n }\n}\n\n// Decide what to do with the generated otel-init at `file`, given its rendered\n// current contents. A missing file is written (skipIfExists honours a race\n// where it appears between plan and apply). A NEAT-owned file (carries\n// OTEL_INIT_HEADER) on an older template — no current stamp — is regenerated so\n// a re-run upgrades the install. A current-stamp NEAT file is already current,\n// and a hand-written init (no header) is never touched.\nasync function planOtelInitGeneration(\n file: string,\n contents: string,\n): Promise<GeneratedFile | null> {\n const existing = await readFileMaybe(file)\n if (existing === null) {\n return { file, contents, skipIfExists: true }\n }\n if (existing.includes(OTEL_INIT_HEADER) && !existing.includes(OTEL_INIT_STAMP)) {\n return { file, contents, skipIfExists: false }\n }\n return null\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n const pkg = await readPackageJson(serviceDir)\n return pkg !== null && typeof pkg.name === 'string'\n}\n\n// Returns true when the currently-installed range and the registry-resolved\n// expected range have no intersection — meaning the installed version is\n// incompatible and an upgrade edit should be emitted.\nfunction needsVersionUpgrade(installed: string, expected: string): boolean {\n return (\n !semver.satisfies(\n semver.minVersion(installed)?.version ?? installed,\n expected,\n ) && !semver.intersects(installed, expected)\n )\n}\n\n// ADR-073 §1 — Next.js detection. A package is Next-flavored when it\n// declares `next` as a (dev)dependency AND ships a `next.config.{js,ts,mjs}`\n// at the package root. Both are required: a stray `next` import without the\n// config file isn't a Next app, and a config file without the dep is dead\n// configuration.\nconst NEXT_CONFIG_CANDIDATES = ['next.config.js', 'next.config.ts', 'next.config.mjs']\n\nasync function findNextConfig(serviceDir: string): Promise<string | null> {\n for (const name of NEXT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nfunction hasNextDependency(pkg: PackageJsonShape): boolean {\n return (\n (pkg.dependencies?.next !== undefined) ||\n (pkg.devDependencies?.next !== undefined)\n )\n}\n\n// Read the merged dep + devDep map once per detection step. Framework checks\n// only care about presence, not version.\nfunction allDeps(pkg: PackageJsonShape): Record<string, string> {\n return { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n}\n\n// ADR-074 §3 — Remix detection. A package is Remix-flavored when it declares\n// `remix` or any `@remix-run/*` package AND ships an entry-server file at one\n// of the canonical paths (`app/entry.server.{ts,tsx,js,jsx}`).\nconst REMIX_ENTRY_CANDIDATES = [\n 'app/entry.server.ts',\n 'app/entry.server.tsx',\n 'app/entry.server.js',\n 'app/entry.server.jsx',\n]\n\nfunction hasRemixDependency(pkg: PackageJsonShape): boolean {\n const deps = allDeps(pkg)\n if ('remix' in deps) return true\n for (const name of Object.keys(deps)) {\n if (name.startsWith('@remix-run/')) return true\n }\n return false\n}\n\nasync function findRemixEntry(serviceDir: string): Promise<string | null> {\n for (const rel of REMIX_ENTRY_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — SvelteKit detection. `@sveltejs/kit` dep, plus either an\n// existing `src/hooks.server.{ts,js}` or a top-level `svelte.config.{js,ts}`\n// (the absent-hooks case where the installer creates the hook file).\nconst SVELTEKIT_HOOKS_CANDIDATES = ['src/hooks.server.ts', 'src/hooks.server.js']\nconst SVELTEKIT_CONFIG_CANDIDATES = ['svelte.config.js', 'svelte.config.ts']\n\nfunction hasSvelteKitDependency(pkg: PackageJsonShape): boolean {\n return '@sveltejs/kit' in allDeps(pkg)\n}\n\nasync function findSvelteKitHooks(serviceDir: string): Promise<string | null> {\n for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nasync function findSvelteKitConfig(serviceDir: string): Promise<string | null> {\n for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — Nuxt detection. `nuxt` dep + `nuxt.config.{ts,js,mjs}`.\nconst NUXT_CONFIG_CANDIDATES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\n\nfunction hasNuxtDependency(pkg: PackageJsonShape): boolean {\n return 'nuxt' in allDeps(pkg)\n}\n\nasync function findNuxtConfig(serviceDir: string): Promise<string | null> {\n for (const name of NUXT_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-074 §3 — Astro detection. `astro` dep + `astro.config.{mjs,ts,js}`.\nconst ASTRO_CONFIG_CANDIDATES = ['astro.config.mjs', 'astro.config.ts', 'astro.config.js']\n\nfunction hasAstroDependency(pkg: PackageJsonShape): boolean {\n return 'astro' in allDeps(pkg)\n}\n\nasync function findAstroConfig(serviceDir: string): Promise<string | null> {\n for (const name of ASTRO_CONFIG_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// Parse the leading major version out of a semver range like \"^14.0.3\" or\n// \"~15.0\" or \"15.0.0\". Returns null when the range can't be read (workspace\n// links, git refs, \"*\", etc.).\nexport function parseNextMajor(range: string | undefined): number | null {\n if (!range) return null\n const cleaned = range.trim().replace(/^[\\^~>=<\\s]+/, '')\n const match = cleaned.match(/^(\\d+)/)\n if (!match) return null\n const n = Number(match[1])\n return Number.isFinite(n) ? n : null\n}\n\nasync function isTypeScriptProject(serviceDir: string): Promise<boolean> {\n return exists(path.join(serviceDir, 'tsconfig.json'))\n}\n\n// ADR-069 §2 + ADR-070 — entry resolution: pkg.main → pkg.bin → scripts.start\n// → scripts.dev → src/index.* → src/{server,main,app}.* → root index.*.\n// Returns the absolute path to the resolved entry, or null when the package\n// is lib-only (no resolvable entry).\nconst INDEX_EXTENSIONS = ['.ts', '.tsx', '.js', '.mjs', '.cjs']\nconst INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`)\nconst SRC_INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `src/index${ext}`)\nconst SRC_NAMED_CANDIDATES = ['server', 'main', 'app'].flatMap((name) =>\n INDEX_EXTENSIONS.map((ext) => `src/${name}${ext}`),\n)\n\n// ADR-070 — script-entry tokeniser. Launchers and similar wrappers we strip\n// before reading the first file-shaped argument. Anything not in this set is\n// treated as a candidate entry if it looks like a relative file path.\nconst SCRIPT_LAUNCHERS = new Set([\n 'node',\n 'ts-node',\n 'tsx',\n 'ts-node-dev',\n 'nodemon',\n 'npx',\n 'pnpm',\n 'yarn',\n 'npm',\n 'cross-env',\n 'dotenv',\n '--',\n])\n\n// True when the token resembles a path inside the package — contains a `/` or\n// ends in one of the JS/TS extensions we instrument.\nfunction looksLikeEntryPath(token: string): boolean {\n if (token.length === 0) return false\n if (token.startsWith('-')) return false\n if (token.includes('=')) return false // env-var assignments\n if (token.includes('/')) return true\n return /\\.(?:m?[jt]sx?|c[jt]s)$/.test(token)\n}\n\n// Bail when the script chains commands or pipes — those scripts mean an\n// orchestrator runs multiple things and our heuristic can't pick safely.\nfunction scriptHasShellChain(script: string): boolean {\n return /(?:&&|\\|\\||;|\\|(?!\\|))/.test(script)\n}\n\n// Pull the first file-shaped argument out of a script invocation, after\n// stripping recognised launchers and inline env-var assignments. Returns\n// undefined when no candidate surfaces (or when shell chaining bails us out).\nexport function entryFromScript(script: string | undefined): string | undefined {\n if (!script) return undefined\n if (scriptHasShellChain(script)) return undefined\n const tokens = script.split(/\\s+/).filter((t) => t.length > 0)\n for (const token of tokens) {\n const lower = token.toLowerCase()\n if (SCRIPT_LAUNCHERS.has(lower)) continue\n // Strip a leading `./` so the existence check resolves cleanly.\n const cleaned = token.startsWith('./') ? token.slice(2) : token\n if (looksLikeEntryPath(cleaned)) return cleaned\n }\n return undefined\n}\n\nexport async function resolveEntry(\n serviceDir: string,\n pkg: PackageJsonShape,\n): Promise<string | null> {\n // 1) pkg.main — but only when it actually exists on disk (ADR-070).\n if (typeof pkg.main === 'string' && pkg.main.length > 0) {\n const candidate = path.resolve(serviceDir, pkg.main)\n if (await exists(candidate)) return candidate\n // Manifest points main at a missing build output (e.g. dist/index.js\n // pre-build). Fall through to bin/scripts/src heuristics rather than\n // marking lib-only.\n }\n // 2) pkg.bin (string or pkg.name-keyed map).\n if (pkg.bin) {\n let binEntry: string | undefined\n if (typeof pkg.bin === 'string') {\n binEntry = pkg.bin\n } else if (pkg.name && typeof pkg.bin[pkg.name] === 'string') {\n binEntry = pkg.bin[pkg.name]\n } else {\n const first = Object.values(pkg.bin)[0]\n if (typeof first === 'string') binEntry = first\n }\n if (binEntry) {\n const candidate = path.resolve(serviceDir, binEntry)\n if (await exists(candidate)) return candidate\n }\n }\n // 3) scripts.start — ADR-070.\n const startEntry = entryFromScript(pkg.scripts?.start)\n if (startEntry) {\n const candidate = path.resolve(serviceDir, startEntry)\n if (await exists(candidate)) return candidate\n }\n // 4) scripts.dev — ADR-070.\n const devEntry = entryFromScript(pkg.scripts?.dev)\n if (devEntry) {\n const candidate = path.resolve(serviceDir, devEntry)\n if (await exists(candidate)) return candidate\n }\n // 5) src/index.* — ADR-070.\n for (const rel of SRC_INDEX_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n // 6) src/server.*, src/main.*, src/app.* — ADR-070.\n for (const rel of SRC_NAMED_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n // 7) root index.* — original ADR-069 §3 fallback.\n for (const name of INDEX_CANDIDATES) {\n const candidate = path.join(serviceDir, name)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\n// ADR-069 §1, §3 — dispatch by entry extension + pkg.type.\ntype EntryFlavor = 'cjs' | 'esm' | 'ts'\n\nexport function dispatchEntry(entryFile: string, pkg: PackageJsonShape): EntryFlavor {\n const ext = path.extname(entryFile).toLowerCase()\n if (ext === '.ts' || ext === '.tsx') return 'ts'\n if (ext === '.mjs') return 'esm'\n if (ext === '.cjs') return 'cjs'\n // .js — disambiguate on pkg.type. \"module\" → ESM, anything else → CJS.\n return pkg.type === 'module' ? 'esm' : 'cjs'\n}\n\n// Generated-file basename per flavor.\nfunction otelInitFilename(flavor: EntryFlavor): string {\n if (flavor === 'ts') return 'otel-init.ts'\n if (flavor === 'esm') return 'otel-init.mjs'\n return 'otel-init.cjs'\n}\n\nfunction otelInitContents(flavor: EntryFlavor): string {\n if (flavor === 'ts') return OTEL_INIT_TS\n if (flavor === 'esm') return OTEL_INIT_ESM\n return OTEL_INIT_CJS\n}\n\n// Build the injection line per flavor. The relative path is computed against\n// the entry's directory so the injection works regardless of the entry's\n// depth inside the package.\nexport function injectionLine(\n flavor: EntryFlavor,\n entryFile: string,\n otelInitFile: string,\n): string {\n let rel = path.relative(path.dirname(entryFile), otelInitFile)\n if (!rel.startsWith('.')) rel = `./${rel}`\n // Normalize to forward slashes for cross-platform module specifiers.\n rel = rel.split(path.sep).join('/')\n if (flavor === 'cjs') return `require('${rel}')`\n if (flavor === 'esm') return `import '${rel}'`\n // TS: drop the .ts extension so the resolver doesn't choke on it under\n // either tsc-output or runtime-loader pipelines.\n const tsRel = rel.replace(/\\.ts$/, '')\n return `import '${tsRel}'`\n}\n\n// Detect whether a given line already matches an injection of our otel-init.\n// Used for the entry-point idempotency check (ADR-069 §6).\nfunction lineIsOtelInjection(line: string): boolean {\n const trimmed = line.trim()\n if (trimmed.length === 0) return false\n // Match require('./otel-init…') and import './otel-init…' shapes.\n return /(?:require\\(|import\\s+)['\"]\\.\\/otel-init[^'\"]*['\"]/.test(trimmed)\n}\n\n// `create-next-app --src-dir` puts source under `src/` and Next then resolves\n// the instrumentation hook from `src/instrumentation.ts`. Routing the\n// generated files to root in that case means the hook never loads. We detect\n// src-layout by the presence of `src/app/` or `src/pages/` AND the absence of\n// the same at the package root — a project with both is treated as flat, the\n// safer default for monorepos that vendor a `src/` subpackage.\nasync function detectsSrcLayout(serviceDir: string): Promise<boolean> {\n const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([\n exists(path.join(serviceDir, 'src', 'app')),\n exists(path.join(serviceDir, 'src', 'pages')),\n exists(path.join(serviceDir, 'app')),\n exists(path.join(serviceDir, 'pages')),\n ])\n return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages\n}\n\n// ADR-073 §1 — Next.js apply path. Emits `instrumentation.{ts,js}` and\n// `instrumentation.node.{ts,js}` at the package root (or under `src/` for\n// `--src-dir` layouts), plus `.env.neat` co-located with them. Skips\n// entry-point injection entirely — Next loads the instrumentation file\n// through its own runtime hook. Queues a next.config edit only when the\n// declared major is < 15 (the flag is on-by-default from Next 15 on).\nasync function planNext(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n nextConfigPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const srcLayout = await detectsSrcLayout(serviceDir)\n // Co-locate the generated files with where Next looks for the hook. When\n // src-layout is detected the framework resolves `src/instrumentation.{ts,js}`\n // and we route the .env.neat alongside so an operator reading the codebase\n // finds the wiring in one place. The flat layout keeps the existing root\n // placement.\n const baseDir = srcLayout ? path.join(serviceDir, 'src') : serviceDir\n const instrumentationFile = path.join(baseDir, useTs ? 'instrumentation.ts' : 'instrumentation.js')\n const instrumentationNodeFile = path.join(\n baseDir,\n useTs ? 'instrumentation.node.ts' : 'instrumentation.node.js',\n )\n const envNeatFile = path.join(baseDir, '.env.neat')\n\n // Dependency edits — `dotenv` is gone repo-wide from v0.4.4 (issue #369),\n // so SDK_PACKAGES has the three OTel packages the apply phase adds and the\n // Next branch shares the same loop as every other framework. Issue #376\n // adds non-bundled instrumentations (Prisma in v0.4.5) — each detected\n // entry contributes one dep + one registration line into the generated\n // instrumentation.node file.\n const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n const dependencyEdits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) {\n if (needsVersionUpgrade(existingDeps[sdk.name]!, sdk.version)) {\n dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name]! })\n }\n continue\n }\n dependencyEdits.push({ file: manifestPath, kind: 'add', name: sdk.name, version: sdk.version })\n }\n const nonBundled = detectNonBundledInstrumentations(pkg)\n for (const inst of nonBundled) {\n if (inst.pkg in existingDeps) {\n if (needsVersionUpgrade(existingDeps[inst.pkg]!, inst.version)) {\n dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg]! })\n }\n continue\n }\n dependencyEdits.push({ file: manifestPath, kind: 'add', name: inst.pkg, version: inst.version })\n }\n\n // Generated files — instrumentation pair + .env.neat. Existing files are\n // preserved (skipIfExists honours user customisations and keeps the apply\n // phase idempotent per ADR-069 §6). The instrumentation.node template\n // carries `__SERVICE_NAME__` (the ServiceNode id) and `__PROJECT__` (the\n // registered project basename — the URL routing key) placeholders we\n // substitute here so the bundler-survivable `process.env.X ||=` lines land\n // with both values verbatim.\n const svcName = serviceNodeName(pkg, serviceDir)\n const projectName = projectToken(pkg, serviceDir, project)\n const registrations = nonBundled.map((i) => i.registration)\n const generatedFiles: GeneratedFile[] = []\n if (!(await exists(instrumentationFile))) {\n generatedFiles.push({\n file: instrumentationFile,\n contents: useTs ? NEXT_INSTRUMENTATION_TS : NEXT_INSTRUMENTATION_JS,\n skipIfExists: true,\n })\n }\n if (!(await exists(instrumentationNodeFile))) {\n generatedFiles.push({\n file: instrumentationNodeFile,\n contents: renderNextInstrumentationNode(\n useTs ? NEXT_INSTRUMENTATION_NODE_TS : NEXT_INSTRUMENTATION_NODE_JS,\n svcName,\n projectName,\n registrations,\n ),\n skipIfExists: true,\n })\n }\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(svcName, projectName),\n skipIfExists: true,\n })\n }\n\n // ADR-073 §1 — `experimental.instrumentationHook: true` is required for\n // Next 13 / 14 and a no-op on Next 15+. Plan the edit only when the\n // declared major is < 15 and the flag isn't already present.\n let nextConfigEdit: InstallPlan['nextConfigEdit']\n const nextRange = pkg.dependencies?.next ?? pkg.devDependencies?.next\n const nextMajor = parseNextMajor(nextRange)\n if (nextMajor !== null && nextMajor < 15) {\n try {\n const raw = await fs.readFile(nextConfigPath, 'utf8')\n if (!raw.includes('instrumentationHook')) {\n nextConfigEdit = {\n file: nextConfigPath,\n reason: `enable experimental.instrumentationHook (Next ${nextMajor} requires the opt-in flag)`,\n }\n }\n } catch {\n // Config disappeared between detect and plan. Skip the edit.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n nextConfigEdit === undefined\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'next',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits: [],\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'next',\n ...(nextConfigEdit ? { nextConfigEdit } : {}),\n }\n}\n\n// ── Meta-framework planners (ADR-074 §3). ───────────────────────────────\n//\n// Each planner mirrors planNext's shape: build dep edits via the same\n// SDK_PACKAGES + existing-deps filter, queue generated files for the\n// framework-canonical hook surface, record `framework: '<name>'`, never\n// inject into pkg.main. Idempotency rides on `skipIfExists` for generated\n// files and on a re-read header-grep for the inject-into-existing case.\n\nfunction buildDependencyEdits(\n pkg: PackageJsonShape,\n manifestPath: string,\n): DependencyEdit[] {\n const existingDeps = allDeps(pkg)\n const edits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) continue\n edits.push({\n file: manifestPath,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n return edits\n}\n\nasync function queueEnvNeat(\n serviceDir: string,\n pkg: PackageJsonShape,\n project: string | undefined,\n generatedFiles: GeneratedFile[],\n): Promise<void> {\n const envNeatFile = path.join(serviceDir, '.env.neat')\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(\n serviceNodeName(pkg, serviceDir),\n projectToken(pkg, serviceDir, project),\n ),\n skipIfExists: true,\n })\n }\n}\n\nfunction renderFrameworkOtelInitForPkg(\n template: string,\n pkg: PackageJsonShape,\n serviceDir: string,\n project: string | undefined,\n): string {\n return renderFrameworkOtelInit(\n template,\n serviceNodeName(pkg, serviceDir),\n projectToken(pkg, serviceDir, project),\n )\n}\n\nfunction fileImportsOtelHook(raw: string, specifiers: readonly string[]): boolean {\n const lines = raw.split(/\\r?\\n/)\n for (const line of lines) {\n const trimmed = line.trim()\n for (const spec of specifiers) {\n const escaped = spec.replace(/\\./g, '\\\\.')\n const pattern = new RegExp(\n `(?:import\\\\s+['\"]${escaped}['\"]|require\\\\(['\"]${escaped}['\"]\\\\))`,\n )\n if (pattern.test(trimmed)) return true\n }\n }\n return false\n}\n\nasync function planRemix(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n entryFile: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelServerFile = path.join(\n serviceDir,\n useTs ? 'app/otel.server.ts' : 'app/otel.server.js',\n )\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n\n if (!(await exists(otelServerFile))) {\n generatedFiles.push({\n file: otelServerFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? REMIX_OTEL_SERVER_TS : REMIX_OTEL_SERVER_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n const entrypointEdits: EntrypointEdit[] = []\n try {\n const raw = await fs.readFile(entryFile, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel.server'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: entryFile,\n before: firstReal,\n after: \"import './otel.server'\",\n })\n }\n } catch {\n // Entry file disappeared between detect and plan; fall through.\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'remix',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'remix',\n }\n}\n\nasync function planSvelteKit(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n hooksFile: string | null,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n )\n const resolvedHooksFile =\n hooksFile ??\n path.join(serviceDir, useTs ? 'src/hooks.server.ts' : 'src/hooks.server.js')\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n const entrypointEdits: EntrypointEdit[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? SVELTEKIT_OTEL_INIT_TS : SVELTEKIT_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n if (hooksFile === null) {\n generatedFiles.push({\n file: resolvedHooksFile,\n contents: useTs ? SVELTEKIT_HOOKS_SERVER_TS : SVELTEKIT_HOOKS_SERVER_JS,\n skipIfExists: true,\n })\n } else {\n try {\n const raw = await fs.readFile(hooksFile, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: hooksFile,\n before: firstReal,\n after: \"import './otel-init'\",\n })\n }\n } catch {\n // Disappeared between detect and plan; fall through.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'sveltekit',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'sveltekit',\n }\n}\n\nasync function planNuxt(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelPluginFile = path.join(\n serviceDir,\n useTs ? 'server/plugins/otel.ts' : 'server/plugins/otel.js',\n )\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'server/plugins/otel-init.ts' : 'server/plugins/otel-init.js',\n )\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? NUXT_OTEL_INIT_TS : NUXT_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n if (!(await exists(otelPluginFile))) {\n generatedFiles.push({\n file: otelPluginFile,\n contents: useTs ? NUXT_OTEL_PLUGIN_TS : NUXT_OTEL_PLUGIN_JS,\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n const empty = dependencyEdits.length === 0 && generatedFiles.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'nuxt',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits: [],\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'nuxt',\n }\n}\n\nconst ASTRO_MIDDLEWARE_CANDIDATES = ['src/middleware.ts', 'src/middleware.js']\n\nasync function findAstroMiddleware(serviceDir: string): Promise<string | null> {\n for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {\n const candidate = path.join(serviceDir, rel)\n if (await exists(candidate)) return candidate\n }\n return null\n}\n\nasync function planAstro(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<InstallPlan> {\n const useTs = await isTypeScriptProject(serviceDir)\n const otelInitFile = path.join(\n serviceDir,\n useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n )\n const existingMiddleware = await findAstroMiddleware(serviceDir)\n const middlewareFile =\n existingMiddleware ??\n path.join(serviceDir, useTs ? 'src/middleware.ts' : 'src/middleware.js')\n\n const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n const generatedFiles: GeneratedFile[] = []\n const entrypointEdits: EntrypointEdit[] = []\n\n if (!(await exists(otelInitFile))) {\n generatedFiles.push({\n file: otelInitFile,\n contents: renderFrameworkOtelInitForPkg(\n useTs ? ASTRO_OTEL_INIT_TS : ASTRO_OTEL_INIT_JS,\n pkg,\n serviceDir,\n project,\n ),\n skipIfExists: true,\n })\n }\n await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n if (existingMiddleware === null) {\n generatedFiles.push({\n file: middlewareFile,\n contents: useTs ? ASTRO_MIDDLEWARE_TS : ASTRO_MIDDLEWARE_JS,\n skipIfExists: true,\n })\n } else {\n try {\n const raw = await fs.readFile(existingMiddleware, 'utf8')\n if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n const lines = raw.split(/\\r?\\n/)\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n entrypointEdits.push({\n file: existingMiddleware,\n before: firstReal,\n after: \"import './otel-init'\",\n })\n }\n } catch {\n // Disappeared between detect and plan; fall through.\n }\n }\n\n const empty =\n dependencyEdits.length === 0 &&\n generatedFiles.length === 0 &&\n entrypointEdits.length === 0\n\n if (empty) {\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n framework: 'astro',\n }\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n framework: 'astro',\n }\n}\n\ntype FrameworkDispatch = () => Promise<InstallPlan>\n\n// ADR-073 §1 + ADR-074 §3 — framework signal lookup. Returns a thunk that\n// invokes the framework-specific planner when a match lands, or null when\n// none do. Detection precedence is Next → Remix → SvelteKit → Nuxt → Astro;\n// the chain bails on the first match. Pulled out of `plan()` so issue\n// #375's lib-only check can see the framework signal upfront — a package\n// with no framework hook AND no Node entry buckets as lib-only regardless\n// of stray Vite config or Expo deps.\nasync function findFrameworkDispatch(\n serviceDir: string,\n pkg: PackageJsonShape,\n manifestPath: string,\n project: string | undefined,\n): Promise<FrameworkDispatch | null> {\n if (hasNextDependency(pkg)) {\n const nextConfig = await findNextConfig(serviceDir)\n if (nextConfig) {\n return () => planNext(serviceDir, pkg, manifestPath, nextConfig, project)\n }\n }\n if (hasRemixDependency(pkg)) {\n const remixEntry = await findRemixEntry(serviceDir)\n if (remixEntry) {\n return () => planRemix(serviceDir, pkg, manifestPath, remixEntry, project)\n }\n }\n if (hasSvelteKitDependency(pkg)) {\n const hooks = await findSvelteKitHooks(serviceDir)\n const config = await findSvelteKitConfig(serviceDir)\n if (hooks || config) {\n return () => planSvelteKit(serviceDir, pkg, manifestPath, hooks, project)\n }\n }\n if (hasNuxtDependency(pkg)) {\n const nuxtConfig = await findNuxtConfig(serviceDir)\n if (nuxtConfig) {\n return () => planNuxt(serviceDir, pkg, manifestPath, project)\n }\n }\n if (hasAstroDependency(pkg)) {\n const astroConfig = await findAstroConfig(serviceDir)\n if (astroConfig) {\n return () => planAstro(serviceDir, pkg, manifestPath, project)\n }\n }\n return null\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n const pkg = await readPackageJson(serviceDir)\n const manifestPath = path.join(serviceDir, 'package.json')\n const project = opts?.project\n const empty: InstallPlan = {\n language: 'javascript',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n generatedFiles: [],\n }\n if (!pkg) return empty\n\n // Issue #375 — classification pipeline order: lib-only → framework →\n // runtime-kind → emit. A package with no framework hook AND no resolvable\n // Node entry is lib-only regardless of stray Vite config or Expo deps. The\n // runtime-kind dispatch only fires for non-framework packages that\n // actually have an entry to instrument; without this ordering, a UI library\n // that ships a `vite.config.ts` for its build pipeline would bucket as\n // browser-bundle and surface in the operator summary as if it were a real\n // SPA the installer was choosing to skip.\n const frameworkDispatch = await findFrameworkDispatch(\n serviceDir,\n pkg,\n manifestPath,\n project,\n )\n\n // Resolve the Node entry up front so the lib-only check can read both\n // signals together. Skipped on the framework branch — frameworks own their\n // boot path and never need a `pkg.main` injection (the chain returns\n // before this line runs).\n let entryFile: string | null = null\n if (!frameworkDispatch) {\n entryFile = await resolveEntry(serviceDir, pkg)\n if (!entryFile) {\n return { ...empty, libOnly: true }\n }\n }\n\n if (frameworkDispatch) {\n return frameworkDispatch()\n }\n\n // Issue #370 — runtime-kind detection sits between the lib-only check and\n // vanilla Node template emission. Browser bundles (Vite) and React Native\n // / Expo packages bucket here so the apply phase skips every write and\n // surfaces the package in the summary instead of injecting a Node SDK hook\n // into code that can't run it.\n const runtimeKind = await detectRuntimeKind(serviceDir, pkg)\n if (runtimeKind !== 'node') {\n return { ...empty, runtimeKind }\n }\n\n // entryFile resolved above on the non-framework branch; the null path\n // already returned lib-only.\n if (!entryFile) {\n return { ...empty, libOnly: true }\n }\n const flavor = dispatchEntry(entryFile, pkg)\n const otelInitFile = path.join(path.dirname(entryFile), otelInitFilename(flavor))\n const envNeatFile = path.join(serviceDir, '.env.neat')\n\n // ── Dependency edits (four-deps invariant; ADR-069 §5). ────────────────\n // Issue #376 — non-bundled instrumentations append additional deps when\n // the host package declares libraries whose runtime traffic bypasses the\n // auto-instrumentation set (Prisma's Rust query engine for v0.4.5; the\n // v0.5.0 registry feeds the same loop with more entries).\n const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n const dependencyEdits: DependencyEdit[] = []\n for (const sdk of SDK_PACKAGES) {\n if (sdk.name in existingDeps) {\n if (needsVersionUpgrade(existingDeps[sdk.name]!, sdk.version)) {\n dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name]! })\n }\n continue\n }\n dependencyEdits.push({ file: manifestPath, kind: 'add', name: sdk.name, version: sdk.version })\n }\n const nonBundled = detectNonBundledInstrumentations(pkg)\n for (const inst of nonBundled) {\n if (inst.pkg in existingDeps) {\n if (needsVersionUpgrade(existingDeps[inst.pkg]!, inst.version)) {\n dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg]! })\n }\n continue\n }\n dependencyEdits.push({ file: manifestPath, kind: 'add', name: inst.pkg, version: inst.version })\n }\n\n // ── Entry-point injection edit (ADR-069 §3). ───────────────────────────\n const entrypointEdits: EntrypointEdit[] = []\n try {\n const raw = await fs.readFile(entryFile, 'utf8')\n const lines = raw.split(/\\r?\\n/)\n // Preserve a shebang on line 1 and check line 2 (the first non-shebang\n // line) for an existing injection.\n const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n if (!lineIsOtelInjection(firstReal)) {\n const inject = injectionLine(flavor, entryFile, otelInitFile)\n // Use the existing first-real line as the `before` marker so the apply\n // phase can splice the injection cleanly even if the file shifts.\n entrypointEdits.push({\n file: entryFile,\n before: firstReal,\n after: inject,\n })\n }\n } catch {\n // Entry file disappeared between resolve and plan (rare). Treat as\n // lib-only.\n return { ...empty, libOnly: true }\n }\n\n // ── Generated files (ADR-069 §1, §4). ──────────────────────────────────\n // v0.4.4 — the otel-init template carries `__SERVICE_NAME__` (the\n // ServiceNode id) and `__PROJECT__` (the URL routing key) placeholders we\n // substitute here. The .env.neat shape lands with the same pair so an\n // operator can grep for both fields in one place.\n // v0.4.5 — `__INSTRUMENTATION_BLOCK__` substitutes to the registration\n // snippets for any non-bundled instrumentations detected above (Prisma\n // for v0.4.5; the v0.5.0 registry will feed more entries through the same\n // path). Empty list collapses cleanly to nothing.\n const svcName = serviceNodeName(pkg, serviceDir)\n const projectName = projectToken(pkg, serviceDir, project)\n const registrations = nonBundled.map((i) => i.registration)\n const generatedFiles: GeneratedFile[] = []\n const otelInitGen = await planOtelInitGeneration(\n otelInitFile,\n renderNodeOtelInit(otelInitContents(flavor), svcName, projectName, registrations),\n )\n if (otelInitGen) generatedFiles.push(otelInitGen)\n if (!(await exists(envNeatFile))) {\n generatedFiles.push({\n file: envNeatFile,\n contents: renderEnvNeat(svcName, projectName),\n skipIfExists: true,\n })\n }\n\n // ── Idempotency check (ADR-069 §6). ────────────────────────────────────\n // If the package is already instrumented end-to-end — deps present, entry\n // already injected, generated files already there — return an empty plan.\n if (\n dependencyEdits.length === 0 &&\n entrypointEdits.length === 0 &&\n generatedFiles.length === 0\n ) {\n return empty\n }\n\n return {\n language: 'javascript',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n generatedFiles,\n entryFile,\n libOnly: false,\n }\n}\n\n// ADR-069 §7 + ADR-073 §1 + ADR-074 §3 — allowed write paths. Anything\n// outside this set inside an installer's apply phase is a contract violation.\nfunction isAllowedWritePath(serviceDir: string, target: string): boolean {\n const rel = path.relative(serviceDir, target)\n if (rel.startsWith('..')) return false\n const base = path.basename(target)\n if (base === 'package.json') return true\n if (base === '.env.neat') return true\n if (/^otel-init\\.(?:js|cjs|mjs|ts)$/.test(base)) return true\n // ADR-073 §1 — Next framework files at the package root, or under src/\n // when create-next-app's --src-dir layout is in use. The instrumentation\n // hook resolves from `src/` in that layout; routing files there is the\n // load-bearing fix for the src-dir shape.\n const relPosix = rel.split(path.sep).join('/')\n if (/^instrumentation(?:\\.node)?\\.(?:js|cjs|mjs|ts)$/.test(base)) {\n if (relPosix === base) return true\n if (relPosix === `src/${base}`) return true\n return false\n }\n if (/^next\\.config\\.(?:js|mjs|ts)$/.test(base)) return true\n // ADR-074 §3 — meta-framework hook surfaces.\n if (relPosix === 'app/otel.server.ts' || relPosix === 'app/otel.server.js') return true\n if (/^app\\/entry\\.server\\.(?:tsx?|jsx?)$/.test(relPosix)) return true\n if (relPosix === 'src/otel-init.ts' || relPosix === 'src/otel-init.js') return true\n if (relPosix === 'src/hooks.server.ts' || relPosix === 'src/hooks.server.js') return true\n if (relPosix === 'server/plugins/otel.ts' || relPosix === 'server/plugins/otel.js') return true\n if (relPosix === 'server/plugins/otel-init.ts' || relPosix === 'server/plugins/otel-init.js') return true\n if (relPosix === 'src/middleware.ts' || relPosix === 'src/middleware.js') return true\n return false\n}\n\nasync function writeAtomic(file: string, contents: string): Promise<void> {\n // Meta-framework branches write to convention-driven subdirs that the user\n // may not have scaffolded yet (`server/plugins/`, `src/`, `app/`). Ensure\n // the parent directory exists before the atomic write; existing parents\n // are a no-op under `recursive: true`.\n await fs.mkdir(path.dirname(file), { recursive: true })\n const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, contents, 'utf8')\n await fs.rename(tmp, file)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n const { serviceDir } = installPlan\n if (installPlan.libOnly) {\n return {\n serviceDir,\n outcome: 'lib-only',\n reason: 'no resolvable entry point',\n writtenFiles: [],\n }\n }\n\n // Issue #370 — non-Node runtimes write nothing. The CLI surfaces the\n // outcome in the summary so the operator can see which packages were\n // skipped and why.\n if (installPlan.runtimeKind === 'browser-bundle') {\n return {\n serviceDir,\n outcome: 'browser-bundle',\n reason: 'browser bundle; Node OTel SDK cannot run here',\n writtenFiles: [],\n }\n }\n if (installPlan.runtimeKind === 'react-native') {\n return {\n serviceDir,\n outcome: 'react-native',\n reason: 'React Native / Expo target; Node OTel SDK cannot run here',\n writtenFiles: [],\n }\n }\n if (installPlan.runtimeKind === 'bun') {\n return { serviceDir, outcome: 'bun', reason: 'Bun runtime; use BYO-OTel', writtenFiles: [] }\n }\n if (installPlan.runtimeKind === 'deno') {\n return { serviceDir, outcome: 'deno', reason: 'Deno runtime; use BYO-OTel', writtenFiles: [] }\n }\n if (installPlan.runtimeKind === 'cloudflare-workers') {\n return {\n serviceDir,\n outcome: 'cloudflare-workers',\n reason: 'Cloudflare Workers runtime; use BYO-OTel',\n writtenFiles: [],\n }\n }\n if (installPlan.runtimeKind === 'electron') {\n return {\n serviceDir,\n outcome: 'electron',\n reason: 'Electron; use BYO-OTel',\n writtenFiles: [],\n }\n }\n\n // Already-instrumented check: an empty plan means there's nothing to do.\n if (\n installPlan.dependencyEdits.length === 0 &&\n installPlan.entrypointEdits.length === 0 &&\n (installPlan.generatedFiles?.length ?? 0) === 0 &&\n installPlan.nextConfigEdit === undefined\n ) {\n return {\n serviceDir,\n outcome: 'already-instrumented',\n writtenFiles: [],\n }\n }\n\n // Validate every target we plan to touch against the allowed-path set.\n // Bail out before any write if a violation slipped through.\n const allTargets = new Set<string>()\n for (const d of installPlan.dependencyEdits) allTargets.add(d.file)\n for (const e of installPlan.entrypointEdits) allTargets.add(e.file)\n for (const g of installPlan.generatedFiles ?? []) allTargets.add(g.file)\n if (installPlan.nextConfigEdit) allTargets.add(installPlan.nextConfigEdit.file)\n for (const target of allTargets) {\n // Entry-point edits land in user source files, not the allowed set —\n // they're explicitly carved out below.\n const isEntryEdit = installPlan.entrypointEdits.some((e) => e.file === target)\n if (isEntryEdit) continue\n if (!isAllowedWritePath(serviceDir, target)) {\n throw new Error(\n `javascript installer: refusing to write outside the allowed path set (ADR-069 §7): ${target}`,\n )\n }\n }\n\n // Snapshot every file we may touch so a partial failure can roll back the\n // batch (ADR-047 §7). Newly-generated files have no prior contents — they\n // get tracked separately so rollback unlinks them instead of restoring.\n const originals = new Map<string, string>()\n const createdFiles: string[] = []\n for (const target of allTargets) {\n if (await exists(target)) {\n try {\n originals.set(target, await fs.readFile(target, 'utf8'))\n } catch {\n // Best-effort. The mutation loop below will throw if this matters.\n }\n }\n }\n\n const writtenFiles: string[] = []\n try {\n // ── 1. Manifest edits (package.json) ─────────────────────────────────\n const manifestTargets = installPlan.dependencyEdits\n .reduce<Set<string>>((acc, e) => {\n acc.add(e.file)\n return acc\n }, new Set())\n for (const file of manifestTargets) {\n const raw = originals.get(file)\n if (raw === undefined) {\n throw new Error(`javascript installer: cannot read ${file} during apply`)\n }\n const pkg = JSON.parse(raw) as PackageJsonShape\n pkg.dependencies = pkg.dependencies ?? {}\n for (const dep of installPlan.dependencyEdits) {\n if (dep.file !== file) continue\n if (dep.kind === 'add') {\n if (!(dep.name in (pkg.dependencies ?? {}))) {\n pkg.dependencies[dep.name] = dep.version\n }\n } else if (dep.kind === 'upgrade') {\n pkg.dependencies[dep.name] = dep.version\n } else {\n delete pkg.dependencies[dep.name]\n }\n }\n const newRaw = JSON.stringify(pkg, null, 2) + '\\n'\n await writeAtomic(file, newRaw)\n writtenFiles.push(file)\n }\n\n // ── 2. Generated files (otel-init, .env.neat) ────────────────────────\n for (const gen of installPlan.generatedFiles ?? []) {\n if (gen.skipIfExists && (await exists(gen.file))) {\n // Skip silently; the contract treats this as part of the\n // already-instrumented path.\n continue\n }\n await writeAtomic(gen.file, gen.contents)\n if (!originals.has(gen.file)) createdFiles.push(gen.file)\n writtenFiles.push(gen.file)\n }\n\n // ── 3. Entry-point injection (require/import on first non-shebang line)\n for (const ep of installPlan.entrypointEdits) {\n const raw = originals.get(ep.file)\n if (raw === undefined) {\n throw new Error(`javascript installer: cannot read entry ${ep.file} during apply`)\n }\n const lines = raw.split(/\\r?\\n/)\n const hasShebang = lines[0]?.startsWith('#!') ?? false\n const insertAt = hasShebang ? 1 : 0\n // Idempotency: if the first non-shebang line already matches our\n // injection pattern, skip — never double-inject.\n const firstReal = lines[insertAt] ?? ''\n if (lineIsOtelInjection(firstReal)) continue\n lines.splice(insertAt, 0, ep.after)\n const newRaw = lines.join('\\n')\n await writeAtomic(ep.file, newRaw)\n writtenFiles.push(ep.file)\n }\n\n // ── 4. Next.js config flag (ADR-073 §1) — only present on the Next\n // path when the declared major is < 15 and the flag isn't already\n // mentioned in the file. Best-effort regex insertion into the first\n // config object literal; bails silently when the shape isn't\n // recognisable so we never corrupt a user-customised config.\n if (installPlan.nextConfigEdit) {\n const target = installPlan.nextConfigEdit.file\n const raw = originals.get(target)\n if (raw !== undefined && !raw.includes('instrumentationHook')) {\n const updated = injectInstrumentationHook(raw)\n if (updated !== null) {\n await writeAtomic(target, updated)\n writtenFiles.push(target)\n }\n }\n }\n } catch (err) {\n await rollback(installPlan, originals, createdFiles)\n throw err\n }\n\n return {\n serviceDir,\n outcome: 'instrumented',\n writtenFiles,\n }\n}\n\nasync function rollback(\n installPlan: InstallPlan,\n originals: Map<string, string>,\n createdFiles: string[],\n): Promise<void> {\n const restored: string[] = []\n const removed: string[] = []\n for (const [file, raw] of originals.entries()) {\n try {\n await fs.writeFile(file, raw, 'utf8')\n restored.push(file)\n } catch {\n // Best-effort: keep going so we restore as much as we can.\n }\n }\n for (const file of createdFiles) {\n try {\n await fs.unlink(file)\n removed.push(file)\n } catch {\n // Best-effort.\n }\n }\n const lines = [\n '# neat-rollback.patch',\n '',\n `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n '# Files listed below were restored to their pre-apply contents.',\n '',\n ...restored.map((f) => `restored: ${f}`),\n ...removed.map((f) => `removed: ${f}`),\n '',\n ]\n const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\n// ADR-073 §1 — best-effort injection of `experimental.instrumentationHook:\n// true` into a next.config.{js,ts,mjs}. Returns the rewritten contents on\n// success, or null when the config shape isn't recognisable (in which case\n// the apply phase leaves the file alone — partial Next coverage is fine,\n// silent corruption of a user's config is not).\n//\n// Recognised shapes:\n// - `module.exports = { ... }` (CJS)\n// - `module.exports = { ... } satisfies NextConfig` (TS-via-CJS)\n// - `export default { ... }` (ESM / TS)\n// - `const nextConfig = { ... }; module.exports = nextConfig` (named CJS)\n// - `const nextConfig: NextConfig = { ... }; export default nextConfig` (TS)\nexport function injectInstrumentationHook(raw: string): string | null {\n if (raw.includes('instrumentationHook')) return raw\n\n // Strategy: find the first config object literal whose contents we can\n // edit, then either merge into an existing `experimental: { ... }` block\n // or insert a fresh `experimental: { instrumentationHook: true }` entry.\n //\n // We look for one of four anchors near a top-level `{` and splice from\n // there. The regexes capture the `{` so we can splice right after it.\n const anchors: Array<{ pattern: RegExp; label: string }> = [\n { pattern: /(module\\.exports\\s*=\\s*\\{)/, label: 'cjs-default' },\n { pattern: /(export\\s+default\\s*\\{)/, label: 'esm-default' },\n { pattern: /(?:const|let|var)\\s+\\w+(?:\\s*:\\s*[^=]+)?\\s*=\\s*(\\{)/, label: 'named-config' },\n ]\n\n for (const { pattern } of anchors) {\n const match = pattern.exec(raw)\n if (!match) continue\n const insertAfter = match.index + match[0].length\n const before = raw.slice(0, insertAfter)\n const after = raw.slice(insertAfter)\n // Insert a leading newline so the injection sits on its own line and\n // doesn't fight any existing trailing-comma style. Two-space indent\n // covers most code-styled configs.\n const injection = '\\n experimental: { instrumentationHook: true },'\n return `${before}${injection}${after}`\n }\n\n return null\n}\n\nexport const javascriptInstaller: Installer = {\n name: 'javascript',\n detect,\n plan,\n apply,\n}\n\n// Re-exports used by the contract test surface.\nexport { NEXT_INSTRUMENTATION_HEADER, OTEL_INIT_HEADER }\n","/**\n * Generated-file templates for the Node SDK installer (ADR-069 §1).\n *\n * Three flavors so the inserted file matches the host package's module\n * system: CJS for `require`-based packages, ESM for `import`-based, TS for\n * TypeScript entries. Env vars are inlined as `process.env.X ||=` defaults\n * rather than loaded from `.env.neat` at runtime — `__dirname` /\n * `import.meta.url` resolve unpredictably once a bundler rewrites the\n * generated file (Brief-smoke evidence, issue #369), so we let the OTel SDK\n * read its config from the same `process.env` either way. Platform env\n * (Vercel / Railway / Fly / etc.) stays authoritative at deploy time;\n * `||=` keeps the local default for laptop dev only.\n */\n\n// Header comment that ships at the top of every generated otel-init. Stable\n// across flavors so a grep for the header line finds every generated file in\n// a target codebase. Used by the idempotency check too (ADR-069 §6).\nexport const OTEL_INIT_HEADER = '// Generated by `neat init --apply` (ADR-069). OpenTelemetry auto-instrumentation hook.'\n\n// Version stamp on the generated otel-init (file-awareness.md §4). A NEAT-owned\n// file carries OTEL_INIT_HEADER; the stamp records which template revision wrote\n// it. On re-run, an existing NEAT-owned file whose stamp is older than the\n// current one is regenerated (a hand-written init — no header — is never\n// touched). Bump the revision whenever the generated body changes shape.\nexport const OTEL_INIT_STAMP =\n '// neat-template-version: 4 — layered file-first capture (ADR-090): stack walk + handler-entry + off-stack facades.'\n\n// OTLP exporter auth (ADR-073 §3/§4, #410). When the operator runs the\n// instrumented app with `NEAT_OTEL_TOKEN` set — the same secret the daemon's\n// OTLP receiver reads (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) — the exporter\n// sends `Authorization: Bearer <token>` so a secured daemon accepts the spans.\n// Unset (laptop dev against a loopback daemon with no token) sends no header,\n// matching the daemon's unauthenticated loopback path. The token is the single\n// source: it lives in the environment, never inlined into the generated file.\n// `||=` keeps any platform-set header (Vercel / Railway / Fly) authoritative.\nexport const OTEL_OTLP_HEADERS_JS =\n \"if (process.env.NEAT_OTEL_TOKEN) process.env.OTEL_EXPORTER_OTLP_HEADERS ||= 'Authorization=Bearer ' + process.env.NEAT_OTEL_TOKEN\"\n\n// Inlined layered call-site capture (file-awareness.md §4–6, ADR-090). The\n// whole mechanism is self-contained — NEAT can't import its own package into a\n// user's generated file, so the runtime logic is inlined verbatim. The exact\n// bytes that ship are exercised by the capture spike\n// (test/callsite-processor.test.ts) so a regression here fails CI before it\n// ships. The `ts` flag adds the few type annotations a strict tsconfig needs;\n// the runtime logic is identical across flavors.\n//\n// Three layers land the user's `file:line:function` on every CLIENT / PRODUCER\n// / SERVER span:\n// 1. Synchronous stack walk at span start — covers the sync-wrapper majority.\n// 2. Handler-entry attribution — stamps the framework SERVER span and pushes\n// the handler frame into the active context so downstream CLIENT/PRODUCER\n// spans inherit it (the floor).\n// 3. Off-stack facades — undici / built-in `fetch` (diagnostics_channel) and\n// Prisma (backdated dispatch) push the call-site frame into context for\n// the inner call; the processor reads it as a fallback.\nfunction neatCaptureSource(ts: boolean): string {\n const spanT = ts ? ': any' : ''\n const strOpt = ts ? ': string | undefined' : ''\n const anyT = ts ? ': any' : ''\n const fnT = ts ? ': any' : ''\n const arrAny = ts ? ': any[]' : ''\n return `// Context key shared by the facade/handler wraps (writers) and the\n// processor fallback (reader). Symbol.for keeps it stable even if the wraps\n// and the processor end up in different module instances.\nconst NEAT_USER_FRAME = Symbol.for('neat.user-frame')\n\nfunction __neatPickUserFrame(stack${strOpt}) {\n const lines = String(stack || '').split('\\\\n')\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i].trim()\n if (raw.indexOf('at ') !== 0) continue\n if (raw.indexOf('node_modules') !== -1) continue\n if (raw.indexOf('@opentelemetry') !== -1) continue\n if (raw.indexOf('node:') !== -1) continue\n if (raw.indexOf('NeatCallSiteSpanProcessor') !== -1) continue\n // Skip NEAT's own inlined wraps/helpers (all carry the __neat prefix) so a\n // facade frame never masquerades as the user's call site.\n if (raw.indexOf('__neat') !== -1) continue\n const bodyText = raw.slice(3)\n const loc = bodyText.match(/:(\\\\d+):(\\\\d+)\\\\)?$/)\n if (!loc) continue\n const paren = bodyText.lastIndexOf('(')\n let filepath${strOpt}\n let fn${strOpt}\n if (paren !== -1) {\n fn = bodyText.slice(0, paren).trim()\n if (fn.indexOf('async ') === 0) fn = fn.slice(6)\n if (fn.indexOf('new ') === 0) fn = fn.slice(4)\n filepath = bodyText.slice(paren + 1, bodyText.length - loc[0].length)\n } else {\n filepath = bodyText.slice(0, bodyText.length - loc[0].length)\n }\n if (filepath.indexOf('file://') === 0) filepath = filepath.slice(7)\n if (!filepath) continue\n return { filepath: filepath, lineno: Number(loc[1]), function: fn || undefined }\n }\n return null\n}\n\n// Layer 2/3 fallback source: the frame a handler-entry or facade wrap pushed\n// into context. Reads the span's own parent context first, then the active\n// context — the capture spike confirmed both return the value for undici.\nfunction __neatFrameFromContext(parentContext${anyT}) {\n try {\n const fromParent =\n parentContext && typeof parentContext.getValue === 'function'\n ? parentContext.getValue(NEAT_USER_FRAME)\n : undefined\n return fromParent || context.active().getValue(NEAT_USER_FRAME) || null\n } catch (_e) {\n return null\n }\n}\n\nfunction __neatSetCodeAttrs(span${spanT}, frame${anyT}) {\n span.setAttribute('code.filepath', frame.filepath)\n if (typeof frame.lineno === 'number') span.setAttribute('code.lineno', frame.lineno)\n if (frame.function) span.setAttribute('code.function', frame.function)\n}\n\nclass NeatCallSiteSpanProcessor {\n onStart(span${spanT}, parentContext${anyT}) {\n if (!span || (span.kind !== 2 && span.kind !== 3)) return\n // Layer 1 — synchronous stack walk (sync-wrapper instrumentations).\n let frame = __neatPickUserFrame(new Error().stack)\n // Layer 2/3 — the handler-entry or off-stack-facade frame from context.\n if (!frame) frame = __neatFrameFromContext(parentContext)\n if (!frame) return\n __neatSetCodeAttrs(span, frame)\n }\n onEnd() {}\n forceFlush() { return Promise.resolve() }\n shutdown() { return Promise.resolve() }\n}\n\n// Capture the caller's synchronous frame at the wrap point and run \\`fn\\` with\n// that frame pushed into the active context (file-awareness.md §4 layer 3). An\n// off-stack instrumentation that creates its span inside \\`fn\\` inherits the\n// frame; the processor reads it via __neatFrameFromContext.\nfunction __neatRunWithUserFrame(fn${fnT}) {\n const frame = __neatPickUserFrame(new Error().stack)\n if (!frame) return fn()\n return context.with(context.active().setValue(NEAT_USER_FRAME, frame), fn)\n}\n\n// Handler-entry attribution (file-awareness.md §4 layer 2). Stamp the framework\n// SERVER span with the handler frame captured at route registration, and push\n// the same frame into context so downstream CLIENT/PRODUCER spans inherit the\n// handler-file floor when their own stack carries none.\nfunction __neatStampHandler(frame${anyT}, run${fnT}) {\n try {\n const active = trace.getActiveSpan()\n if (active && active.kind === 1 && typeof active.setAttribute === 'function') {\n __neatSetCodeAttrs(active, frame)\n }\n } catch (_e) {}\n try {\n return context.with(context.active().setValue(NEAT_USER_FRAME, frame), run)\n } catch (_e) {\n return run()\n }\n}\n\n// require-in-the-middle is a transitive dependency of the OTel instrumentation\n// packages NEAT installs, so it resolves in any instrumented CJS service.\n// Guarded: when it's absent (or the host runs as pure ESM, where require isn't\n// defined) the off-stack/handler wraps degrade to the stack walk + context\n// floor, never to a crash.\nfunction __neatHook(modules${arrAny}, onload${fnT}) {\n try {\n const RITM = require('require-in-the-middle')\n const Hook = RITM && RITM.Hook ? RITM.Hook : RITM\n new Hook(modules, { internals: false }, onload)\n return true\n } catch (_e) {\n return false\n }\n}\n\n// Off-stack facade: Node's built-in fetch / undici. The instrumentation creates\n// the CLIENT span inside a diagnostics_channel handler detached from the\n// caller's stack, so wrap the global so the user frame is in context when the\n// span is created. The capture spike (2026-05-28) validated this on real\n// undici. .name is restored to 'fetch' for ecosystem compatibility; the inner\n// __neat name is what the frame skip keys on.\nfunction __neatWrapFetch() {\n try {\n const g${anyT} = globalThis\n if (typeof g.fetch === 'function' && !g.fetch.__neatWrapped) {\n const realFetch = g.fetch\n // The wrapper keeps its __neat-prefixed name so the frame skip in\n // __neatPickUserFrame never mistakes the wrapper's own frame for the\n // user's call site (renaming it to 'fetch' would defeat the skip).\n const __neatFetch${anyT} = function (input${anyT}, init${anyT}) {\n return __neatRunWithUserFrame(function () { return realFetch(input, init) })\n }\n __neatFetch.__neatWrapped = true\n g.fetch = __neatFetch\n }\n } catch (_e) {}\n}\n\n// Off-stack facade: @prisma/client. Prisma's query engine backdates its spans\n// from Rust, off the caller's stack. Wrap the model methods on the client\n// prototype so the call-site frame (still synchronous at \\`prisma.user.find\\`)\n// is pushed into context for the engine dispatch.\nfunction __neatWrapPrisma() {\n __neatHook(['@prisma/client'], function (exports${anyT}) {\n try {\n const Client = exports && exports.PrismaClient\n if (typeof Client === 'function' && !Client.__neatWrapped) {\n const ops = ['findUnique','findUniqueOrThrow','findFirst','findFirstOrThrow','findMany','create','createMany','update','updateMany','upsert','delete','deleteMany','count','aggregate','groupBy']\n const __neatPrismaWrapModel = function (model${anyT}) {\n if (!model || model.__neatWrapped) return model\n for (let i = 0; i < ops.length; i++) {\n const op = ops[i]\n const orig = model[op]\n if (typeof orig !== 'function') continue\n model[op] = function __neatPrismaOp(${ts ? '...args: any[]' : '...args'}) {\n const self = this\n return __neatRunWithUserFrame(function () { return orig.apply(self, args) })\n }\n }\n model.__neatWrapped = true\n return model\n }\n const proto = Client.prototype\n const handler = function (model${anyT}) { return __neatPrismaWrapModel(model) }\n // Model accessors are lazily created getters on the instance; wrap the\n // \\`$extends\\`-free common path by trapping property access via a proxy\n // on each constructed client.\n exports.PrismaClient = new Proxy(Client, {\n construct(Target${anyT}, argList${anyT}, NewTarget${anyT}) {\n const instance = Reflect.construct(Target, argList, NewTarget)\n return new Proxy(instance, {\n get(target${anyT}, prop${anyT}, receiver${anyT}) {\n const value = Reflect.get(target, prop, receiver)\n if (value && typeof value === 'object' && typeof prop === 'string' && prop[0] !== '$' && prop[0] !== '_') {\n return handler(value)\n }\n return value\n },\n })\n },\n })\n exports.PrismaClient.__neatWrapped = true\n void proto\n }\n } catch (_e) {}\n return exports\n })\n}\n\n// Handler-entry facades. express / connect share the Layer model (each route\n// handler is a function registered on a Router); the wrap captures the\n// registration frame and stamps + propagates it when the handler runs. The\n// registry is the extensibility seam — koa, fastify (via @fastify/otel),\n// nestjs, restify, and hapi add an entry as their patch surface is wired.\nfunction __neatWrapConnectStyle(mod${anyT}) {\n try {\n // express() returns an app whose route verbs live on Router.prototype and\n // the application proto; connect apps expose \\`use\\`. Wrap the registration\n // verbs so the user handler is wound with its registration frame.\n const verbs = ['use','get','post','put','delete','patch','all','options','head']\n const wrapTarget = function (target${anyT}) {\n if (!target || target.__neatVerbsWrapped) return\n for (let i = 0; i < verbs.length; i++) {\n const verb = verbs[i]\n const orig = target[verb]\n if (typeof orig !== 'function') continue\n target[verb] = function __neatVerb(${ts ? '...args: any[]' : '...args'}) {\n const frame = __neatPickUserFrame(new Error().stack)\n if (frame) {\n for (let a = 0; a < args.length; a++) {\n const h = args[a]\n if (typeof h === 'function' && !h.__neatHandlerWrapped && h.length <= 4) {\n const inner = h\n const __neatHandler${anyT} = function (${ts ? '...hargs: any[]' : '...hargs'}) {\n const self = this\n return __neatStampHandler(frame, function () { return inner.apply(self, hargs) })\n }\n __neatHandler.__neatHandlerWrapped = true\n args[a] = __neatHandler\n }\n }\n }\n return orig.apply(this, args)\n }\n }\n target.__neatVerbsWrapped = true\n }\n if (mod && mod.Router && mod.Router.prototype) wrapTarget(mod.Router.prototype)\n if (mod && mod.application) wrapTarget(mod.application)\n if (mod && mod.prototype) wrapTarget(mod.prototype)\n } catch (_e) {}\n}\n\nfunction __neatInstallHandlerEntry() {\n __neatHook(['express'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n __neatHook(['connect'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n}\n\n// Install every off-stack and handler-entry wrap. Called once after sdk.start()\n// — before user code requires the framework / Prisma modules, so the hooks land\n// on first require. Each wrap is independently guarded.\nfunction __neatInstallFacades() {\n __neatWrapFetch()\n __neatWrapPrisma()\n __neatInstallHandlerEntry()\n}`\n}\n\n// The runtime capture source, exported so the capture spike can materialise and\n// exercise the exact bytes that ship in the generated file.\nexport const CALLSITE_PROCESSOR_JS = neatCaptureSource(false)\nexport const CALLSITE_PROCESSOR_TS = neatCaptureSource(true)\n\n// Post-`sdk.start()` wiring. NodeSDK keeps its env-configured OTLP exporter\n// (passing `spanProcessors` to the constructor would replace it); we add the\n// call-site processor to the started provider via the public `getDelegate()` +\n// `addSpanProcessor()` surface, then assert it actually attached (file-\n// awareness.md §4 / ADR-090). A wiring regression that would silently drop\n// file-first capture throws loudly at boot instead of shipping service-level-\n// only spans. The facade/handler wraps install last, so a span export path is\n// live before any user module loads.\nfunction neatWireCaptureSource(ts: boolean): string {\n const providerT = ts ? ': any' : ''\n return `try {\n const provider${providerT} = trace.getTracerProvider()\n const delegate = provider && typeof provider.getDelegate === 'function' ? provider.getDelegate() : provider\n if (!delegate || typeof delegate.addSpanProcessor !== 'function') {\n throw new Error('[neat] could not resolve a TracerProvider to attach the call-site processor; file-first OBSERVED capture would be silent (file-awareness.md §4)')\n }\n const __neatProcessor = new NeatCallSiteSpanProcessor()\n delegate.addSpanProcessor(__neatProcessor)\n // Post-init assertion: confirm attachment on providers that expose their\n // processor list. An un-introspectable provider is trusted (we just called\n // its addSpanProcessor); a list that exists and lacks our processor throws.\n const registered = delegate._registeredSpanProcessors\n if (Array.isArray(registered) && registered.indexOf(__neatProcessor) === -1) {\n throw new Error('[neat] call-site processor did not attach to the active TracerProvider (file-awareness.md §4)')\n }\n} catch (err) {\n throw err\n}\ntry {\n __neatInstallFacades()\n} catch (_e) {\n // Facade install is best-effort: the stack-walk + handler-entry floor still\n // attribute the sync-wrapper majority even if an off-stack wrap fails.\n}`\n}\n\n// __SERVICE_NAME__ → the ServiceNode id (the package's `pkg.name`, or the\n// directory basename for nameless packages); __PROJECT__ → the registered\n// project basename; __INSTRUMENTATION_BLOCK__ → a (possibly empty) sequence\n// of `instrumentations.push(...)` lines for non-bundled instrumentations\n// (Prisma for v0.4.5; more libraries via the v0.5.0 registry). All three are\n// substituted at apply time via renderNodeOtelInit().\n//\n// v0.4.5 — explicit `NodeSDK` construction replaces the\n// `auto-instrumentations-node/register` shorthand so non-bundled libraries\n// (Prisma's Rust query engine bypasses node-pg; Drizzle, BetterAuth, etc.\n// have their own packages) can compose into the same `instrumentations`\n// array without templating a different file shape per library.\nexport const OTEL_INIT_CJS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\nconst { trace, context } = require('@opentelemetry/api')\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(false)}\n`\n\nexport const OTEL_INIT_ESM = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(false)}\n`\n\nexport const OTEL_INIT_TS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\n// @ts-nocheck — generated runtime shim. The layered capture mechanism uses\n// dynamic patterns (facade wraps, Proxy traps, a createRequire bridge) that a\n// strict user tsconfig would reject; suppressing type-checking here keeps the\n// generated file from breaking the host project's \\`tsc\\` gate (#427) without\n// constraining the runtime logic. The file is regenerated, never hand-edited.\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_TS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(true)}\n`\n\n// Substitute __SERVICE_NAME__, __PROJECT__, and __INSTRUMENTATION_BLOCK__\n// at apply time. The third arg is a list of registration snippets — one per\n// non-bundled instrumentation the installer detected (e.g. Prisma). An empty\n// list collapses the placeholder to nothing so the generated file stays\n// readable on the common \"auto-instrumentations covers everything\" path.\nexport function renderNodeOtelInit(\n template: string,\n serviceName: string,\n projectName: string,\n registrations: readonly string[] = [],\n): string {\n const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// .env.neat shape (ADR-069 §4, amended v0.4.1 — refs #339, v0.4.4 — refs\n// #367 + #369, v0.4.8 — refs #410). Two keys: OTEL_SERVICE_NAME (the\n// ServiceNode id — the package's own name, scope-preserved, so spans land on\n// per-service nodes inside the project's graph) and\n// OTEL_EXPORTER_OTLP_TRACES_ENDPOINT (the project-scoped URL the daemon mounts\n// at /projects/<project>/v1/traces). Both env vars are advisory only — the\n// generated `otel-init` inlines them via `process.env.X ||=` so bundlers can't\n// lose them; the file is kept so operators can grep for service.name → project\n// mapping in one place. A commented `NEAT_OTEL_TOKEN` hint documents the single\n// source of the OTLP bearer (#410): set it to the secret the daemon's receiver\n// expects and the generated init sends `Authorization: Bearer <token>`.\nexport function renderEnvNeat(serviceName: string, projectName: string): string {\n return [\n '# Generated by `neat init --apply` (ADR-069).',\n `OTEL_SERVICE_NAME=${serviceName}`,\n `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/projects/${projectName}/v1/traces`,\n '# Set NEAT_OTEL_TOKEN to the daemon\\'s OTLP secret to authenticate exported spans (#410).',\n '# NEAT_OTEL_TOKEN=',\n '',\n ].join('\\n')\n}\n\n// ── Next.js framework-aware templates (ADR-073 §1, ADR-069 §3). ─────────\n//\n// Next.js owns its own boot — `pkg.main` is unused, and the auto-instrumentation\n// register hook can't run before user code. Next 13+ ships an `instrumentation`\n// file at the project root with an async `register()` export the framework\n// invokes during server start (Node runtime only). For Edge / browser runtimes\n// the file is ignored.\n//\n// Two-file shape: `instrumentation.{ts,js}` keeps the runtime gate so the\n// Node SDK doesn't load on the Edge runtime; `instrumentation.node.{ts,js}`\n// carries the SDK init itself. Both files sit at the project root.\n\nexport const NEXT_INSTRUMENTATION_HEADER =\n '// Generated by `neat init --apply` (ADR-073). Next.js instrumentation hook.'\n\nexport const NEXT_INSTRUMENTATION_TS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('./instrumentation.node')\n }\n}\n`\n\nexport const NEXT_INSTRUMENTATION_JS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n if (process.env.NEXT_RUNTIME === 'nodejs') {\n await import('./instrumentation.node')\n }\n}\n`\n\n// Env vars are inlined as process.env defaults so they survive Turbopack /\n// Webpack bundling — `import.meta.url` resolves to a path under .next/dev/\n// server/chunks/ once Next compiles this file, which would miss .env.neat.\n// `process.env.X ||=` keeps platform env (Vercel / Railway / Fly / etc.)\n// authoritative at deploy time while the local default carries the routing\n// key the daemon needs to map spans back to this project. The endpoint uses\n// the project-scoped URL form so the daemon never has to guess which project\n// owns the span (issue #367); the OTel SDK reads the env vars from\n// process.env directly, so no file-system lookup is required at runtime.\nexport const NEXT_INSTRUMENTATION_NODE_TS = `${NEXT_INSTRUMENTATION_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\nexport const NEXT_INSTRUMENTATION_NODE_JS = `${NEXT_INSTRUMENTATION_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\n// Substitute the placeholders at apply time so the generated file carries the\n// ServiceNode id (`__SERVICE_NAME__`) and the registered project name\n// (`__PROJECT__`) verbatim. The two roles diverged in v0.4.4: the service name\n// names the ServiceNode inside one project's graph, the project basename is\n// the URL routing key. v0.4.5 adds __INSTRUMENTATION_BLOCK__ — a (possibly\n// empty) sequence of `instrumentations.push(...)` calls for non-bundled\n// libraries like Prisma whose query engines bypass the auto-instrumentation\n// set's coverage.\nexport function renderNextInstrumentationNode(\n template: string,\n serviceName: string,\n projectName: string,\n registrations: readonly string[] = [],\n): string {\n const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// ── Meta-framework templates (ADR-074 §3). ──────────────────────────────\n//\n// Remix, SvelteKit, Nuxt, and Astro each own their boot path. The installer\n// emits one OTel-init module that loads `.env.neat` and starts the Node SDK,\n// then either creates or injects an import into the framework's canonical\n// hook file. Templates mirror the Next.js pair in shape — one generated init\n// module, one optional framework-hook stub for the absent-file case.\n\nexport const FRAMEWORK_OTEL_INIT_HEADER =\n '// Generated by `neat init --apply` (ADR-074). OpenTelemetry SDK hook.'\n\n// Same inline-defaults pattern as the plain-Node + Next templates: env vars\n// arrive on `process.env` via the apply-time substitution below so bundler\n// path mangling (issue #369) can't lose them. `__SERVICE_NAME__` /\n// `__PROJECT__` are substituted via renderFrameworkOtelInit().\nconst FRAMEWORK_OTEL_INIT_TS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst sdk = new NodeSDK({\n serviceName: process.env.OTEL_SERVICE_NAME,\n instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n`\n\nconst FRAMEWORK_OTEL_INIT_JS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst sdk = new NodeSDK({\n serviceName: process.env.OTEL_SERVICE_NAME,\n instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n`\n\nexport function renderFrameworkOtelInit(\n template: string,\n serviceName: string,\n projectName: string,\n): string {\n return template\n .replace(/__SERVICE_NAME__/g, serviceName)\n .replace(/__PROJECT__/g, projectName)\n}\n\n// Remix — `app/otel.server.{ts,js}` carries the SDK bootstrap. The framework\n// loads `entry.server.*` at server-process start, and a top-of-module import\n// of `./otel.server` runs the bootstrap before any request handler imports.\nexport const REMIX_OTEL_SERVER_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const REMIX_OTEL_SERVER_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\n// SvelteKit — `src/otel-init.{ts,js}` carries the SDK bootstrap; the\n// framework's `src/hooks.server.{ts,js}` imports it. When hooks.server is\n// absent, the installer writes the stub below alongside the import.\nexport const SVELTEKIT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const SVELTEKIT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const SVELTEKIT_HOOKS_SERVER_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport type { Handle } from '@sveltejs/kit'\n\nexport const handle: Handle = async ({ event, resolve }) => {\n return resolve(event)\n}\n`\n\nexport const SVELTEKIT_HOOKS_SERVER_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\n/** @type {import('@sveltejs/kit').Handle} */\nexport const handle = async ({ event, resolve }) => {\n return resolve(event)\n}\n`\n\n// Nuxt — `server/plugins/otel.{ts,js}` is the convention-loaded plugin file;\n// it imports the sibling `otel-init.{ts,js}` which carries the SDK bootstrap.\nexport const NUXT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const NUXT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const NUXT_OTEL_PLUGIN_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nexport default defineNitroPlugin(() => {\n // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\nexport const NUXT_OTEL_PLUGIN_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nrequire('./otel-init')\n\nmodule.exports = defineNitroPlugin(() => {\n // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\n// Astro — `src/middleware.{ts,js}` runs once at module-load (and then per\n// request via onRequest). The top-of-module import of `./otel-init` boots\n// the SDK before the first request lands.\nexport const ASTRO_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const ASTRO_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const ASTRO_MIDDLEWARE_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n return next()\n})\n`\n\nexport const ASTRO_MIDDLEWARE_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n return next()\n})\n`\n","/**\n * Python SDK installer (ADR-047).\n *\n * `detect` matches on the canonical Python project markers — requirements.txt,\n * pyproject.toml, setup.py. `plan` produces dependency edits against the\n * primary manifest and entrypoint edits against a Procfile when one exists.\n *\n * MVP scope:\n * - requirements.txt is the full-fidelity manifest (read / append).\n * - pyproject.toml dependencies live inside a TOML `dependencies = [...]`\n * block; we line-insert into that block when found, otherwise hold off\n * on rewriting until a successor ADR addresses TOML editing properly.\n * - Procfile lines starting with `python` get prefixed with\n * `opentelemetry-instrument`.\n *\n * Lockfiles (poetry.lock, Pipfile.lock) are never touched. After `--apply`,\n * init's summary tells the user to run `pip install -r requirements.txt`\n * (or `poetry lock && poetry install`) so they own the lockfile commit.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n ApplyResult,\n DependencyEdit,\n EntrypointEdit,\n EnvEdit,\n Installer,\n InstallPlan,\n} from './shared.js'\n\nconst SDK_PACKAGES = [\n { name: 'opentelemetry-distro', version: '>=0.49b0' },\n { name: 'opentelemetry-exporter-otlp', version: '>=1.28.0' },\n] as const\n\nconst OTEL_ENV: EnvEdit = {\n file: null,\n key: 'OTEL_EXPORTER_OTLP_ENDPOINT',\n value: 'http://localhost:4318',\n}\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await fs.stat(p)\n return true\n } catch {\n return false\n }\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n const markers = ['requirements.txt', 'pyproject.toml', 'setup.py']\n for (const m of markers) {\n if (await exists(path.join(serviceDir, m))) return true\n }\n return false\n}\n\n// Strip a requirements.txt line down to its lower-cased package name.\n// `flask==3.0.0` → `flask`, `Flask>=2 ; python_version>\"3.6\"` → `flask`.\nfunction reqPackageName(line: string): string {\n const stripped = line.split('#')[0]?.trim() ?? ''\n const head = stripped.split(/[\\s;]/)[0] ?? ''\n return head.replace(/[<>=!~].*$/, '').toLowerCase()\n}\n\nasync function planRequirementsTxtEdits(\n serviceDir: string,\n): Promise<{ manifest: string; missing: typeof SDK_PACKAGES[number][] } | null> {\n const file = path.join(serviceDir, 'requirements.txt')\n if (!(await exists(file))) return null\n const raw = await fs.readFile(file, 'utf8')\n const presentNames = new Set(\n raw\n .split(/\\r?\\n/)\n .map(reqPackageName)\n .filter((n) => n.length > 0),\n )\n const missing = SDK_PACKAGES.filter((p) => !presentNames.has(p.name.toLowerCase()))\n return { manifest: file, missing: [...missing] }\n}\n\nasync function planProcfileEdits(serviceDir: string): Promise<EntrypointEdit[]> {\n const procfile = path.join(serviceDir, 'Procfile')\n if (!(await exists(procfile))) return []\n const raw = await fs.readFile(procfile, 'utf8')\n const edits: EntrypointEdit[] = []\n for (const line of raw.split(/\\r?\\n/)) {\n if (line.length === 0) continue\n // Procfile lines look like `<process>: <cmd>`. Prefix the cmd when it\n // starts with python and isn't already wrapped.\n const m = line.match(/^([a-zA-Z0-9_-]+):\\s*(.+)$/)\n if (!m) continue\n const cmd = m[2]!\n if (!/^python\\b/.test(cmd)) continue\n if (cmd.startsWith('opentelemetry-instrument ')) continue\n const after = `${m[1]}: opentelemetry-instrument ${cmd}`\n edits.push({ file: procfile, before: line, after })\n }\n return edits\n}\n\nasync function plan(serviceDir: string): Promise<InstallPlan> {\n const empty: InstallPlan = {\n language: 'python',\n serviceDir,\n dependencyEdits: [],\n entrypointEdits: [],\n envEdits: [],\n }\n\n const dependencyEdits: DependencyEdit[] = []\n const reqs = await planRequirementsTxtEdits(serviceDir)\n if (reqs) {\n for (const sdk of reqs.missing) {\n dependencyEdits.push({\n file: reqs.manifest,\n kind: 'add',\n name: sdk.name,\n version: sdk.version,\n })\n }\n }\n // pyproject.toml / setup.py without requirements.txt: deferred to a\n // successor ADR. The patch will note it; apply is a no-op for those\n // manifests in the MVP.\n\n const entrypointEdits = await planProcfileEdits(serviceDir)\n\n if (dependencyEdits.length === 0 && entrypointEdits.length === 0) {\n return empty\n }\n return {\n language: 'python',\n serviceDir,\n dependencyEdits,\n entrypointEdits,\n envEdits: [OTEL_ENV],\n }\n}\n\nasync function applyRequirementsTxt(\n manifest: string,\n edits: DependencyEdit[],\n original: string,\n): Promise<void> {\n // Append missing packages on their own lines. Preserve a trailing newline.\n const newlines = edits\n .filter((e) => e.kind === 'add')\n .map((e) => `${e.name}${e.version}`)\n const trailing = original.endsWith('\\n') ? '' : '\\n'\n const next = `${original}${trailing}${newlines.join('\\n')}\\n`\n const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, next, 'utf8')\n await fs.rename(tmp, manifest)\n}\n\nasync function applyProcfile(\n procfile: string,\n edits: EntrypointEdit[],\n original: string,\n): Promise<void> {\n let next = original\n for (const e of edits) {\n if (!next.includes(e.before)) continue\n next = next.replace(e.before, e.after)\n }\n const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`\n await fs.writeFile(tmp, next, 'utf8')\n await fs.rename(tmp, procfile)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n const { serviceDir } = installPlan\n const touched = new Set<string>()\n for (const e of installPlan.dependencyEdits) touched.add(e.file)\n for (const e of installPlan.entrypointEdits) touched.add(e.file)\n if (touched.size === 0) {\n return { serviceDir, outcome: 'already-instrumented', writtenFiles: [] }\n }\n\n const originals = new Map<string, string>()\n for (const file of touched) {\n try {\n originals.set(file, await fs.readFile(file, 'utf8'))\n } catch {\n // Mutation will fail loudly below; rollback covers what did land.\n }\n }\n\n const writtenFiles: string[] = []\n try {\n for (const file of touched) {\n const raw = originals.get(file)\n if (raw === undefined) {\n throw new Error(`python installer: cannot read ${file} during apply`)\n }\n const base = path.basename(file)\n if (base === 'requirements.txt') {\n const edits = installPlan.dependencyEdits.filter((e) => e.file === file)\n if (edits.length > 0) {\n await applyRequirementsTxt(file, edits, raw)\n writtenFiles.push(file)\n }\n } else if (base === 'Procfile') {\n const edits = installPlan.entrypointEdits.filter((e) => e.file === file)\n if (edits.length > 0) {\n await applyProcfile(file, edits, raw)\n writtenFiles.push(file)\n }\n }\n // pyproject.toml / setup.py: MVP no-op as planned above.\n }\n } catch (err) {\n await rollback(installPlan, originals)\n throw err\n }\n\n return { serviceDir, outcome: 'instrumented', writtenFiles }\n}\n\nasync function rollback(\n installPlan: InstallPlan,\n originals: Map<string, string>,\n): Promise<void> {\n const restored: string[] = []\n for (const [file, raw] of originals.entries()) {\n try {\n await fs.writeFile(file, raw, 'utf8')\n restored.push(file)\n } catch {\n // Best-effort.\n }\n }\n const lines = [\n '# neat-rollback.patch',\n '',\n `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n '# Files listed below were restored to their pre-apply contents.',\n '',\n ...restored.map((f) => `restored: ${f}`),\n '',\n ]\n const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\nexport const pythonInstaller: Installer = {\n name: 'python',\n detect,\n plan,\n apply,\n}\n","/**\n * Shared types for SDK installer modules (ADR-047).\n *\n * Each language has its own installer at `installers/<language>.ts` exporting\n * a `detect / plan / apply` triple. Plans are pure data — no fs side effects\n * during planning — so `init --dry-run` can render a patch without ever\n * touching the project. `apply` runs the codemod in place.\n *\n * Step 2 (this PR) ships the interface and an empty registry. Step 3 (Node\n * installer) and step 4 (Python installer) populate it.\n */\n\n// Field names match ADR-047's documented patch shape exactly: `file`, `kind`,\n// `name`, `version`. Patches will be reviewed by humans and matched in tests\n// by name; renaming for clarity would have cost more than it bought.\n\nexport interface DependencyEdit {\n file: string\n kind: 'add' | 'remove' | 'upgrade'\n name: string\n version: string\n fromVersion?: string\n}\n\nexport interface EntrypointEdit {\n file: string\n before: string\n after: string\n}\n\nexport interface EnvEdit {\n // `null` denotes a recommendation only — the user will set the env var in\n // their orchestration layer, NEAT does not write a `.env` file.\n file: string | null\n key: string\n value: string\n}\n\n// Files the installer generates from scratch (ADR-069 §1). The generated\n// `otel-init.{js,ts}` for the Node installer rides here, along with the\n// per-package `.env.neat` (ADR-069 §4). Treated as additive writes — the\n// apply phase skips any file already present (ADR-069 §6).\nexport interface GeneratedFile {\n file: string\n contents: string\n // When true, write only if the file does not already exist. The apply\n // phase logs an `already instrumented` / `already present` notice instead\n // of overwriting (ADR-069 §6).\n skipIfExists?: boolean\n}\n\nexport interface InstallPlan {\n // Free-form language tag matching the service node's language: `'javascript'`,\n // `'python'`, …\n language: string\n // Service directory the plan targets. Absolute path.\n serviceDir: string\n dependencyEdits: DependencyEdit[]\n entrypointEdits: EntrypointEdit[]\n envEdits: EnvEdit[]\n // ADR-069 §1, §4 — generated files (otel-init, .env.neat). Optional so\n // installers that don't generate files (the Python installer at MVP) can\n // omit it.\n generatedFiles?: GeneratedFile[]\n // ADR-069 §2 — flagged when entry-point resolution found nothing.\n // The apply phase records this in the summary and skips all file writes\n // for the package.\n libOnly?: boolean\n // ADR-069 §2 — resolved entry-point path (absolute). Present when the\n // installer is going to inject the require/import. Absent for libOnly\n // packages and for the Python installer.\n entryFile?: string\n // ADR-073 §1 + ADR-074 §3 — when a framework owns its own boot, the\n // installer skips `pkg.main` injection and emits framework-native\n // instrumentation files instead. Five values today: Next.js from v0.3.8,\n // then Remix / SvelteKit / Nuxt / Astro from v0.3.9.\n framework?: 'next' | 'remix' | 'sveltekit' | 'nuxt' | 'astro'\n // v0.4.4 / issue #370 — when a JavaScript package isn't a Node service\n // (browser bundle, React Native), the installer records the runtime here\n // and writes nothing. Absent → vanilla Node default (the existing apply\n // path). Browser-side OTel support (`@opentelemetry/sdk-trace-web`) lands\n // in a future release.\n runtimeKind?: 'browser-bundle' | 'react-native' | 'bun' | 'deno' | 'cloudflare-workers' | 'electron'\n // ADR-073 §1 — Next.js' `next.config.{js,ts,mjs}` may need the\n // `experimental.instrumentationHook: true` flag set when the major\n // version is < 15. The apply phase mutates the file in place when this\n // field is set. Absent → no config mutation planned.\n nextConfigEdit?: {\n file: string\n // Reason this edit is queued — surfaces in the dry-run patch and the\n // apply summary so the operator knows why their next.config moved.\n reason: string\n }\n}\n\n// ADR-069 §9 — apply outcome per service. The CLI surfaces these counts\n// at the end of `neat init --apply`. v0.4.4 / issue #370 — two new buckets\n// for non-Node JavaScript runtimes: `browser-bundle` (Vite, esbuild-shipped\n// SPAs) and `react-native` (Expo / RN bare). The Node SDK can't run in\n// either; both buckets skip every write and surface the package in the\n// summary so the operator knows the frontend wasn't instrumented.\nexport type ApplyOutcome =\n | 'instrumented'\n | 'already-instrumented'\n | 'lib-only'\n | 'failed'\n | 'browser-bundle'\n | 'react-native'\n | 'bun'\n | 'deno'\n | 'cloudflare-workers'\n | 'electron'\n\nexport interface ApplyResult {\n serviceDir: string\n outcome: ApplyOutcome\n // Free-form reason string for `lib-only` / `failed` outcomes. Surfaced\n // in the CLI summary so the user knows why a package was skipped.\n reason?: string\n // Absolute paths the apply phase actually wrote to. Used by the contract\n // test that asserts the allowed-path-set restriction (ADR-069 §7).\n writtenFiles: string[]\n}\n\n// Plan-time inputs the orchestrator threads through (v0.4.1 — refs #339).\n// `project` is the registered project name — the routing key the daemon\n// owns. When present the installer writes it as `OTEL_SERVICE_NAME` so the\n// OTLP wire and the registry agree end-to-end. Absent → installers fall\n// back to a package-local default for ad-hoc / test usage.\nexport interface PlanOptions {\n project?: string\n}\n\nexport interface Installer {\n // Free-form module name. Used for the patch header and for diagnostics.\n name: string\n // Returns true if the installer thinks `serviceDir` is shaped like a project\n // it can instrument. Cheap; no fs writes.\n detect(serviceDir: string): boolean | Promise<boolean>\n // Builds an `InstallPlan` describing the edits the installer would make.\n // Pure data; no fs writes. An empty plan (every edits array empty) means\n // the SDK is already installed and there is nothing to do.\n plan(serviceDir: string, opts?: PlanOptions): InstallPlan | Promise<InstallPlan>\n // Apply a previously-produced plan. Mutates files in place. On failure,\n // produces `<serviceDir>/neat-rollback.patch` per ADR-047 #7. Returns a\n // structured outcome so the CLI can surface coverage (ADR-069 §9).\n apply(plan: InstallPlan): Promise<ApplyResult>\n}\n\nexport function isEmptyPlan(plan: InstallPlan): boolean {\n return (\n plan.dependencyEdits.length === 0 &&\n plan.entrypointEdits.length === 0 &&\n plan.envEdits.length === 0 &&\n (plan.generatedFiles?.length ?? 0) === 0 &&\n plan.nextConfigEdit === undefined\n )\n}\n","/**\n * One-command orchestrator (ADR-073 §1).\n *\n * Bare `neat <path>` dispatches here when the first positional argument\n * resolves to a directory and doesn't match a registered verb. Six steps,\n * in order:\n *\n * 1. Discovery + extraction (per static-extraction contract).\n * 2. `.gitignore` automation (ADR-073 §6) + project registration.\n * 3. SDK install apply — patches manifests + writes otel-init + writes\n * `.env.neat`. Default yes; `--no-instrument` opts out.\n * 4. Daemon spawn — `neatd start --detach` if no daemon is running.\n * Polls `/health` up to 15s for readiness.\n * 5. Browser open against the web UI on port 6328 (T9 NEAT).\n * Default yes; `--no-open` and headless runs skip the launch.\n * 6. Summary block — value-forward findings + OTel env-vars block.\n *\n * `neat init` retains its patch-by-default contract (ADR-046 §5). The\n * orchestrator runs apply unconditionally because the bare-`<path>` shape's\n * user intent is \"make this work end-to-end.\"\n */\n\nimport { promises as fs } from 'node:fs'\nimport http from 'node:http'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport readline from 'node:readline'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { discoverServices } from './extract/services.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { pathsForProject } from './projects.js'\nimport { addProject, listProjects, ProjectNameCollisionError, setStatus } from './registry.js'\nimport {\n isEmptyPlan,\n pickInstaller,\n type InstallPlan,\n} from './installers/index.js'\nimport {\n detectPackageManager,\n runPackageManagerInstall,\n type PackageManager,\n type PackageManagerInvocation,\n} from './installers/package-manager.js'\n\nexport interface OrchestratorOptions {\n scanPath: string\n // Project name resolution mirrors `neat init` — basename of the scan\n // path unless overridden via --project.\n project: string\n projectExplicit: boolean\n // Skip step 3 (SDK install apply).\n noInstrument: boolean\n // Skip step 5 (browser open).\n noOpen: boolean\n // Skip the interactive prompt (CI invocation flag — implied when\n // stdin/stdout aren't a TTY).\n yes: boolean\n // Dashboard URL — defaults to http://localhost:6328 (T9 NEAT, ADR-059).\n dashboardUrl?: string\n // Health-check timeout in ms. Default 15s.\n daemonReadyTimeoutMs?: number\n}\n\nexport interface OrchestratorResult {\n exitCode: number\n // High-level step-by-step status for the test surface.\n steps: {\n discovery: { services: number; languages: string[] }\n extraction: { nodesAdded: number; edgesAdded: number }\n gitignore: 'added' | 'created' | 'unchanged'\n apply: {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n skipped: boolean\n bun?: number\n deno?: number\n cloudflareWorkers?: number\n electron?: number\n // Issue #381 — package-manager invocations the orchestrator ran\n // after apply() mutated package.json. Absent for `--no-instrument`\n // runs and runs where every plan was empty.\n packageManagerInstalls?: PackageManagerInvocation[]\n }\n daemon: 'spawned' | 'already-running' | 'timed-out' | 'skipped'\n browser: 'opened' | 'skipped' | 'failed'\n }\n}\n\n// Shared sub-pipeline `neat sync` re-uses (ADR-074 §1). Discovery + extract\n// + snapshot write. Distinct from the first-run-only steps (registry add,\n// daemon spawn, browser open, summary block) that the orchestrator owns\n// directly.\nexport interface ExtractAndPersistOptions {\n scanPath: string\n project: string\n projectExplicit: boolean\n // When true, skip persisting to disk — for `neat sync --dry-run`.\n dryRun?: boolean\n}\n\nexport interface ExtractAndPersistResult {\n graph: ReturnType<typeof getGraph>\n graphKey: string\n services: Awaited<ReturnType<typeof discoverServices>>\n languages: string[]\n nodesAdded: number\n edgesAdded: number\n snapshotPath: string\n errorsPath: string\n}\n\nexport async function extractAndPersist(\n opts: ExtractAndPersistOptions,\n): Promise<ExtractAndPersistResult> {\n const services = await discoverServices(opts.scanPath)\n const languages = [...new Set(services.map((s) => s.node.language))].sort()\n\n const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n resetGraph(graphKey)\n const graph = getGraph(graphKey)\n const projectPaths = pathsForProject(graphKey, path.join(opts.scanPath, 'neat-out'))\n const extraction = await extractFromDirectory(graph, opts.scanPath, {\n errorsPath: projectPaths.errorsPath,\n })\n if (!opts.dryRun) {\n await saveGraphToDisk(graph, projectPaths.snapshotPath)\n }\n return {\n graph,\n graphKey,\n services,\n languages,\n nodesAdded: extraction.nodesAdded,\n edgesAdded: extraction.edgesAdded,\n snapshotPath: projectPaths.snapshotPath,\n errorsPath: projectPaths.errorsPath,\n }\n}\n\n// SDK-install apply over a discovered service list. Returns the same shape\n// the orchestrator's result.steps.apply uses so callers (orchestrator + sync)\n// share the rollup logic. v0.4.1 / refs #339 — `project` is threaded through\n// to the installer so the per-package `.env.neat` carries\n// `OTEL_SERVICE_NAME=<project>`, matching the daemon's routing key.\nexport interface ApplyInstallersTally {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n browserBundle: number\n reactNative: number\n // Issues #389 #390 — BYO-OTel out-of-scope runtime counters.\n bun: number\n deno: number\n cloudflareWorkers: number\n electron: number\n // Issue #381 — package-manager invocations the orchestrator ran after\n // apply() mutated package.json. One entry per distinct lockfile-owning\n // directory (monorepos share a single install run regardless of how\n // many sub-packages got instrumented). Empty when nothing was added to\n // any package.json.\n packageManagerInstalls: PackageManagerInvocation[]\n}\n\n// Knobs the test surface uses to swap the real spawn for a no-op. Default\n// uses the real installer; the contract suite passes a stub so the wiring\n// can be asserted without spawning npm against an unreliable registry.\nexport interface ApplyInstallersOptions {\n runInstall?: (cmd: { pm: PackageManager; cwd: string; args: string[] }) => Promise<PackageManagerInvocation>\n resolveManager?: (serviceDir: string) => Promise<{ pm: PackageManager; cwd: string; args: string[] }>\n}\n\nexport async function applyInstallersOver(\n services: Awaited<ReturnType<typeof discoverServices>>,\n project: string,\n options: ApplyInstallersOptions = {},\n): Promise<ApplyInstallersTally> {\n const resolveManager = options.resolveManager ?? detectPackageManager\n const runInstall = options.runInstall ?? runPackageManagerInstall\n let instrumented = 0\n let already = 0\n let libOnly = 0\n let browserBundle = 0\n let reactNative = 0\n let bun = 0\n let deno = 0\n let cloudflareWorkers = 0\n let electron = 0\n // Distinct install commands keyed by `<pm>:<cwd>` so a monorepo with\n // multiple instrumented sub-packages still runs install exactly once at\n // its workspace root. The first plan that landed a dep edit for a given\n // root wins; later sub-packages skip the re-run.\n const installPlans = new Map<string, { pm: PackageManager; cwd: string; args: string[] }>()\n for (const svc of services) {\n const installer = await pickInstaller(svc.dir)\n if (!installer) continue\n const plan: InstallPlan = await installer.plan(svc.dir, { project })\n if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) {\n already++\n continue\n }\n const outcome = await installer.apply(plan)\n if (outcome.outcome === 'instrumented') {\n instrumented++\n // Schedule an install whenever apply() actually added deps. The\n // generated otel-init file lives under the service dir but the\n // packages the user must resolve at runtime (`@opentelemetry/sdk-node`,\n // `@prisma/instrumentation`) live in package.json — without the\n // install, the next `npm run dev` throws `Cannot find module ...`\n // before any of NEAT's code even loads.\n if (plan.dependencyEdits.length > 0) {\n const cmd = await resolveManager(svc.dir)\n const key = `${cmd.pm}:${cmd.cwd}`\n if (!installPlans.has(key)) installPlans.set(key, cmd)\n }\n } else if (outcome.outcome === 'already-instrumented') already++\n else if (outcome.outcome === 'lib-only') libOnly++\n else if (outcome.outcome === 'browser-bundle') {\n browserBundle++\n console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`)\n } else if (outcome.outcome === 'react-native') {\n reactNative++\n const svcName = path.basename(svc.dir)\n console.log(\n `neat: ${svc.dir} detected as React Native / Expo\\n` +\n ` The installer doesn't cover this runtime deterministically.\\n` +\n ` Configure your OTel binding to send spans to:\\n` +\n ` http://localhost:4318/projects/${project}/v1/traces\\n` +\n ` Set OTEL_SERVICE_NAME=${svcName}\\n` +\n ` See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n )\n } else if (outcome.outcome === 'bun') {\n bun++\n const svcName = path.basename(svc.dir)\n console.log(\n `neat: ${svc.dir} detected as Bun\\n` +\n ` The installer doesn't cover this runtime deterministically.\\n` +\n ` Configure your OTel binding to send spans to:\\n` +\n ` http://localhost:4318/projects/${project}/v1/traces\\n` +\n ` Set OTEL_SERVICE_NAME=${svcName}\\n` +\n ` See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n )\n } else if (outcome.outcome === 'deno') {\n deno++\n const svcName = path.basename(svc.dir)\n console.log(\n `neat: ${svc.dir} detected as Deno\\n` +\n ` The installer doesn't cover this runtime deterministically.\\n` +\n ` Configure your OTel binding to send spans to:\\n` +\n ` http://localhost:4318/projects/${project}/v1/traces\\n` +\n ` Set OTEL_SERVICE_NAME=${svcName}\\n` +\n ` See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n )\n } else if (outcome.outcome === 'cloudflare-workers') {\n cloudflareWorkers++\n const svcName = path.basename(svc.dir)\n console.log(\n `neat: ${svc.dir} detected as Cloudflare Workers\\n` +\n ` The installer doesn't cover this runtime deterministically.\\n` +\n ` Configure your OTel binding to send spans to:\\n` +\n ` http://localhost:4318/projects/${project}/v1/traces\\n` +\n ` Set OTEL_SERVICE_NAME=${svcName}\\n` +\n ` See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n )\n } else if (outcome.outcome === 'electron') {\n electron++\n const svcName = path.basename(svc.dir)\n console.log(\n `neat: ${svc.dir} detected as Electron\\n` +\n ` The installer doesn't cover this runtime deterministically.\\n` +\n ` Configure your OTel binding to send spans to:\\n` +\n ` http://localhost:4318/projects/${project}/v1/traces\\n` +\n ` Set OTEL_SERVICE_NAME=${svcName}\\n` +\n ` See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n )\n }\n }\n\n // Run each distinct install command serially. Parallelism would race the\n // lockfile in the rare monorepo-of-monorepos case and most package\n // managers serialise themselves internally anyway — the time saving is\n // tiny next to the operator-trust cost of a corrupted lockfile.\n const packageManagerInstalls: PackageManagerInvocation[] = []\n for (const cmd of installPlans.values()) {\n console.log(`running \\`${cmd.pm} ${cmd.args.join(' ')}\\` in ${cmd.cwd}`)\n const result = await runInstall(cmd)\n packageManagerInstalls.push(result)\n if (result.exitCode !== 0) {\n console.error(\n `neat: ${cmd.pm} install failed in ${cmd.cwd} (exit ${result.exitCode}); run it manually to surface the error.`,\n )\n if (result.stderr.length > 0) {\n for (const line of result.stderr.split(/\\r?\\n/).slice(0, 20)) {\n console.error(` ${line}`)\n }\n }\n }\n }\n\n return {\n instrumented,\n alreadyInstrumented: already,\n libOnly,\n browserBundle,\n reactNative,\n bun,\n deno,\n cloudflareWorkers,\n electron,\n packageManagerInstalls,\n }\n}\n\nasync function promptYesNo(question: string): Promise<boolean> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n return new Promise((resolve) => {\n rl.question(`${question} [Y/n] `, (answer) => {\n rl.close()\n const trimmed = answer.trim().toLowerCase()\n resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes')\n })\n })\n}\n\n// 60s covers boot + per-project graph load across a registry with several\n// sibling projects. Issue #340 — `app.listen()` now returns the moment the\n// socket binds, so the steady-state happy path lands well inside the first\n// second; the longer ceiling is the cold-clone window where multi-project\n// bootstraps run in the background after listen.\nconst DEFAULT_DAEMON_READY_TIMEOUT_MS = 60_000\n\n// 500ms poll cadence — responsive enough that the operator sees a fresh\n// status line on every transition without spamming the daemon.\nconst PROBE_INTERVAL_MS = 500\n\ninterface DaemonHealthResponse {\n ok?: boolean\n uptimeMs?: number\n projects?: Array<{\n name: string\n status?: 'bootstrapping' | 'active' | 'broken'\n elapsedMs?: number\n }>\n}\n\nasync function fetchDaemonHealth(restPort: number): Promise<DaemonHealthResponse | null> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${restPort}/health`, (res) => {\n const ok = res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300\n if (!ok) {\n res.resume()\n resolve(null)\n return\n }\n let body = ''\n res.setEncoding('utf8')\n res.on('data', (chunk: string) => { body += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(body) as DaemonHealthResponse)\n } catch {\n resolve({ ok: true })\n }\n })\n })\n req.on('error', () => resolve(null))\n req.setTimeout(1000, () => {\n req.destroy()\n resolve(null)\n })\n })\n}\n\nasync function checkDaemonHealth(restPort: number): Promise<boolean> {\n const body = await fetchDaemonHealth(restPort)\n return body !== null\n}\n\nasync function probeProjectHealth(\n restPort: number,\n name: string,\n): Promise<'bootstrapping' | 'active' | 'broken'> {\n return new Promise((resolve) => {\n const req = http.get(\n `http://127.0.0.1:${restPort}/projects/${encodeURIComponent(name)}/health`,\n (res) => {\n const code = res.statusCode ?? 0\n res.resume()\n if (code >= 200 && code < 300) resolve('active')\n else resolve('bootstrapping')\n },\n )\n req.on('error', () => resolve('bootstrapping'))\n req.setTimeout(1000, () => {\n req.destroy()\n resolve('bootstrapping')\n })\n })\n}\n\n// Resolve the project-status set the wait loop branches on. Prefers the\n// daemon-wide /health response when it carries the list; otherwise reads\n// the registry directly and probes each project's per-project /health.\n// The fallback handles the case where the daemon-wide /health hasn't\n// landed in this branch's main yet.\nasync function snapshotProjectStatus(\n restPort: number,\n body: DaemonHealthResponse,\n): Promise<Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken' }>> {\n if (body.projects && body.projects.length > 0) {\n return body.projects.map((p) => ({\n name: p.name,\n status: p.status ?? 'active',\n }))\n }\n const entries = await listProjects().catch(() => [])\n if (entries.length === 0) return []\n return Promise.all(\n entries.map(async (entry) => ({\n name: entry.name,\n status: await probeProjectHealth(restPort, entry.name),\n })),\n )\n}\n\ninterface DaemonReadyResult {\n ready: boolean\n brokenProjects: string[]\n stillBootstrapping: string[]\n}\n\nasync function waitForDaemonReady(restPort: number, timeoutMs: number): Promise<DaemonReadyResult> {\n const deadline = Date.now() + timeoutMs\n let lastBootstrapping: string[] = []\n while (Date.now() < deadline) {\n const body = await fetchDaemonHealth(restPort)\n if (body !== null) {\n const projects = await snapshotProjectStatus(restPort, body)\n const bootstrapping = projects\n .filter((p) => p.status === 'bootstrapping')\n .map((p) => p.name)\n const broken = projects.filter((p) => p.status === 'broken').map((p) => p.name)\n if (bootstrapping.length === 0) {\n return { ready: true, brokenProjects: broken, stillBootstrapping: [] }\n }\n const key = bootstrapping.slice().sort().join(',')\n const prevKey = lastBootstrapping.slice().sort().join(',')\n if (key !== prevKey) {\n const plural = bootstrapping.length === 1 ? '' : 's'\n console.log(\n `neat: waiting on ${bootstrapping.length} project${plural}: ${bootstrapping.join(', ')}`,\n )\n lastBootstrapping = bootstrapping\n }\n }\n await new Promise((r) => setTimeout(r, PROBE_INTERVAL_MS))\n }\n const final = await fetchDaemonHealth(restPort)\n const projects = final ? await snapshotProjectStatus(restPort, final) : []\n return {\n ready: false,\n brokenProjects: projects.filter((p) => p.status === 'broken').map((p) => p.name),\n stillBootstrapping: projects\n .filter((p) => p.status === 'bootstrapping')\n .map((p) => p.name),\n }\n}\n\n// Port-availability probe (#377 / ADR-079 §2).\n//\n// The orchestrator's daemon-spawn step assumes `:8080` (REST), `:4318` (OTLP\n// HTTP), and `:6328` (web UI) are free. When a sibling daemon from another\n// terminal session — or any unrelated listener — is holding one of them, the\n// spawn exits 1 with no actionable message. The probe runs before\n// `spawnDaemonDetached()` and surfaces the named port plus recovery commands\n// on collision, exiting with code 3 (environmental) per the CLI exit-code\n// surface.\nexport const NEAT_PORTS = [8080, 4318, 6328] as const\n\nexport async function isPortFree(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer()\n server.once('error', () => resolve(false))\n server.once('listening', () => server.close(() => resolve(true)))\n server.listen(port, '127.0.0.1')\n })\n}\n\nexport async function probePortsFree(): Promise<\n { free: true } | { free: false; held: number }\n> {\n for (const port of NEAT_PORTS) {\n if (!(await isPortFree(port))) return { free: false, held: port }\n }\n return { free: true }\n}\n\nexport function formatPortCollisionMessage(port: number): string[] {\n return [\n `neat: port ${port} is in use; the NEAT daemon needs it.`,\n ` run \\`neatd stop\\` to release the previous daemon, or`,\n ` \\`lsof -i :${port}\\` to find the holding process.`,\n ]\n}\n\n// Spawn the daemon as a child process the orchestrator drives. Returns the\n// child handle so the caller can read its stderr verbatim when the bind\n// gate (or any other startup failure) reports back through that pipe\n// (issue #341). The `detached: true` + `unref()` pair survives the\n// orchestrator exiting cleanly; the inherited stderr keeps the operator\n// informed when something does fail.\nfunction spawnDaemonDetached(): import('node:child_process').ChildProcess {\n // Resolve the neatd entry inside the @neat.is/core dist next to this\n // file. `import.meta.url` is post-bundling — at runtime, this resolves\n // to `<core>/dist/neatd.{js,cjs}`. We pick the .cjs because tsup ships\n // it in both forms and node tolerates either.\n const here = path.dirname(new URL(import.meta.url).pathname)\n const candidates = [\n path.join(here, 'neatd.cjs'),\n path.join(here, 'neatd.js'),\n ]\n let entry: string | null = null\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fsSync = require('node:fs') as typeof import('node:fs')\n for (const c of candidates) {\n try {\n fsSync.accessSync(c)\n entry = c\n break\n } catch {\n // try next\n }\n }\n if (!entry) {\n throw new Error(`orchestrator: cannot locate neatd entry in ${here}`)\n }\n\n // ADR-073 §3 + issue #341 — first-touch path is loopback-only. When the\n // operator hasn't set `NEAT_AUTH_TOKEN` the orchestrator hard-pins\n // HOST=127.0.0.1 in the child env so `assertBindAuthority` lets the bind\n // through. Public-bind is opt-in via the token (and an explicit\n // `HOST=0.0.0.0` if the operator wants the literal). The parent's HOST is\n // preserved untouched when the token is set — that's the deploy path,\n // where the platform owns the bind decision.\n const env = { ...process.env }\n const hasToken = typeof env.NEAT_AUTH_TOKEN === 'string' && env.NEAT_AUTH_TOKEN.length > 0\n if (!hasToken && (!env.HOST || env.HOST.length === 0)) {\n env.HOST = '127.0.0.1'\n }\n\n const child = spawn(process.execPath, [entry, 'start'], {\n detached: true,\n // stderr inherits the orchestrator's fd so the daemon's\n // `BindAuthorityError` message lands in front of the operator instead\n // of being swallowed (issue #341).\n stdio: ['ignore', 'ignore', 'inherit'],\n env,\n })\n child.unref()\n return child\n}\n\nfunction openBrowser(url: string): 'opened' | 'failed' {\n // Skip when running headlessly; we don't want CI invocations to fail\n // because xdg-open isn't installed.\n if (!process.stdout.isTTY) return 'failed'\n const platform = process.platform\n const cmd =\n platform === 'darwin' ? 'open' :\n platform === 'win32' ? 'cmd' :\n 'xdg-open'\n const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]\n try {\n const child = spawn(cmd, args, { detached: true, stdio: 'ignore' })\n child.on('error', () => {})\n child.unref()\n return 'opened'\n } catch {\n return 'failed'\n }\n}\n\nexport async function runOrchestrator(opts: OrchestratorOptions): Promise<OrchestratorResult> {\n const result: OrchestratorResult = {\n exitCode: 0,\n steps: {\n discovery: { services: 0, languages: [] },\n extraction: { nodesAdded: 0, edgesAdded: 0 },\n gitignore: 'unchanged',\n apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: false },\n daemon: 'skipped',\n browser: 'skipped',\n },\n }\n\n // ── Path validation ───────────────────────────────────────────────────\n const stat = await fs.stat(opts.scanPath).catch(() => null)\n if (!stat || !stat.isDirectory()) {\n console.error(`neat: ${opts.scanPath} is not a directory`)\n result.exitCode = 2\n return result\n }\n\n console.log(`neat: ${opts.scanPath}`)\n console.log('')\n\n // ── Step 1: discovery, Step 2: extraction + snapshot ─────────────────\n // Shared with `neat sync` (ADR-074 §1) via extractAndPersist.\n const persisted = await extractAndPersist({\n scanPath: opts.scanPath,\n project: opts.project,\n projectExplicit: opts.projectExplicit,\n })\n const { graph, services, languages } = persisted\n result.steps.discovery = { services: services.length, languages }\n console.log(`discovered ${services.length} service(s) across ${languages.length} language(s)`)\n\n // ── Confirmation prompt (default yes; --no-instrument or no-TTY skip)\n let runApply = !opts.noInstrument\n if (runApply && !opts.yes && process.stdout.isTTY && process.stdin.isTTY) {\n runApply = await promptYesNo('instrument your services and open the dashboard?')\n }\n\n result.steps.extraction = {\n nodesAdded: persisted.nodesAdded,\n edgesAdded: persisted.edgesAdded,\n }\n\n const gi = await ensureNeatOutIgnored(opts.scanPath)\n result.steps.gitignore = gi.action\n if (gi.action !== 'unchanged') {\n console.log(`${gi.action} .gitignore (neat-out/)`)\n }\n\n let currentProjectName = opts.project\n try {\n const entry = await addProject({\n name: opts.project,\n path: opts.scanPath,\n languages,\n status: 'active',\n })\n currentProjectName = entry.name\n } catch (err) {\n if (!(err instanceof ProjectNameCollisionError)) throw err\n // Same path, same name → re-init. Different path → bail with a clear\n // message so the operator can pass --project <other-name>.\n console.error(`neat: ${err.message}`)\n console.error('pass --project <other-name> to register under a different name.')\n result.exitCode = 1\n return result\n }\n\n // Narrow the active-project surface to what the operator is currently in.\n // Every other `active` entry transitions to `paused`; `broken` is left alone\n // so the daemon's broken-path handling still surfaces. `neat resume <name>`\n // brings any of them back when cross-project work is the explicit intent.\n const siblings = await listProjects()\n const paused: string[] = []\n for (const p of siblings) {\n if (p.name !== currentProjectName && p.status === 'active') {\n await setStatus(p.name, 'paused')\n paused.push(p.name)\n }\n }\n if (paused.length > 0) {\n const plural = paused.length === 1 ? '' : 's'\n console.log(\n `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n )\n }\n\n // ── Step 3: SDK install apply (default yes; --no-instrument skips) ───\n if (!runApply) {\n result.steps.apply.skipped = true\n console.log('skipped instrumentation (--no-instrument)')\n } else {\n const tally = await applyInstallersOver(services, opts.project)\n result.steps.apply = { ...tally, skipped: false }\n console.log(\n `instrumented ${tally.instrumented}, already ${tally.alreadyInstrumented}, lib-only ${tally.libOnly}`,\n )\n const failedInstalls = tally.packageManagerInstalls.filter((i) => i.exitCode !== 0)\n if (failedInstalls.length > 0) {\n result.exitCode = 1\n }\n }\n\n // ── Step 4: daemon spawn + health poll ───────────────────────────────\n const restPort = Number(process.env.PORT ?? 8080)\n const timeoutMs = opts.daemonReadyTimeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS\n if (await checkDaemonHealth(restPort)) {\n result.steps.daemon = 'already-running'\n } else {\n const probe = await probePortsFree()\n if (!probe.free) {\n for (const line of formatPortCollisionMessage(probe.held)) {\n console.error(line)\n }\n result.exitCode = 3\n return result\n }\n try {\n spawnDaemonDetached()\n } catch (err) {\n console.error(`neat: daemon spawn failed — ${(err as Error).message}`)\n result.exitCode = 1\n return result\n }\n const ready = await waitForDaemonReady(restPort, timeoutMs)\n result.steps.daemon = ready.ready ? 'spawned' : 'timed-out'\n if (!ready.ready) {\n console.error(`neat: daemon did not become ready within ${timeoutMs}ms`)\n if (ready.stillBootstrapping.length > 0) {\n console.error(\n `neat: still bootstrapping: ${ready.stillBootstrapping.join(', ')}`,\n )\n }\n if (ready.brokenProjects.length > 0) {\n console.error(`neat: broken projects: ${ready.brokenProjects.join(', ')}`)\n }\n result.exitCode = 1\n return result\n }\n if (ready.brokenProjects.length > 0) {\n console.warn(\n `neat: ${ready.brokenProjects.length} project(s) reported broken: ${ready.brokenProjects.join(', ')}`,\n )\n }\n }\n\n // ── Step 5: browser open ─────────────────────────────────────────────\n const dashboardUrl = opts.dashboardUrl ?? 'http://localhost:6328'\n if (opts.noOpen || !process.stdout.isTTY) {\n result.steps.browser = 'skipped'\n } else {\n result.steps.browser = openBrowser(dashboardUrl)\n }\n\n // ── Step 6: summary (stub — PR 4 replaces with the value-forward shape)\n printSummary(result, graph, dashboardUrl)\n\n return result\n}\n\nfunction printSummary(\n result: OrchestratorResult,\n graph: ReturnType<typeof getGraph>,\n dashboardUrl: string,\n): void {\n const nodes: GraphNode[] = []\n graph.forEachNode((_id, attrs) => nodes.push(attrs))\n const edges: GraphEdge[] = []\n graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n const byNode = new Map<string, number>()\n for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n const byEdge = new Map<string, number>()\n for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n\n console.log('')\n console.log('=== summary ===')\n console.log(`graph: ${graph.order} nodes, ${graph.size} edges`)\n for (const [t, c] of [...byNode.entries()].sort()) console.log(` ${t}: ${c}`)\n for (const [t, c] of [...byEdge.entries()].sort()) console.log(` ${t}: ${c}`)\n console.log('')\n console.log(`dashboard: ${dashboardUrl}`)\n}\n","/**\n * Lifecycle-verb implementations for the CLI. Query verbs live in\n * `cli-client.ts` next to the REST client; lifecycle verbs (currently\n * `neat sync`) live here because they orchestrate filesystem work and\n * daemon-state probes rather than wrapping a single REST endpoint.\n */\n\nimport path from 'node:path'\nimport type { RegistryEntry } from '@neat.is/types'\nimport {\n applyInstallersOver,\n extractAndPersist,\n type ExtractAndPersistResult,\n} from './orchestrator.js'\nimport { listProjects, normalizeProjectPath } from './registry.js'\nimport { saveGraphToDisk, type PersistedGraph } from './persist.js'\nimport {\n HttpError,\n pushSnapshotToRemote,\n resolveAuthToken,\n TransportError,\n} from './cli-client.js'\n\nexport interface SyncOptions {\n // Project name from `--project <name>`. When absent, sync resolves the\n // project by matching the cwd against the registered project paths.\n project?: string\n // Push the snapshot to a remote daemon URL. When absent, sync runs against\n // the local daemon on http://localhost:8080.\n to?: string\n // Bearer token for the remote daemon. Falls back to NEAT_REMOTE_TOKEN env.\n token?: string\n // Skip writing the snapshot or notifying the daemon. Mirrors `neat <path>\n // --dry-run`.\n dryRun: boolean\n // Skip the SDK install apply step.\n noInstrument: boolean\n // Emit a structured JSON payload on stdout instead of human text.\n json: boolean\n // Override the local daemon URL. Defaults to NEAT_API_URL or\n // http://localhost:8080. Useful for tests.\n daemonUrl?: string\n // Working directory the verb resolves against when `--project` isn't\n // passed. Defaults to process.cwd(); tests override.\n cwd?: string\n}\n\nexport interface SyncResult {\n exitCode: number\n // Stable shape across human / json output paths. cli.ts decides which\n // formatter to invoke based on `--json`.\n project: string\n scanPath: string\n nodesAdded: number\n edgesAdded: number\n snapshotPath: string | null\n // Tracks which branch the run took for `--json` consumers.\n mode: 'dry-run' | 'local' | 'remote'\n daemon: 'reloaded' | 'down' | 'remote-ok' | 'skipped'\n apply: {\n instrumented: number\n alreadyInstrumented: number\n libOnly: number\n skipped: boolean\n }\n // Soft warning lines surfaced to stderr in the human path. Empty when the\n // run was fully clean.\n warnings: string[]\n}\n\nasync function resolveProjectEntry(opts: SyncOptions): Promise<RegistryEntry | null> {\n const entries = await listProjects()\n if (opts.project) {\n const match = entries.find((e) => e.name === opts.project)\n return match ?? null\n }\n const cwd = opts.cwd ?? process.cwd()\n const resolvedCwd = await normalizeProjectPath(cwd)\n // Match by path: the cwd must be inside (or equal to) the registered path.\n for (const entry of entries) {\n if (\n resolvedCwd === entry.path ||\n resolvedCwd.startsWith(`${entry.path}${path.sep}`)\n ) {\n return entry\n }\n }\n return null\n}\n\nasync function checkDaemonHealth(baseUrl: string): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl.replace(/\\/$/, '')}/health`, {\n signal: AbortSignal.timeout(1500),\n })\n return res.ok\n } catch {\n return false\n }\n}\n\nfunction snapshotForGraph(persisted: ExtractAndPersistResult): PersistedGraph {\n return {\n schemaVersion: 3,\n exportedAt: new Date().toISOString(),\n graph: persisted.graph.export(),\n }\n}\n\nfunction emitResult(result: SyncResult, json: boolean): void {\n if (json) {\n process.stdout.write(JSON.stringify(result, null, 2) + '\\n')\n return\n }\n const verb =\n result.mode === 'dry-run'\n ? 'dry-run'\n : result.mode === 'remote'\n ? 'pushed'\n : 'synced'\n console.log(\n `${verb}: ${result.project} — ${result.nodesAdded} node(s) and ${result.edgesAdded} edge(s) added` +\n (result.snapshotPath ? `; snapshot at ${result.snapshotPath}` : ''),\n )\n if (!result.apply.skipped) {\n const { instrumented, alreadyInstrumented, libOnly } = result.apply\n console.log(\n `instrumented ${instrumented}, already ${alreadyInstrumented}, lib-only ${libOnly}`,\n )\n } else {\n console.log('skipped instrumentation (--no-instrument)')\n }\n for (const warn of result.warnings) console.error(warn)\n}\n\nexport async function runSync(opts: SyncOptions): Promise<SyncResult> {\n const entry = await resolveProjectEntry(opts)\n if (!entry) {\n const target = opts.project ?? opts.cwd ?? process.cwd()\n console.error(\n `neat sync: no registered project ${\n opts.project ? `named \"${opts.project}\"` : `covers ${target}`\n }. Run \\`neat <path>\\` or \\`neat init <path>\\` first.`,\n )\n return {\n exitCode: 1,\n project: opts.project ?? '',\n scanPath: target,\n nodesAdded: 0,\n edgesAdded: 0,\n snapshotPath: null,\n mode: opts.to ? 'remote' : 'local',\n daemon: 'skipped',\n apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: true },\n warnings: [],\n }\n }\n\n // ── Step 1 + 2: discovery + extraction (no snapshot in dry-run) ─────\n const persisted = await extractAndPersist({\n scanPath: entry.path,\n project: entry.name,\n projectExplicit: true,\n dryRun: true,\n })\n\n let snapshotPath: string | null = null\n if (!opts.dryRun) {\n const target = persisted.snapshotPath\n await saveGraphToDisk(persisted.graph, target)\n snapshotPath = target\n }\n\n // ── Step 3: SDK install apply (default yes; --dry-run + --no-instrument skip)\n const skipApply = opts.dryRun || opts.noInstrument\n const applyTally = skipApply\n ? { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, browserBundle: 0, reactNative: 0 }\n : await applyInstallersOver(persisted.services, entry.name)\n\n // ── Step 4: daemon notify ────────────────────────────────────────────\n const warnings: string[] = []\n let daemonState: SyncResult['daemon'] = 'skipped'\n let exitCode = 0\n const mode: SyncResult['mode'] = opts.dryRun ? 'dry-run' : opts.to ? 'remote' : 'local'\n\n if (!opts.dryRun) {\n const snapshot = snapshotForGraph(persisted)\n if (opts.to) {\n const token = opts.token ?? process.env.NEAT_REMOTE_TOKEN\n try {\n await pushSnapshotToRemote({\n baseUrl: opts.to,\n token,\n project: entry.name,\n snapshot,\n })\n daemonState = 'remote-ok'\n } catch (err) {\n if (err instanceof HttpError) {\n console.error(`neat sync: ${err.message}`)\n exitCode = 1\n } else if (err instanceof TransportError) {\n console.error(`neat sync: ${err.message}`)\n exitCode = 3\n } else {\n console.error(`neat sync: ${(err as Error).message}`)\n exitCode = 1\n }\n daemonState = 'skipped'\n }\n } else {\n const daemonUrl =\n opts.daemonUrl ?? process.env.NEAT_API_URL ?? 'http://localhost:8080'\n const healthy = await checkDaemonHealth(daemonUrl)\n if (healthy) {\n try {\n await pushSnapshotToRemote({\n baseUrl: daemonUrl,\n token: resolveAuthToken(),\n project: entry.name,\n snapshot,\n })\n daemonState = 'reloaded'\n } catch (err) {\n warnings.push(\n `neat sync: daemon merge failed — ${(err as Error).message}. Snapshot is on disk at ${snapshotPath}.`,\n )\n daemonState = 'down'\n exitCode = 2\n }\n } else {\n warnings.push(\n 'neat sync: daemon not running; snapshot updated, run `neatd start` to serve it',\n )\n daemonState = 'down'\n exitCode = 2\n }\n }\n }\n\n const result: SyncResult = {\n exitCode,\n project: entry.name,\n scanPath: entry.path,\n nodesAdded: persisted.nodesAdded,\n edgesAdded: persisted.edgesAdded,\n snapshotPath,\n mode,\n daemon: daemonState,\n apply: { ...applyTally, skipped: skipApply },\n warnings,\n }\n\n emitResult(result, opts.json)\n return result\n}\n","// REST helper + CLI verb implementations for `neat <verb>` (ADR-050).\n//\n// The HttpClient and its createHttpClient factory are the \"shared REST helper\n// module\" the contract calls for — one endpoint surface, two consumers\n// (`packages/mcp/src/client.ts` re-exports from here, the CLI dispatcher\n// imports it directly).\n//\n// Verb handlers live alongside the client because they're tightly coupled:\n// each verb maps 1:1 to an MCP tool from ADR-039, but produces the structured\n// `{ summary, block, confidence, provenance }` shape (ADR-050 #3) in pure\n// data form. cli.ts formats that shape into either human-readable text or\n// `--json` output.\n\nimport type {\n BlastRadiusAffectedNode,\n BlastRadiusResult,\n Divergence,\n DivergenceResult,\n DivergenceType,\n ErrorEvent,\n GraphEdge,\n GraphNode,\n HypotheticalAction,\n PolicyViolation,\n RootCauseResult,\n TransitiveDependenciesResult,\n} from '@neat.is/types'\nimport { Provenance } from '@neat.is/types'\n\n// ──────────────────────────────────────────────────────────────────────────\n// REST client\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface HttpClient {\n get<T>(path: string): Promise<T>\n post?<T>(path: string, body: unknown): Promise<T>\n}\n\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly responseBody: string = '',\n ) {\n super(message)\n this.name = 'HttpError'\n }\n}\n\n// Network-level failures (ECONNREFUSED, ETIMEDOUT, DNS) — distinct from\n// HttpError so the CLI can map them to exit code 3 (daemon-down) without\n// parsing error strings.\nexport class TransportError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'TransportError'\n }\n}\n\n// Single-source the bearer for every first-party read (ADR-073 §3). The CLI\n// query verbs, `neat sync`, the MCP server, and the snapshot push all read the\n// token from here so a new read site can't quietly skip auth. Returns\n// undefined when the env var is unset or empty — a loopback dev daemon stays\n// reachable without a token.\nexport function resolveAuthToken(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const t = env.NEAT_AUTH_TOKEN\n return t && t.length > 0 ? t : undefined\n}\n\nexport function createHttpClient(baseUrl: string, bearerToken?: string): HttpClient {\n const root = baseUrl.replace(/\\/$/, '')\n const authHeader = bearerToken && bearerToken.length > 0\n ? { authorization: `Bearer ${bearerToken}` }\n : {}\n return {\n async get<T>(path: string): Promise<T> {\n let res: Response\n try {\n res = await fetch(`${root}${path}`, {\n headers: { ...authHeader },\n })\n } catch (err) {\n throw new TransportError(\n `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n )\n }\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n throw new HttpError(\n res.status,\n `${res.status} ${res.statusText} on GET ${path}: ${body}`,\n body,\n )\n }\n return (await res.json()) as T\n },\n async post<T>(path: string, body: unknown): Promise<T> {\n let res: Response\n try {\n res = await fetch(`${root}${path}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...authHeader },\n body: JSON.stringify(body),\n })\n } catch (err) {\n throw new TransportError(\n `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n )\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new HttpError(\n res.status,\n `${res.status} ${res.statusText} on POST ${path}: ${text}`,\n text,\n )\n }\n return (await res.json()) as T\n },\n }\n}\n\n// Project routing per ADR-050 #2: `--project <name>` (handled in cli.ts) →\n// `NEAT_PROJECT` env → `default`. The default routes hit the legacy\n// unprefixed URLs which the core resolves to project=`default`.\nfunction projectPath(project: string | undefined, suffix: string): string {\n if (!project) return suffix\n return `/projects/${encodeURIComponent(project)}${suffix}`\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verb result shape (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface VerbResult {\n // NL paragraph. What was found and why it matters.\n summary: string\n // Structured payload — usually a bulleted list. Empty when the summary\n // already conveys everything.\n block?: string\n // Per-result confidence in [0, 1]. Undefined → footer reads \"n/a\".\n confidence?: number\n // Per-result provenance. String, array (mixed paths), or undefined.\n provenance?: string | string[]\n}\n\n// Common shape the nine verbs produce. cli.ts renders this to text or JSON.\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verbs\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface RootCauseInput {\n errorNode: string\n errorId?: string\n project?: string\n}\n\nexport async function runRootCause(\n client: HttpClient,\n input: RootCauseInput,\n): Promise<VerbResult> {\n const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : ''\n const path = projectPath(\n input.project,\n `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`,\n )\n try {\n const result = await client.get<RootCauseResult>(path)\n const arrowPath = result.traversalPath.join(' ← ')\n const provenances = result.edgeProvenances.length\n ? result.edgeProvenances.join(', ')\n : '(direct, no edges traversed)'\n const summary =\n `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` +\n result.rootCauseReason +\n (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : '')\n const blockLines = [\n `Traversal path: ${arrowPath}`,\n `Edge provenances: ${provenances}`,\n ]\n if (result.fixRecommendation) blockLines.push(`Recommended fix: ${result.fixRecommendation}`)\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: result.confidence,\n provenance: result.edgeProvenances.length ? result.edgeProvenances : undefined,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return {\n summary: `No root cause found for ${input.errorNode}. The node may be healthy, or it may not exist in the graph.`,\n }\n }\n throw err\n }\n}\n\nexport interface BlastRadiusInput {\n nodeId: string\n depth?: number\n project?: string\n}\n\nexport async function runBlastRadius(\n client: HttpClient,\n input: BlastRadiusInput,\n): Promise<VerbResult> {\n const qs = input.depth !== undefined ? `?depth=${input.depth}` : ''\n const path = projectPath(\n input.project,\n `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`,\n )\n try {\n const result = await client.get<BlastRadiusResult>(path)\n if (result.totalAffected === 0) {\n return {\n summary: `${result.origin} has no downstream dependencies. Nothing else would break if it failed.`,\n }\n }\n const sorted = [...result.affectedNodes].sort(\n (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n )\n const blockLines = sorted.map(formatBlastEntry)\n const minConfidence = sorted.reduce(\n (m, n) => Math.min(m, n.confidence),\n Number.POSITIVE_INFINITY,\n )\n const provenances = [...new Set(sorted.map((n) => n.edgeProvenance))]\n return {\n summary: `Blast radius for ${result.origin}: ${result.totalAffected} affected node${result.totalAffected === 1 ? '' : 's'} reachable downstream.`,\n block: blockLines.join('\\n'),\n confidence: Number.isFinite(minConfidence) ? minConfidence : undefined,\n provenance: provenances.length ? provenances : undefined,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\nfunction formatBlastEntry(n: BlastRadiusAffectedNode): string {\n const tag = n.edgeProvenance === Provenance.STALE ? ' [STALE — last seen too long ago]' : ''\n return ` • ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`\n}\n\nexport interface DependenciesInput {\n nodeId: string\n depth?: number\n project?: string\n}\n\nexport async function runDependencies(\n client: HttpClient,\n input: DependenciesInput,\n): Promise<VerbResult> {\n const depth = input.depth ?? 3\n const path = projectPath(\n input.project,\n `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`,\n )\n try {\n const result = await client.get<TransitiveDependenciesResult>(path)\n if (result.total === 0) {\n return {\n summary:\n depth === 1\n ? `${input.nodeId} has no direct dependencies in the graph.`\n : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`,\n }\n }\n const byDistance = new Map<number, typeof result.dependencies>()\n for (const dep of result.dependencies) {\n const ring = byDistance.get(dep.distance) ?? []\n ring.push(dep)\n byDistance.set(dep.distance, ring)\n }\n const blockLines: string[] = []\n for (const distance of [...byDistance.keys()].sort((a, b) => a - b)) {\n const label = distance === 1 ? 'Direct (distance 1)' : `Distance ${distance}`\n blockLines.push(`${label}:`)\n for (const dep of byDistance.get(distance)!) {\n blockLines.push(` • ${dep.nodeId} — ${dep.edgeType} (${dep.provenance})`)\n }\n }\n const provenances = [...new Set(result.dependencies.map((d) => d.provenance))]\n const directCount = byDistance.get(1)?.length ?? 0\n const summary =\n depth === 1\n ? `${input.nodeId} has ${directCount} direct dependenc${directCount === 1 ? 'y' : 'ies'}.`\n : `${input.nodeId} has ${result.total} dependenc${result.total === 1 ? 'y' : 'ies'} reachable to depth ${depth} (${directCount} direct).`\n return { summary, block: blockLines.join('\\n'), provenance: provenances }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\ninterface EdgesResponse {\n inbound: GraphEdge[]\n outbound: GraphEdge[]\n}\n\nexport async function runObservedDependencies(\n client: HttpClient,\n input: DependenciesInput,\n): Promise<VerbResult> {\n try {\n const edges = await client.get<EdgesResponse>(\n projectPath(input.project, `/graph/edges/${encodeURIComponent(input.nodeId)}`),\n )\n const observed = edges.outbound.filter((e) => e.provenance === Provenance.OBSERVED)\n if (observed.length === 0) {\n const hasExtracted = edges.outbound.some((e) => e.provenance === Provenance.EXTRACTED)\n const note = hasExtracted\n ? ' Static (EXTRACTED) dependencies exist but no runtime traffic has been seen — is OTel running?'\n : ''\n return { summary: `No OBSERVED dependencies for ${input.nodeId}.${note}` }\n }\n const blockLines = observed.map((e) => ` • ${e.target} — ${e.type}${edgeMeta(e)}`)\n return {\n summary: `${input.nodeId} has ${observed.length} runtime dependenc${observed.length === 1 ? 'y' : 'ies'} confirmed by OTel.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.OBSERVED,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId} not found in the graph.` }\n }\n throw err\n }\n}\n\nfunction edgeMeta(e: GraphEdge): string {\n const bits: string[] = []\n if (e.signal) {\n bits.push(`spans=${e.signal.spanCount}`)\n if (e.signal.errorCount > 0) bits.push(`errors=${e.signal.errorCount}`)\n if (e.signal.lastObservedAgeMs !== undefined) {\n bits.push(`age=${formatDuration(e.signal.lastObservedAgeMs)}`)\n }\n } else if (e.callCount !== undefined) {\n bits.push(`callCount=${e.callCount}`)\n }\n if (e.lastObserved) bits.push(`lastObserved=${e.lastObserved}`)\n if (e.confidence !== undefined) bits.push(`confidence=${e.confidence}`)\n return bits.length ? ` [${bits.join(', ')}]` : ''\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`\n const s = Math.round(ms / 1000)\n if (s < 60) return `${s}s`\n const m = Math.round(s / 60)\n if (m < 60) return `${m}m`\n const h = Math.round(m / 60)\n if (h < 48) return `${h}h`\n return `${Math.round(h / 24)}d`\n}\n\nexport interface IncidentsInput {\n nodeId?: string\n limit?: number\n project?: string\n}\n\n// `neat incidents` shape: with a node id, returns that node's incidents.\n// Without one, returns the global recent log.\nexport async function runIncidents(\n client: HttpClient,\n input: IncidentsInput,\n): Promise<VerbResult> {\n const path = input.nodeId\n ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`)\n : projectPath(input.project, '/incidents')\n try {\n const body = await client.get<{ count: number; total: number; events: ErrorEvent[] }>(path)\n const events = body.events\n if (events.length === 0) {\n return {\n summary: input.nodeId\n ? `No incidents recorded against ${input.nodeId}.`\n : 'No incidents recorded.',\n }\n }\n const ordered = [...events].reverse().slice(0, input.limit ?? 20)\n const blockLines: string[] = []\n for (const ev of ordered) {\n blockLines.push(` ${ev.timestamp} — ${ev.service}: ${ev.errorMessage}`)\n blockLines.push(` trace=${ev.traceId} span=${ev.spanId}`)\n }\n const target = input.nodeId ?? 'the project'\n return {\n summary: `${target} has ${body.total} recorded incident${body.total === 1 ? '' : 's'}; showing the ${ordered.length} most recent.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.OBSERVED,\n }\n } catch (err) {\n if (err instanceof HttpError && err.status === 404) {\n return { summary: `Node ${input.nodeId ?? ''} not found in the graph.` }\n }\n throw err\n }\n}\n\nexport interface SearchInput {\n query: string\n project?: string\n}\n\ninterface SearchResponse {\n query: string\n provider?: 'ollama' | 'transformers' | 'substring'\n matches: (GraphNode & { score?: number })[]\n}\n\nexport async function runSearch(\n client: HttpClient,\n input: SearchInput,\n): Promise<VerbResult> {\n const result = await client.get<SearchResponse>(\n projectPath(input.project, `/search?q=${encodeURIComponent(input.query)}`),\n )\n if (result.matches.length === 0) {\n return { summary: `No matches for \"${input.query}\".` }\n }\n const provider = result.provider ?? 'substring'\n const blockLines: string[] = []\n let topScore: number | undefined\n for (const n of result.matches) {\n const score = provider !== 'substring' && typeof n.score === 'number' ? n.score : undefined\n const scoreBit = score !== undefined ? ` [score=${score.toFixed(2)}]` : ''\n if (score !== undefined && (topScore === undefined || score > topScore)) topScore = score\n blockLines.push(\n ` • ${n.id} (${n.type}) — ${(n as { name?: string }).name ?? n.id}${scoreBit}`,\n )\n }\n return {\n summary: `Found ${result.matches.length} match${result.matches.length === 1 ? '' : 'es'} for \"${input.query}\" via ${provider} provider.`,\n block: blockLines.join('\\n'),\n confidence: topScore,\n }\n}\n\nexport interface DiffInput {\n againstSnapshot: string\n project?: string\n}\n\ninterface GraphDiffResponse {\n base: { exportedAt?: string }\n current: { exportedAt: string }\n added: { nodes: GraphNode[]; edges: GraphEdge[] }\n removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n changed: {\n nodes: { id: string; before: GraphNode; after: GraphNode }[]\n edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n }\n}\n\nexport async function runDiff(client: HttpClient, input: DiffInput): Promise<VerbResult> {\n const result = await client.get<GraphDiffResponse>(\n projectPath(\n input.project,\n `/graph/diff?against=${encodeURIComponent(input.againstSnapshot)}`,\n ),\n )\n const total =\n result.added.nodes.length +\n result.added.edges.length +\n result.removed.nodes.length +\n result.removed.edges.length +\n result.changed.nodes.length +\n result.changed.edges.length\n const baseLabel = result.base.exportedAt ?? 'unknown'\n if (total === 0) {\n return {\n summary: `No differences between the current graph and ${input.againstSnapshot} (base exportedAt=${baseLabel}).`,\n }\n }\n const blockLines: string[] = [\n ` base exportedAt: ${baseLabel}`,\n ` current exportedAt: ${result.current.exportedAt}`,\n '',\n ]\n if (result.added.nodes.length || result.added.edges.length) {\n blockLines.push('Added:')\n for (const n of result.added.nodes) blockLines.push(` + node ${n.id} (${n.type})`)\n for (const e of result.added.edges)\n blockLines.push(` + edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n blockLines.push('')\n }\n if (result.removed.nodes.length || result.removed.edges.length) {\n blockLines.push('Removed:')\n for (const n of result.removed.nodes) blockLines.push(` - node ${n.id} (${n.type})`)\n for (const e of result.removed.edges)\n blockLines.push(` - edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n blockLines.push('')\n }\n if (result.changed.nodes.length || result.changed.edges.length) {\n blockLines.push('Changed:')\n for (const c of result.changed.nodes) {\n blockLines.push(` ~ node ${c.id} — ${summariseAttrDiff(c.before, c.after)}`)\n }\n for (const c of result.changed.edges) {\n const provBit =\n c.before.provenance !== c.after.provenance\n ? `provenance ${c.before.provenance} → ${c.after.provenance}`\n : summariseAttrDiff(c.before, c.after)\n blockLines.push(` ~ edge ${c.id} — ${provBit}`)\n }\n }\n return {\n summary: `Diff against ${input.againstSnapshot}: ${total} change${total === 1 ? '' : 's'} between the snapshot and the live graph.`,\n block: blockLines.join('\\n').trimEnd(),\n }\n}\n\nfunction summariseAttrDiff(\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): string {\n const keys = new Set([...Object.keys(before), ...Object.keys(after)])\n const changed: string[] = []\n for (const k of keys) {\n if (JSON.stringify(before[k]) !== JSON.stringify(after[k])) changed.push(k)\n }\n return changed.length === 0 ? 'attributes differ' : `fields changed: ${changed.sort().join(', ')}`\n}\n\nexport interface StaleEdgesInput {\n limit?: number\n edgeType?: string\n project?: string\n}\n\ninterface StaleEventResponse {\n edgeId: string\n source: string\n target: string\n edgeType: string\n thresholdMs: number\n ageMs: number\n lastObserved: string\n transitionedAt: string\n}\n\nexport async function runStaleEdges(\n client: HttpClient,\n input: StaleEdgesInput,\n): Promise<VerbResult> {\n const params = new URLSearchParams()\n if (input.limit !== undefined) params.set('limit', String(input.limit))\n if (input.edgeType) params.set('edgeType', input.edgeType)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const body = await client.get<{ count: number; total: number; events: StaleEventResponse[] }>(\n projectPath(input.project, `/stale-events${qs}`),\n )\n const events = body.events\n if (events.length === 0) {\n return {\n summary: input.edgeType\n ? `No stale ${input.edgeType} edges recorded.`\n : 'No stale-edge transitions recorded yet.',\n }\n }\n const blockLines = events.map(\n (e) =>\n ` ${e.transitionedAt} — ${e.source} -[${e.edgeType}]-> ${e.target}` +\n ` (last seen ${e.lastObserved}, threshold ${formatDuration(e.thresholdMs)})`,\n )\n return {\n summary: `${events.length} stale-edge transition${events.length === 1 ? '' : 's'} recorded${input.edgeType ? ` for ${input.edgeType}` : ''}.`,\n block: blockLines.join('\\n'),\n provenance: Provenance.STALE,\n }\n}\n\nexport interface PoliciesInput {\n nodeId?: string\n policyId?: string\n hypotheticalAction?: HypotheticalAction\n project?: string\n}\n\ninterface PoliciesCheckResponse {\n allowed: boolean\n hypotheticalAction?: HypotheticalAction\n violations: PolicyViolation[]\n}\n\nexport async function runPolicies(\n client: HttpClient,\n input: PoliciesInput,\n): Promise<VerbResult> {\n let violations: PolicyViolation[]\n let allowed = true\n let hypothetical: HypotheticalAction | undefined\n\n if (input.hypotheticalAction) {\n if (typeof client.post !== 'function') {\n throw new Error('HttpClient does not support POST — required for policies dry-run')\n }\n const body = await client.post<PoliciesCheckResponse>(\n projectPath(input.project, '/policies/check'),\n { hypotheticalAction: input.hypotheticalAction },\n )\n violations = body.violations\n allowed = body.allowed\n hypothetical = body.hypotheticalAction\n } else {\n const params = new URLSearchParams()\n if (input.policyId) params.set('policyId', input.policyId)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const body = await client.get<{ violations: PolicyViolation[] }>(\n projectPath(input.project, `/policies/violations${qs}`),\n )\n violations = body.violations\n allowed = violations.every((v) => v.onViolation !== 'block')\n }\n\n // Optional --node filter is applied here against the returned set; the\n // server-side endpoint doesn't take a node-id query yet.\n if (input.nodeId) {\n violations = violations.filter(\n (v) => v.subject.nodeId === input.nodeId || v.subject.path?.includes(input.nodeId!),\n )\n }\n\n if (violations.length === 0) {\n return {\n summary: hypothetical\n ? `No violations would result from the hypothetical action (${hypothetical.kind}).`\n : 'No policy violations recorded.',\n }\n }\n\n const blockCount = violations.filter((v) => v.onViolation === 'block').length\n const summaryParts: string[] = []\n if (hypothetical) {\n summaryParts.push(\n `Hypothetical ${hypothetical.kind} would surface ${violations.length} violation${violations.length === 1 ? '' : 's'}`,\n )\n } else {\n summaryParts.push(\n `${violations.length} policy violation${violations.length === 1 ? '' : 's'} currently recorded`,\n )\n }\n if (blockCount > 0) summaryParts.push(`${blockCount} of which block`)\n if (!allowed && hypothetical) summaryParts.push('action denied')\n const summary = summaryParts.join('; ') + '.'\n\n const blockLines = violations.map((v) => {\n const subject = v.subject.nodeId ?? v.subject.edgeId ?? v.subject.path?.[0] ?? '(global)'\n return ` • [${v.severity}/${v.onViolation}] ${v.policyName}: ${v.message} — ${subject}`\n })\n const severities = [...new Set(violations.map((v) => v.severity))]\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: hypothetical ? 0.7 : 1,\n provenance: severities.join(' '),\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// divergences (ADR-060) — the tenth verb. Amends ADR-050's nine-verb\n// allowlist; the verb mirrors the get_divergences MCP tool.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface DivergencesInput {\n type?: ReadonlyArray<DivergenceType>\n minConfidence?: number\n node?: string\n project?: string\n}\n\nfunction formatDivergenceLine(d: Divergence): string {\n switch (d.type) {\n case 'missing-observed':\n case 'missing-extracted':\n return ` • [${d.type}] ${d.source} → ${d.target} (${d.edgeType}) — confidence ${d.confidence.toFixed(2)}`\n case 'version-mismatch':\n return ` • [${d.type}] ${d.source} → ${d.target} — declared ${d.extractedVersion}, observed engine ${d.observedVersion} (${d.compatibility})`\n case 'host-mismatch':\n return ` • [${d.type}] ${d.source} → ${d.target} — declared host ${d.extractedHost}, observed host ${d.observedHost}`\n case 'compat-violation':\n return ` • [${d.type}] ${d.source} → ${d.target} — ${d.rule.kind}${d.rule.package ? ` (${d.rule.package})` : ''}`\n }\n}\n\nexport async function runDivergences(\n client: HttpClient,\n input: DivergencesInput,\n): Promise<VerbResult> {\n const params = new URLSearchParams()\n if (input.type && input.type.length > 0) params.set('type', input.type.join(','))\n if (input.minConfidence !== undefined) {\n params.set('minConfidence', String(input.minConfidence))\n }\n if (input.node) params.set('node', input.node)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n const result = await client.get<DivergenceResult>(\n projectPath(input.project, `/graph/divergences${qs}`),\n )\n if (result.totalAffected === 0) {\n return {\n summary:\n 'No divergences found between the declared (EXTRACTED) and observed (OBSERVED) views of the graph.',\n }\n }\n const headline = result.divergences[0]!\n const summary =\n `Found ${result.totalAffected} divergence${result.totalAffected === 1 ? '' : 's'} between code and production. ` +\n `Highest-confidence: ${headline.type} on ${headline.source} → ${headline.target}. ${headline.reason}`\n const blockLines: string[] = []\n for (const d of result.divergences) {\n blockLines.push(formatDivergenceLine(d))\n blockLines.push(` reason: ${d.reason}`)\n blockLines.push(` recommendation: ${d.recommendation}`)\n }\n const maxConfidence = result.divergences.reduce(\n (m, d) => Math.max(m, d.confidence),\n 0,\n )\n return {\n summary,\n block: blockLines.join('\\n'),\n confidence: maxConfidence,\n provenance: 'composite (EXTRACTED + OBSERVED)',\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Output formatting (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction formatFooter(\n confidence: number | undefined,\n provenance: string | string[] | undefined,\n): string {\n const c = confidence === undefined ? 'n/a' : confidence.toFixed(2)\n const p =\n provenance === undefined\n ? 'n/a'\n : Array.isArray(provenance)\n ? [...new Set(provenance)].join(', ')\n : provenance\n return `confidence: ${c} · provenance: ${p}`\n}\n\n// Default human output (NL summary + table-shaped block + footer). Mirrors\n// the three-part MCP response from ADR-039 in plain text.\nexport function formatHuman(result: VerbResult): string {\n const sections: string[] = [result.summary.trim()]\n if (result.block && result.block.trim().length > 0) sections.push(result.block.trimEnd())\n sections.push(formatFooter(result.confidence, result.provenance))\n return sections.join('\\n\\n')\n}\n\n// `--json` output. Same three sections as named fields per ADR-050 #3.\nexport function formatJson(result: VerbResult): string {\n return JSON.stringify(\n {\n summary: result.summary,\n block: result.block ?? '',\n confidence: result.confidence ?? null,\n provenance: result.provenance ?? null,\n },\n null,\n 2,\n )\n}\n\n// Exit-code mapping for thrown errors (ADR-050 #4):\n// 0 — success (handled at the call site, never via throw)\n// 1 — server error (HttpError)\n// 2 — misuse (handled in cli.ts before any network call)\n// 3 — daemon unreachable (TransportError)\nexport function exitCodeForError(err: unknown): number {\n if (err instanceof TransportError) return 3\n if (err instanceof HttpError) return 1\n return 1\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot push (ADR-074 §1)\n//\n// `neat sync` (local + --to <url>) feeds the freshly extracted snapshot into\n// either the local daemon or a remote one. The endpoint is dual-mounted via\n// registerRoutes — default project lands at /snapshot, named projects at\n// /projects/:project/snapshot. The helper goes through the shared\n// HttpClient so the verb stays on the same network path as every query verb.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface PushSnapshotInput {\n baseUrl: string\n token: string | undefined\n project: string\n snapshot: unknown\n}\n\nexport interface PushSnapshotResult {\n project: string\n nodesAdded: number\n edgesAdded: number\n nodeCount: number\n edgeCount: number\n}\n\nexport function createSnapshotPushClient(\n baseUrl: string,\n token: string | undefined,\n): HttpClient {\n return createHttpClient(baseUrl, token && token.length > 0 ? token : undefined)\n}\n\nexport async function pushSnapshotToRemote(\n input: PushSnapshotInput,\n): Promise<PushSnapshotResult> {\n const client = createSnapshotPushClient(input.baseUrl, input.token)\n if (typeof client.post !== 'function') {\n throw new Error('HttpClient does not support POST — required for snapshot push')\n }\n return client.post<PushSnapshotResult>(\n `/projects/${encodeURIComponent(input.project)}/snapshot`,\n { snapshot: input.snapshot },\n )\n}\n"],"mappings":"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","names":["path","path","import_node_path","import_node_crypto","path","protobuf","reshapeGrpcRequest","Fastify","import_node_path","import_node_url","import_fastify","import_node_path","import_node_fs","import_node_url","GraphDefault","import_node_fs","import_node_path","import_node_fs","import_node_path","import_types","path","os","semver","fs","path","serviceId","frontierId","fs","path","import_types","path","entry","fs","path","frontierId","serviceId","fs","path","import_node_fs","import_node_path","import_minimatch","import_types","import_node_fs","import_node_path","import_types","fs","path","parseYaml","import_node_fs","import_node_path","entry","path","fs","parseToml","import_node_fs","import_node_path","path","fs","import_node_fs","import_node_path","fs","path","fs","path","path","fs","ignore","entry","import_node_path","import_node_fs","import_yaml","import_types","serviceId","path","fs","entry","import_node_fs","import_node_path","import_types","fs","entry","path","toPosix","import_node_path","toPosix","path","import_node_path","import_node_fs","import_types","Parser","JavaScript","Python","fs","path","toPosix","snippet","import_node_path","import_types","import_node_path","path","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","path","parse","fs","entry","path","import_node_path","parse","path","parse","parse","import_node_path","parse","path","entry","parse","import_node_path","parse","path","entry","import_node_path","parse","path","toPosix","path","import_node_fs","import_node_path","import_types","fs","entry","path","toPosix","import_types","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_tree_sitter_python","import_types","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","makePyParser","Python","path","toPosix","import_node_path","import_types","path","import_node_path","import_types","path","import_node_path","import_types","findAll","path","import_node_path","import_types","path","toPosix","http","import_node_path","import_types","import_types","path","import_node_path","import_node_fs","import_types","path","fs","toPosix","import_node_fs","import_node_path","fs","entry","path","import_node_fs","import_node_path","import_yaml","walkYamlFiles","fs","entry","path","import_node_path","import_node_fs","import_node_path","import_types","path","path","import_types","import_node_fs","import_node_path","import_types","fs","path","import_node_fs","import_node_path","path","fs","import_types","import_node_fs","import_node_path","import_types","import_node_fs","import_node_path","import_node_os","import_node_fs","import_node_path","exists","fs","path","fileExists","fs","path","os","entry","snippet","allDeps","registryResolve","registryList","import_node_fs","fs","entry","import_node_path","path","import_node_fs","import_node_os","import_node_path","import_types","path","os","fs","entry","status","violations","blocking","Fastify","cors","entry","import_node_fs","import_node_path","import_node_crypto","fs","path","entry","idx","path","fs","chokidar","import_node_fs","import_node_path","import_node_child_process","import_node_crypto","renderOtelEnvBlock","path","fs","import_node_fs","import_node_path","import_semver","path","fs","exists","readPackageJson","semver","import_node_fs","import_node_path","SDK_PACKAGES","OTEL_ENV","exists","fs","detect","path","plan","apply","rollback","plan","plan","import_node_fs","import_node_path","import_node_child_process","path","plan","readline","http","entry","projects","net","fs","import_node_path","import_types","status","path","entry","path","checkDaemonHealth","import_types","path","plan","fs","entry","snippet","apply","renderOtelEnvBlock"]}
|