reasonix 0.41.0 → 0.43.0

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 (186) hide show
  1. package/README.md +26 -3
  2. package/dashboard/dist/app.js +98 -3
  3. package/dashboard/dist/app.js.map +1 -1
  4. package/dist/cli/{acp-64VQZLDJ.js → acp-DAGPCVFZ.js} +33 -28
  5. package/dist/cli/acp-DAGPCVFZ.js.map +1 -0
  6. package/dist/cli/chat-7ES4IBNH.js +50 -0
  7. package/dist/cli/{chunk-E46ECXJD.js → chunk-2425HK6U.js} +2 -1
  8. package/dist/cli/{chunk-E46ECXJD.js.map → chunk-2425HK6U.js.map} +1 -1
  9. package/dist/cli/chunk-25T6CVUP.js +172 -0
  10. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  11. package/dist/cli/{chunk-CD4SCQL4.js → chunk-2K65GZBT.js} +11 -2
  12. package/dist/cli/chunk-2K65GZBT.js.map +1 -0
  13. package/dist/cli/{chunk-H4OLWRSX.js → chunk-2KDUS647.js} +5 -4
  14. package/dist/cli/chunk-2KDUS647.js.map +1 -0
  15. package/dist/cli/chunk-2R4QCDOZ.js +11392 -0
  16. package/dist/cli/chunk-2R4QCDOZ.js.map +1 -0
  17. package/dist/cli/{chunk-3Q3C4W66.js → chunk-2UQP6H6T.js} +2 -1
  18. package/dist/cli/{chunk-3Q3C4W66.js.map → chunk-2UQP6H6T.js.map} +1 -1
  19. package/dist/cli/chunk-2Z35JOA4.js +96 -0
  20. package/dist/cli/chunk-2Z35JOA4.js.map +1 -0
  21. package/dist/cli/chunk-32TIKD5U.js +54 -0
  22. package/dist/cli/{chunk-L7W3HJZQ.js.map → chunk-32TIKD5U.js.map} +1 -1
  23. package/dist/cli/{chunk-A3LL4XDV.js → chunk-3BXRZFWS.js} +59 -3
  24. package/dist/cli/chunk-3BXRZFWS.js.map +1 -0
  25. package/dist/cli/{chunk-SXLJBFIV.js → chunk-3Z6IBU3D.js} +11 -7
  26. package/dist/cli/chunk-3Z6IBU3D.js.map +1 -0
  27. package/dist/cli/{chunk-A7VHMMDE.js → chunk-45U62RI3.js} +12 -5
  28. package/dist/cli/chunk-45U62RI3.js.map +1 -0
  29. package/dist/cli/{chunk-7VFNPMKG.js → chunk-4QUNBQQ2.js} +3 -2
  30. package/dist/cli/{chunk-7VFNPMKG.js.map → chunk-4QUNBQQ2.js.map} +1 -1
  31. package/dist/cli/{chunk-ARF3N2SY.js → chunk-5JJRUIPA.js} +4 -3
  32. package/dist/cli/{chunk-ARF3N2SY.js.map → chunk-5JJRUIPA.js.map} +1 -1
  33. package/dist/cli/{chunk-CFY2XLY6.js → chunk-6AK4EY3D.js} +7 -5
  34. package/dist/cli/{chunk-CFY2XLY6.js.map → chunk-6AK4EY3D.js.map} +1 -1
  35. package/dist/cli/chunk-6G3CUUFG.js +34320 -0
  36. package/dist/cli/chunk-6G3CUUFG.js.map +1 -0
  37. package/dist/cli/{chunk-YJFKFTAL.js → chunk-6PBZN4VI.js} +15 -3
  38. package/dist/cli/chunk-6PBZN4VI.js.map +1 -0
  39. package/dist/cli/{chunk-4W2CICFQ.js → chunk-6PZ3CXBP.js} +71 -60
  40. package/dist/cli/chunk-6PZ3CXBP.js.map +1 -0
  41. package/dist/cli/chunk-74EX7SUH.js +25293 -0
  42. package/dist/cli/chunk-74EX7SUH.js.map +1 -0
  43. package/dist/cli/{chunk-WE3YZULK.js → chunk-7O5ALB4C.js} +3 -2
  44. package/dist/cli/{chunk-WE3YZULK.js.map → chunk-7O5ALB4C.js.map} +1 -1
  45. package/dist/cli/{chunk-2CXPDAWX.js → chunk-DOYHN4KB.js} +3 -2
  46. package/dist/cli/{chunk-2CXPDAWX.js.map → chunk-DOYHN4KB.js.map} +1 -1
  47. package/dist/cli/{chunk-VFG4GIT3.js → chunk-F3PXYSNN.js} +3 -2
  48. package/dist/cli/{chunk-VFG4GIT3.js.map → chunk-F3PXYSNN.js.map} +1 -1
  49. package/dist/cli/{chunk-7SPOFTMT.js → chunk-FHOGSSCH.js} +4 -3
  50. package/dist/cli/{chunk-7SPOFTMT.js.map → chunk-FHOGSSCH.js.map} +1 -1
  51. package/dist/cli/{chunk-LTXADNCO.js → chunk-H6PS7IUE.js} +3 -2
  52. package/dist/cli/{chunk-LTXADNCO.js.map → chunk-H6PS7IUE.js.map} +1 -1
  53. package/dist/cli/{chunk-ZTLZO42A.js → chunk-HFEAY5DT.js} +3 -2
  54. package/dist/cli/{chunk-ZTLZO42A.js.map → chunk-HFEAY5DT.js.map} +1 -1
  55. package/dist/cli/{chunk-FWGEHRB7.js → chunk-J5XJHLWM.js} +2 -1
  56. package/dist/cli/{chunk-FWGEHRB7.js.map → chunk-J5XJHLWM.js.map} +1 -1
  57. package/dist/cli/{chunk-Y5XNV3NX.js → chunk-JMBMLOBP.js} +2 -1
  58. package/dist/cli/{chunk-Y5XNV3NX.js.map → chunk-JMBMLOBP.js.map} +1 -1
  59. package/dist/cli/{chunk-BYZGO3BX.js → chunk-O52OLQL3.js} +11 -3
  60. package/dist/cli/chunk-O52OLQL3.js.map +1 -0
  61. package/dist/cli/{chunk-4DCHFFEY.js → chunk-OSZC7C6F.js} +3 -2
  62. package/dist/cli/{chunk-4DCHFFEY.js.map → chunk-OSZC7C6F.js.map} +1 -1
  63. package/dist/cli/chunk-P7EKE5ZQ.js +60641 -0
  64. package/dist/cli/chunk-P7EKE5ZQ.js.map +1 -0
  65. package/dist/cli/{chunk-FM57FNPJ.js → chunk-PLHAZOLZ.js} +2 -1
  66. package/dist/cli/{chunk-FM57FNPJ.js.map → chunk-PLHAZOLZ.js.map} +1 -1
  67. package/dist/cli/{chunk-BOFL3T45.js → chunk-PQXPXJBJ.js} +12 -11
  68. package/dist/cli/chunk-PQXPXJBJ.js.map +1 -0
  69. package/dist/cli/{chunk-DAEAAVDF.js → chunk-PV55UMTO.js} +2 -1
  70. package/dist/cli/{chunk-DAEAAVDF.js.map → chunk-PV55UMTO.js.map} +1 -1
  71. package/dist/cli/{chunk-MHGPBJ2T.js → chunk-RE4RAVFF.js} +45 -10
  72. package/dist/cli/chunk-RE4RAVFF.js.map +1 -0
  73. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  74. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  75. package/dist/cli/{chunk-WJ3YX4PZ.js → chunk-SZ5XES2N.js} +3 -2
  76. package/dist/cli/{chunk-WJ3YX4PZ.js.map → chunk-SZ5XES2N.js.map} +1 -1
  77. package/dist/cli/{chunk-UV7XJUJH.js → chunk-TJX6BFZZ.js} +16 -9
  78. package/dist/cli/{chunk-UV7XJUJH.js.map → chunk-TJX6BFZZ.js.map} +1 -1
  79. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  80. package/dist/cli/{chunk-KZYLMMU5.js → chunk-VK5HG73G.js} +13 -12
  81. package/dist/cli/{chunk-KZYLMMU5.js.map → chunk-VK5HG73G.js.map} +1 -1
  82. package/dist/cli/{chunk-4H3ZRJ2U.js → chunk-XCGGEJTI.js} +4 -3
  83. package/dist/cli/{chunk-4H3ZRJ2U.js.map → chunk-XCGGEJTI.js.map} +1 -1
  84. package/dist/cli/{chunk-SOZE7V7V.js → chunk-XJXDHAES.js} +3 -2
  85. package/dist/cli/{chunk-SOZE7V7V.js.map → chunk-XJXDHAES.js.map} +1 -1
  86. package/dist/cli/chunk-XPDVG52A.js +2648 -0
  87. package/dist/cli/chunk-XPDVG52A.js.map +1 -0
  88. package/dist/cli/{chunk-CRPQUBP6.js → chunk-XXC2BYTV.js} +2 -1
  89. package/dist/cli/{chunk-CRPQUBP6.js.map → chunk-XXC2BYTV.js.map} +1 -1
  90. package/dist/cli/{chunk-AT6GGIBV.js → chunk-YFGF5NKA.js} +17 -14
  91. package/dist/cli/{chunk-AT6GGIBV.js.map → chunk-YFGF5NKA.js.map} +1 -1
  92. package/dist/cli/{chunk-ORM6PK57.js → chunk-YQ6NTIIE.js} +2 -1
  93. package/dist/cli/{chunk-ORM6PK57.js.map → chunk-YQ6NTIIE.js.map} +1 -1
  94. package/dist/cli/{chunk-RAUPWSYA.js → chunk-YYQAUTTN.js} +3 -2
  95. package/dist/cli/{chunk-RAUPWSYA.js.map → chunk-YYQAUTTN.js.map} +1 -1
  96. package/dist/cli/chunk-ZZM6QJ4W.js +109 -0
  97. package/dist/cli/chunk-ZZM6QJ4W.js.map +1 -0
  98. package/dist/cli/{code-X3M6ENTQ.js → code-SMKEW6CD.js} +60 -56
  99. package/dist/cli/code-SMKEW6CD.js.map +1 -0
  100. package/dist/cli/{commands-QY7MSQG7.js → commands-FVVB5FZF.js} +7 -5
  101. package/dist/cli/{commands-QY7MSQG7.js.map → commands-FVVB5FZF.js.map} +1 -1
  102. package/dist/cli/{commit-BRCQ3OQO.js → commit-HE4VSPZ7.js} +7 -4
  103. package/dist/cli/{commit-BRCQ3OQO.js.map → commit-HE4VSPZ7.js.map} +1 -1
  104. package/dist/cli/{desktop-ZTMHQR2Y.js → desktop-Q7NDXCON.js} +162 -74
  105. package/dist/cli/desktop-Q7NDXCON.js.map +1 -0
  106. package/dist/cli/devtools-YECO25QO.js +3719 -0
  107. package/dist/cli/devtools-YECO25QO.js.map +1 -0
  108. package/dist/cli/diff-435UTPC5.js +165 -0
  109. package/dist/cli/{diff-YASCB7PU.js.map → diff-435UTPC5.js.map} +1 -1
  110. package/dist/cli/doctor-OT7KH75K.js +27 -0
  111. package/dist/cli/{events-2AJTXR7I.js → events-XEFAD5VX.js} +6 -4
  112. package/dist/cli/{events-2AJTXR7I.js.map → events-XEFAD5VX.js.map} +1 -1
  113. package/dist/cli/index.js +3209 -133
  114. package/dist/cli/index.js.map +1 -1
  115. package/dist/cli/{mcp-YMWBLRR7.js → mcp-WUL2WO75.js} +6 -4
  116. package/dist/cli/{mcp-YMWBLRR7.js.map → mcp-WUL2WO75.js.map} +1 -1
  117. package/dist/cli/{mcp-browse-XLDUE6SB.js → mcp-browse-RR7R4XET.js} +32 -21
  118. package/dist/cli/{mcp-browse-XLDUE6SB.js.map → mcp-browse-RR7R4XET.js.map} +1 -1
  119. package/dist/cli/{mcp-inspect-H4D2HSJP.js → mcp-inspect-REGLYBWT.js} +8 -5
  120. package/dist/cli/{mcp-inspect-H4D2HSJP.js.map → mcp-inspect-REGLYBWT.js.map} +1 -1
  121. package/dist/cli/package.json +3 -0
  122. package/dist/cli/prompt-UW6EFLVR.js +16 -0
  123. package/dist/cli/{prune-sessions-4N3BVST2.js → prune-sessions-3RWUBYRS.js} +4 -2
  124. package/dist/cli/{prune-sessions-4N3BVST2.js.map → prune-sessions-3RWUBYRS.js.map} +1 -1
  125. package/dist/cli/{replay-3GTWM75X.js → replay-YOURXV4C.js} +42 -30
  126. package/dist/cli/{replay-3GTWM75X.js.map → replay-YOURXV4C.js.map} +1 -1
  127. package/dist/cli/{run-BLZPTRDX.js → run-Q6BUXV66.js} +24 -21
  128. package/dist/cli/{run-BLZPTRDX.js.map → run-Q6BUXV66.js.map} +1 -1
  129. package/dist/cli/{server-DRFPXXSH.js → server-XGDBRWMB.js} +40 -43
  130. package/dist/cli/server-XGDBRWMB.js.map +1 -0
  131. package/dist/cli/{sessions-BOWFPTXT.js → sessions-FH7QVYSY.js} +22 -19
  132. package/dist/cli/{sessions-BOWFPTXT.js.map → sessions-FH7QVYSY.js.map} +1 -1
  133. package/dist/cli/setup-VDS6SVEP.js +618 -0
  134. package/dist/cli/setup-VDS6SVEP.js.map +1 -0
  135. package/dist/cli/stats-MQVI2XQH.js +14 -0
  136. package/dist/cli/update-6ITLPRDV.js +15 -0
  137. package/dist/cli/update-6ITLPRDV.js.map +1 -0
  138. package/dist/cli/version-DAHGZY5N.js +33 -0
  139. package/dist/cli/{version-XQXYSJ5L.js.map → version-DAHGZY5N.js.map} +1 -1
  140. package/dist/index.d.ts +12 -3
  141. package/dist/index.js +182 -97
  142. package/dist/index.js.map +1 -1
  143. package/package.json +1 -1
  144. package/dist/cli/acp-64VQZLDJ.js.map +0 -1
  145. package/dist/cli/chat-ZAGX52RV.js +0 -46
  146. package/dist/cli/chunk-4W2CICFQ.js.map +0 -1
  147. package/dist/cli/chunk-5X7LZJDE.js +0 -36
  148. package/dist/cli/chunk-5X7LZJDE.js.map +0 -1
  149. package/dist/cli/chunk-65Q5HQ26.js +0 -892
  150. package/dist/cli/chunk-65Q5HQ26.js.map +0 -1
  151. package/dist/cli/chunk-A3LL4XDV.js.map +0 -1
  152. package/dist/cli/chunk-A7VHMMDE.js.map +0 -1
  153. package/dist/cli/chunk-AFFZF3MW.js +0 -36
  154. package/dist/cli/chunk-AFFZF3MW.js.map +0 -1
  155. package/dist/cli/chunk-BOFL3T45.js.map +0 -1
  156. package/dist/cli/chunk-BYZGO3BX.js.map +0 -1
  157. package/dist/cli/chunk-CD4SCQL4.js.map +0 -1
  158. package/dist/cli/chunk-CPOV2O73.js +0 -39
  159. package/dist/cli/chunk-CPOV2O73.js.map +0 -1
  160. package/dist/cli/chunk-F2AV2QDK.js +0 -16514
  161. package/dist/cli/chunk-F2AV2QDK.js.map +0 -1
  162. package/dist/cli/chunk-H4OLWRSX.js.map +0 -1
  163. package/dist/cli/chunk-IEA6JOIP.js +0 -5430
  164. package/dist/cli/chunk-IEA6JOIP.js.map +0 -1
  165. package/dist/cli/chunk-L7W3HJZQ.js +0 -46
  166. package/dist/cli/chunk-LN27AKV3.js +0 -26
  167. package/dist/cli/chunk-LN27AKV3.js.map +0 -1
  168. package/dist/cli/chunk-MHGPBJ2T.js.map +0 -1
  169. package/dist/cli/chunk-SXLJBFIV.js.map +0 -1
  170. package/dist/cli/chunk-YJFKFTAL.js.map +0 -1
  171. package/dist/cli/code-X3M6ENTQ.js.map +0 -1
  172. package/dist/cli/desktop-ZTMHQR2Y.js.map +0 -1
  173. package/dist/cli/diff-YASCB7PU.js +0 -153
  174. package/dist/cli/doctor-XCN5ETVP.js +0 -24
  175. package/dist/cli/prompt-RSIHN62V.js +0 -14
  176. package/dist/cli/server-DRFPXXSH.js.map +0 -1
  177. package/dist/cli/setup-FQL2JJC2.js +0 -516
  178. package/dist/cli/setup-FQL2JJC2.js.map +0 -1
  179. package/dist/cli/stats-5RJCATCE.js +0 -12
  180. package/dist/cli/update-GUCWB4UN.js +0 -13
  181. package/dist/cli/version-XQXYSJ5L.js +0 -30
  182. /package/dist/cli/{chat-ZAGX52RV.js.map → chat-7ES4IBNH.js.map} +0 -0
  183. /package/dist/cli/{doctor-XCN5ETVP.js.map → chunk-TUK7OWJA.js.map} +0 -0
  184. /package/dist/cli/{prompt-RSIHN62V.js.map → doctor-OT7KH75K.js.map} +0 -0
  185. /package/dist/cli/{stats-5RJCATCE.js.map → prompt-UW6EFLVR.js.map} +0 -0
  186. /package/dist/cli/{update-GUCWB4UN.js.map → stats-MQVI2XQH.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index/semantic/builder.ts","../../src/index/semantic/chunker.ts","../../src/index/semantic/embedding.ts","../../src/index/semantic/store.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { type ResolvedEmbeddingConfig, resolveSemanticEmbeddingConfig } from \"../../config.js\";\nimport { type ResolvedIndexConfig, defaultIndexConfig } from \"../config.js\";\nimport { walkChunks } from \"./chunker.js\";\nimport type { CodeChunk, SkipReason } from \"./chunker.js\";\nimport { embed, embedAll, probeOllama } from \"./embedding.js\";\nimport type { EmbedOptions } from \"./embedding.js\";\nimport {\n compareIndexIdentity,\n normalize,\n openStore,\n readIndexMeta,\n wipeStoreFiles,\n} from \"./store.js\";\nimport type { IndexEntry, IndexIdentity, IndexMismatch, SearchHit } from \"./store.js\";\n\nexport const INDEX_DIR_NAME = path.join(\".reasonix\", \"semantic\");\n\ntype BuildOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n windowLines?: number;\n overlap?: number;\n rebuild?: boolean;\n indexConfig?: ResolvedIndexConfig;\n onProgress?: (info: BuildProgress) => void;\n configPath?: string;\n};\n\nexport type SkipBuckets = Record<SkipReason, number>;\n\nexport interface BuildProgress {\n phase: \"setup\" | \"scan\" | \"embed\" | \"write\" | \"done\";\n filesScanned?: number;\n chunksTotal?: number;\n chunksDone?: number;\n filesSkipped?: number;\n filesChanged?: number;\n skipBuckets?: SkipBuckets;\n}\n\nexport interface BuildResult {\n filesScanned: number;\n filesChanged: number;\n chunksAdded: number;\n chunksRemoved: number;\n chunksSkipped: number;\n skipBuckets: SkipBuckets;\n durationMs: number;\n}\n\nfunction emptyBuckets(): SkipBuckets {\n return {\n defaultDir: 0,\n defaultFile: 0,\n binaryExt: 0,\n binaryContent: 0,\n tooLarge: 0,\n gitignore: 0,\n pattern: 0,\n readError: 0,\n };\n}\n\nexport async function buildIndex(root: string, opts: BuildOptions = {}): Promise<BuildResult> {\n const t0 = Date.now();\n const indexDir = path.join(root, INDEX_DIR_NAME);\n const resolved = resolveBuildEmbeddingConfig(opts);\n\n opts.onProgress?.({ phase: \"setup\" });\n throwIfAborted(opts.signal);\n await probeEmbeddingProvider(resolved, opts.signal);\n throwIfAborted(opts.signal);\n\n if (opts.rebuild) await wipeStoreFiles(indexDir);\n const store = await openStore(indexDir, {\n provider: resolved.provider,\n model: resolved.model,\n });\n\n const lastMtimes = store.fileMtimes();\n const seenPaths = new Set<string>();\n const fileChunks = new Map<string, { chunks: CodeChunk[]; mtimeMs: number }>();\n let filesScanned = 0;\n let filesSkipped = 0;\n const skipBuckets = emptyBuckets();\n for await (const chunk of walkChunks(root, {\n windowLines: opts.windowLines,\n overlap: opts.overlap,\n config: opts.indexConfig ?? defaultIndexConfig(),\n onSkip: (_p, reason) => {\n skipBuckets[reason]++;\n },\n })) {\n throwIfAborted(opts.signal);\n seenPaths.add(chunk.path);\n let bucket = fileChunks.get(chunk.path);\n if (!bucket) {\n filesScanned++;\n const abs = path.join(root, chunk.path);\n let mtimeMs = 0;\n try {\n const stat = await fs.stat(abs);\n mtimeMs = stat.mtimeMs;\n } catch {\n continue;\n }\n const last = lastMtimes.get(chunk.path);\n if (last !== undefined && last === mtimeMs && !opts.rebuild) {\n filesSkipped++;\n continue;\n }\n bucket = { chunks: [], mtimeMs };\n fileChunks.set(chunk.path, bucket);\n }\n bucket.chunks.push(chunk);\n opts.onProgress?.({ phase: \"scan\", filesScanned });\n }\n\n throwIfAborted(opts.signal);\n const deletedPaths: string[] = [];\n for (const oldPath of lastMtimes.keys()) {\n if (!seenPaths.has(oldPath)) deletedPaths.push(oldPath);\n }\n const replacePaths = [...fileChunks.keys()].filter((p) => lastMtimes.has(p));\n throwIfAborted(opts.signal);\n const removed = await store.remove([...deletedPaths, ...replacePaths]);\n\n let chunksAdded = 0;\n let chunksSkipped = 0;\n const filesChanged = fileChunks.size;\n let chunksTotal = 0;\n for (const { chunks } of fileChunks.values()) chunksTotal += chunks.length;\n let chunksDone = 0;\n for (const [, bucket] of fileChunks) {\n throwIfAborted(opts.signal);\n if (bucket.chunks.length === 0) continue;\n const texts = bucket.chunks.map((c) => c.text);\n const vectors = await embedAll(texts, {\n ...resolved,\n signal: opts.signal,\n onProgress: (done, total) => {\n opts.onProgress?.({\n phase: \"embed\",\n filesScanned,\n filesChanged,\n chunksTotal,\n chunksDone: chunksDone + done,\n });\n if (done === total) chunksDone += total;\n },\n onError: (idx, err) => {\n chunksSkipped++;\n const c = bucket.chunks[idx];\n const where = c ? `${c.path}:${c.startLine}-${c.endLine}` : `chunk #${idx}`;\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`\\n ! skipped ${where}: ${msg}\\n`);\n },\n });\n throwIfAborted(opts.signal);\n const entries: IndexEntry[] = [];\n for (let i = 0; i < bucket.chunks.length; i++) {\n const vec = vectors[i];\n if (!vec) continue;\n const c = bucket.chunks[i];\n if (!c) continue;\n normalize(vec);\n entries.push({\n path: c.path,\n startLine: c.startLine,\n endLine: c.endLine,\n text: c.text,\n embedding: vec,\n mtimeMs: bucket.mtimeMs,\n });\n }\n throwIfAborted(opts.signal);\n if (entries.length > 0) await store.add(entries);\n chunksAdded += entries.length;\n }\n\n throwIfAborted(opts.signal);\n opts.onProgress?.({\n phase: \"done\",\n filesScanned,\n filesSkipped,\n filesChanged,\n chunksTotal,\n chunksDone,\n skipBuckets,\n });\n\n return {\n filesScanned,\n filesChanged,\n chunksAdded,\n chunksRemoved: removed,\n chunksSkipped,\n skipBuckets,\n durationMs: Date.now() - t0,\n };\n}\n\ntype QueryOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n topK?: number;\n minScore?: number;\n configPath?: string;\n};\n\nexport async function querySemantic(\n root: string,\n query: string,\n opts: QueryOptions = {},\n): Promise<SearchHit[] | null> {\n const indexDir = path.join(root, INDEX_DIR_NAME);\n const resolved = resolveQueryEmbeddingConfig(opts);\n const store = await openStore(indexDir, {\n provider: resolved.provider,\n model: resolved.model,\n });\n if (store.empty) return null;\n const qvec = await embed(query, { ...resolved, signal: opts.signal });\n normalize(qvec);\n return store.search(qvec, opts.topK ?? 8, opts.minScore ?? 0.3);\n}\n\nexport async function indexExists(root: string): Promise<boolean> {\n const meta = path.join(root, INDEX_DIR_NAME, \"index.meta.json\");\n try {\n await fs.access(meta);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function indexCompatible(\n root: string,\n opts: { provider?: \"ollama\" | \"openai-compat\"; model?: string; configPath?: string } = {},\n): Promise<boolean> {\n const meta = await readIndexMeta(path.join(root, INDEX_DIR_NAME));\n if (!meta) return false;\n return compareIndexIdentity(meta, resolveIndexIdentity(opts)) === null;\n}\n\nfunction resolveBuildEmbeddingConfig(opts: BuildOptions): ResolvedEmbeddingConfig {\n if (opts.provider === \"openai-compat\") {\n if (!opts.baseUrl || !opts.apiKey || !opts.model) {\n throw new Error(\n \"OpenAI-compatible embeddings require baseUrl, apiKey, and model when passed directly.\",\n );\n }\n return {\n provider: \"openai-compat\",\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n model: opts.model,\n extraBody: opts.extraBody ?? {},\n timeoutMs: opts.timeoutMs ?? 30_000,\n };\n }\n if (opts.baseUrl || opts.model) {\n return {\n provider: \"ollama\",\n baseUrl: opts.baseUrl ?? process.env.OLLAMA_URL ?? \"http://localhost:11434\",\n model: opts.model ?? process.env.REASONIX_EMBED_MODEL ?? \"nomic-embed-text\",\n timeoutMs: opts.timeoutMs ?? 30_000,\n };\n }\n return resolveSemanticEmbeddingConfig(opts.configPath);\n}\n\nfunction resolveIndexIdentity(opts: {\n provider?: \"ollama\" | \"openai-compat\";\n model?: string;\n configPath?: string;\n}): IndexIdentity {\n if (opts.provider && opts.model) {\n return { provider: opts.provider, model: opts.model };\n }\n const resolved = resolveSemanticEmbeddingConfig(opts.configPath);\n return { provider: resolved.provider, model: resolved.model };\n}\n\nfunction resolveQueryEmbeddingConfig(opts: QueryOptions): ResolvedEmbeddingConfig {\n return resolveBuildEmbeddingConfig(opts);\n}\n\nasync function probeEmbeddingProvider(\n config: ResolvedEmbeddingConfig,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (config.provider === \"openai-compat\") return;\n const probe = await probeOllama({ baseUrl: config.baseUrl, signal });\n if (!probe.ok) {\n throw new Error(\n `Ollama is not reachable: ${probe.error}. Install from https://ollama.com, then \\`ollama serve\\` and \\`ollama pull ${config.model}\\`.`,\n );\n }\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"semantic indexing aborted\");\n }\n}\n","/** Line-window chunker (not AST) — language-agnostic, every chunk carries exact startLine/endLine for cite-back. */\n\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { type GitignoreLayer, ignoredByLayers, loadGitignoreAt } from \"../../gitignore.js\";\nimport {\n type IndexFilters,\n type ResolvedIndexConfig,\n compileFilters,\n defaultIndexConfig,\n} from \"../config.js\";\n\nexport interface CodeChunk {\n /** Path relative to the index root, forward slashes. Stable across OS. */\n path: string;\n /** 1-based, inclusive. */\n startLine: number;\n endLine: number;\n text: string;\n}\n\nexport type SkipReason =\n | \"defaultDir\"\n | \"defaultFile\"\n | \"binaryExt\"\n | \"binaryContent\"\n | \"tooLarge\"\n | \"gitignore\"\n | \"pattern\"\n | \"readError\";\n\nexport interface ChunkOptions {\n /** Lines per window. Default 60. */\n windowLines?: number;\n /** Lines of overlap between consecutive windows. Default 12. */\n overlap?: number;\n /** Default 4000 — keeps unicode-heavy slices under nomic-embed-text's 8K-token window. */\n maxChunkChars?: number;\n /** Resolved exclude/limit settings. Falls back to package defaults when omitted. */\n config?: ResolvedIndexConfig;\n /** Tally callback for files that didn't make it into the index. */\n onSkip?: (relPath: string, reason: SkipReason) => void;\n}\n\n/** Default character cap per chunk — sized for nomic-embed-text. */\nexport const DEFAULT_MAX_CHUNK_CHARS = 4000;\n\nexport function chunkText(\n text: string,\n filePath: string,\n windowLines: number,\n overlap: number,\n maxChunkChars: number = DEFAULT_MAX_CHUNK_CHARS,\n): CodeChunk[] {\n const lines = text.split(/\\r?\\n/);\n if (lines.length === 0 || (lines.length === 1 && lines[0] === \"\")) return [];\n const stride = Math.max(1, windowLines - overlap);\n const chunks: CodeChunk[] = [];\n for (let start = 0; start < lines.length; start += stride) {\n const end = Math.min(lines.length, start + windowLines);\n const slice = lines.slice(start, end).join(\"\\n\").trim();\n if (slice.length === 0) {\n if (end >= lines.length) break;\n continue;\n }\n const window: CodeChunk = {\n path: filePath,\n startLine: start + 1,\n endLine: end,\n text: slice,\n };\n for (const sub of safeSplit(window, maxChunkChars)) chunks.push(sub);\n if (end >= lines.length) break;\n }\n return chunks;\n}\n\nfunction safeSplit(chunk: CodeChunk, maxChars: number): CodeChunk[] {\n if (chunk.text.length <= maxChars) return [chunk];\n const lines = chunk.text.split(\"\\n\");\n const out: CodeChunk[] = [];\n let bufLines: string[] = [];\n let bufStart = chunk.startLine;\n let bufLen = 0;\n const flush = (untilLineNo: number): void => {\n if (bufLines.length === 0) return;\n out.push({\n path: chunk.path,\n startLine: bufStart,\n endLine: untilLineNo,\n text: bufLines.join(\"\\n\"),\n });\n bufLines = [];\n bufLen = 0;\n };\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n const lineLen = line.length + 1;\n if (lineLen > maxChars) {\n flush(chunk.startLine + i - 1);\n out.push({\n path: chunk.path,\n startLine: chunk.startLine + i,\n endLine: chunk.startLine + i,\n text: line.slice(0, maxChars),\n });\n bufStart = chunk.startLine + i + 1;\n continue;\n }\n if (bufLen + lineLen > maxChars && bufLines.length > 0) {\n flush(chunk.startLine + i - 1);\n bufStart = chunk.startLine + i;\n }\n bufLines.push(line);\n bufLen += lineLen;\n }\n flush(chunk.endLine);\n return out;\n}\n\nfunction toForwardRel(root: string, abs: string): string {\n return path.relative(root, abs).split(path.sep).join(\"/\");\n}\n\ninterface WalkFrame {\n dir: string;\n layers: readonly GitignoreLayer[];\n}\n\nexport async function* walkChunks(\n root: string,\n opts: ChunkOptions = {},\n): AsyncGenerator<CodeChunk> {\n const windowLines = opts.windowLines ?? 60;\n const overlap = Math.min(opts.overlap ?? 12, Math.max(0, windowLines - 1));\n const maxChunkChars = opts.maxChunkChars ?? DEFAULT_MAX_CHUNK_CHARS;\n const filters: IndexFilters = compileFilters(opts.config ?? defaultIndexConfig());\n const onSkip = opts.onSkip ?? (() => {});\n\n const initial: GitignoreLayer[] = [];\n if (filters.respectGitignore) {\n const rootIg = await loadGitignoreAt(root);\n if (rootIg) initial.push({ dirAbs: root, ig: rootIg });\n }\n\n const stack: WalkFrame[] = [{ dir: root, layers: initial }];\n while (stack.length > 0) {\n const frame = stack.pop();\n if (!frame) break;\n const { dir, layers } = frame;\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n const name = entry.name;\n const abs = path.join(dir, name);\n const rel = toForwardRel(root, abs);\n if (entry.isDirectory()) {\n if (filters.dirSet.has(name)) {\n onSkip(rel, \"defaultDir\");\n continue;\n }\n if (filters.respectGitignore && ignoredByLayers(layers, abs, true)) {\n onSkip(rel, \"gitignore\");\n continue;\n }\n if (filters.patternMatch(`${rel}/`) || filters.patternMatch(rel)) {\n onSkip(rel, \"pattern\");\n continue;\n }\n const childLayers = filters.respectGitignore ? await extendLayers(layers, abs) : layers;\n stack.push({ dir: abs, layers: childLayers });\n continue;\n }\n if (!entry.isFile()) continue;\n if (filters.fileSet.has(name)) {\n onSkip(rel, \"defaultFile\");\n continue;\n }\n const ext = path.extname(name).toLowerCase();\n if (filters.extSet.has(ext)) {\n onSkip(rel, \"binaryExt\");\n continue;\n }\n if (filters.respectGitignore && ignoredByLayers(layers, abs, false)) {\n onSkip(rel, \"gitignore\");\n continue;\n }\n if (filters.patternMatch(rel)) {\n onSkip(rel, \"pattern\");\n continue;\n }\n // Open once and check size + read against the same fd. Skipping\n // a path-based `fs.stat` upstream is intentional — stat→open is\n // the TOCTOU shape CodeQL flags as js/file-system-race.\n const result = await readSizeBoundedFile(abs, filters.maxFileBytes);\n if (result.kind === \"skip\") {\n onSkip(rel, result.reason);\n continue;\n }\n const text = result.text;\n if (text.indexOf(\"\\0\") !== -1) {\n onSkip(rel, \"binaryContent\");\n continue;\n }\n for (const chunk of chunkText(text, rel, windowLines, overlap, maxChunkChars)) {\n yield chunk;\n }\n }\n }\n}\n\nasync function extendLayers(\n layers: readonly GitignoreLayer[],\n dirAbs: string,\n): Promise<readonly GitignoreLayer[]> {\n const ig = await loadGitignoreAt(dirAbs);\n return ig ? [...layers, { dirAbs, ig }] : layers;\n}\n\nexport async function chunkDirectory(root: string, opts: ChunkOptions = {}): Promise<CodeChunk[]> {\n const out: CodeChunk[] = [];\n for await (const c of walkChunks(root, opts)) out.push(c);\n return out;\n}\n\ntype ReadFileResult = { kind: \"ok\"; text: string } | { kind: \"skip\"; reason: SkipReason };\n\nasync function readSizeBoundedFile(abs: string, maxBytes: number): Promise<ReadFileResult> {\n try {\n const fh = await fs.open(abs, \"r\");\n try {\n const stat = await fh.stat();\n if (stat.size > maxBytes) return { kind: \"skip\", reason: \"tooLarge\" };\n return { kind: \"ok\", text: await fh.readFile(\"utf8\") };\n } finally {\n await fh.close();\n }\n } catch {\n return { kind: \"skip\", reason: \"readError\" };\n }\n}\n","const DEFAULT_OLLAMA_URL = \"http://localhost:11434\";\nconst DEFAULT_EMBED_MODEL = \"nomic-embed-text\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport type EmbedOptions =\n | {\n provider?: \"ollama\";\n baseUrl?: string;\n model?: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n }\n | {\n provider: \"openai-compat\";\n baseUrl: string;\n apiKey: string;\n model: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n };\n\nexport class EmbeddingError extends Error {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"EmbeddingError\";\n }\n}\n\nexport async function embed(text: string, opts: EmbedOptions = {}): Promise<Float32Array> {\n if (opts.provider === \"openai-compat\") return await embedOpenAICompat(text, opts);\n return await embedOllama(text, opts);\n}\n\nexport async function embedAll(\n texts: readonly string[],\n opts: EmbedOptions & {\n onProgress?: (done: number, total: number) => void;\n onError?: (index: number, err: unknown) => void;\n } = {},\n): Promise<Array<Float32Array | null>> {\n if (opts.provider === \"openai-compat\") return await embedAllOpenAICompat(texts, opts);\n const out: Array<Float32Array | null> = [];\n for (let i = 0; i < texts.length; i++) {\n if (opts.signal?.aborted) throw new EmbeddingError(\"embedding aborted\");\n const text = texts[i];\n if (text === undefined) continue;\n try {\n out.push(await embed(text, opts));\n } catch (err) {\n if (isAbortError(err) || opts.signal?.aborted) {\n throw new EmbeddingError(\"embedding aborted\", err);\n }\n opts.onError?.(i, err);\n out.push(null);\n }\n opts.onProgress?.(i + 1, texts.length);\n }\n return out;\n}\n\nexport async function probeOllama(\n opts: { baseUrl?: string; signal?: AbortSignal } = {},\n): Promise<{ ok: true; models: string[] } | { ok: false; error: string }> {\n const baseUrl = opts.baseUrl ?? process.env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL;\n try {\n const res = await fetch(`${baseUrl}/api/tags`, { signal: opts.signal });\n if (!res.ok) return { ok: false, error: `Ollama returned ${res.status}` };\n const json = (await res.json()) as { models?: Array<{ name?: string }> };\n const models = (json.models ?? [])\n .map((m) => m.name)\n .filter((n): n is string => typeof n === \"string\");\n return { ok: true, models };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { ok: false, error: msg };\n }\n}\n\nasync function embedOllama(\n text: string,\n opts: Extract<EmbedOptions, { provider?: \"ollama\" }>,\n): Promise<Float32Array> {\n const baseUrl = opts.baseUrl ?? process.env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL;\n const model = opts.model ?? process.env.REASONIX_EMBED_MODEL ?? DEFAULT_EMBED_MODEL;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const { controller, cleanup } = composeAbort(opts.signal, timeoutMs, \"embedding timeout\");\n\n let res: Response;\n try {\n res = await fetch(`${baseUrl}/api/embeddings`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ model, prompt: text }),\n signal: controller.signal,\n });\n } catch (err) {\n cleanup();\n const msg = err instanceof Error ? err.message : String(err);\n if (/ECONNREFUSED|connect ECONNREFUSED|fetch failed/i.test(msg)) {\n throw new EmbeddingError(\n `Cannot reach Ollama at ${baseUrl}. Install from https://ollama.com, then run \\`ollama pull ${model}\\` and \\`ollama serve\\`. Override the URL via OLLAMA_URL.`,\n err,\n );\n }\n throw new EmbeddingError(`embedding request failed: ${msg}`, err);\n } finally {\n cleanup();\n }\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n if (res.status === 404 && /model.*not found/i.test(body)) {\n throw new EmbeddingError(\n `Embedding model \"${model}\" not pulled. Run \\`ollama pull ${model}\\` once, then retry.`,\n );\n }\n throw new EmbeddingError(`Ollama returned ${res.status}: ${body.slice(0, 200)}`);\n }\n\n const json = (await res.json()) as { embedding?: unknown };\n if (!json.embedding || !Array.isArray(json.embedding)) {\n throw new EmbeddingError(\"Ollama response missing 'embedding' array\");\n }\n return toFloat32Array(json.embedding, \"embedding\");\n}\n\nasync function embedOpenAICompat(\n text: string,\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }>,\n): Promise<Float32Array> {\n const vectors = await requestOpenAICompatEmbeddings(text, opts);\n const v = vectors[0];\n if (!v) {\n throw new EmbeddingError(\n `Embedding provider returned no vector for the input (model ${opts.model})`,\n );\n }\n return v;\n}\n\nasync function embedAllOpenAICompat(\n texts: readonly string[],\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }> & {\n onProgress?: (done: number, total: number) => void;\n onError?: (index: number, err: unknown) => void;\n },\n): Promise<Array<Float32Array | null>> {\n if (texts.length === 0) return [];\n if (opts.signal?.aborted) throw new EmbeddingError(\"embedding aborted\");\n const vectors = await requestOpenAICompatEmbeddings([...texts], opts);\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i] === null) {\n opts.onError?.(\n i,\n new EmbeddingError(\n `provider dropped input ${i} from the batch (model ${opts.model} returned no embedding for it)`,\n ),\n );\n }\n }\n opts.onProgress?.(texts.length, texts.length);\n return vectors;\n}\n\nasync function requestOpenAICompatEmbeddings(\n input: string | string[],\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }>,\n): Promise<Array<Float32Array | null>> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const { controller, cleanup } = composeAbort(opts.signal, timeoutMs, \"embedding timeout\");\n const url = opts.baseUrl.trim();\n const body = {\n ...(opts.extraBody ?? {}),\n model: opts.model,\n input,\n encoding_format: \"float\",\n };\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${opts.apiKey}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n cleanup();\n if (isAbortError(err) || opts.signal?.aborted) {\n throw new EmbeddingError(\"embedding aborted\", err);\n }\n const msg = err instanceof Error ? err.message : String(err);\n throw new EmbeddingError(`Cannot reach OpenAI-compatible embeddings at ${url}: ${msg}`, err);\n } finally {\n cleanup();\n }\n\n if (!res.ok) {\n const raw = await res.text().catch(() => \"\");\n const bodyText = raw.slice(0, 300);\n if (res.status === 401 || res.status === 403) {\n throw new EmbeddingError(\n `OpenAI-compatible API rejected the API key for ${url}. Response ${res.status}: ${bodyText}`,\n );\n }\n if (res.status === 404) {\n throw new EmbeddingError(\n `Embeddings endpoint not found at ${url}. Check the configured API URL. Response ${res.status}: ${bodyText}`,\n );\n }\n if (res.status === 400) {\n throw new EmbeddingError(\n `Embedding provider returned 400: ${bodyText}. Check model and custom request body fields.`,\n );\n }\n throw new EmbeddingError(`OpenAI-compatible API returned ${res.status}: ${bodyText}`);\n }\n\n const json = (await res.json()) as {\n data?: Array<{ index?: unknown; embedding?: unknown }>;\n };\n if (!Array.isArray(json.data)) {\n throw new EmbeddingError(\"OpenAI-compatible response missing 'data' array\");\n }\n const size = Array.isArray(input) ? input.length : 1;\n const out: Array<Float32Array | null> = new Array(size).fill(null);\n for (const row of json.data) {\n const rawIndex = row.index;\n if (\n typeof rawIndex !== \"number\" ||\n !Number.isInteger(rawIndex) ||\n rawIndex < 0 ||\n rawIndex >= size\n ) {\n throw new EmbeddingError(\"OpenAI-compatible response returned an invalid embedding index\");\n }\n const index = rawIndex;\n if (!Array.isArray(row.embedding)) {\n throw new EmbeddingError(`OpenAI-compatible response missing embedding for index ${index}`);\n }\n out[index] = toFloat32Array(row.embedding, `data[${index}].embedding`);\n }\n return out;\n}\n\nfunction toFloat32Array(values: unknown[], label: string): Float32Array {\n const out = new Float32Array(values.length);\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new EmbeddingError(`${label}[${i}] is not a finite number`);\n }\n out[i] = value;\n }\n return out;\n}\n\nfunction composeAbort(\n signal: AbortSignal | undefined,\n timeoutMs: number,\n reason: string,\n): { controller: AbortController; cleanup: () => void } {\n const controller = new AbortController();\n const onCallerAbort = () => controller.abort(signal?.reason);\n if (signal) {\n if (signal.aborted) controller.abort(signal.reason);\n else signal.addEventListener(\"abort\", onCallerAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(new Error(reason)), timeoutMs);\n return {\n controller,\n cleanup: () => {\n clearTimeout(timer);\n if (signal) signal.removeEventListener(\"abort\", onCallerAbort);\n },\n };\n}\n\nfunction isAbortError(err: unknown): boolean {\n if (err instanceof Error) {\n if (err.name === \"AbortError\") return true;\n if (/aborted/i.test(err.message)) return true;\n }\n return false;\n}\n","/** JSONL append-only (Ctrl+C-safe) + linear cosine scan over unboxed Float32Array — fast enough for ≤10k chunks. */\n\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport type { EmbeddingProvider } from \"../../config.js\";\nimport type { CodeChunk } from \"./chunker.js\";\n\nexport interface IndexEntry extends CodeChunk {\n embedding: Float32Array;\n mtimeMs: number;\n}\n\nexport interface SearchHit {\n entry: IndexEntry;\n score: number;\n}\n\nexport type IndexMismatch = \"provider\" | \"model\";\n\nexport interface IndexIdentity {\n provider: EmbeddingProvider;\n model: string;\n}\n\nexport interface IndexMeta extends IndexIdentity {\n version: number;\n dim: number;\n updatedAt: string;\n}\n\nexport const STORE_VERSION = 1;\n\nconst META_FILE = \"index.meta.json\";\nconst DATA_FILE = \"index.jsonl\";\n\nexport async function readIndexMeta(indexDir: string): Promise<IndexMeta | null> {\n try {\n const raw = await fs.readFile(path.join(indexDir, META_FILE), \"utf8\");\n return normalizeMeta(JSON.parse(raw) as Partial<IndexMeta>);\n } catch {\n return null;\n }\n}\n\nexport function compareIndexIdentity(\n meta: IndexIdentity,\n identity: IndexIdentity,\n): IndexMismatch | null {\n if (meta.provider !== identity.provider) return \"provider\";\n if (meta.model !== identity.model) return \"model\";\n return null;\n}\n\nexport async function wipeStoreFiles(indexDir: string): Promise<void> {\n await fs.rm(path.join(indexDir, DATA_FILE), { force: true });\n await fs.rm(path.join(indexDir, META_FILE), { force: true });\n}\n\nexport class SemanticStore {\n private entries: IndexEntry[] = [];\n private byPath = new Map<string, IndexEntry[]>();\n private dim = 0;\n\n constructor(\n public readonly indexDir: string,\n public readonly identity: IndexIdentity,\n ) {}\n\n get provider(): EmbeddingProvider {\n return this.identity.provider;\n }\n\n get model(): string {\n return this.identity.model;\n }\n\n get empty(): boolean {\n return this.entries.length === 0;\n }\n\n get size(): number {\n return this.entries.length;\n }\n\n get all(): readonly IndexEntry[] {\n return this.entries;\n }\n\n fileMtimes(): Map<string, number> {\n const out = new Map<string, number>();\n for (const [p, group] of this.byPath) {\n const first = group[0];\n if (first) out.set(p, first.mtimeMs);\n }\n return out;\n }\n\n async add(entries: readonly IndexEntry[]): Promise<void> {\n if (entries.length === 0) return;\n if (this.dim === 0) this.dim = entries[0]!.embedding.length;\n const lines: string[] = [];\n for (const e of entries) {\n if (e.embedding.length !== this.dim) {\n throw new Error(\n `embedding dim mismatch: expected ${this.dim}, got ${e.embedding.length} for ${e.path}:${e.startLine}`,\n );\n }\n this.entries.push(e);\n const list = this.byPath.get(e.path);\n if (list) list.push(e);\n else this.byPath.set(e.path, [e]);\n lines.push(serializeEntry(e));\n }\n await fs.mkdir(this.indexDir, { recursive: true });\n await fs.appendFile(path.join(this.indexDir, DATA_FILE), `${lines.join(\"\\n\")}\\n`, \"utf8\");\n await this.writeMeta();\n }\n\n async remove(paths: readonly string[]): Promise<number> {\n if (paths.length === 0) return 0;\n const drop = new Set(paths);\n const before = this.entries.length;\n this.entries = this.entries.filter((e) => !drop.has(e.path));\n for (const p of paths) this.byPath.delete(p);\n const removed = before - this.entries.length;\n if (removed > 0) await this.flush();\n return removed;\n }\n\n search(query: Float32Array, topK = 8, minScore = 0): SearchHit[] {\n if (this.entries.length === 0) return [];\n if (query.length !== this.dim && this.dim !== 0) {\n throw new Error(`query dim ${query.length} ≠ index dim ${this.dim}`);\n }\n const heap: SearchHit[] = [];\n for (const entry of this.entries) {\n const score = dot(query, entry.embedding);\n if (score < minScore) continue;\n if (heap.length < topK) {\n heap.push({ entry, score });\n if (heap.length === topK) heap.sort((a, b) => a.score - b.score);\n } else if (score > heap[0]!.score) {\n heap[0] = { entry, score };\n for (let i = 0; i < heap.length - 1; i++) {\n if (heap[i]!.score > heap[i + 1]!.score) {\n const tmp = heap[i]!;\n heap[i] = heap[i + 1]!;\n heap[i + 1] = tmp;\n }\n }\n }\n }\n return heap.sort((a, b) => b.score - a.score);\n }\n\n private async flush(): Promise<void> {\n await fs.mkdir(this.indexDir, { recursive: true });\n const tmp = path.join(this.indexDir, `${DATA_FILE}.tmp`);\n const final = path.join(this.indexDir, DATA_FILE);\n const lines = this.entries.map(serializeEntry).join(\"\\n\");\n await fs.writeFile(tmp, lines.length > 0 ? `${lines}\\n` : \"\", \"utf8\");\n await fs.rename(tmp, final);\n await this.writeMeta();\n }\n\n private async writeMeta(): Promise<void> {\n const meta: IndexMeta = {\n version: STORE_VERSION,\n provider: this.provider,\n model: this.model,\n dim: this.dim,\n updatedAt: new Date().toISOString(),\n };\n await fs.writeFile(\n path.join(this.indexDir, META_FILE),\n `${JSON.stringify(meta, null, 2)}\\n`,\n \"utf8\",\n );\n }\n\n async wipe(): Promise<void> {\n this.entries = [];\n this.byPath.clear();\n this.dim = 0;\n await wipeStoreFiles(this.indexDir);\n }\n}\n\nexport async function openStore(indexDir: string, identity: IndexIdentity): Promise<SemanticStore> {\n const store = new SemanticStore(indexDir, identity);\n const dataPath = path.join(indexDir, DATA_FILE);\n\n const meta = await readIndexMeta(indexDir);\n\n if (meta) {\n if (meta.version !== STORE_VERSION) {\n throw new Error(\n `Index format version ${meta.version} does not match current ${STORE_VERSION}. Run \\`reasonix index --rebuild\\`.`,\n );\n }\n const mismatch = compareIndexIdentity(meta, identity);\n if (mismatch !== null) {\n throw new Error(\n `Index was built with provider \"${meta.provider}\" model \"${meta.model}\" but current config is provider \"${identity.provider}\" model \"${identity.model}\". Run \\`reasonix index --rebuild\\`.`,\n );\n }\n }\n\n let raw: string;\n try {\n raw = await fs.readFile(dataPath, \"utf8\");\n } catch {\n return store;\n }\n for (const line of raw.split(\"\\n\")) {\n if (line.length === 0) continue;\n try {\n const entry = deserializeEntry(line);\n (store as unknown as { dim: number }).dim = entry.embedding.length;\n (store as unknown as { entries: IndexEntry[] }).entries.push(entry);\n const map = (store as unknown as { byPath: Map<string, IndexEntry[]> }).byPath;\n const list = map.get(entry.path);\n if (list) list.push(entry);\n else map.set(entry.path, [entry]);\n } catch {\n /* tolerate malformed line */\n }\n }\n return store;\n}\n\nexport function normalize(v: Float32Array): Float32Array {\n let sum = 0;\n for (let i = 0; i < v.length; i++) sum += v[i]! * v[i]!;\n const inv = sum > 0 ? 1 / Math.sqrt(sum) : 0;\n for (let i = 0; i < v.length; i++) v[i] = v[i]! * inv;\n return v;\n}\n\nfunction dot(a: Float32Array, b: Float32Array): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += a[i]! * b[i]!;\n return s;\n}\n\nfunction serializeEntry(e: IndexEntry): string {\n const buf = Buffer.from(e.embedding.buffer, e.embedding.byteOffset, e.embedding.byteLength);\n return JSON.stringify({\n p: e.path,\n s: e.startLine,\n e: e.endLine,\n m: e.mtimeMs,\n t: e.text,\n v: buf.toString(\"base64\"),\n });\n}\n\nfunction deserializeEntry(line: string): IndexEntry {\n const parsed = JSON.parse(line) as {\n p: string;\n s: number;\n e: number;\n m: number;\n t: string;\n v: string;\n };\n const buf = Buffer.from(parsed.v, \"base64\");\n const embedding = new Float32Array(\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength),\n );\n return {\n path: parsed.p,\n startLine: parsed.s,\n endLine: parsed.e,\n mtimeMs: parsed.m,\n text: parsed.t,\n embedding: new Float32Array(embedding),\n };\n}\n\nfunction normalizeMeta(meta: Partial<IndexMeta>): IndexMeta {\n return {\n version: typeof meta.version === \"number\" ? meta.version : STORE_VERSION,\n provider: meta.provider === \"openai-compat\" ? \"openai-compat\" : \"ollama\",\n model: typeof meta.model === \"string\" ? meta.model : \"\",\n dim: typeof meta.dim === \"number\" ? meta.dim : 0,\n updatedAt: typeof meta.updatedAt === \"string\" ? meta.updatedAt : new Date(0).toISOString(),\n };\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","fs"]}
1
+ {"version":3,"sources":["../../src/index/semantic/builder.ts","../../src/index/semantic/chunker.ts","../../src/index/semantic/embedding.ts","../../src/index/semantic/store.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { type ResolvedEmbeddingConfig, resolveSemanticEmbeddingConfig } from \"../../config.js\";\nimport { type ResolvedIndexConfig, defaultIndexConfig } from \"../config.js\";\nimport { walkChunks } from \"./chunker.js\";\nimport type { CodeChunk, SkipReason } from \"./chunker.js\";\nimport { embed, embedAll, probeOllama } from \"./embedding.js\";\nimport type { EmbedOptions } from \"./embedding.js\";\nimport {\n compareIndexIdentity,\n normalize,\n openStore,\n readIndexMeta,\n wipeStoreFiles,\n} from \"./store.js\";\nimport type { IndexEntry, IndexIdentity, IndexMismatch, SearchHit } from \"./store.js\";\n\nexport const INDEX_DIR_NAME = path.join(\".reasonix\", \"semantic\");\n\ntype BuildOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n windowLines?: number;\n overlap?: number;\n rebuild?: boolean;\n indexConfig?: ResolvedIndexConfig;\n onProgress?: (info: BuildProgress) => void;\n configPath?: string;\n};\n\nexport type SkipBuckets = Record<SkipReason, number>;\n\nexport interface BuildProgress {\n phase: \"setup\" | \"scan\" | \"embed\" | \"write\" | \"done\";\n filesScanned?: number;\n chunksTotal?: number;\n chunksDone?: number;\n filesSkipped?: number;\n filesChanged?: number;\n skipBuckets?: SkipBuckets;\n}\n\nexport interface BuildResult {\n filesScanned: number;\n filesChanged: number;\n chunksAdded: number;\n chunksRemoved: number;\n chunksSkipped: number;\n skipBuckets: SkipBuckets;\n durationMs: number;\n}\n\nfunction emptyBuckets(): SkipBuckets {\n return {\n defaultDir: 0,\n defaultFile: 0,\n binaryExt: 0,\n binaryContent: 0,\n tooLarge: 0,\n gitignore: 0,\n pattern: 0,\n readError: 0,\n };\n}\n\nexport async function buildIndex(root: string, opts: BuildOptions = {}): Promise<BuildResult> {\n const t0 = Date.now();\n const indexDir = path.join(root, INDEX_DIR_NAME);\n const resolved = resolveBuildEmbeddingConfig(opts);\n\n opts.onProgress?.({ phase: \"setup\" });\n throwIfAborted(opts.signal);\n await probeEmbeddingProvider(resolved, opts.signal);\n throwIfAborted(opts.signal);\n\n if (opts.rebuild) await wipeStoreFiles(indexDir);\n const store = await openStore(indexDir, {\n provider: resolved.provider,\n model: resolved.model,\n });\n\n const lastMtimes = store.fileMtimes();\n const seenPaths = new Set<string>();\n const fileChunks = new Map<string, { chunks: CodeChunk[]; mtimeMs: number }>();\n let filesScanned = 0;\n let filesSkipped = 0;\n const skipBuckets = emptyBuckets();\n for await (const chunk of walkChunks(root, {\n windowLines: opts.windowLines,\n overlap: opts.overlap,\n config: opts.indexConfig ?? defaultIndexConfig(),\n onSkip: (_p, reason) => {\n skipBuckets[reason]++;\n },\n })) {\n throwIfAborted(opts.signal);\n seenPaths.add(chunk.path);\n let bucket = fileChunks.get(chunk.path);\n if (!bucket) {\n filesScanned++;\n const abs = path.join(root, chunk.path);\n let mtimeMs = 0;\n try {\n const stat = await fs.stat(abs);\n mtimeMs = stat.mtimeMs;\n } catch {\n continue;\n }\n const last = lastMtimes.get(chunk.path);\n if (last !== undefined && last === mtimeMs && !opts.rebuild) {\n filesSkipped++;\n continue;\n }\n bucket = { chunks: [], mtimeMs };\n fileChunks.set(chunk.path, bucket);\n }\n bucket.chunks.push(chunk);\n opts.onProgress?.({ phase: \"scan\", filesScanned });\n }\n\n throwIfAborted(opts.signal);\n const deletedPaths: string[] = [];\n for (const oldPath of lastMtimes.keys()) {\n if (!seenPaths.has(oldPath)) deletedPaths.push(oldPath);\n }\n const replacePaths = [...fileChunks.keys()].filter((p) => lastMtimes.has(p));\n throwIfAborted(opts.signal);\n const removed = await store.remove([...deletedPaths, ...replacePaths]);\n\n let chunksAdded = 0;\n let chunksSkipped = 0;\n const filesChanged = fileChunks.size;\n let chunksTotal = 0;\n for (const { chunks } of fileChunks.values()) chunksTotal += chunks.length;\n let chunksDone = 0;\n for (const [, bucket] of fileChunks) {\n throwIfAborted(opts.signal);\n if (bucket.chunks.length === 0) continue;\n const texts = bucket.chunks.map((c) => c.text);\n const vectors = await embedAll(texts, {\n ...resolved,\n signal: opts.signal,\n onProgress: (done, total) => {\n opts.onProgress?.({\n phase: \"embed\",\n filesScanned,\n filesChanged,\n chunksTotal,\n chunksDone: chunksDone + done,\n });\n if (done === total) chunksDone += total;\n },\n onError: (idx, err) => {\n chunksSkipped++;\n const c = bucket.chunks[idx];\n const where = c ? `${c.path}:${c.startLine}-${c.endLine}` : `chunk #${idx}`;\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`\\n ! skipped ${where}: ${msg}\\n`);\n },\n });\n throwIfAborted(opts.signal);\n const entries: IndexEntry[] = [];\n for (let i = 0; i < bucket.chunks.length; i++) {\n const vec = vectors[i];\n if (!vec) continue;\n const c = bucket.chunks[i];\n if (!c) continue;\n normalize(vec);\n entries.push({\n path: c.path,\n startLine: c.startLine,\n endLine: c.endLine,\n text: c.text,\n embedding: vec,\n mtimeMs: bucket.mtimeMs,\n });\n }\n throwIfAborted(opts.signal);\n if (entries.length > 0) await store.add(entries);\n chunksAdded += entries.length;\n }\n\n throwIfAborted(opts.signal);\n opts.onProgress?.({\n phase: \"done\",\n filesScanned,\n filesSkipped,\n filesChanged,\n chunksTotal,\n chunksDone,\n skipBuckets,\n });\n\n return {\n filesScanned,\n filesChanged,\n chunksAdded,\n chunksRemoved: removed,\n chunksSkipped,\n skipBuckets,\n durationMs: Date.now() - t0,\n };\n}\n\ntype QueryOptions = {\n provider?: \"ollama\" | \"openai-compat\";\n baseUrl?: string;\n apiKey?: string;\n model?: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n topK?: number;\n minScore?: number;\n configPath?: string;\n};\n\nexport async function querySemantic(\n root: string,\n query: string,\n opts: QueryOptions = {},\n): Promise<SearchHit[] | null> {\n const indexDir = path.join(root, INDEX_DIR_NAME);\n const resolved = resolveQueryEmbeddingConfig(opts);\n const store = await openStore(indexDir, {\n provider: resolved.provider,\n model: resolved.model,\n });\n if (store.empty) return null;\n const qvec = await embed(query, { ...resolved, signal: opts.signal });\n normalize(qvec);\n return store.search(qvec, opts.topK ?? 8, opts.minScore ?? 0.3);\n}\n\nexport async function indexExists(root: string): Promise<boolean> {\n const meta = path.join(root, INDEX_DIR_NAME, \"index.meta.json\");\n try {\n await fs.access(meta);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function indexCompatible(\n root: string,\n opts: { provider?: \"ollama\" | \"openai-compat\"; model?: string; configPath?: string } = {},\n): Promise<boolean> {\n const meta = await readIndexMeta(path.join(root, INDEX_DIR_NAME));\n if (!meta) return false;\n return compareIndexIdentity(meta, resolveIndexIdentity(opts)) === null;\n}\n\nfunction resolveBuildEmbeddingConfig(opts: BuildOptions): ResolvedEmbeddingConfig {\n if (opts.provider === \"openai-compat\") {\n if (!opts.baseUrl || !opts.apiKey || !opts.model) {\n throw new Error(\n \"OpenAI-compatible embeddings require baseUrl, apiKey, and model when passed directly.\",\n );\n }\n return {\n provider: \"openai-compat\",\n baseUrl: opts.baseUrl,\n apiKey: opts.apiKey,\n model: opts.model,\n extraBody: opts.extraBody ?? {},\n timeoutMs: opts.timeoutMs ?? 30_000,\n };\n }\n if (opts.baseUrl || opts.model) {\n return {\n provider: \"ollama\",\n baseUrl: opts.baseUrl ?? process.env.OLLAMA_URL ?? \"http://localhost:11434\",\n model: opts.model ?? process.env.REASONIX_EMBED_MODEL ?? \"nomic-embed-text\",\n timeoutMs: opts.timeoutMs ?? 30_000,\n };\n }\n return resolveSemanticEmbeddingConfig(opts.configPath);\n}\n\nfunction resolveIndexIdentity(opts: {\n provider?: \"ollama\" | \"openai-compat\";\n model?: string;\n configPath?: string;\n}): IndexIdentity {\n if (opts.provider && opts.model) {\n return { provider: opts.provider, model: opts.model };\n }\n const resolved = resolveSemanticEmbeddingConfig(opts.configPath);\n return { provider: resolved.provider, model: resolved.model };\n}\n\nfunction resolveQueryEmbeddingConfig(opts: QueryOptions): ResolvedEmbeddingConfig {\n return resolveBuildEmbeddingConfig(opts);\n}\n\nasync function probeEmbeddingProvider(\n config: ResolvedEmbeddingConfig,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (config.provider === \"openai-compat\") return;\n const probe = await probeOllama({ baseUrl: config.baseUrl, signal });\n if (!probe.ok) {\n throw new Error(\n `Ollama is not reachable: ${probe.error}. Install from https://ollama.com, then \\`ollama serve\\` and \\`ollama pull ${config.model}\\`.`,\n );\n }\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) {\n throw new Error(\"semantic indexing aborted\");\n }\n}\n","/** Line-window chunker (not AST) — language-agnostic, every chunk carries exact startLine/endLine for cite-back. */\n\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { type GitignoreLayer, ignoredByLayers, loadGitignoreAt } from \"../../gitignore.js\";\nimport {\n type IndexFilters,\n type ResolvedIndexConfig,\n compileFilters,\n defaultIndexConfig,\n} from \"../config.js\";\n\nexport interface CodeChunk {\n /** Path relative to the index root, forward slashes. Stable across OS. */\n path: string;\n /** 1-based, inclusive. */\n startLine: number;\n endLine: number;\n text: string;\n}\n\nexport type SkipReason =\n | \"defaultDir\"\n | \"defaultFile\"\n | \"binaryExt\"\n | \"binaryContent\"\n | \"tooLarge\"\n | \"gitignore\"\n | \"pattern\"\n | \"readError\";\n\nexport interface ChunkOptions {\n /** Lines per window. Default 60. */\n windowLines?: number;\n /** Lines of overlap between consecutive windows. Default 12. */\n overlap?: number;\n /** Default 4000 — keeps unicode-heavy slices under nomic-embed-text's 8K-token window. */\n maxChunkChars?: number;\n /** Resolved exclude/limit settings. Falls back to package defaults when omitted. */\n config?: ResolvedIndexConfig;\n /** Tally callback for files that didn't make it into the index. */\n onSkip?: (relPath: string, reason: SkipReason) => void;\n}\n\n/** Default character cap per chunk — sized for nomic-embed-text. */\nexport const DEFAULT_MAX_CHUNK_CHARS = 4000;\n\nexport function chunkText(\n text: string,\n filePath: string,\n windowLines: number,\n overlap: number,\n maxChunkChars: number = DEFAULT_MAX_CHUNK_CHARS,\n): CodeChunk[] {\n const lines = text.split(/\\r?\\n/);\n if (lines.length === 0 || (lines.length === 1 && lines[0] === \"\")) return [];\n const stride = Math.max(1, windowLines - overlap);\n const chunks: CodeChunk[] = [];\n for (let start = 0; start < lines.length; start += stride) {\n const end = Math.min(lines.length, start + windowLines);\n const slice = lines.slice(start, end).join(\"\\n\").trim();\n if (slice.length === 0) {\n if (end >= lines.length) break;\n continue;\n }\n const window: CodeChunk = {\n path: filePath,\n startLine: start + 1,\n endLine: end,\n text: slice,\n };\n for (const sub of safeSplit(window, maxChunkChars)) chunks.push(sub);\n if (end >= lines.length) break;\n }\n return chunks;\n}\n\nfunction safeSplit(chunk: CodeChunk, maxChars: number): CodeChunk[] {\n if (chunk.text.length <= maxChars) return [chunk];\n const lines = chunk.text.split(\"\\n\");\n const out: CodeChunk[] = [];\n let bufLines: string[] = [];\n let bufStart = chunk.startLine;\n let bufLen = 0;\n const flush = (untilLineNo: number): void => {\n if (bufLines.length === 0) return;\n out.push({\n path: chunk.path,\n startLine: bufStart,\n endLine: untilLineNo,\n text: bufLines.join(\"\\n\"),\n });\n bufLines = [];\n bufLen = 0;\n };\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n const lineLen = line.length + 1;\n if (lineLen > maxChars) {\n flush(chunk.startLine + i - 1);\n out.push({\n path: chunk.path,\n startLine: chunk.startLine + i,\n endLine: chunk.startLine + i,\n text: line.slice(0, maxChars),\n });\n bufStart = chunk.startLine + i + 1;\n continue;\n }\n if (bufLen + lineLen > maxChars && bufLines.length > 0) {\n flush(chunk.startLine + i - 1);\n bufStart = chunk.startLine + i;\n }\n bufLines.push(line);\n bufLen += lineLen;\n }\n flush(chunk.endLine);\n return out;\n}\n\nfunction toForwardRel(root: string, abs: string): string {\n return path.relative(root, abs).split(path.sep).join(\"/\");\n}\n\ninterface WalkFrame {\n dir: string;\n layers: readonly GitignoreLayer[];\n}\n\nexport async function* walkChunks(\n root: string,\n opts: ChunkOptions = {},\n): AsyncGenerator<CodeChunk> {\n const windowLines = opts.windowLines ?? 60;\n const overlap = Math.min(opts.overlap ?? 12, Math.max(0, windowLines - 1));\n const maxChunkChars = opts.maxChunkChars ?? DEFAULT_MAX_CHUNK_CHARS;\n const filters: IndexFilters = compileFilters(opts.config ?? defaultIndexConfig());\n const onSkip = opts.onSkip ?? (() => {});\n\n const initial: GitignoreLayer[] = [];\n if (filters.respectGitignore) {\n const rootIg = await loadGitignoreAt(root);\n if (rootIg) initial.push({ dirAbs: root, ig: rootIg });\n }\n\n const stack: WalkFrame[] = [{ dir: root, layers: initial }];\n while (stack.length > 0) {\n const frame = stack.pop();\n if (!frame) break;\n const { dir, layers } = frame;\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n const name = entry.name;\n const abs = path.join(dir, name);\n const rel = toForwardRel(root, abs);\n if (entry.isDirectory()) {\n if (filters.dirSet.has(name)) {\n onSkip(rel, \"defaultDir\");\n continue;\n }\n if (filters.respectGitignore && ignoredByLayers(layers, abs, true)) {\n onSkip(rel, \"gitignore\");\n continue;\n }\n if (filters.patternMatch(`${rel}/`) || filters.patternMatch(rel)) {\n onSkip(rel, \"pattern\");\n continue;\n }\n const childLayers = filters.respectGitignore ? await extendLayers(layers, abs) : layers;\n stack.push({ dir: abs, layers: childLayers });\n continue;\n }\n if (!entry.isFile()) continue;\n if (filters.fileSet.has(name)) {\n onSkip(rel, \"defaultFile\");\n continue;\n }\n const ext = path.extname(name).toLowerCase();\n if (filters.extSet.has(ext)) {\n onSkip(rel, \"binaryExt\");\n continue;\n }\n if (filters.respectGitignore && ignoredByLayers(layers, abs, false)) {\n onSkip(rel, \"gitignore\");\n continue;\n }\n if (filters.patternMatch(rel)) {\n onSkip(rel, \"pattern\");\n continue;\n }\n // Open once and check size + read against the same fd. Skipping\n // a path-based `fs.stat` upstream is intentional — stat→open is\n // the TOCTOU shape CodeQL flags as js/file-system-race.\n const result = await readSizeBoundedFile(abs, filters.maxFileBytes);\n if (result.kind === \"skip\") {\n onSkip(rel, result.reason);\n continue;\n }\n const text = result.text;\n if (text.indexOf(\"\\0\") !== -1) {\n onSkip(rel, \"binaryContent\");\n continue;\n }\n for (const chunk of chunkText(text, rel, windowLines, overlap, maxChunkChars)) {\n yield chunk;\n }\n }\n }\n}\n\nasync function extendLayers(\n layers: readonly GitignoreLayer[],\n dirAbs: string,\n): Promise<readonly GitignoreLayer[]> {\n const ig = await loadGitignoreAt(dirAbs);\n return ig ? [...layers, { dirAbs, ig }] : layers;\n}\n\nexport async function chunkDirectory(root: string, opts: ChunkOptions = {}): Promise<CodeChunk[]> {\n const out: CodeChunk[] = [];\n for await (const c of walkChunks(root, opts)) out.push(c);\n return out;\n}\n\ntype ReadFileResult = { kind: \"ok\"; text: string } | { kind: \"skip\"; reason: SkipReason };\n\nasync function readSizeBoundedFile(abs: string, maxBytes: number): Promise<ReadFileResult> {\n try {\n const fh = await fs.open(abs, \"r\");\n try {\n const stat = await fh.stat();\n if (stat.size > maxBytes) return { kind: \"skip\", reason: \"tooLarge\" };\n return { kind: \"ok\", text: await fh.readFile(\"utf8\") };\n } finally {\n await fh.close();\n }\n } catch {\n return { kind: \"skip\", reason: \"readError\" };\n }\n}\n","const DEFAULT_OLLAMA_URL = \"http://localhost:11434\";\nconst DEFAULT_EMBED_MODEL = \"nomic-embed-text\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport type EmbedOptions =\n | {\n provider?: \"ollama\";\n baseUrl?: string;\n model?: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n }\n | {\n provider: \"openai-compat\";\n baseUrl: string;\n apiKey: string;\n model: string;\n extraBody?: Record<string, unknown>;\n timeoutMs?: number;\n signal?: AbortSignal;\n };\n\nexport class EmbeddingError extends Error {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"EmbeddingError\";\n }\n}\n\nexport async function embed(text: string, opts: EmbedOptions = {}): Promise<Float32Array> {\n if (opts.provider === \"openai-compat\") return await embedOpenAICompat(text, opts);\n return await embedOllama(text, opts);\n}\n\nexport async function embedAll(\n texts: readonly string[],\n opts: EmbedOptions & {\n onProgress?: (done: number, total: number) => void;\n onError?: (index: number, err: unknown) => void;\n } = {},\n): Promise<Array<Float32Array | null>> {\n if (opts.provider === \"openai-compat\") return await embedAllOpenAICompat(texts, opts);\n const out: Array<Float32Array | null> = [];\n for (let i = 0; i < texts.length; i++) {\n if (opts.signal?.aborted) throw new EmbeddingError(\"embedding aborted\");\n const text = texts[i];\n if (text === undefined) continue;\n try {\n out.push(await embed(text, opts));\n } catch (err) {\n if (isAbortError(err) || opts.signal?.aborted) {\n throw new EmbeddingError(\"embedding aborted\", err);\n }\n opts.onError?.(i, err);\n out.push(null);\n }\n opts.onProgress?.(i + 1, texts.length);\n }\n return out;\n}\n\nexport async function probeOllama(\n opts: { baseUrl?: string; signal?: AbortSignal } = {},\n): Promise<{ ok: true; models: string[] } | { ok: false; error: string }> {\n const baseUrl = opts.baseUrl ?? process.env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL;\n try {\n const res = await fetch(`${baseUrl}/api/tags`, { signal: opts.signal });\n if (!res.ok) return { ok: false, error: `Ollama returned ${res.status}` };\n const json = (await res.json()) as { models?: Array<{ name?: string }> };\n const models = (json.models ?? [])\n .map((m) => m.name)\n .filter((n): n is string => typeof n === \"string\");\n return { ok: true, models };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { ok: false, error: msg };\n }\n}\n\nasync function embedOllama(\n text: string,\n opts: Extract<EmbedOptions, { provider?: \"ollama\" }>,\n): Promise<Float32Array> {\n const baseUrl = opts.baseUrl ?? process.env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL;\n const model = opts.model ?? process.env.REASONIX_EMBED_MODEL ?? DEFAULT_EMBED_MODEL;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const { controller, cleanup } = composeAbort(opts.signal, timeoutMs, \"embedding timeout\");\n\n let res: Response;\n try {\n res = await fetch(`${baseUrl}/api/embeddings`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ model, prompt: text }),\n signal: controller.signal,\n });\n } catch (err) {\n cleanup();\n const msg = err instanceof Error ? err.message : String(err);\n if (/ECONNREFUSED|connect ECONNREFUSED|fetch failed/i.test(msg)) {\n throw new EmbeddingError(\n `Cannot reach Ollama at ${baseUrl}. Install from https://ollama.com, then run \\`ollama pull ${model}\\` and \\`ollama serve\\`. Override the URL via OLLAMA_URL.`,\n err,\n );\n }\n throw new EmbeddingError(`embedding request failed: ${msg}`, err);\n } finally {\n cleanup();\n }\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n if (res.status === 404 && /model.*not found/i.test(body)) {\n throw new EmbeddingError(\n `Embedding model \"${model}\" not pulled. Run \\`ollama pull ${model}\\` once, then retry.`,\n );\n }\n throw new EmbeddingError(`Ollama returned ${res.status}: ${body.slice(0, 200)}`);\n }\n\n const json = (await res.json()) as { embedding?: unknown };\n if (!json.embedding || !Array.isArray(json.embedding)) {\n throw new EmbeddingError(\"Ollama response missing 'embedding' array\");\n }\n return toFloat32Array(json.embedding, \"embedding\");\n}\n\nasync function embedOpenAICompat(\n text: string,\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }>,\n): Promise<Float32Array> {\n const vectors = await requestOpenAICompatEmbeddings(text, opts);\n const v = vectors[0];\n if (!v) {\n throw new EmbeddingError(\n `Embedding provider returned no vector for the input (model ${opts.model})`,\n );\n }\n return v;\n}\n\nasync function embedAllOpenAICompat(\n texts: readonly string[],\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }> & {\n onProgress?: (done: number, total: number) => void;\n onError?: (index: number, err: unknown) => void;\n },\n): Promise<Array<Float32Array | null>> {\n if (texts.length === 0) return [];\n if (opts.signal?.aborted) throw new EmbeddingError(\"embedding aborted\");\n const vectors = await requestOpenAICompatEmbeddings([...texts], opts);\n for (let i = 0; i < vectors.length; i++) {\n if (vectors[i] === null) {\n opts.onError?.(\n i,\n new EmbeddingError(\n `provider dropped input ${i} from the batch (model ${opts.model} returned no embedding for it)`,\n ),\n );\n }\n }\n opts.onProgress?.(texts.length, texts.length);\n return vectors;\n}\n\nasync function requestOpenAICompatEmbeddings(\n input: string | string[],\n opts: Extract<EmbedOptions, { provider: \"openai-compat\" }>,\n): Promise<Array<Float32Array | null>> {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const { controller, cleanup } = composeAbort(opts.signal, timeoutMs, \"embedding timeout\");\n const url = opts.baseUrl.trim();\n const body = {\n ...(opts.extraBody ?? {}),\n model: opts.model,\n input,\n encoding_format: \"float\",\n };\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${opts.apiKey}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n cleanup();\n if (isAbortError(err) || opts.signal?.aborted) {\n throw new EmbeddingError(\"embedding aborted\", err);\n }\n const msg = err instanceof Error ? err.message : String(err);\n throw new EmbeddingError(`Cannot reach OpenAI-compatible embeddings at ${url}: ${msg}`, err);\n } finally {\n cleanup();\n }\n\n if (!res.ok) {\n const raw = await res.text().catch(() => \"\");\n const bodyText = raw.slice(0, 300);\n if (res.status === 401 || res.status === 403) {\n throw new EmbeddingError(\n `OpenAI-compatible API rejected the API key for ${url}. Response ${res.status}: ${bodyText}`,\n );\n }\n if (res.status === 404) {\n throw new EmbeddingError(\n `Embeddings endpoint not found at ${url}. Check the configured API URL. Response ${res.status}: ${bodyText}`,\n );\n }\n if (res.status === 400) {\n throw new EmbeddingError(\n `Embedding provider returned 400: ${bodyText}. Check model and custom request body fields.`,\n );\n }\n throw new EmbeddingError(`OpenAI-compatible API returned ${res.status}: ${bodyText}`);\n }\n\n const json = (await res.json()) as {\n data?: Array<{ index?: unknown; embedding?: unknown }>;\n };\n if (!Array.isArray(json.data)) {\n throw new EmbeddingError(\"OpenAI-compatible response missing 'data' array\");\n }\n const size = Array.isArray(input) ? input.length : 1;\n const out: Array<Float32Array | null> = new Array(size).fill(null);\n for (const row of json.data) {\n const rawIndex = row.index;\n if (\n typeof rawIndex !== \"number\" ||\n !Number.isInteger(rawIndex) ||\n rawIndex < 0 ||\n rawIndex >= size\n ) {\n throw new EmbeddingError(\"OpenAI-compatible response returned an invalid embedding index\");\n }\n const index = rawIndex;\n if (!Array.isArray(row.embedding)) {\n throw new EmbeddingError(`OpenAI-compatible response missing embedding for index ${index}`);\n }\n out[index] = toFloat32Array(row.embedding, `data[${index}].embedding`);\n }\n return out;\n}\n\nfunction toFloat32Array(values: unknown[], label: string): Float32Array {\n const out = new Float32Array(values.length);\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new EmbeddingError(`${label}[${i}] is not a finite number`);\n }\n out[i] = value;\n }\n return out;\n}\n\nfunction composeAbort(\n signal: AbortSignal | undefined,\n timeoutMs: number,\n reason: string,\n): { controller: AbortController; cleanup: () => void } {\n const controller = new AbortController();\n const onCallerAbort = () => controller.abort(signal?.reason);\n if (signal) {\n if (signal.aborted) controller.abort(signal.reason);\n else signal.addEventListener(\"abort\", onCallerAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(new Error(reason)), timeoutMs);\n return {\n controller,\n cleanup: () => {\n clearTimeout(timer);\n if (signal) signal.removeEventListener(\"abort\", onCallerAbort);\n },\n };\n}\n\nfunction isAbortError(err: unknown): boolean {\n if (err instanceof Error) {\n if (err.name === \"AbortError\") return true;\n if (/aborted/i.test(err.message)) return true;\n }\n return false;\n}\n","/** JSONL append-only (Ctrl+C-safe) + linear cosine scan over unboxed Float32Array — fast enough for ≤10k chunks. */\n\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport type { EmbeddingProvider } from \"../../config.js\";\nimport type { CodeChunk } from \"./chunker.js\";\n\nexport interface IndexEntry extends CodeChunk {\n embedding: Float32Array;\n mtimeMs: number;\n}\n\nexport interface SearchHit {\n entry: IndexEntry;\n score: number;\n}\n\nexport type IndexMismatch = \"provider\" | \"model\";\n\nexport interface IndexIdentity {\n provider: EmbeddingProvider;\n model: string;\n}\n\nexport interface IndexMeta extends IndexIdentity {\n version: number;\n dim: number;\n updatedAt: string;\n}\n\nexport const STORE_VERSION = 1;\n\nconst META_FILE = \"index.meta.json\";\nconst DATA_FILE = \"index.jsonl\";\n\nexport async function readIndexMeta(indexDir: string): Promise<IndexMeta | null> {\n try {\n const raw = await fs.readFile(path.join(indexDir, META_FILE), \"utf8\");\n return normalizeMeta(JSON.parse(raw) as Partial<IndexMeta>);\n } catch {\n return null;\n }\n}\n\nexport function compareIndexIdentity(\n meta: IndexIdentity,\n identity: IndexIdentity,\n): IndexMismatch | null {\n if (meta.provider !== identity.provider) return \"provider\";\n if (meta.model !== identity.model) return \"model\";\n return null;\n}\n\nexport async function wipeStoreFiles(indexDir: string): Promise<void> {\n await fs.rm(path.join(indexDir, DATA_FILE), { force: true });\n await fs.rm(path.join(indexDir, META_FILE), { force: true });\n}\n\nexport class SemanticStore {\n private entries: IndexEntry[] = [];\n private byPath = new Map<string, IndexEntry[]>();\n private dim = 0;\n\n constructor(\n public readonly indexDir: string,\n public readonly identity: IndexIdentity,\n ) {}\n\n get provider(): EmbeddingProvider {\n return this.identity.provider;\n }\n\n get model(): string {\n return this.identity.model;\n }\n\n get empty(): boolean {\n return this.entries.length === 0;\n }\n\n get size(): number {\n return this.entries.length;\n }\n\n get all(): readonly IndexEntry[] {\n return this.entries;\n }\n\n fileMtimes(): Map<string, number> {\n const out = new Map<string, number>();\n for (const [p, group] of this.byPath) {\n const first = group[0];\n if (first) out.set(p, first.mtimeMs);\n }\n return out;\n }\n\n async add(entries: readonly IndexEntry[]): Promise<void> {\n if (entries.length === 0) return;\n if (this.dim === 0) this.dim = entries[0]!.embedding.length;\n const lines: string[] = [];\n for (const e of entries) {\n if (e.embedding.length !== this.dim) {\n throw new Error(\n `embedding dim mismatch: expected ${this.dim}, got ${e.embedding.length} for ${e.path}:${e.startLine}`,\n );\n }\n this.entries.push(e);\n const list = this.byPath.get(e.path);\n if (list) list.push(e);\n else this.byPath.set(e.path, [e]);\n lines.push(serializeEntry(e));\n }\n await fs.mkdir(this.indexDir, { recursive: true });\n await fs.appendFile(path.join(this.indexDir, DATA_FILE), `${lines.join(\"\\n\")}\\n`, \"utf8\");\n await this.writeMeta();\n }\n\n async remove(paths: readonly string[]): Promise<number> {\n if (paths.length === 0) return 0;\n const drop = new Set(paths);\n const before = this.entries.length;\n this.entries = this.entries.filter((e) => !drop.has(e.path));\n for (const p of paths) this.byPath.delete(p);\n const removed = before - this.entries.length;\n if (removed > 0) await this.flush();\n return removed;\n }\n\n search(query: Float32Array, topK = 8, minScore = 0): SearchHit[] {\n if (this.entries.length === 0) return [];\n if (query.length !== this.dim && this.dim !== 0) {\n throw new Error(`query dim ${query.length} ≠ index dim ${this.dim}`);\n }\n const heap: SearchHit[] = [];\n for (const entry of this.entries) {\n const score = dot(query, entry.embedding);\n if (score < minScore) continue;\n if (heap.length < topK) {\n heap.push({ entry, score });\n if (heap.length === topK) heap.sort((a, b) => a.score - b.score);\n } else if (score > heap[0]!.score) {\n heap[0] = { entry, score };\n for (let i = 0; i < heap.length - 1; i++) {\n if (heap[i]!.score > heap[i + 1]!.score) {\n const tmp = heap[i]!;\n heap[i] = heap[i + 1]!;\n heap[i + 1] = tmp;\n }\n }\n }\n }\n return heap.sort((a, b) => b.score - a.score);\n }\n\n private async flush(): Promise<void> {\n await fs.mkdir(this.indexDir, { recursive: true });\n const tmp = path.join(this.indexDir, `${DATA_FILE}.tmp`);\n const final = path.join(this.indexDir, DATA_FILE);\n const lines = this.entries.map(serializeEntry).join(\"\\n\");\n await fs.writeFile(tmp, lines.length > 0 ? `${lines}\\n` : \"\", \"utf8\");\n await fs.rename(tmp, final);\n await this.writeMeta();\n }\n\n private async writeMeta(): Promise<void> {\n const meta: IndexMeta = {\n version: STORE_VERSION,\n provider: this.provider,\n model: this.model,\n dim: this.dim,\n updatedAt: new Date().toISOString(),\n };\n await fs.writeFile(\n path.join(this.indexDir, META_FILE),\n `${JSON.stringify(meta, null, 2)}\\n`,\n \"utf8\",\n );\n }\n\n async wipe(): Promise<void> {\n this.entries = [];\n this.byPath.clear();\n this.dim = 0;\n await wipeStoreFiles(this.indexDir);\n }\n}\n\nexport async function openStore(indexDir: string, identity: IndexIdentity): Promise<SemanticStore> {\n const store = new SemanticStore(indexDir, identity);\n const dataPath = path.join(indexDir, DATA_FILE);\n\n const meta = await readIndexMeta(indexDir);\n\n if (meta) {\n if (meta.version !== STORE_VERSION) {\n throw new Error(\n `Index format version ${meta.version} does not match current ${STORE_VERSION}. Run \\`reasonix index --rebuild\\`.`,\n );\n }\n const mismatch = compareIndexIdentity(meta, identity);\n if (mismatch !== null) {\n throw new Error(\n `Index was built with provider \"${meta.provider}\" model \"${meta.model}\" but current config is provider \"${identity.provider}\" model \"${identity.model}\". Run \\`reasonix index --rebuild\\`.`,\n );\n }\n }\n\n let raw: string;\n try {\n raw = await fs.readFile(dataPath, \"utf8\");\n } catch {\n return store;\n }\n for (const line of raw.split(\"\\n\")) {\n if (line.length === 0) continue;\n try {\n const entry = deserializeEntry(line);\n (store as unknown as { dim: number }).dim = entry.embedding.length;\n (store as unknown as { entries: IndexEntry[] }).entries.push(entry);\n const map = (store as unknown as { byPath: Map<string, IndexEntry[]> }).byPath;\n const list = map.get(entry.path);\n if (list) list.push(entry);\n else map.set(entry.path, [entry]);\n } catch {\n /* tolerate malformed line */\n }\n }\n return store;\n}\n\nexport function normalize(v: Float32Array): Float32Array {\n let sum = 0;\n for (let i = 0; i < v.length; i++) sum += v[i]! * v[i]!;\n const inv = sum > 0 ? 1 / Math.sqrt(sum) : 0;\n for (let i = 0; i < v.length; i++) v[i] = v[i]! * inv;\n return v;\n}\n\nfunction dot(a: Float32Array, b: Float32Array): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += a[i]! * b[i]!;\n return s;\n}\n\nfunction serializeEntry(e: IndexEntry): string {\n const buf = Buffer.from(e.embedding.buffer, e.embedding.byteOffset, e.embedding.byteLength);\n return JSON.stringify({\n p: e.path,\n s: e.startLine,\n e: e.endLine,\n m: e.mtimeMs,\n t: e.text,\n v: buf.toString(\"base64\"),\n });\n}\n\nfunction deserializeEntry(line: string): IndexEntry {\n const parsed = JSON.parse(line) as {\n p: string;\n s: number;\n e: number;\n m: number;\n t: string;\n v: string;\n };\n const buf = Buffer.from(parsed.v, \"base64\");\n const embedding = new Float32Array(\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength),\n );\n return {\n path: parsed.p,\n startLine: parsed.s,\n endLine: parsed.e,\n mtimeMs: parsed.m,\n text: parsed.t,\n embedding: new Float32Array(embedding),\n };\n}\n\nfunction normalizeMeta(meta: Partial<IndexMeta>): IndexMeta {\n return {\n version: typeof meta.version === \"number\" ? meta.version : STORE_VERSION,\n provider: meta.provider === \"openai-compat\" ? \"openai-compat\" : \"ollama\",\n model: typeof meta.model === \"string\" ? meta.model : \"\",\n dim: typeof meta.dim === \"number\" ? meta.dim : 0,\n updatedAt: typeof meta.updatedAt === \"string\" ? meta.updatedAt : new Date(0).toISOString(),\n };\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","fs"]}
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
2
3
  import {
3
4
  MCP_CATALOG
4
- } from "./chunk-FM57FNPJ.js";
5
+ } from "./chunk-PLHAZOLZ.js";
5
6
 
6
7
  // src/mcp/registry-fetch.ts
7
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -337,4 +338,4 @@ export {
337
338
  specStringFor,
338
339
  handleToFetchResult
339
340
  };
340
- //# sourceMappingURL=chunk-SOZE7V7V.js.map
341
+ //# sourceMappingURL=chunk-XJXDHAES.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/registry-fetch.ts"],"sourcesContent":["/** Primary: registry.modelcontextprotocol.io. Fallback: registry.smithery.ai. Last resort: bundled MCP_CATALOG. */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { MCP_CATALOG } from \"./catalog.js\";\nimport type {\n CacheFile,\n CachePagination,\n RegistryEntry,\n RegistryInstall,\n RegistrySource,\n} from \"./registry-types.js\";\n\nexport const OFFICIAL_REGISTRY_URL = \"https://registry.modelcontextprotocol.io/v0/servers\";\nexport const SMITHERY_REGISTRY_URL = \"https://registry.smithery.ai/servers\";\nexport const CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nexport const FETCH_TIMEOUT_MS = 10_000;\nexport const CACHE_SCHEMA_VERSION = 2;\n\nexport function defaultCachePath(): string {\n return join(homedir(), \".reasonix\", \"mcp-registry-cache.json\");\n}\n\nfunction readCache(path: string): CacheFile | null {\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<CacheFile>;\n if (\n parsed.schemaVersion !== CACHE_SCHEMA_VERSION ||\n typeof parsed.fetchedAt !== \"number\" ||\n !Array.isArray(parsed.entries) ||\n typeof parsed.pagination?.pagesLoaded !== \"number\"\n ) {\n return null;\n }\n return parsed as CacheFile;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(path: string, file: CacheFile): void {\n try {\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(path, JSON.stringify(file, null, 2));\n } catch {\n /* cache failures are non-fatal */\n }\n}\n\nasync function timeoutFetch(url: string, fetcher: typeof fetch): Promise<Response> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);\n try {\n return await fetcher(url, { signal: ctrl.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\ninterface OfficialPackage {\n registryType?: string;\n identifier?: string;\n version?: string;\n transport?: { type?: string };\n environmentVariables?: Array<{ name?: string }>;\n}\n\ninterface OfficialServerCore {\n name?: string;\n title?: string;\n description?: string;\n packages?: OfficialPackage[];\n remotes?: Array<{ type?: string; url?: string }>;\n websiteUrl?: string;\n icons?: Array<{ src?: string }>;\n}\n\ninterface OfficialServerEntry {\n server?: OfficialServerCore;\n}\n\ninterface OfficialResponse {\n servers?: OfficialServerEntry[];\n metadata?: { nextCursor?: string };\n}\n\nfunction normalizeOfficialPackage(pkg: OfficialPackage | undefined): RegistryInstall | undefined {\n if (!pkg) return undefined;\n const runtime = pkg.registryType === \"npm\" ? \"npm\" : pkg.registryType === \"pypi\" ? \"pypi\" : null;\n if (!runtime) return undefined;\n const t = pkg.transport?.type;\n const transport: RegistryInstall[\"transport\"] =\n t === \"sse\" ? \"sse\" : t === \"streamable-http\" ? \"streamable-http\" : \"stdio\";\n const requiredEnv = (pkg.environmentVariables ?? [])\n .map((e) => e.name)\n .filter((n): n is string => typeof n === \"string\" && n.length > 0);\n const install: RegistryInstall = { runtime, transport };\n if (pkg.identifier) install.packageId = pkg.identifier;\n if (pkg.version) install.version = pkg.version;\n if (requiredEnv.length > 0) install.requiredEnv = requiredEnv;\n return install;\n}\n\nfunction normalizeOfficial(server: OfficialServerCore | undefined): RegistryEntry | null {\n if (!server?.name) return null;\n let install = normalizeOfficialPackage(server.packages?.[0]);\n if (!install && server.remotes?.[0]?.url) {\n const remote = server.remotes[0];\n const transport: RegistryInstall[\"transport\"] =\n remote.type === \"streamable-http\" ? \"streamable-http\" : \"sse\";\n install = { runtime: \"remote\", transport, url: remote.url };\n }\n const entry: RegistryEntry = {\n name: server.name,\n title: server.title || server.name,\n description: server.description ?? \"\",\n source: \"official\",\n };\n if (install) entry.install = install;\n if (server.websiteUrl) entry.homepage = server.websiteUrl;\n const icon = server.icons?.find((i) => i.src)?.src;\n if (icon) entry.iconUrl = icon;\n return entry;\n}\n\ninterface OfficialPageResult {\n entries: RegistryEntry[];\n nextCursor: string | null;\n}\n\nexport async function fetchOfficialPage(\n cursor: string | null,\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<OfficialPageResult> {\n const url = cursor\n ? `${OFFICIAL_REGISTRY_URL}?cursor=${encodeURIComponent(cursor)}`\n : OFFICIAL_REGISTRY_URL;\n const resp = await timeoutFetch(url, fetcher);\n if (!resp.ok) throw new Error(`official registry HTTP ${resp.status}`);\n const json = (await resp.json()) as OfficialResponse;\n const entries: RegistryEntry[] = [];\n for (const e of json.servers ?? []) {\n const norm = normalizeOfficial(e.server);\n if (norm) entries.push(norm);\n }\n return { entries, nextCursor: json.metadata?.nextCursor ?? null };\n}\n\ninterface SmitheryServer {\n qualifiedName?: string;\n displayName?: string;\n description?: string;\n useCount?: number;\n homepage?: string;\n iconUrl?: string;\n}\n\ninterface SmitheryResponse {\n servers?: SmitheryServer[];\n pagination?: { totalPages?: number; pageSize?: number };\n}\n\nfunction normalizeSmithery(s: SmitheryServer): RegistryEntry | null {\n if (!s.qualifiedName) return null;\n const entry: RegistryEntry = {\n name: s.qualifiedName,\n title: s.displayName || s.qualifiedName,\n description: s.description ?? \"\",\n source: \"smithery\",\n };\n if (typeof s.useCount === \"number\") entry.popularity = s.useCount;\n if (s.homepage) entry.homepage = s.homepage;\n if (s.iconUrl) entry.iconUrl = s.iconUrl;\n return entry;\n}\n\ninterface SmitheryConnection {\n type?: string;\n deploymentUrl?: string;\n bundleUrl?: string;\n runtime?: string;\n}\n\ninterface SmitheryDetailResponse {\n qualifiedName?: string;\n remote?: boolean;\n deploymentUrl?: string | null;\n connections?: SmitheryConnection[];\n}\n\n/** Resolve a Smithery listing entry into a runnable install. http → streamable-http remote; stdio → spawn via @smithery/cli. */\nexport async function fetchSmitheryDetail(\n qualifiedName: string,\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<RegistryInstall | null> {\n const url = `${SMITHERY_REGISTRY_URL}/${encodeURIComponent(qualifiedName)}`;\n const resp = await timeoutFetch(url, fetcher);\n if (!resp.ok) return null;\n const json = (await resp.json()) as SmitheryDetailResponse;\n const conn = json.connections?.[0];\n if (!conn) return null;\n if (conn.type === \"http\" || conn.type === \"ws\") {\n const deploymentUrl = conn.deploymentUrl ?? json.deploymentUrl;\n if (!deploymentUrl) return null;\n return { runtime: \"remote\", transport: \"streamable-http\", url: deploymentUrl };\n }\n if (conn.type === \"stdio\") {\n return {\n runtime: \"npm\",\n packageId: \"@smithery/cli\",\n transport: \"stdio\",\n extraArgs: [\"run\", qualifiedName],\n };\n }\n return null;\n}\n\nexport async function fetchSmitheryFirstPage(\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<RegistryEntry[]> {\n const resp = await timeoutFetch(SMITHERY_REGISTRY_URL, fetcher);\n if (!resp.ok) throw new Error(`smithery HTTP ${resp.status}`);\n const json = (await resp.json()) as SmitheryResponse;\n const entries = (json.servers ?? [])\n .map(normalizeSmithery)\n .filter((x): x is RegistryEntry => x !== null);\n if (entries.length === 0) throw new Error(\"smithery returned no entries\");\n return entries;\n}\n\nexport function fallbackFromCatalog(): RegistryEntry[] {\n return MCP_CATALOG.map((e) => ({\n name: e.name,\n title: e.name,\n description: e.summary,\n source: \"local\" as const,\n install: {\n runtime: \"npm\" as const,\n packageId: e.package,\n transport: \"stdio\" as const,\n },\n }));\n}\n\nexport type FetchProgress = (info: {\n source: \"official\" | \"smithery\";\n page: number;\n entries: number;\n}) => void;\n\nexport interface FetchOptions {\n /** Force a network refresh even when cache is fresh. */\n noCache?: boolean;\n /** Override fetch — primarily for tests. */\n fetcher?: typeof fetch;\n /** Override cache file path — primarily for tests. */\n cachePath?: string;\n /** Skip the fallback chain and force a specific source. */\n preferSource?: \"official\" | \"smithery\" | \"local\";\n /** Progress callback — once per fetched page. */\n onProgress?: FetchProgress;\n}\n\nexport interface RegistryHandle {\n source: RegistrySource;\n /** Always present; mutated in place by loadMorePages. */\n cache: CacheFile;\n fromCache: boolean;\n fetchedAt: number;\n errors: string[];\n /** When source === \"official\", the path this handle persists to. Smithery + local are not persisted incrementally. */\n cachePath: string;\n}\n\nfunction newOfficialCache(initial: OfficialPageResult): CacheFile {\n const seen = new Map<string, RegistryEntry>();\n for (const e of initial.entries) if (!seen.has(e.name)) seen.set(e.name, e);\n return {\n schemaVersion: CACHE_SCHEMA_VERSION,\n fetchedAt: Date.now(),\n source: \"official\",\n entries: [...seen.values()],\n pagination: { pagesLoaded: 1, nextCursor: initial.nextCursor },\n };\n}\n\nfunction newStaticCache(source: RegistrySource, entries: RegistryEntry[]): CacheFile {\n return {\n schemaVersion: CACHE_SCHEMA_VERSION,\n fetchedAt: Date.now(),\n source,\n entries,\n pagination: { pagesLoaded: 1, nextCursor: null },\n };\n}\n\n/** Open the registry: returns a handle with at least one page loaded. Caller can advance via loadMorePages. */\nexport async function openRegistry(opts: FetchOptions = {}): Promise<RegistryHandle> {\n const fetcher = opts.fetcher ?? globalThis.fetch;\n const cachePath = opts.cachePath ?? defaultCachePath();\n const errors: string[] = [];\n\n if (!opts.noCache && !opts.preferSource) {\n const cached = readCache(cachePath);\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS && cached.entries.length > 0) {\n return {\n source: cached.source,\n cache: cached,\n fromCache: true,\n fetchedAt: cached.fetchedAt,\n errors: [],\n cachePath,\n };\n }\n }\n\n const tryOfficial = async (): Promise<RegistryHandle> => {\n const first = await fetchOfficialPage(null, fetcher);\n const cache = newOfficialCache(first);\n opts.onProgress?.({ source: \"official\", page: 1, entries: cache.entries.length });\n writeCache(cachePath, cache);\n return {\n source: \"official\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n const trySmithery = async (): Promise<RegistryHandle> => {\n const entries = await fetchSmitheryFirstPage(fetcher);\n const cache = newStaticCache(\"smithery\", entries);\n opts.onProgress?.({ source: \"smithery\", page: 1, entries: entries.length });\n writeCache(cachePath, cache);\n return {\n source: \"smithery\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n const tryLocal = (): RegistryHandle => {\n const cache = newStaticCache(\"local\", fallbackFromCatalog());\n return {\n source: \"local\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n if (opts.preferSource === \"local\") return tryLocal();\n if (opts.preferSource === \"smithery\") {\n try {\n return await trySmithery();\n } catch (e) {\n errors.push(`smithery: ${(e as Error).message}`);\n return tryLocal();\n }\n }\n\n try {\n return await tryOfficial();\n } catch (e) {\n errors.push(`official: ${(e as Error).message}`);\n }\n try {\n return await trySmithery();\n } catch (e) {\n errors.push(`smithery: ${(e as Error).message}`);\n }\n\n const stale = readCache(cachePath);\n if (stale) {\n return {\n source: stale.source,\n cache: stale,\n fromCache: true,\n fetchedAt: stale.fetchedAt,\n errors,\n cachePath,\n };\n }\n return tryLocal();\n}\n\nexport interface LoadMoreOptions {\n /** Number of additional pages to fetch (cap). Stops early when the source is exhausted. */\n pages?: number;\n /** Override fetch — primarily for tests. */\n fetcher?: typeof fetch;\n /** Stop early if filter() finds at least this many matching entries (across all loaded pages). */\n matchTarget?: number;\n /** Filter applied for matchTarget counting. */\n filter?: (e: RegistryEntry) => boolean;\n /** Progress callback. */\n onProgress?: FetchProgress;\n}\n\nexport interface LoadMoreResult {\n pagesAdded: number;\n newEntries: number;\n exhausted: boolean;\n}\n\n/** Advance an official-source handle by fetching more pages on demand. Smithery / local handles are no-ops. */\nexport async function loadMorePages(\n handle: RegistryHandle,\n opts: LoadMoreOptions = {},\n): Promise<LoadMoreResult> {\n if (handle.source !== \"official\") {\n return { pagesAdded: 0, newEntries: 0, exhausted: true };\n }\n const cache = handle.cache;\n if (cache.pagination.nextCursor === null) {\n return { pagesAdded: 0, newEntries: 0, exhausted: true };\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch;\n const limit = opts.pages ?? 1;\n const seen = new Set(cache.entries.map((e) => e.name));\n const matchCount = (): number => {\n if (!opts.filter) return 0;\n let n = 0;\n for (const e of cache.entries) if (opts.filter(e)) n++;\n return n;\n };\n\n let pagesAdded = 0;\n let newEntries = 0;\n for (let i = 0; i < limit; i++) {\n if (cache.pagination.nextCursor === null) break;\n if (opts.matchTarget !== undefined && matchCount() >= opts.matchTarget) break;\n const result = await fetchOfficialPage(cache.pagination.nextCursor, fetcher);\n for (const e of result.entries) {\n if (!seen.has(e.name)) {\n seen.add(e.name);\n cache.entries.push(e);\n newEntries++;\n }\n }\n cache.pagination.pagesLoaded += 1;\n cache.pagination.nextCursor = result.nextCursor;\n pagesAdded += 1;\n opts.onProgress?.({\n source: \"official\",\n page: cache.pagination.pagesLoaded,\n entries: cache.entries.length,\n });\n }\n\n if (pagesAdded > 0) writeCache(handle.cachePath, cache);\n return {\n pagesAdded,\n newEntries,\n exhausted: cache.pagination.nextCursor === null,\n };\n}\n\n/** Build a `--mcp`-format spec string from a registry install descriptor. */\nexport function specStringFor(name: string, install: RegistryInstall): string {\n const localName = name.split(\"/\").pop() ?? name;\n const safe = localName.replace(/[^a-zA-Z0-9_-]/g, \"-\").replace(/^-+|-+$/g, \"\") || \"mcp\";\n if (install.runtime === \"remote\") {\n if (!install.url) throw new Error(`remote install for ${name} has no URL`);\n if (install.transport === \"streamable-http\") return `${safe}=streamable+${install.url}`;\n return `${safe}=${install.url}`;\n }\n const trail = install.extraArgs?.length ? ` ${install.extraArgs.join(\" \")}` : \"\";\n if (install.runtime === \"npm\") {\n if (!install.packageId) throw new Error(`npm install for ${name} has no packageId`);\n const pinned = install.version ? `${install.packageId}@${install.version}` : install.packageId;\n return `${safe}=npx -y ${pinned}${trail}`;\n }\n if (install.runtime === \"pypi\") {\n if (!install.packageId) throw new Error(`pypi install for ${name} has no packageId`);\n return `${safe}=uvx ${install.packageId}${trail}`;\n }\n throw new Error(`unsupported install runtime: ${(install as RegistryInstall).runtime}`);\n}\n\n/** Re-exported for consumers that want a shape compatible with the old fetchRegistry result. */\nexport interface FetchResult {\n entries: RegistryEntry[];\n source: RegistrySource;\n fromCache: boolean;\n fetchedAt: number;\n errors: string[];\n /** Whether more pages are available beyond what's already loaded. */\n hasMore: boolean;\n}\n\nexport function handleToFetchResult(handle: RegistryHandle): FetchResult {\n return {\n entries: handle.cache.entries,\n source: handle.source,\n fromCache: handle.fromCache,\n fetchedAt: handle.fetchedAt,\n errors: handle.errors,\n hasMore: handle.cache.pagination.nextCursor !== null,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/mcp/registry-fetch.ts"],"sourcesContent":["/** Primary: registry.modelcontextprotocol.io. Fallback: registry.smithery.ai. Last resort: bundled MCP_CATALOG. */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { MCP_CATALOG } from \"./catalog.js\";\nimport type {\n CacheFile,\n CachePagination,\n RegistryEntry,\n RegistryInstall,\n RegistrySource,\n} from \"./registry-types.js\";\n\nexport const OFFICIAL_REGISTRY_URL = \"https://registry.modelcontextprotocol.io/v0/servers\";\nexport const SMITHERY_REGISTRY_URL = \"https://registry.smithery.ai/servers\";\nexport const CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nexport const FETCH_TIMEOUT_MS = 10_000;\nexport const CACHE_SCHEMA_VERSION = 2;\n\nexport function defaultCachePath(): string {\n return join(homedir(), \".reasonix\", \"mcp-registry-cache.json\");\n}\n\nfunction readCache(path: string): CacheFile | null {\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<CacheFile>;\n if (\n parsed.schemaVersion !== CACHE_SCHEMA_VERSION ||\n typeof parsed.fetchedAt !== \"number\" ||\n !Array.isArray(parsed.entries) ||\n typeof parsed.pagination?.pagesLoaded !== \"number\"\n ) {\n return null;\n }\n return parsed as CacheFile;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(path: string, file: CacheFile): void {\n try {\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(path, JSON.stringify(file, null, 2));\n } catch {\n /* cache failures are non-fatal */\n }\n}\n\nasync function timeoutFetch(url: string, fetcher: typeof fetch): Promise<Response> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);\n try {\n return await fetcher(url, { signal: ctrl.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\ninterface OfficialPackage {\n registryType?: string;\n identifier?: string;\n version?: string;\n transport?: { type?: string };\n environmentVariables?: Array<{ name?: string }>;\n}\n\ninterface OfficialServerCore {\n name?: string;\n title?: string;\n description?: string;\n packages?: OfficialPackage[];\n remotes?: Array<{ type?: string; url?: string }>;\n websiteUrl?: string;\n icons?: Array<{ src?: string }>;\n}\n\ninterface OfficialServerEntry {\n server?: OfficialServerCore;\n}\n\ninterface OfficialResponse {\n servers?: OfficialServerEntry[];\n metadata?: { nextCursor?: string };\n}\n\nfunction normalizeOfficialPackage(pkg: OfficialPackage | undefined): RegistryInstall | undefined {\n if (!pkg) return undefined;\n const runtime = pkg.registryType === \"npm\" ? \"npm\" : pkg.registryType === \"pypi\" ? \"pypi\" : null;\n if (!runtime) return undefined;\n const t = pkg.transport?.type;\n const transport: RegistryInstall[\"transport\"] =\n t === \"sse\" ? \"sse\" : t === \"streamable-http\" ? \"streamable-http\" : \"stdio\";\n const requiredEnv = (pkg.environmentVariables ?? [])\n .map((e) => e.name)\n .filter((n): n is string => typeof n === \"string\" && n.length > 0);\n const install: RegistryInstall = { runtime, transport };\n if (pkg.identifier) install.packageId = pkg.identifier;\n if (pkg.version) install.version = pkg.version;\n if (requiredEnv.length > 0) install.requiredEnv = requiredEnv;\n return install;\n}\n\nfunction normalizeOfficial(server: OfficialServerCore | undefined): RegistryEntry | null {\n if (!server?.name) return null;\n let install = normalizeOfficialPackage(server.packages?.[0]);\n if (!install && server.remotes?.[0]?.url) {\n const remote = server.remotes[0];\n const transport: RegistryInstall[\"transport\"] =\n remote.type === \"streamable-http\" ? \"streamable-http\" : \"sse\";\n install = { runtime: \"remote\", transport, url: remote.url };\n }\n const entry: RegistryEntry = {\n name: server.name,\n title: server.title || server.name,\n description: server.description ?? \"\",\n source: \"official\",\n };\n if (install) entry.install = install;\n if (server.websiteUrl) entry.homepage = server.websiteUrl;\n const icon = server.icons?.find((i) => i.src)?.src;\n if (icon) entry.iconUrl = icon;\n return entry;\n}\n\ninterface OfficialPageResult {\n entries: RegistryEntry[];\n nextCursor: string | null;\n}\n\nexport async function fetchOfficialPage(\n cursor: string | null,\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<OfficialPageResult> {\n const url = cursor\n ? `${OFFICIAL_REGISTRY_URL}?cursor=${encodeURIComponent(cursor)}`\n : OFFICIAL_REGISTRY_URL;\n const resp = await timeoutFetch(url, fetcher);\n if (!resp.ok) throw new Error(`official registry HTTP ${resp.status}`);\n const json = (await resp.json()) as OfficialResponse;\n const entries: RegistryEntry[] = [];\n for (const e of json.servers ?? []) {\n const norm = normalizeOfficial(e.server);\n if (norm) entries.push(norm);\n }\n return { entries, nextCursor: json.metadata?.nextCursor ?? null };\n}\n\ninterface SmitheryServer {\n qualifiedName?: string;\n displayName?: string;\n description?: string;\n useCount?: number;\n homepage?: string;\n iconUrl?: string;\n}\n\ninterface SmitheryResponse {\n servers?: SmitheryServer[];\n pagination?: { totalPages?: number; pageSize?: number };\n}\n\nfunction normalizeSmithery(s: SmitheryServer): RegistryEntry | null {\n if (!s.qualifiedName) return null;\n const entry: RegistryEntry = {\n name: s.qualifiedName,\n title: s.displayName || s.qualifiedName,\n description: s.description ?? \"\",\n source: \"smithery\",\n };\n if (typeof s.useCount === \"number\") entry.popularity = s.useCount;\n if (s.homepage) entry.homepage = s.homepage;\n if (s.iconUrl) entry.iconUrl = s.iconUrl;\n return entry;\n}\n\ninterface SmitheryConnection {\n type?: string;\n deploymentUrl?: string;\n bundleUrl?: string;\n runtime?: string;\n}\n\ninterface SmitheryDetailResponse {\n qualifiedName?: string;\n remote?: boolean;\n deploymentUrl?: string | null;\n connections?: SmitheryConnection[];\n}\n\n/** Resolve a Smithery listing entry into a runnable install. http → streamable-http remote; stdio → spawn via @smithery/cli. */\nexport async function fetchSmitheryDetail(\n qualifiedName: string,\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<RegistryInstall | null> {\n const url = `${SMITHERY_REGISTRY_URL}/${encodeURIComponent(qualifiedName)}`;\n const resp = await timeoutFetch(url, fetcher);\n if (!resp.ok) return null;\n const json = (await resp.json()) as SmitheryDetailResponse;\n const conn = json.connections?.[0];\n if (!conn) return null;\n if (conn.type === \"http\" || conn.type === \"ws\") {\n const deploymentUrl = conn.deploymentUrl ?? json.deploymentUrl;\n if (!deploymentUrl) return null;\n return { runtime: \"remote\", transport: \"streamable-http\", url: deploymentUrl };\n }\n if (conn.type === \"stdio\") {\n return {\n runtime: \"npm\",\n packageId: \"@smithery/cli\",\n transport: \"stdio\",\n extraArgs: [\"run\", qualifiedName],\n };\n }\n return null;\n}\n\nexport async function fetchSmitheryFirstPage(\n fetcher: typeof fetch = globalThis.fetch,\n): Promise<RegistryEntry[]> {\n const resp = await timeoutFetch(SMITHERY_REGISTRY_URL, fetcher);\n if (!resp.ok) throw new Error(`smithery HTTP ${resp.status}`);\n const json = (await resp.json()) as SmitheryResponse;\n const entries = (json.servers ?? [])\n .map(normalizeSmithery)\n .filter((x): x is RegistryEntry => x !== null);\n if (entries.length === 0) throw new Error(\"smithery returned no entries\");\n return entries;\n}\n\nexport function fallbackFromCatalog(): RegistryEntry[] {\n return MCP_CATALOG.map((e) => ({\n name: e.name,\n title: e.name,\n description: e.summary,\n source: \"local\" as const,\n install: {\n runtime: \"npm\" as const,\n packageId: e.package,\n transport: \"stdio\" as const,\n },\n }));\n}\n\nexport type FetchProgress = (info: {\n source: \"official\" | \"smithery\";\n page: number;\n entries: number;\n}) => void;\n\nexport interface FetchOptions {\n /** Force a network refresh even when cache is fresh. */\n noCache?: boolean;\n /** Override fetch — primarily for tests. */\n fetcher?: typeof fetch;\n /** Override cache file path — primarily for tests. */\n cachePath?: string;\n /** Skip the fallback chain and force a specific source. */\n preferSource?: \"official\" | \"smithery\" | \"local\";\n /** Progress callback — once per fetched page. */\n onProgress?: FetchProgress;\n}\n\nexport interface RegistryHandle {\n source: RegistrySource;\n /** Always present; mutated in place by loadMorePages. */\n cache: CacheFile;\n fromCache: boolean;\n fetchedAt: number;\n errors: string[];\n /** When source === \"official\", the path this handle persists to. Smithery + local are not persisted incrementally. */\n cachePath: string;\n}\n\nfunction newOfficialCache(initial: OfficialPageResult): CacheFile {\n const seen = new Map<string, RegistryEntry>();\n for (const e of initial.entries) if (!seen.has(e.name)) seen.set(e.name, e);\n return {\n schemaVersion: CACHE_SCHEMA_VERSION,\n fetchedAt: Date.now(),\n source: \"official\",\n entries: [...seen.values()],\n pagination: { pagesLoaded: 1, nextCursor: initial.nextCursor },\n };\n}\n\nfunction newStaticCache(source: RegistrySource, entries: RegistryEntry[]): CacheFile {\n return {\n schemaVersion: CACHE_SCHEMA_VERSION,\n fetchedAt: Date.now(),\n source,\n entries,\n pagination: { pagesLoaded: 1, nextCursor: null },\n };\n}\n\n/** Open the registry: returns a handle with at least one page loaded. Caller can advance via loadMorePages. */\nexport async function openRegistry(opts: FetchOptions = {}): Promise<RegistryHandle> {\n const fetcher = opts.fetcher ?? globalThis.fetch;\n const cachePath = opts.cachePath ?? defaultCachePath();\n const errors: string[] = [];\n\n if (!opts.noCache && !opts.preferSource) {\n const cached = readCache(cachePath);\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS && cached.entries.length > 0) {\n return {\n source: cached.source,\n cache: cached,\n fromCache: true,\n fetchedAt: cached.fetchedAt,\n errors: [],\n cachePath,\n };\n }\n }\n\n const tryOfficial = async (): Promise<RegistryHandle> => {\n const first = await fetchOfficialPage(null, fetcher);\n const cache = newOfficialCache(first);\n opts.onProgress?.({ source: \"official\", page: 1, entries: cache.entries.length });\n writeCache(cachePath, cache);\n return {\n source: \"official\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n const trySmithery = async (): Promise<RegistryHandle> => {\n const entries = await fetchSmitheryFirstPage(fetcher);\n const cache = newStaticCache(\"smithery\", entries);\n opts.onProgress?.({ source: \"smithery\", page: 1, entries: entries.length });\n writeCache(cachePath, cache);\n return {\n source: \"smithery\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n const tryLocal = (): RegistryHandle => {\n const cache = newStaticCache(\"local\", fallbackFromCatalog());\n return {\n source: \"local\",\n cache,\n fromCache: false,\n fetchedAt: cache.fetchedAt,\n errors,\n cachePath,\n };\n };\n\n if (opts.preferSource === \"local\") return tryLocal();\n if (opts.preferSource === \"smithery\") {\n try {\n return await trySmithery();\n } catch (e) {\n errors.push(`smithery: ${(e as Error).message}`);\n return tryLocal();\n }\n }\n\n try {\n return await tryOfficial();\n } catch (e) {\n errors.push(`official: ${(e as Error).message}`);\n }\n try {\n return await trySmithery();\n } catch (e) {\n errors.push(`smithery: ${(e as Error).message}`);\n }\n\n const stale = readCache(cachePath);\n if (stale) {\n return {\n source: stale.source,\n cache: stale,\n fromCache: true,\n fetchedAt: stale.fetchedAt,\n errors,\n cachePath,\n };\n }\n return tryLocal();\n}\n\nexport interface LoadMoreOptions {\n /** Number of additional pages to fetch (cap). Stops early when the source is exhausted. */\n pages?: number;\n /** Override fetch — primarily for tests. */\n fetcher?: typeof fetch;\n /** Stop early if filter() finds at least this many matching entries (across all loaded pages). */\n matchTarget?: number;\n /** Filter applied for matchTarget counting. */\n filter?: (e: RegistryEntry) => boolean;\n /** Progress callback. */\n onProgress?: FetchProgress;\n}\n\nexport interface LoadMoreResult {\n pagesAdded: number;\n newEntries: number;\n exhausted: boolean;\n}\n\n/** Advance an official-source handle by fetching more pages on demand. Smithery / local handles are no-ops. */\nexport async function loadMorePages(\n handle: RegistryHandle,\n opts: LoadMoreOptions = {},\n): Promise<LoadMoreResult> {\n if (handle.source !== \"official\") {\n return { pagesAdded: 0, newEntries: 0, exhausted: true };\n }\n const cache = handle.cache;\n if (cache.pagination.nextCursor === null) {\n return { pagesAdded: 0, newEntries: 0, exhausted: true };\n }\n\n const fetcher = opts.fetcher ?? globalThis.fetch;\n const limit = opts.pages ?? 1;\n const seen = new Set(cache.entries.map((e) => e.name));\n const matchCount = (): number => {\n if (!opts.filter) return 0;\n let n = 0;\n for (const e of cache.entries) if (opts.filter(e)) n++;\n return n;\n };\n\n let pagesAdded = 0;\n let newEntries = 0;\n for (let i = 0; i < limit; i++) {\n if (cache.pagination.nextCursor === null) break;\n if (opts.matchTarget !== undefined && matchCount() >= opts.matchTarget) break;\n const result = await fetchOfficialPage(cache.pagination.nextCursor, fetcher);\n for (const e of result.entries) {\n if (!seen.has(e.name)) {\n seen.add(e.name);\n cache.entries.push(e);\n newEntries++;\n }\n }\n cache.pagination.pagesLoaded += 1;\n cache.pagination.nextCursor = result.nextCursor;\n pagesAdded += 1;\n opts.onProgress?.({\n source: \"official\",\n page: cache.pagination.pagesLoaded,\n entries: cache.entries.length,\n });\n }\n\n if (pagesAdded > 0) writeCache(handle.cachePath, cache);\n return {\n pagesAdded,\n newEntries,\n exhausted: cache.pagination.nextCursor === null,\n };\n}\n\n/** Build a `--mcp`-format spec string from a registry install descriptor. */\nexport function specStringFor(name: string, install: RegistryInstall): string {\n const localName = name.split(\"/\").pop() ?? name;\n const safe = localName.replace(/[^a-zA-Z0-9_-]/g, \"-\").replace(/^-+|-+$/g, \"\") || \"mcp\";\n if (install.runtime === \"remote\") {\n if (!install.url) throw new Error(`remote install for ${name} has no URL`);\n if (install.transport === \"streamable-http\") return `${safe}=streamable+${install.url}`;\n return `${safe}=${install.url}`;\n }\n const trail = install.extraArgs?.length ? ` ${install.extraArgs.join(\" \")}` : \"\";\n if (install.runtime === \"npm\") {\n if (!install.packageId) throw new Error(`npm install for ${name} has no packageId`);\n const pinned = install.version ? `${install.packageId}@${install.version}` : install.packageId;\n return `${safe}=npx -y ${pinned}${trail}`;\n }\n if (install.runtime === \"pypi\") {\n if (!install.packageId) throw new Error(`pypi install for ${name} has no packageId`);\n return `${safe}=uvx ${install.packageId}${trail}`;\n }\n throw new Error(`unsupported install runtime: ${(install as RegistryInstall).runtime}`);\n}\n\n/** Re-exported for consumers that want a shape compatible with the old fetchRegistry result. */\nexport interface FetchResult {\n entries: RegistryEntry[];\n source: RegistrySource;\n fromCache: boolean;\n fetchedAt: number;\n errors: string[];\n /** Whether more pages are available beyond what's already loaded. */\n hasMore: boolean;\n}\n\nexport function handleToFetchResult(handle: RegistryHandle): FetchResult {\n return {\n entries: handle.cache.entries,\n source: handle.source,\n fromCache: handle.fromCache,\n fetchedAt: handle.fetchedAt,\n errors: handle.errors,\n hasMore: handle.cache.pagination.nextCursor !== null,\n };\n}\n"],"mappings":"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","names":[]}