@neat.is/core 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/neatd.js CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startDaemon
4
- } from "./chunk-6JT6L2OV.js";
4
+ } from "./chunk-HWO746IM.js";
5
5
  import {
6
6
  listProjects,
7
7
  registryPath
8
- } from "./chunk-WX55TLUT.js";
9
- import "./chunk-6SFEITLJ.js";
8
+ } from "./chunk-GAYTAGEH.js";
10
9
 
11
10
  // src/neatd.ts
12
11
  import { promises as fs } from "fs";
package/dist/neatd.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/neatd.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `neatd` — distribution-layer daemon CLI (ADR-049).\n *\n * Subcommands:\n * neatd start [--foreground] boot the daemon and watch the registry\n * neatd stop signal the running daemon to shut down\n * neatd reload signal the running daemon to re-read the registry\n * neatd status print PID + per-project last-seen timestamps\n *\n * MVP runs in foreground only. Backgrounding is the supervisor's job\n * (launchd / systemd / nohup) — `neatd start` blocks until SIGINT/SIGTERM.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { startDaemon } from './daemon.js'\nimport { listProjects, registryPath } from './registry.js'\n\nfunction neatHome(): string {\n if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {\n return path.resolve(process.env.NEAT_HOME)\n }\n const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n return path.join(home, '.neat')\n}\n\nasync function readPid(): Promise<number | null> {\n try {\n const raw = await fs.readFile(path.join(neatHome(), 'neatd.pid'), 'utf8')\n const n = Number.parseInt(raw.trim(), 10)\n return Number.isFinite(n) ? n : null\n } catch {\n return null\n }\n}\n\nfunction usage(): void {\n console.log('usage: neatd <start|stop|reload|status> [--foreground]')\n}\n\nasync function cmdStart(): Promise<void> {\n const handle = await startDaemon()\n console.log(`neatd: started, PID ${process.pid}, ${handle.slots.size} project(s)`)\n console.log(`neatd: registry at ${registryPath()}`)\n console.log('neatd: SIGHUP reloads, SIGTERM/SIGINT stops')\n\n let stopping = false\n const shutdown = (signal: NodeJS.Signals): void => {\n if (stopping) return\n stopping = true\n console.log(`neatd: ${signal} received, stopping…`)\n void handle\n .stop()\n .catch((err) => console.error(`neatd: shutdown error — ${(err as Error).message}`))\n .finally(() => process.exit(0))\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n\n // Block forever — supervisors keep us in the foreground.\n await new Promise<void>(() => {})\n}\n\nasync function cmdStop(): Promise<void> {\n const pid = await readPid()\n if (pid === null) {\n console.error('neatd: no running daemon found (no PID file)')\n process.exit(1)\n }\n try {\n process.kill(pid, 'SIGTERM')\n console.log(`neatd: SIGTERM sent to PID ${pid}`)\n } catch (err) {\n console.error(`neatd: failed to signal PID ${pid} — ${(err as Error).message}`)\n process.exit(1)\n }\n}\n\nasync function cmdReload(): Promise<void> {\n const pid = await readPid()\n if (pid === null) {\n console.error('neatd: no running daemon found (no PID file)')\n process.exit(1)\n }\n try {\n process.kill(pid, 'SIGHUP')\n console.log(`neatd: SIGHUP sent to PID ${pid}`)\n } catch (err) {\n console.error(`neatd: failed to signal PID ${pid} — ${(err as Error).message}`)\n process.exit(1)\n }\n}\n\nasync function cmdStatus(): Promise<void> {\n const pid = await readPid()\n console.log(`pid: ${pid ?? '(not running)'}`)\n console.log(`registry: ${registryPath()}`)\n const projects = await listProjects().catch(() => [])\n if (projects.length === 0) {\n console.log('projects: (none)')\n return\n }\n console.log('projects:')\n for (const p of projects) {\n const seen = p.lastSeenAt ?? 'never'\n console.log(` ${p.name}\\t${p.status}\\t${p.path}\\tlast-seen=${seen}`)\n }\n}\n\nasync function main(): Promise<void> {\n const cmd = process.argv[2]\n if (!cmd || cmd === '-h' || cmd === '--help') {\n usage()\n process.exit(cmd ? 0 : 2)\n }\n\n if (cmd === 'start') return cmdStart()\n if (cmd === 'stop') return cmdStop()\n if (cmd === 'reload') return cmdReload()\n if (cmd === 'status') return cmdStatus()\n\n console.error(`neatd: unknown command \"${cmd}\"`)\n usage()\n process.exit(1)\n}\n\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/]neatd\\.(?:cjs|js)$/.test(entry) || entry.endsWith('/neatd')) {\n main().catch((err) => {\n console.error(err)\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/neatd.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `neatd` — distribution-layer daemon CLI (ADR-049).\n *\n * Subcommands:\n * neatd start [--foreground] boot the daemon and watch the registry\n * neatd stop signal the running daemon to shut down\n * neatd reload signal the running daemon to re-read the registry\n * neatd status print PID + per-project last-seen timestamps\n *\n * MVP runs in foreground only. Backgrounding is the supervisor's job\n * (launchd / systemd / nohup) — `neatd start` blocks until SIGINT/SIGTERM.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { startDaemon } from './daemon.js'\nimport { listProjects, registryPath } from './registry.js'\n\nfunction neatHome(): string {\n if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {\n return path.resolve(process.env.NEAT_HOME)\n }\n const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n return path.join(home, '.neat')\n}\n\nasync function readPid(): Promise<number | null> {\n try {\n const raw = await fs.readFile(path.join(neatHome(), 'neatd.pid'), 'utf8')\n const n = Number.parseInt(raw.trim(), 10)\n return Number.isFinite(n) ? n : null\n } catch {\n return null\n }\n}\n\nfunction usage(): void {\n console.log('usage: neatd <start|stop|reload|status> [--foreground]')\n}\n\nasync function cmdStart(): Promise<void> {\n const handle = await startDaemon()\n console.log(`neatd: started, PID ${process.pid}, ${handle.slots.size} project(s)`)\n console.log(`neatd: registry at ${registryPath()}`)\n console.log('neatd: SIGHUP reloads, SIGTERM/SIGINT stops')\n\n let stopping = false\n const shutdown = (signal: NodeJS.Signals): void => {\n if (stopping) return\n stopping = true\n console.log(`neatd: ${signal} received, stopping…`)\n void handle\n .stop()\n .catch((err) => console.error(`neatd: shutdown error — ${(err as Error).message}`))\n .finally(() => process.exit(0))\n }\n process.on('SIGTERM', shutdown)\n process.on('SIGINT', shutdown)\n\n // Block forever — supervisors keep us in the foreground.\n await new Promise<void>(() => {})\n}\n\nasync function cmdStop(): Promise<void> {\n const pid = await readPid()\n if (pid === null) {\n console.error('neatd: no running daemon found (no PID file)')\n process.exit(1)\n }\n try {\n process.kill(pid, 'SIGTERM')\n console.log(`neatd: SIGTERM sent to PID ${pid}`)\n } catch (err) {\n console.error(`neatd: failed to signal PID ${pid} — ${(err as Error).message}`)\n process.exit(1)\n }\n}\n\nasync function cmdReload(): Promise<void> {\n const pid = await readPid()\n if (pid === null) {\n console.error('neatd: no running daemon found (no PID file)')\n process.exit(1)\n }\n try {\n process.kill(pid, 'SIGHUP')\n console.log(`neatd: SIGHUP sent to PID ${pid}`)\n } catch (err) {\n console.error(`neatd: failed to signal PID ${pid} — ${(err as Error).message}`)\n process.exit(1)\n }\n}\n\nasync function cmdStatus(): Promise<void> {\n const pid = await readPid()\n console.log(`pid: ${pid ?? '(not running)'}`)\n console.log(`registry: ${registryPath()}`)\n const projects = await listProjects().catch(() => [])\n if (projects.length === 0) {\n console.log('projects: (none)')\n return\n }\n console.log('projects:')\n for (const p of projects) {\n const seen = p.lastSeenAt ?? 'never'\n console.log(` ${p.name}\\t${p.status}\\t${p.path}\\tlast-seen=${seen}`)\n }\n}\n\nasync function main(): Promise<void> {\n const cmd = process.argv[2]\n if (!cmd || cmd === '-h' || cmd === '--help') {\n usage()\n process.exit(cmd ? 0 : 2)\n }\n\n if (cmd === 'start') return cmdStart()\n if (cmd === 'stop') return cmdStop()\n if (cmd === 'reload') return cmdReload()\n if (cmd === 'status') return cmdStatus()\n\n console.error(`neatd: unknown command \"${cmd}\"`)\n usage()\n process.exit(1)\n}\n\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/]neatd\\.(?:cjs|js)$/.test(entry) || entry.endsWith('/neatd')) {\n main().catch((err) => {\n console.error(err)\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
package/dist/server.cjs CHANGED
@@ -99,8 +99,8 @@ function reshapeGrpcRequest(req) {
99
99
  };
100
100
  }
101
101
  function resolveProtoRoot() {
102
- const here = import_node_path29.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
103
- return import_node_path29.default.resolve(here, "..", "proto");
102
+ const here = import_node_path30.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
103
+ return import_node_path30.default.resolve(here, "..", "proto");
104
104
  }
105
105
  function loadTraceService() {
106
106
  const protoRoot = resolveProtoRoot();
@@ -155,13 +155,13 @@ async function startOtelGrpcReceiver(opts) {
155
155
  })
156
156
  };
157
157
  }
158
- var import_node_url, import_node_path29, grpc, protoLoader;
158
+ var import_node_url, import_node_path30, grpc, protoLoader;
159
159
  var init_otel_grpc = __esm({
160
160
  "src/otel-grpc.ts"() {
161
161
  "use strict";
162
162
  init_cjs_shims();
163
163
  import_node_url = require("url");
164
- import_node_path29 = __toESM(require("path"), 1);
164
+ import_node_path30 = __toESM(require("path"), 1);
165
165
  grpc = __toESM(require("@grpc/grpc-js"), 1);
166
166
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
167
167
  init_otel();
@@ -258,10 +258,10 @@ function parseOtlpRequest(body) {
258
258
  }
259
259
  function loadProtobufDecoder() {
260
260
  if (exportTraceServiceRequestType) return exportTraceServiceRequestType;
261
- const here = import_node_path30.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
262
- const protoRoot = import_node_path30.default.resolve(here, "..", "proto");
261
+ const here = import_node_path31.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
262
+ const protoRoot = import_node_path31.default.resolve(here, "..", "proto");
263
263
  const root = new import_protobufjs.default.Root();
264
- root.resolvePath = (_origin, target) => import_node_path30.default.resolve(protoRoot, target);
264
+ root.resolvePath = (_origin, target) => import_node_path31.default.resolve(protoRoot, target);
265
265
  root.loadSync(
266
266
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
267
267
  { keepCase: true }
@@ -353,12 +353,12 @@ async function buildOtelReceiver(opts) {
353
353
  };
354
354
  return decorated;
355
355
  }
356
- var import_node_path30, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
356
+ var import_node_path31, import_node_url2, import_fastify2, import_protobufjs, exportTraceServiceRequestType;
357
357
  var init_otel = __esm({
358
358
  "src/otel.ts"() {
359
359
  "use strict";
360
360
  init_cjs_shims();
361
- import_node_path30 = __toESM(require("path"), 1);
361
+ import_node_path31 = __toESM(require("path"), 1);
362
362
  import_node_url2 = require("url");
363
363
  import_fastify2 = __toESM(require("fastify"), 1);
364
364
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -368,7 +368,7 @@ var init_otel = __esm({
368
368
 
369
369
  // src/server.ts
370
370
  init_cjs_shims();
371
- var import_node_path32 = __toESM(require("path"), 1);
371
+ var import_node_path33 = __toESM(require("path"), 1);
372
372
 
373
373
  // src/graph.ts
374
374
  init_cjs_shims();
@@ -392,7 +392,7 @@ function getGraph(project = DEFAULT_PROJECT) {
392
392
  init_cjs_shims();
393
393
  var import_fastify = __toESM(require("fastify"), 1);
394
394
  var import_cors = __toESM(require("@fastify/cors"), 1);
395
- var import_types18 = require("@neat.is/types");
395
+ var import_types19 = require("@neat.is/types");
396
396
 
397
397
  // src/policy.ts
398
398
  init_cjs_shims();
@@ -713,6 +713,18 @@ function deprecatedApis() {
713
713
  return currentMatrix().deprecatedApis ?? [];
714
714
  }
715
715
 
716
+ // src/events.ts
717
+ init_cjs_shims();
718
+ var import_node_events = require("events");
719
+ var EVENT_BUS_CHANNEL = "event";
720
+ var NeatEventBus = class extends import_node_events.EventEmitter {
721
+ };
722
+ var eventBus = new NeatEventBus();
723
+ eventBus.setMaxListeners(0);
724
+ function emitNeatEvent(envelope) {
725
+ eventBus.emit(EVENT_BUS_CHANNEL, envelope);
726
+ }
727
+
716
728
  // src/traverse.ts
717
729
  init_cjs_shims();
718
730
  var import_types = require("@neat.is/types");
@@ -800,19 +812,19 @@ function confidenceFromMix(edges, now = Date.now()) {
800
812
  function longestIncomingWalk(graph, start, maxDepth) {
801
813
  let best = { path: [start], edges: [] };
802
814
  const visited = /* @__PURE__ */ new Set([start]);
803
- function step(node, path33, edges) {
804
- if (path33.length > best.path.length) {
805
- best = { path: [...path33], edges: [...edges] };
815
+ function step(node, path34, edges) {
816
+ if (path34.length > best.path.length) {
817
+ best = { path: [...path34], edges: [...edges] };
806
818
  }
807
- if (path33.length - 1 >= maxDepth) return;
819
+ if (path34.length - 1 >= maxDepth) return;
808
820
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
809
821
  for (const [srcId, edge] of incoming) {
810
822
  if (visited.has(srcId)) continue;
811
823
  visited.add(srcId);
812
- path33.push(srcId);
824
+ path34.push(srcId);
813
825
  edges.push(edge);
814
- step(srcId, path33, edges);
815
- path33.pop();
826
+ step(srcId, path34, edges);
827
+ path34.pop();
816
828
  edges.pop();
817
829
  visited.delete(srcId);
818
830
  }
@@ -1276,9 +1288,11 @@ async function loadPolicyFile(policyPath) {
1276
1288
  }
1277
1289
  var PolicyViolationsLog = class {
1278
1290
  path;
1291
+ project;
1279
1292
  seen = null;
1280
- constructor(logPath) {
1293
+ constructor(logPath, project = DEFAULT_PROJECT) {
1281
1294
  this.path = logPath;
1295
+ this.project = project;
1282
1296
  }
1283
1297
  async append(v) {
1284
1298
  if (!this.seen) await this.hydrate();
@@ -1286,6 +1300,11 @@ var PolicyViolationsLog = class {
1286
1300
  this.seen.add(v.id);
1287
1301
  await import_node_fs2.promises.mkdir(import_node_path2.default.dirname(this.path), { recursive: true });
1288
1302
  await import_node_fs2.promises.appendFile(this.path, JSON.stringify(v) + "\n", "utf8");
1303
+ emitNeatEvent({
1304
+ type: "policy-violation",
1305
+ project: this.project,
1306
+ payload: { violation: v }
1307
+ });
1289
1308
  return true;
1290
1309
  }
1291
1310
  async readAll() {
@@ -1741,6 +1760,7 @@ async function markStaleEdges(graph, options = {}) {
1741
1760
  const thresholds = options.thresholds ?? loadStaleThresholdsFromEnv();
1742
1761
  const now = options.now ?? Date.now();
1743
1762
  const events = [];
1763
+ const project = options.project ?? DEFAULT_PROJECT;
1744
1764
  graph.forEachEdge((id, attrs) => {
1745
1765
  const e = attrs;
1746
1766
  if (e.provenance !== import_types3.Provenance.OBSERVED) return;
@@ -1760,6 +1780,15 @@ async function markStaleEdges(graph, options = {}) {
1760
1780
  lastObserved: e.lastObserved,
1761
1781
  transitionedAt: new Date(now).toISOString()
1762
1782
  });
1783
+ emitNeatEvent({
1784
+ type: "stale-transition",
1785
+ project,
1786
+ payload: {
1787
+ edgeId: id,
1788
+ from: import_types3.Provenance.OBSERVED,
1789
+ to: import_types3.Provenance.STALE
1790
+ }
1791
+ });
1763
1792
  }
1764
1793
  });
1765
1794
  if (options.staleEventsPath && events.length > 0) {
@@ -1790,7 +1819,8 @@ function startStalenessLoop(graph, options = {}) {
1790
1819
  try {
1791
1820
  await markStaleEdges(graph, {
1792
1821
  thresholds: options.thresholds,
1793
- staleEventsPath: options.staleEventsPath
1822
+ staleEventsPath: options.staleEventsPath,
1823
+ project: options.project
1794
1824
  });
1795
1825
  if (options.onPolicyTrigger) await options.onPolicyTrigger(graph);
1796
1826
  } catch (err) {
@@ -3020,7 +3050,15 @@ async function addHttpCallEdges(graph, services) {
3020
3050
  const seenTargets = /* @__PURE__ */ new Map();
3021
3051
  for (const file of files) {
3022
3052
  const parser = import_node_path18.default.extname(file.path) === ".py" ? pyParser : jsParser;
3023
- const targets = callsFromSource(file.content, parser, knownHosts);
3053
+ let targets;
3054
+ try {
3055
+ targets = callsFromSource(file.content, parser, knownHosts);
3056
+ } catch (err) {
3057
+ console.warn(
3058
+ `[neat] http call extraction skipped ${file.path}: ${err.message}`
3059
+ );
3060
+ continue;
3061
+ }
3024
3062
  for (const t of targets) {
3025
3063
  const targetId = hostToNodeId.get(t);
3026
3064
  if (!targetId || targetId === service.node.id) continue;
@@ -3549,11 +3587,22 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
3549
3587
  const phase5 = await addInfra(graph, scanPath, services);
3550
3588
  const frontiersPromoted = promoteFrontierNodes(graph);
3551
3589
  if (opts.onPolicyTrigger) await opts.onPolicyTrigger(graph);
3552
- return {
3590
+ const result = {
3553
3591
  nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
3554
3592
  edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
3555
3593
  frontiersPromoted
3556
3594
  };
3595
+ emitNeatEvent({
3596
+ type: "extraction-complete",
3597
+ project: opts.project ?? DEFAULT_PROJECT,
3598
+ payload: {
3599
+ project: opts.project ?? DEFAULT_PROJECT,
3600
+ fileCount: services.length,
3601
+ nodesAdded: result.nodesAdded,
3602
+ edgesAdded: result.edgesAdded
3603
+ }
3604
+ });
3605
+ return result;
3557
3606
  }
3558
3607
 
3559
3608
  // src/diff.ts
@@ -3689,6 +3738,94 @@ function parseExtraProjects(raw) {
3689
3738
  return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0 && p !== DEFAULT_PROJECT);
3690
3739
  }
3691
3740
 
3741
+ // src/registry.ts
3742
+ init_cjs_shims();
3743
+ var import_node_fs16 = require("fs");
3744
+ var import_node_os2 = __toESM(require("os"), 1);
3745
+ var import_node_path28 = __toESM(require("path"), 1);
3746
+ var import_types18 = require("@neat.is/types");
3747
+ function neatHome() {
3748
+ const override = process.env.NEAT_HOME;
3749
+ if (override && override.length > 0) return import_node_path28.default.resolve(override);
3750
+ return import_node_path28.default.join(import_node_os2.default.homedir(), ".neat");
3751
+ }
3752
+ function registryPath() {
3753
+ return import_node_path28.default.join(neatHome(), "projects.json");
3754
+ }
3755
+ async function readRegistry() {
3756
+ const file = registryPath();
3757
+ let raw;
3758
+ try {
3759
+ raw = await import_node_fs16.promises.readFile(file, "utf8");
3760
+ } catch (err) {
3761
+ if (err.code === "ENOENT") {
3762
+ return { version: 1, projects: [] };
3763
+ }
3764
+ throw err;
3765
+ }
3766
+ const parsed = JSON.parse(raw);
3767
+ return import_types18.RegistryFileSchema.parse(parsed);
3768
+ }
3769
+ async function listProjects() {
3770
+ const reg = await readRegistry();
3771
+ return reg.projects;
3772
+ }
3773
+
3774
+ // src/streaming.ts
3775
+ init_cjs_shims();
3776
+ var SSE_HEARTBEAT_MS = 3e4;
3777
+ var SSE_BACKPRESSURE_CAP = 1e3;
3778
+ function handleSse(req, reply, opts) {
3779
+ const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS;
3780
+ const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP;
3781
+ reply.raw.setHeader("Content-Type", "text/event-stream");
3782
+ reply.raw.setHeader("Cache-Control", "no-cache, no-transform");
3783
+ reply.raw.setHeader("Connection", "keep-alive");
3784
+ reply.raw.setHeader("X-Accel-Buffering", "no");
3785
+ reply.raw.flushHeaders?.();
3786
+ let pending = 0;
3787
+ let dropped = false;
3788
+ const closeConnection = () => {
3789
+ if (dropped) return;
3790
+ dropped = true;
3791
+ eventBus.off(EVENT_BUS_CHANNEL, listener);
3792
+ clearInterval(heartbeat);
3793
+ if (!reply.raw.writableEnded) reply.raw.end();
3794
+ };
3795
+ const writeFrame = (frame) => {
3796
+ if (dropped) return;
3797
+ if (pending >= backpressureCap) {
3798
+ const errFrame = `event: error
3799
+ data: ${JSON.stringify({ reason: "backpressure" })}
3800
+
3801
+ `;
3802
+ reply.raw.write(errFrame);
3803
+ closeConnection();
3804
+ return;
3805
+ }
3806
+ pending++;
3807
+ reply.raw.write(frame, () => {
3808
+ pending = Math.max(0, pending - 1);
3809
+ });
3810
+ };
3811
+ const listener = (envelope) => {
3812
+ if (envelope.project !== opts.project) return;
3813
+ writeFrame(`event: ${envelope.type}
3814
+ data: ${JSON.stringify(envelope.payload)}
3815
+
3816
+ `);
3817
+ };
3818
+ eventBus.on(EVENT_BUS_CHANNEL, listener);
3819
+ const heartbeat = setInterval(() => {
3820
+ if (dropped) return;
3821
+ reply.raw.write(":heartbeat\n\n");
3822
+ }, heartbeatMs);
3823
+ if (typeof heartbeat.unref === "function") heartbeat.unref();
3824
+ req.raw.on("close", closeConnection);
3825
+ reply.raw.on("close", closeConnection);
3826
+ reply.raw.on("error", closeConnection);
3827
+ }
3828
+
3692
3829
  // src/api.ts
3693
3830
  function serializeGraph(graph) {
3694
3831
  const nodes = [];
@@ -3737,6 +3874,11 @@ function buildLegacyRegistry(opts) {
3737
3874
  }
3738
3875
  function registerRoutes(scope, ctx) {
3739
3876
  const { registry, startedAt, errorsPathFor, staleEventsPathFor } = ctx;
3877
+ scope.get("/events", (req, reply) => {
3878
+ const proj = resolveProject(registry, req, reply);
3879
+ if (!proj) return;
3880
+ handleSse(req, reply, { project: proj.name });
3881
+ });
3740
3882
  scope.get("/health", async (req, reply) => {
3741
3883
  const proj = resolveProject(registry, req, reply);
3742
3884
  if (!proj) return;
@@ -3947,7 +4089,7 @@ function registerRoutes(scope, ctx) {
3947
4089
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
3948
4090
  let violations = await log.readAll();
3949
4091
  if (req.query.severity) {
3950
- const sev = import_types18.PolicySeveritySchema.safeParse(req.query.severity);
4092
+ const sev = import_types19.PolicySeveritySchema.safeParse(req.query.severity);
3951
4093
  if (!sev.success) {
3952
4094
  return reply.code(400).send({
3953
4095
  error: "invalid severity",
@@ -3964,7 +4106,7 @@ function registerRoutes(scope, ctx) {
3964
4106
  scope.post("/policies/check", async (req, reply) => {
3965
4107
  const proj = resolveProject(registry, req, reply);
3966
4108
  if (!proj) return;
3967
- const parsed = import_types18.PoliciesCheckBodySchema.safeParse(req.body ?? {});
4109
+ const parsed = import_types19.PoliciesCheckBodySchema.safeParse(req.body ?? {});
3968
4110
  if (!parsed.success) {
3969
4111
  return reply.code(400).send({
3970
4112
  error: "invalid /policies/check body",
@@ -4028,17 +4170,16 @@ async function buildApi(opts) {
4028
4170
  staleEventsPathFor,
4029
4171
  policyFilePathFor
4030
4172
  };
4031
- app.get("/projects", async () => ({
4032
- projects: registry.list().map((name) => {
4033
- const proj = registry.get(name);
4034
- return {
4035
- name,
4036
- nodeCount: proj.graph.order,
4037
- edgeCount: proj.graph.size,
4038
- scanPath: proj.scanPath
4039
- };
4040
- })
4041
- }));
4173
+ app.get("/projects", async (_req, reply) => {
4174
+ try {
4175
+ return await listProjects();
4176
+ } catch (err) {
4177
+ return reply.code(500).send({
4178
+ error: "failed to read project registry",
4179
+ details: err.message
4180
+ });
4181
+ }
4182
+ });
4042
4183
  registerRoutes(app, routeCtx);
4043
4184
  await app.register(
4044
4185
  async (scope) => {
@@ -4051,8 +4192,8 @@ async function buildApi(opts) {
4051
4192
 
4052
4193
  // src/persist.ts
4053
4194
  init_cjs_shims();
4054
- var import_node_fs16 = require("fs");
4055
- var import_node_path28 = __toESM(require("path"), 1);
4195
+ var import_node_fs17 = require("fs");
4196
+ var import_node_path29 = __toESM(require("path"), 1);
4056
4197
  var SCHEMA_VERSION = 2;
4057
4198
  function migrateV1ToV2(payload) {
4058
4199
  const nodes = payload.graph.nodes;
@@ -4066,7 +4207,7 @@ function migrateV1ToV2(payload) {
4066
4207
  return { ...payload, schemaVersion: 2 };
4067
4208
  }
4068
4209
  async function ensureDir(filePath) {
4069
- await import_node_fs16.promises.mkdir(import_node_path28.default.dirname(filePath), { recursive: true });
4210
+ await import_node_fs17.promises.mkdir(import_node_path29.default.dirname(filePath), { recursive: true });
4070
4211
  }
4071
4212
  async function saveGraphToDisk(graph, outPath) {
4072
4213
  await ensureDir(outPath);
@@ -4076,13 +4217,13 @@ async function saveGraphToDisk(graph, outPath) {
4076
4217
  graph: graph.export()
4077
4218
  };
4078
4219
  const tmp = `${outPath}.tmp`;
4079
- await import_node_fs16.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
4080
- await import_node_fs16.promises.rename(tmp, outPath);
4220
+ await import_node_fs17.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
4221
+ await import_node_fs17.promises.rename(tmp, outPath);
4081
4222
  }
4082
4223
  async function loadGraphFromDisk(graph, outPath) {
4083
4224
  let raw;
4084
4225
  try {
4085
- raw = await import_node_fs16.promises.readFile(outPath, "utf8");
4226
+ raw = await import_node_fs17.promises.readFile(outPath, "utf8");
4086
4227
  } catch (err) {
4087
4228
  if (err.code === "ENOENT") return;
4088
4229
  throw err;
@@ -4139,8 +4280,8 @@ init_otel_grpc();
4139
4280
 
4140
4281
  // src/search.ts
4141
4282
  init_cjs_shims();
4142
- var import_node_fs17 = require("fs");
4143
- var import_node_path31 = __toESM(require("path"), 1);
4283
+ var import_node_fs18 = require("fs");
4284
+ var import_node_path32 = __toESM(require("path"), 1);
4144
4285
  var import_node_crypto = require("crypto");
4145
4286
  var DEFAULT_LIMIT = 10;
4146
4287
  var NOMIC_DIM = 768;
@@ -4270,7 +4411,7 @@ async function pickEmbedder() {
4270
4411
  }
4271
4412
  async function readCache(cachePath) {
4272
4413
  try {
4273
- const raw = await import_node_fs17.promises.readFile(cachePath, "utf8");
4414
+ const raw = await import_node_fs18.promises.readFile(cachePath, "utf8");
4274
4415
  const parsed = JSON.parse(raw);
4275
4416
  if (parsed.version !== 1) return null;
4276
4417
  return parsed;
@@ -4279,8 +4420,8 @@ async function readCache(cachePath) {
4279
4420
  }
4280
4421
  }
4281
4422
  async function writeCache(cachePath, cache) {
4282
- await import_node_fs17.promises.mkdir(import_node_path31.default.dirname(cachePath), { recursive: true });
4283
- await import_node_fs17.promises.writeFile(cachePath, JSON.stringify(cache));
4423
+ await import_node_fs18.promises.mkdir(import_node_path32.default.dirname(cachePath), { recursive: true });
4424
+ await import_node_fs18.promises.writeFile(cachePath, JSON.stringify(cache));
4284
4425
  }
4285
4426
  var VectorIndex = class {
4286
4427
  constructor(embedder, cachePath) {
@@ -4459,14 +4600,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
4459
4600
  async function main() {
4460
4601
  const baseDirEnv = process.env.NEAT_OUT_DIR;
4461
4602
  const legacyOutPath = process.env.NEAT_OUT_PATH;
4462
- const baseDir = baseDirEnv ? import_node_path32.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path32.default.resolve(import_node_path32.default.dirname(legacyOutPath)) : import_node_path32.default.resolve("./neat-out");
4463
- const defaultScanPath = import_node_path32.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
4603
+ const baseDir = baseDirEnv ? import_node_path33.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path33.default.resolve(import_node_path33.default.dirname(legacyOutPath)) : import_node_path33.default.resolve("./neat-out");
4604
+ const defaultScanPath = import_node_path33.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
4464
4605
  const registry = new Projects();
4465
4606
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
4466
4607
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
4467
4608
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
4468
4609
  const projectScan = process.env[envKey];
4469
- await bootProject(registry, name, projectScan ? import_node_path32.default.resolve(projectScan) : void 0, baseDir);
4610
+ await bootProject(registry, name, projectScan ? import_node_path33.default.resolve(projectScan) : void 0, baseDir);
4470
4611
  }
4471
4612
  const host = process.env.HOST ?? "0.0.0.0";
4472
4613
  const port = Number(process.env.PORT ?? 8080);