@neat.is/core 0.10.5 → 0.10.6-dev.20261008

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.
Files changed (47) hide show
  1. package/dist/{chunk-DVCGDMTZ.js → chunk-6QMWJAWR.js} +1454 -1019
  2. package/dist/chunk-6QMWJAWR.js.map +1 -0
  3. package/dist/{chunk-Q2SL2SVH.js → chunk-EMFX3V77.js} +43 -224
  4. package/dist/chunk-EMFX3V77.js.map +1 -0
  5. package/dist/chunk-MR64ICXX.js +19 -0
  6. package/dist/chunk-MR64ICXX.js.map +1 -0
  7. package/dist/{chunk-EFBWQIKG.js → chunk-QPG2QXCW.js} +11 -27
  8. package/dist/chunk-QPG2QXCW.js.map +1 -0
  9. package/dist/chunk-RGYC5U2Q.js +511 -0
  10. package/dist/chunk-RGYC5U2Q.js.map +1 -0
  11. package/dist/{chunk-LXQCL4MP.js → chunk-TZXSWSHX.js} +2 -2
  12. package/dist/{chunk-BC53SCT7.js → chunk-VFZ6CXLI.js} +20 -6
  13. package/dist/chunk-VFZ6CXLI.js.map +1 -0
  14. package/dist/cli.cjs +2065 -1178
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.d.cts +2 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +249 -76
  19. package/dist/cli.js.map +1 -1
  20. package/dist/index.cjs +1653 -952
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +45 -99
  23. package/dist/index.d.ts +45 -99
  24. package/dist/index.js +18 -15
  25. package/dist/neatd.cjs +1666 -965
  26. package/dist/neatd.cjs.map +1 -1
  27. package/dist/neatd.js +7 -4
  28. package/dist/neatd.js.map +1 -1
  29. package/dist/otel-grpc-CCCI772O.js +11 -0
  30. package/dist/registry.cjs +570 -0
  31. package/dist/registry.cjs.map +1 -0
  32. package/dist/registry.d.cts +220 -0
  33. package/dist/registry.d.ts +220 -0
  34. package/dist/registry.js +62 -0
  35. package/dist/registry.js.map +1 -0
  36. package/dist/server.cjs +1384 -657
  37. package/dist/server.cjs.map +1 -1
  38. package/dist/server.js +10 -6
  39. package/dist/server.js.map +1 -1
  40. package/package.json +9 -3
  41. package/dist/chunk-BC53SCT7.js.map +0 -1
  42. package/dist/chunk-DVCGDMTZ.js.map +0 -1
  43. package/dist/chunk-EFBWQIKG.js.map +0 -1
  44. package/dist/chunk-Q2SL2SVH.js.map +0 -1
  45. package/dist/otel-grpc-B7ABHLV7.js +0 -10
  46. /package/dist/{chunk-LXQCL4MP.js.map → chunk-TZXSWSHX.js.map} +0 -0
  47. /package/dist/{otel-grpc-B7ABHLV7.js.map → otel-grpc-CCCI772O.js.map} +0 -0
package/dist/server.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
- buildSearchIndex
3
- } from "./chunk-BC53SCT7.js";
2
+ buildSearchIndex,
3
+ searchProviderFromEnv
4
+ } from "./chunk-VFZ6CXLI.js";
4
5
  import {
5
6
  DEFAULT_PROJECT,
6
7
  Projects,
@@ -13,15 +14,17 @@ import {
13
14
  pathsForProject,
14
15
  startPersistLoop,
15
16
  startStalenessLoop
16
- } from "./chunk-DVCGDMTZ.js";
17
+ } from "./chunk-6QMWJAWR.js";
18
+ import "./chunk-RGYC5U2Q.js";
17
19
  import {
18
20
  startOtelGrpcReceiver
19
- } from "./chunk-LXQCL4MP.js";
21
+ } from "./chunk-TZXSWSHX.js";
20
22
  import {
21
23
  assertBindAuthority,
22
24
  buildOtelReceiver,
23
25
  readAuthEnv
24
- } from "./chunk-EFBWQIKG.js";
26
+ } from "./chunk-QPG2QXCW.js";
27
+ import "./chunk-MR64ICXX.js";
25
28
 
26
29
  // src/server.ts
27
30
  import path from "path";
@@ -40,7 +43,8 @@ async function bootProject(registry, name, scanPath, baseDir) {
40
43
  startPersistLoop(graph, paths.snapshotPath);
41
44
  startStalenessLoop(graph, { staleEventsPath: paths.staleEventsPath });
42
45
  const searchIndex = await buildSearchIndex(graph, {
43
- cachePath: paths.embeddingsCachePath
46
+ cachePath: paths.embeddingsCachePath,
47
+ forceProvider: searchProviderFromEnv()
44
48
  }).catch((err) => {
45
49
  console.warn(
46
50
  `[${name}] semantic_search: index build failed (${err.message}); falling back to inline substring`
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import path from 'node:path'\nimport type { FastifyInstance } from 'fastify'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { makeSpanHandler, startStalenessLoop } from './ingest.js'\nimport { buildSearchIndex } from './search.js'\nimport { Projects, parseExtraProjects, pathsForProject } from './projects.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\n\nasync function bootProject(\n registry: Projects,\n name: string,\n scanPath: string | undefined,\n baseDir: string,\n): Promise<void> {\n const paths = pathsForProject(name, baseDir)\n const graph = getGraph(name)\n await loadGraphFromDisk(graph, paths.snapshotPath)\n\n if (scanPath) {\n const r = await extractFromDirectory(graph, scanPath)\n console.log(\n `[${name}] extract: ${r.nodesAdded} new nodes, ${r.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n } else {\n console.log(`[${name}] loaded ${graph.order} nodes / ${graph.size} edges from snapshot`)\n }\n\n startPersistLoop(graph, paths.snapshotPath)\n startStalenessLoop(graph, { staleEventsPath: paths.staleEventsPath })\n\n const searchIndex = await buildSearchIndex(graph, {\n cachePath: paths.embeddingsCachePath,\n }).catch((err) => {\n console.warn(\n `[${name}] semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n return undefined\n })\n if (searchIndex) {\n console.log(`[${name}] semantic_search: ${searchIndex.provider} provider`)\n }\n\n registry.set(name, {\n scanPath,\n paths,\n searchIndex,\n })\n}\n\nasync function main(): Promise<void> {\n const baseDirEnv = process.env.NEAT_OUT_DIR\n const legacyOutPath = process.env.NEAT_OUT_PATH\n const baseDir = baseDirEnv\n ? path.resolve(baseDirEnv)\n : legacyOutPath\n ? path.resolve(path.dirname(legacyOutPath))\n : path.resolve('./neat-out')\n\n const defaultScanPath = path.resolve(process.env.NEAT_SCAN_PATH ?? './demo')\n const registry = new Projects()\n\n // Default project always exists. NEAT_SCAN_PATH still wires it to a scan\n // root so existing single-project users see no behaviour change.\n await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir)\n\n // Extra projects come from NEAT_PROJECTS=a,b,c. Their snapshots load from\n // <baseDir>/<name>.json; they have no scan path by default (callers can\n // POST /projects/<name>/graph/scan after wiring NEAT_PROJECT_SCAN_PATH_<NAME>).\n for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {\n const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`\n const projectScan = process.env[envKey]\n await bootProject(registry, name, projectScan ? path.resolve(projectScan) : undefined, baseDir)\n }\n\n const host = process.env.HOST ?? '0.0.0.0'\n const port = Number(process.env.PORT ?? 8080)\n const otelPort = Number(process.env.OTEL_PORT ?? 4318)\n\n // ADR-073 §3 — refuse to bind a public address without a token.\n const auth = readAuthEnv()\n assertBindAuthority(host, auth.authToken)\n\n // Set once the OTLP receiver is built below; its routes answer on the REST\n // port too (see buildApi's `otlpReceiver`).\n let otelReceiver: FastifyInstance | undefined\n const app = await buildApi({\n projects: registry,\n authToken: auth.authToken,\n trustProxy: auth.trustProxy,\n publicRead: auth.publicRead,\n otlpReceiver: () => otelReceiver,\n })\n await app.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` base dir: ${baseDir}`)\n console.log(` projects: ${registry.list().join(', ')}`)\n\n // OTel ingest stays single-project for now: spans always land in the\n // default project's graph + errors log. Multi-project routing for spans\n // is a future concern (would need a header / resource attr).\n const defaultCtx = registry.get(DEFAULT_PROJECT)\n if (defaultCtx) {\n const onSpan = makeSpanHandler({\n graph: defaultCtx.graph,\n errorsPath: defaultCtx.paths.errorsPath,\n })\n const otelApp = await buildOtelReceiver({\n onSpan,\n authToken: auth.otelToken,\n trustProxy: auth.trustProxy,\n })\n otelReceiver = otelApp\n await otelApp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n if (process.env.NEAT_OTLP_GRPC === 'true') {\n const grpcPort = Number(process.env.NEAT_OTLP_GRPC_PORT ?? 4317)\n const grpcReceiver = await startOtelGrpcReceiver({\n onSpan,\n host,\n port: grpcPort,\n authToken: auth.otelToken,\n trustProxy: auth.trustProxy,\n })\n console.log(`neat-core OTLP/gRPC receiver on ${grpcReceiver.address}`)\n }\n }\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import path from 'node:path'\nimport type { FastifyInstance } from 'fastify'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildOtelReceiver } from './otel.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { makeSpanHandler, startStalenessLoop } from './ingest.js'\nimport { buildSearchIndex, searchProviderFromEnv } from './search.js'\nimport { Projects, parseExtraProjects, pathsForProject } from './projects.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\n\nasync function bootProject(\n registry: Projects,\n name: string,\n scanPath: string | undefined,\n baseDir: string,\n): Promise<void> {\n const paths = pathsForProject(name, baseDir)\n const graph = getGraph(name)\n await loadGraphFromDisk(graph, paths.snapshotPath)\n\n if (scanPath) {\n const r = await extractFromDirectory(graph, scanPath)\n console.log(\n `[${name}] extract: ${r.nodesAdded} new nodes, ${r.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n )\n } else {\n console.log(`[${name}] loaded ${graph.order} nodes / ${graph.size} edges from snapshot`)\n }\n\n startPersistLoop(graph, paths.snapshotPath)\n startStalenessLoop(graph, { staleEventsPath: paths.staleEventsPath })\n\n const searchIndex = await buildSearchIndex(graph, {\n cachePath: paths.embeddingsCachePath,\n forceProvider: searchProviderFromEnv(),\n }).catch((err) => {\n console.warn(\n `[${name}] semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n )\n return undefined\n })\n if (searchIndex) {\n console.log(`[${name}] semantic_search: ${searchIndex.provider} provider`)\n }\n\n registry.set(name, {\n scanPath,\n paths,\n searchIndex,\n })\n}\n\nasync function main(): Promise<void> {\n const baseDirEnv = process.env.NEAT_OUT_DIR\n const legacyOutPath = process.env.NEAT_OUT_PATH\n const baseDir = baseDirEnv\n ? path.resolve(baseDirEnv)\n : legacyOutPath\n ? path.resolve(path.dirname(legacyOutPath))\n : path.resolve('./neat-out')\n\n const defaultScanPath = path.resolve(process.env.NEAT_SCAN_PATH ?? './demo')\n const registry = new Projects()\n\n // Default project always exists. NEAT_SCAN_PATH still wires it to a scan\n // root so existing single-project users see no behaviour change.\n await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir)\n\n // Extra projects come from NEAT_PROJECTS=a,b,c. Their snapshots load from\n // <baseDir>/<name>.json; they have no scan path by default (callers can\n // POST /projects/<name>/graph/scan after wiring NEAT_PROJECT_SCAN_PATH_<NAME>).\n for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {\n const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`\n const projectScan = process.env[envKey]\n await bootProject(registry, name, projectScan ? path.resolve(projectScan) : undefined, baseDir)\n }\n\n const host = process.env.HOST ?? '0.0.0.0'\n const port = Number(process.env.PORT ?? 8080)\n const otelPort = Number(process.env.OTEL_PORT ?? 4318)\n\n // ADR-073 §3 — refuse to bind a public address without a token.\n const auth = readAuthEnv()\n assertBindAuthority(host, auth.authToken)\n\n // Set once the OTLP receiver is built below; its routes answer on the REST\n // port too (see buildApi's `otlpReceiver`).\n let otelReceiver: FastifyInstance | undefined\n const app = await buildApi({\n projects: registry,\n authToken: auth.authToken,\n trustProxy: auth.trustProxy,\n publicRead: auth.publicRead,\n otlpReceiver: () => otelReceiver,\n })\n await app.listen({ port, host })\n console.log(`neat-core listening on http://${host}:${port}`)\n console.log(` base dir: ${baseDir}`)\n console.log(` projects: ${registry.list().join(', ')}`)\n\n // OTel ingest stays single-project for now: spans always land in the\n // default project's graph + errors log. Multi-project routing for spans\n // is a future concern (would need a header / resource attr).\n const defaultCtx = registry.get(DEFAULT_PROJECT)\n if (defaultCtx) {\n const onSpan = makeSpanHandler({\n graph: defaultCtx.graph,\n errorsPath: defaultCtx.paths.errorsPath,\n })\n const otelApp = await buildOtelReceiver({\n onSpan,\n authToken: auth.otelToken,\n trustProxy: auth.trustProxy,\n })\n otelReceiver = otelApp\n await otelApp.listen({ port: otelPort, host })\n console.log(`neat-core OTLP receiver on http://${host}:${otelPort}/v1/traces`)\n\n if (process.env.NEAT_OTLP_GRPC === 'true') {\n const grpcPort = Number(process.env.NEAT_OTLP_GRPC_PORT ?? 4317)\n const grpcReceiver = await startOtelGrpcReceiver({\n onSpan,\n host,\n port: grpcPort,\n authToken: auth.otelToken,\n trustProxy: auth.trustProxy,\n })\n console.log(`neat-core OTLP/gRPC receiver on ${grpcReceiver.address}`)\n }\n }\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neat.is/core",
3
- "version": "0.10.5",
3
+ "version": "0.10.6-dev.20261008",
4
4
  "description": "NEAT graph engine: tree-sitter extraction, OTel ingest, REST API",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://neat.is",
@@ -26,7 +26,12 @@
26
26
  "require": "./dist/index.cjs"
27
27
  },
28
28
  "./dist/cli.cjs": "./dist/cli.cjs",
29
- "./dist/neatd.cjs": "./dist/neatd.cjs"
29
+ "./dist/neatd.cjs": "./dist/neatd.cjs",
30
+ "./registry": {
31
+ "types": "./dist/registry.d.ts",
32
+ "import": "./dist/registry.js",
33
+ "require": "./dist/registry.cjs"
34
+ }
30
35
  },
31
36
  "bin": {
32
37
  "neat": "./dist/cli.cjs",
@@ -51,7 +56,7 @@
51
56
  "@fastify/cors": "^10.0.0",
52
57
  "@grpc/grpc-js": "^1.14.3",
53
58
  "@grpc/proto-loader": "^0.8.0",
54
- "@neat.is/types": "^0.10.5",
59
+ "@neat.is/types": "^0.10.6-dev.20261008",
55
60
  "chokidar": "^4.0.3",
56
61
  "fastify": "^5.0.0",
57
62
  "graphology": "^0.25.4",
@@ -82,6 +87,7 @@
82
87
  "zod": "^3.23.8"
83
88
  },
84
89
  "devDependencies": {
90
+ "@neat.is/action": "*",
85
91
  "@opentelemetry/api": "^1.9.0",
86
92
  "@opentelemetry/exporter-trace-otlp-proto": "^0.52.0",
87
93
  "@opentelemetry/resources": "^1.25.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/search.ts"],"sourcesContent":["// 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 case 'RouteNode': {\n const method = (node as { method?: string }).method\n const tmpl = (node as { pathTemplate?: string }).pathTemplate\n if (method) parts.push(`method=${method}`)\n if (tmpl) parts.push(`path=${tmpl}`)\n break\n }\n case 'GraphQLOperationNode': {\n const opType = (node as { operationType?: string }).operationType\n if (opType) parts.push(`operationType=${opType}`)\n break\n }\n case 'GrpcMethodNode': {\n const rpcService = (node as { rpcService?: string }).rpcService\n const rpcMethod = (node as { rpcMethod?: string }).rpcMethod\n if (rpcService) parts.push(`rpcService=${rpcService}`)\n if (rpcMethod) parts.push(`rpcMethod=${rpcMethod}`)\n break\n }\n case 'WebSocketChannelNode': {\n const channel = (node as { channel?: string }).channel\n if (channel) parts.push(`channel=${channel}`)\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// --------------------------------------------------------- Bounded init (#819)\n\n// How long to wait for the embedder to initialize before giving up and falling\n// back to the substring index. `pickEmbedder` reaches makeTransformersEmbedder,\n// which loads an ONNX/WASM runtime and — on a cold cache — downloads the model.\n// Either can stall: an offline or throttled network on first run, or a\n// pathological native-init on a runtime NEAT doesn't target (the Node-26 report\n// in #819). Left unbounded, that stall hangs the whole `neat watch` / dev-server\n// bring-up with no output — the worst UX, since the operator sees neither the\n// receiver come up nor an error. Bounding it turns the stall into one warning\n// line plus a substring-search fallback, so the graph stays queryable and the\n// daemon still comes up. Generous by default so a legitimately slow first-run\n// model download still lands; NEAT_SEARCH_INIT_TIMEOUT_MS overrides, and `0`\n// restores the old wait-forever behaviour for anyone who wants it.\nconst DEFAULT_SEARCH_INIT_TIMEOUT_MS = 30_000\n\nfunction searchInitTimeoutMs(): number {\n const env = process.env.NEAT_SEARCH_INIT_TIMEOUT_MS\n if (env !== undefined && env.length > 0) {\n const n = Number.parseInt(env, 10)\n if (Number.isFinite(n) && n >= 0) return n\n }\n return DEFAULT_SEARCH_INIT_TIMEOUT_MS\n}\n\n// Resolve an embedder, bounded by `timeoutMs`. A non-positive timeout means no\n// bound (wait for the factory however long it takes). On timeout we log a single\n// warning naming the stall and return null — the caller then builds the\n// substring index instead of hanging. The factory promise is left to settle in\n// the background (harmless: nothing downstream awaits it, and a later refresh\n// rebuilds the vector index if the process is still up); the point is that the\n// bring-up never blocks on it past the bound. A factory that rejects propagates\n// unchanged — that's an already-handled failure mode (buildSearchIndex's callers\n// fall back to substring on a throw); only the never-settles case is new here.\nasync function resolveEmbedderBounded(\n factory: () => Promise<Embedder | null>,\n timeoutMs: number,\n): Promise<Embedder | null> {\n if (timeoutMs <= 0) return factory()\n let timer: ReturnType<typeof setTimeout> | undefined\n const TIMED_OUT = Symbol('embedder-init-timeout')\n const timeout = new Promise<typeof TIMED_OUT>((resolve) => {\n timer = setTimeout(() => resolve(TIMED_OUT), timeoutMs)\n // Don't let the fallback timer keep the event loop alive on its own.\n timer.unref?.()\n })\n try {\n const result = await Promise.race([factory(), timeout])\n if (result === TIMED_OUT) {\n console.warn(\n `semantic_search: embedder init exceeded ${timeoutMs}ms; falling back to substring search. ` +\n `Set NEAT_SEARCH_INIT_TIMEOUT_MS to raise the bound (or 0 to wait indefinitely).`,\n )\n return null\n }\n return result\n } finally {\n if (timer) clearTimeout(timer)\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 // Override the embedder resolver (defaults to `pickEmbedder`, the\n // Ollama → transformers chain). Test seam for the init-timeout fallback\n // below — inject a factory that stalls to prove the bring-up degrades to\n // substring instead of hanging (#819), without a real model load.\n embedderFactory?: () => Promise<Embedder | null>\n // Upper bound on embedder init before falling back to substring (#819).\n // Defaults to NEAT_SEARCH_INIT_TIMEOUT_MS or 30s; `0` waits indefinitely.\n initTimeoutMs?: number\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 // Bound the embedder init so a stalled model load / native init can't hang\n // the bring-up — it degrades to substring instead (#819).\n const factory = options.embedderFactory ?? pickEmbedder\n embedder = await resolveEmbedderBounded(\n factory,\n options.initTimeoutMs ?? searchInitTimeoutMs(),\n )\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"],"mappings":"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","names":["idx"]}