@neat.is/core 0.2.5
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/compat.json +120 -0
- package/dist/chunk-6JT6L2OV.js +164 -0
- package/dist/chunk-6JT6L2OV.js.map +1 -0
- package/dist/chunk-6SFEITLJ.js +3371 -0
- package/dist/chunk-6SFEITLJ.js.map +1 -0
- package/dist/chunk-I5IMCXRO.js +325 -0
- package/dist/chunk-I5IMCXRO.js.map +1 -0
- package/dist/chunk-T2U4U256.js +462 -0
- package/dist/chunk-T2U4U256.js.map +1 -0
- package/dist/chunk-WX55TLUT.js +184 -0
- package/dist/chunk-WX55TLUT.js.map +1 -0
- package/dist/chunk-XOOCA5T7.js +290 -0
- package/dist/chunk-XOOCA5T7.js.map +1 -0
- package/dist/cli.cjs +5754 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +36 -0
- package/dist/cli.d.ts +36 -0
- package/dist/cli.js +1175 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +4552 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +408 -0
- package/dist/index.d.ts +408 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/neatd.cjs +3070 -0
- package/dist/neatd.cjs.map +1 -0
- package/dist/neatd.d.cts +1 -0
- package/dist/neatd.d.ts +1 -0
- package/dist/neatd.js +114 -0
- package/dist/neatd.js.map +1 -0
- package/dist/otel-grpc-B4XBSI4W.js +9 -0
- package/dist/otel-grpc-B4XBSI4W.js.map +1 -0
- package/dist/server.cjs +4499 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +2 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/package.json +77 -0
- package/proto/opentelemetry/proto/collector/trace/v1/trace_service.proto +31 -0
- package/proto/opentelemetry/proto/common/v1/common.proto +46 -0
- package/proto/opentelemetry/proto/resource/v1/resource.proto +19 -0
- package/proto/opentelemetry/proto/trace/v1/trace.proto +93 -0
package/compat.json
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pairs": [
|
|
3
|
+
{
|
|
4
|
+
"kind": "driver-engine",
|
|
5
|
+
"driver": "pg",
|
|
6
|
+
"engine": "postgresql",
|
|
7
|
+
"minDriverVersion": "8.0.0",
|
|
8
|
+
"minEngineVersion": "14",
|
|
9
|
+
"reason": "PostgreSQL 14+ requires scram-sha-256 auth by default; pg < 8.0.0 only speaks md5."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"kind": "driver-engine",
|
|
13
|
+
"driver": "mysql2",
|
|
14
|
+
"engine": "mysql",
|
|
15
|
+
"minDriverVersion": "3.0.0",
|
|
16
|
+
"minEngineVersion": "8",
|
|
17
|
+
"reason": "MySQL 8 defaults to caching_sha2_password; mysql2 < 3.0.0 doesn't negotiate it."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"kind": "driver-engine",
|
|
21
|
+
"driver": "mongoose",
|
|
22
|
+
"engine": "mongodb",
|
|
23
|
+
"minDriverVersion": "7.0.0",
|
|
24
|
+
"minEngineVersion": "7",
|
|
25
|
+
"reason": "MongoDB 7 drops legacy wire-protocol opcodes that mongoose < 7.0.0 still emits."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"kind": "driver-engine",
|
|
29
|
+
"driver": "psycopg2",
|
|
30
|
+
"engine": "postgresql",
|
|
31
|
+
"minDriverVersion": "2.9.0",
|
|
32
|
+
"minEngineVersion": "14",
|
|
33
|
+
"reason": "PostgreSQL 14+ requires scram-sha-256 auth by default; psycopg2 < 2.9.0 only speaks md5."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"kind": "driver-engine",
|
|
37
|
+
"driver": "pymongo",
|
|
38
|
+
"engine": "mongodb",
|
|
39
|
+
"minDriverVersion": "4.0.0",
|
|
40
|
+
"minEngineVersion": "7",
|
|
41
|
+
"reason": "MongoDB 7 drops legacy wire-protocol opcodes that pymongo < 4.0.0 still emits."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"kind": "driver-engine",
|
|
45
|
+
"driver": "mysql-connector-python",
|
|
46
|
+
"engine": "mysql",
|
|
47
|
+
"minDriverVersion": "8.0.0",
|
|
48
|
+
"minEngineVersion": "8",
|
|
49
|
+
"reason": "MySQL 8 defaults to caching_sha2_password; mysql-connector-python < 8.0.0 doesn't negotiate it."
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"nodeEngineConstraints": [
|
|
53
|
+
{
|
|
54
|
+
"kind": "node-engine",
|
|
55
|
+
"package": "vitest",
|
|
56
|
+
"packageMinVersion": "2.0.0",
|
|
57
|
+
"minNodeVersion": "18.0.0",
|
|
58
|
+
"reason": "vitest >= 2.0 drops Node 16 support; requires Node 18+."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"kind": "node-engine",
|
|
62
|
+
"package": "next",
|
|
63
|
+
"packageMinVersion": "14.0.0",
|
|
64
|
+
"minNodeVersion": "18.17.0",
|
|
65
|
+
"reason": "Next 14+ requires Node 18.17+ (uses APIs introduced in that minor)."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"kind": "node-engine",
|
|
69
|
+
"package": "@modelcontextprotocol/sdk",
|
|
70
|
+
"packageMinVersion": "1.0.0",
|
|
71
|
+
"minNodeVersion": "18.0.0",
|
|
72
|
+
"reason": "@modelcontextprotocol/sdk >= 1 requires Node 18+ (web-streams polyfill removed)."
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"packageConflicts": [
|
|
76
|
+
{
|
|
77
|
+
"kind": "package-conflict",
|
|
78
|
+
"package": "@tanstack/react-query",
|
|
79
|
+
"packageMinVersion": "5.0.0",
|
|
80
|
+
"requires": {
|
|
81
|
+
"name": "react",
|
|
82
|
+
"minVersion": "18.0.0"
|
|
83
|
+
},
|
|
84
|
+
"reason": "@tanstack/react-query 5+ uses useSyncExternalStore — only available in React 18+."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"kind": "package-conflict",
|
|
88
|
+
"package": "react-router-dom",
|
|
89
|
+
"packageMinVersion": "7.0.0",
|
|
90
|
+
"requires": {
|
|
91
|
+
"name": "react",
|
|
92
|
+
"minVersion": "18.0.0"
|
|
93
|
+
},
|
|
94
|
+
"reason": "react-router-dom 7+ requires React 18+."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"kind": "package-conflict",
|
|
98
|
+
"package": "next",
|
|
99
|
+
"packageMinVersion": "14.0.0",
|
|
100
|
+
"requires": {
|
|
101
|
+
"name": "react",
|
|
102
|
+
"minVersion": "18.2.0"
|
|
103
|
+
},
|
|
104
|
+
"reason": "Next.js 14+ requires React 18.2+."
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"deprecatedApis": [
|
|
108
|
+
{
|
|
109
|
+
"kind": "deprecated-api",
|
|
110
|
+
"package": "request",
|
|
111
|
+
"packageMaxVersion": "2.88.2",
|
|
112
|
+
"reason": "request is deprecated; use undici, node-fetch, or axios instead."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"kind": "deprecated-api",
|
|
116
|
+
"package": "node-uuid",
|
|
117
|
+
"reason": "node-uuid is deprecated; use the `uuid` package."
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listProjects,
|
|
3
|
+
registryPath,
|
|
4
|
+
setStatus,
|
|
5
|
+
touchLastSeen,
|
|
6
|
+
writeAtomically
|
|
7
|
+
} from "./chunk-WX55TLUT.js";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_PROJECT,
|
|
10
|
+
extractFromDirectory,
|
|
11
|
+
getGraph,
|
|
12
|
+
loadGraphFromDisk,
|
|
13
|
+
pathsForProject,
|
|
14
|
+
resetGraph,
|
|
15
|
+
startPersistLoop
|
|
16
|
+
} from "./chunk-6SFEITLJ.js";
|
|
17
|
+
|
|
18
|
+
// src/daemon.ts
|
|
19
|
+
import { promises as fs } from "fs";
|
|
20
|
+
import path from "path";
|
|
21
|
+
function neatHomeFor(opts) {
|
|
22
|
+
if (opts.neatHome && opts.neatHome.length > 0) return path.resolve(opts.neatHome);
|
|
23
|
+
const env = process.env.NEAT_HOME;
|
|
24
|
+
if (env && env.length > 0) return path.resolve(env);
|
|
25
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
26
|
+
return path.join(home, ".neat");
|
|
27
|
+
}
|
|
28
|
+
function routeSpanToProject(serviceName, projects) {
|
|
29
|
+
if (!serviceName) return DEFAULT_PROJECT;
|
|
30
|
+
for (const entry of projects) {
|
|
31
|
+
if (entry.status !== "active") continue;
|
|
32
|
+
if (entry.languages.length === 0) {
|
|
33
|
+
}
|
|
34
|
+
if (entry.name === serviceName) return entry.name;
|
|
35
|
+
}
|
|
36
|
+
return DEFAULT_PROJECT;
|
|
37
|
+
}
|
|
38
|
+
async function bootstrapProject(entry) {
|
|
39
|
+
try {
|
|
40
|
+
const stat = await fs.stat(entry.path);
|
|
41
|
+
if (!stat.isDirectory()) {
|
|
42
|
+
throw new Error(`registered path ${entry.path} is not a directory`);
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
await setStatus(entry.name, "broken").catch(() => {
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
entry,
|
|
49
|
+
// Empty graph is fine — `slots` keeps the entry visible in `status`
|
|
50
|
+
// output; nothing routes to it because it's not 'active'.
|
|
51
|
+
graph: getGraph(`__broken__:${entry.name}`),
|
|
52
|
+
outPath: "",
|
|
53
|
+
stopPersist: () => {
|
|
54
|
+
},
|
|
55
|
+
status: "broken",
|
|
56
|
+
errorReason: err.message
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
resetGraph(entry.name);
|
|
60
|
+
const graph = getGraph(entry.name);
|
|
61
|
+
const outPath = pathsForProject(
|
|
62
|
+
entry.name,
|
|
63
|
+
path.join(entry.path, "neat-out")
|
|
64
|
+
).snapshotPath;
|
|
65
|
+
await loadGraphFromDisk(graph, outPath);
|
|
66
|
+
await extractFromDirectory(graph, entry.path);
|
|
67
|
+
const stopPersist = startPersistLoop(graph, outPath);
|
|
68
|
+
await touchLastSeen(entry.name).catch(() => {
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
entry,
|
|
72
|
+
graph,
|
|
73
|
+
outPath,
|
|
74
|
+
stopPersist,
|
|
75
|
+
status: "active"
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function startDaemon(opts = {}) {
|
|
79
|
+
const home = neatHomeFor(opts);
|
|
80
|
+
const regPath = registryPath();
|
|
81
|
+
try {
|
|
82
|
+
await fs.access(regPath);
|
|
83
|
+
} catch {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const pidPath = path.join(home, "neatd.pid");
|
|
89
|
+
await writeAtomically(pidPath, `${process.pid}
|
|
90
|
+
`);
|
|
91
|
+
const slots = /* @__PURE__ */ new Map();
|
|
92
|
+
async function loadAll() {
|
|
93
|
+
const projects = await listProjects();
|
|
94
|
+
const seen = /* @__PURE__ */ new Set();
|
|
95
|
+
for (const entry of projects) {
|
|
96
|
+
seen.add(entry.name);
|
|
97
|
+
if (slots.has(entry.name)) continue;
|
|
98
|
+
try {
|
|
99
|
+
const slot = await bootstrapProject(entry);
|
|
100
|
+
slots.set(entry.name, slot);
|
|
101
|
+
if (slot.status === "broken") {
|
|
102
|
+
console.warn(`neatd: project "${entry.name}" broken \u2014 ${slot.errorReason}`);
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`neatd: project "${entry.name}" active (${entry.path})`);
|
|
105
|
+
}
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.warn(
|
|
108
|
+
`neatd: project "${entry.name}" failed to bootstrap \u2014 ${err.message}`
|
|
109
|
+
);
|
|
110
|
+
await setStatus(entry.name, "broken").catch(() => {
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const [name, slot] of [...slots.entries()]) {
|
|
115
|
+
if (seen.has(name)) continue;
|
|
116
|
+
try {
|
|
117
|
+
slot.stopPersist();
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
slots.delete(name);
|
|
121
|
+
console.log(`neatd: project "${name}" removed from registry \u2014 stopped`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
await loadAll();
|
|
125
|
+
let reloading = null;
|
|
126
|
+
const reload = async () => {
|
|
127
|
+
if (reloading) return reloading;
|
|
128
|
+
reloading = (async () => {
|
|
129
|
+
try {
|
|
130
|
+
await loadAll();
|
|
131
|
+
} finally {
|
|
132
|
+
reloading = null;
|
|
133
|
+
}
|
|
134
|
+
})();
|
|
135
|
+
return reloading;
|
|
136
|
+
};
|
|
137
|
+
const sighupHandler = () => {
|
|
138
|
+
void reload().catch((err) => {
|
|
139
|
+
console.warn(`neatd: SIGHUP reload failed \u2014 ${err.message}`);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
process.on("SIGHUP", sighupHandler);
|
|
143
|
+
let stopped = false;
|
|
144
|
+
const stop = async () => {
|
|
145
|
+
if (stopped) return;
|
|
146
|
+
stopped = true;
|
|
147
|
+
process.off("SIGHUP", sighupHandler);
|
|
148
|
+
for (const slot of slots.values()) {
|
|
149
|
+
try {
|
|
150
|
+
slot.stopPersist();
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
await fs.unlink(pidPath).catch(() => {
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
return { slots, reload, stop, pidPath };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
routeSpanToProject,
|
|
162
|
+
startDaemon
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=chunk-6JT6L2OV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon.ts"],"sourcesContent":["/**\n * Multi-project daemon (ADR-049).\n *\n * Single long-lived process watching every project in the machine-level registry.\n * Per-project graph isolation: each registered project owns its own\n * `MultiDirectedGraph` slot keyed by name (ADR-026), and a failure during\n * one project's bootstrap is logged + marked `broken` without taking down\n * the rest of the daemon.\n *\n * MVP scope (v0.2.5):\n * - Read registry; refuse to boot when it's missing.\n * - Write PID at `~/.neat/neatd.pid` for external supervisors.\n * - Per project: load any existing snapshot, run initial extraction,\n * start a per-project persist loop.\n * - SIGHUP triggers a reload — re-reads the registry, picks up new\n * projects, drops removed ones, leaves untouched ones in place.\n * - Provide `routeSpanToProject(serviceName, projects)` for OTel ingest\n * to dispatch by `service.name` across registered projects, falling\n * back to `default` for unknown services per ADR-033.\n *\n * Out of MVP scope (deferred):\n * - Live OTel listener wiring per project — daemon exposes the routing\n * primitive; the actual receiver attachment lands alongside v0.2.6.\n * - Policy reload on `policy.json` mtime — `startWatch` already does this\n * per-project; the daemon-level loop reuses that machinery in a follow-up.\n * - Auto-restart on crash. PID file is the supervisor handoff.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { DEFAULT_PROJECT, getGraph, resetGraph, type NeatGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { pathsForProject } from './projects.js'\nimport {\n listProjects,\n registryPath,\n setStatus,\n touchLastSeen,\n writeAtomically,\n} from './registry.js'\nimport type { RegistryEntry } from '@neat.is/types'\n\nexport interface DaemonOptions {\n // Defaults to `~/.neat/`. Honors NEAT_HOME the same way registry.ts does.\n // Tests override via NEAT_HOME and don't pass this directly.\n neatHome?: string\n}\n\nexport interface ProjectSlot {\n entry: RegistryEntry\n graph: NeatGraph\n outPath: string\n stopPersist: () => void\n status: 'active' | 'broken'\n errorReason?: string\n}\n\nexport interface DaemonHandle {\n // The slots currently being managed, keyed by project name. Tests inspect\n // this to assert isolation properties.\n slots: Map<string, ProjectSlot>\n // Re-read the registry. New entries get bootstrapped, removed ones get\n // their persist loops stopped, existing ones stay running.\n reload: () => Promise<void>\n // Graceful shutdown — stop every project's persist loop and remove the\n // PID file.\n stop: () => Promise<void>\n // Path to the PID file the daemon owns. Useful for test assertions.\n pidPath: string\n}\n\nfunction neatHomeFor(opts: DaemonOptions): string {\n if (opts.neatHome && opts.neatHome.length > 0) return path.resolve(opts.neatHome)\n const env = process.env.NEAT_HOME\n if (env && env.length > 0) return path.resolve(env)\n const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n return path.join(home, '.neat')\n}\n\n/**\n * Resolve which project's graph an OTel span belongs to. Looks up the\n * `service.name` against the registry and returns the matching project's\n * name, or `DEFAULT_PROJECT` for unknown services so the FrontierNode\n * auto-creation flow keeps working per ADR-033.\n *\n * Pure function. Daemon callers pass a snapshot of the registry to avoid\n * per-span fs reads.\n */\nexport function routeSpanToProject(\n serviceName: string | undefined,\n projects: ReadonlyArray<RegistryEntry>,\n): string {\n if (!serviceName) return DEFAULT_PROJECT\n for (const entry of projects) {\n if (entry.status !== 'active') continue\n if (entry.languages.length === 0) {\n // No language data yet — still acceptable to match by name.\n }\n if (entry.name === serviceName) return entry.name\n }\n return DEFAULT_PROJECT\n}\n\nasync function bootstrapProject(entry: RegistryEntry): Promise<ProjectSlot> {\n // Path missing on disk → mark broken and surface the reason. Daemon\n // continues with the rest of the registry.\n try {\n const stat = await fs.stat(entry.path)\n if (!stat.isDirectory()) {\n throw new Error(`registered path ${entry.path} is not a directory`)\n }\n } catch (err) {\n await setStatus(entry.name, 'broken').catch(() => {})\n return {\n entry,\n // Empty graph is fine — `slots` keeps the entry visible in `status`\n // output; nothing routes to it because it's not 'active'.\n graph: getGraph(`__broken__:${entry.name}`),\n outPath: '',\n stopPersist: () => {},\n status: 'broken',\n errorReason: (err as Error).message,\n }\n }\n\n // Use the project name as the in-memory graph key. Any prior contents\n // are wiped because the daemon owns the slot for the lifetime of this\n // bootstrap (ADR-030 — mutation authority).\n resetGraph(entry.name)\n const graph = getGraph(entry.name)\n const outPath = pathsForProject(\n entry.name,\n path.join(entry.path, 'neat-out'),\n ).snapshotPath\n\n await loadGraphFromDisk(graph, outPath)\n await extractFromDirectory(graph, entry.path)\n const stopPersist = startPersistLoop(graph, outPath)\n await touchLastSeen(entry.name).catch(() => {})\n\n return {\n entry,\n graph,\n outPath,\n stopPersist,\n status: 'active',\n }\n}\n\nexport async function startDaemon(opts: DaemonOptions = {}): Promise<DaemonHandle> {\n const home = neatHomeFor(opts)\n const regPath = registryPath()\n // Graceful degradation per ADR-049 #6: missing registry refuses to boot\n // with a clear error rather than silently coming up empty.\n try {\n await fs.access(regPath)\n } catch {\n throw new Error(\n `neatd: registry not found at ${regPath}. Run \\`neat init <path>\\` to register a project before starting the daemon.`,\n )\n }\n\n const pidPath = path.join(home, 'neatd.pid')\n await writeAtomically(pidPath, `${process.pid}\\n`)\n\n const slots = new Map<string, ProjectSlot>()\n\n async function loadAll(): Promise<void> {\n const projects = await listProjects()\n const seen = new Set<string>()\n for (const entry of projects) {\n seen.add(entry.name)\n if (slots.has(entry.name)) continue\n try {\n const slot = await bootstrapProject(entry)\n slots.set(entry.name, slot)\n if (slot.status === 'broken') {\n console.warn(`neatd: project \"${entry.name}\" broken — ${slot.errorReason}`)\n } else {\n console.log(`neatd: project \"${entry.name}\" active (${entry.path})`)\n }\n } catch (err) {\n console.warn(\n `neatd: project \"${entry.name}\" failed to bootstrap — ${(err as Error).message}`,\n )\n await setStatus(entry.name, 'broken').catch(() => {})\n }\n }\n // Drop entries the registry no longer carries.\n for (const [name, slot] of [...slots.entries()]) {\n if (seen.has(name)) continue\n try {\n slot.stopPersist()\n } catch {\n // best-effort\n }\n slots.delete(name)\n console.log(`neatd: project \"${name}\" removed from registry — stopped`)\n }\n }\n\n await loadAll()\n\n let reloading: Promise<void> | null = null\n const reload = async (): Promise<void> => {\n if (reloading) return reloading\n reloading = (async () => {\n try {\n await loadAll()\n } finally {\n reloading = null\n }\n })()\n return reloading\n }\n\n // SIGHUP — external \"reload your config\" signal. ADR-049 #2.\n const sighupHandler = (): void => {\n void reload().catch((err) => {\n console.warn(`neatd: SIGHUP reload failed — ${(err as Error).message}`)\n })\n }\n process.on('SIGHUP', sighupHandler)\n\n let stopped = false\n const stop = async (): Promise<void> => {\n if (stopped) return\n stopped = true\n process.off('SIGHUP', sighupHandler)\n for (const slot of slots.values()) {\n try {\n slot.stopPersist()\n } catch {\n // best-effort\n }\n }\n await fs.unlink(pidPath).catch(() => {})\n }\n\n return { slots, reload, stop, pidPath }\n}\n"],"mappings":"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","names":[]}
|