distill-mcp 0.6.0-beta

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 (440) hide show
  1. package/bin/cli.js +133 -0
  2. package/dist/analytics/session-tracker.d.ts +74 -0
  3. package/dist/analytics/session-tracker.d.ts.map +1 -0
  4. package/dist/analytics/session-tracker.js +123 -0
  5. package/dist/ast/benchmark.test.d.ts +7 -0
  6. package/dist/ast/benchmark.test.d.ts.map +1 -0
  7. package/dist/ast/benchmark.test.js +175 -0
  8. package/dist/ast/go/index.d.ts +9 -0
  9. package/dist/ast/go/index.d.ts.map +1 -0
  10. package/dist/ast/go/index.js +8 -0
  11. package/dist/ast/go/parser.d.ts +31 -0
  12. package/dist/ast/go/parser.d.ts.map +1 -0
  13. package/dist/ast/go/parser.js +428 -0
  14. package/dist/ast/go/parser.test.d.ts +5 -0
  15. package/dist/ast/go/parser.test.d.ts.map +1 -0
  16. package/dist/ast/go/parser.test.js +241 -0
  17. package/dist/ast/go/queries.d.ts +51 -0
  18. package/dist/ast/go/queries.d.ts.map +1 -0
  19. package/dist/ast/go/queries.js +114 -0
  20. package/dist/ast/go/utils.d.ts +66 -0
  21. package/dist/ast/go/utils.d.ts.map +1 -0
  22. package/dist/ast/go/utils.js +140 -0
  23. package/dist/ast/index.d.ts +39 -0
  24. package/dist/ast/index.d.ts.map +1 -0
  25. package/dist/ast/index.js +245 -0
  26. package/dist/ast/php/index.d.ts +9 -0
  27. package/dist/ast/php/index.d.ts.map +1 -0
  28. package/dist/ast/php/index.js +8 -0
  29. package/dist/ast/php/parser.d.ts +31 -0
  30. package/dist/ast/php/parser.d.ts.map +1 -0
  31. package/dist/ast/php/parser.js +388 -0
  32. package/dist/ast/php/parser.test.d.ts +5 -0
  33. package/dist/ast/php/parser.test.d.ts.map +1 -0
  34. package/dist/ast/php/parser.test.js +328 -0
  35. package/dist/ast/php/queries.d.ts +61 -0
  36. package/dist/ast/php/queries.d.ts.map +1 -0
  37. package/dist/ast/php/queries.js +117 -0
  38. package/dist/ast/php/utils.d.ts +83 -0
  39. package/dist/ast/php/utils.d.ts.map +1 -0
  40. package/dist/ast/php/utils.js +246 -0
  41. package/dist/ast/python/index.d.ts +9 -0
  42. package/dist/ast/python/index.d.ts.map +1 -0
  43. package/dist/ast/python/index.js +8 -0
  44. package/dist/ast/python/parser.d.ts +32 -0
  45. package/dist/ast/python/parser.d.ts.map +1 -0
  46. package/dist/ast/python/parser.js +422 -0
  47. package/dist/ast/python/parser.test.d.ts +5 -0
  48. package/dist/ast/python/parser.test.d.ts.map +1 -0
  49. package/dist/ast/python/parser.test.js +186 -0
  50. package/dist/ast/python/queries.d.ts +73 -0
  51. package/dist/ast/python/queries.d.ts.map +1 -0
  52. package/dist/ast/python/queries.js +137 -0
  53. package/dist/ast/python/utils.d.ts +63 -0
  54. package/dist/ast/python/utils.d.ts.map +1 -0
  55. package/dist/ast/python/utils.js +159 -0
  56. package/dist/ast/quick-scan.d.ts +40 -0
  57. package/dist/ast/quick-scan.d.ts.map +1 -0
  58. package/dist/ast/quick-scan.js +287 -0
  59. package/dist/ast/rust/index.d.ts +9 -0
  60. package/dist/ast/rust/index.d.ts.map +1 -0
  61. package/dist/ast/rust/index.js +8 -0
  62. package/dist/ast/rust/parser.d.ts +31 -0
  63. package/dist/ast/rust/parser.d.ts.map +1 -0
  64. package/dist/ast/rust/parser.js +416 -0
  65. package/dist/ast/rust/parser.test.d.ts +5 -0
  66. package/dist/ast/rust/parser.test.d.ts.map +1 -0
  67. package/dist/ast/rust/parser.test.js +329 -0
  68. package/dist/ast/rust/queries.d.ts +66 -0
  69. package/dist/ast/rust/queries.d.ts.map +1 -0
  70. package/dist/ast/rust/queries.js +132 -0
  71. package/dist/ast/rust/utils.d.ts +91 -0
  72. package/dist/ast/rust/utils.d.ts.map +1 -0
  73. package/dist/ast/rust/utils.js +254 -0
  74. package/dist/ast/swift/index.d.ts +10 -0
  75. package/dist/ast/swift/index.d.ts.map +1 -0
  76. package/dist/ast/swift/index.js +8 -0
  77. package/dist/ast/swift/parser.d.ts +31 -0
  78. package/dist/ast/swift/parser.d.ts.map +1 -0
  79. package/dist/ast/swift/parser.js +554 -0
  80. package/dist/ast/swift/parser.test.d.ts +5 -0
  81. package/dist/ast/swift/parser.test.d.ts.map +1 -0
  82. package/dist/ast/swift/parser.test.js +398 -0
  83. package/dist/ast/swift/queries.d.ts +71 -0
  84. package/dist/ast/swift/queries.d.ts.map +1 -0
  85. package/dist/ast/swift/queries.js +137 -0
  86. package/dist/ast/swift/utils.d.ts +94 -0
  87. package/dist/ast/swift/utils.d.ts.map +1 -0
  88. package/dist/ast/swift/utils.js +411 -0
  89. package/dist/ast/types.d.ts +96 -0
  90. package/dist/ast/types.d.ts.map +1 -0
  91. package/dist/ast/types.js +21 -0
  92. package/dist/ast/typescript.d.ts +24 -0
  93. package/dist/ast/typescript.d.ts.map +1 -0
  94. package/dist/ast/typescript.js +357 -0
  95. package/dist/cache/file-hash.d.ts +33 -0
  96. package/dist/cache/file-hash.d.ts.map +1 -0
  97. package/dist/cache/file-hash.js +59 -0
  98. package/dist/cache/index.d.ts +9 -0
  99. package/dist/cache/index.d.ts.map +1 -0
  100. package/dist/cache/index.js +8 -0
  101. package/dist/cache/smart-cache.d.ts +68 -0
  102. package/dist/cache/smart-cache.d.ts.map +1 -0
  103. package/dist/cache/smart-cache.js +266 -0
  104. package/dist/cache/types.d.ts +102 -0
  105. package/dist/cache/types.d.ts.map +1 -0
  106. package/dist/cache/types.js +6 -0
  107. package/dist/cli/analyze.d.ts +43 -0
  108. package/dist/cli/analyze.d.ts.map +1 -0
  109. package/dist/cli/analyze.js +250 -0
  110. package/dist/cli/doctor.d.ts +2 -0
  111. package/dist/cli/doctor.d.ts.map +1 -0
  112. package/dist/cli/doctor.js +127 -0
  113. package/dist/cli/hooks.d.ts +14 -0
  114. package/dist/cli/hooks.d.ts.map +1 -0
  115. package/dist/cli/hooks.js +229 -0
  116. package/dist/cli/index.d.ts +5 -0
  117. package/dist/cli/index.d.ts.map +1 -0
  118. package/dist/cli/index.js +4 -0
  119. package/dist/cli/setup.d.ts +10 -0
  120. package/dist/cli/setup.d.ts.map +1 -0
  121. package/dist/cli/setup.js +117 -0
  122. package/dist/cli/utils.d.ts +30 -0
  123. package/dist/cli/utils.d.ts.map +1 -0
  124. package/dist/cli/utils.js +116 -0
  125. package/dist/compressors/config.d.ts +9 -0
  126. package/dist/compressors/config.d.ts.map +1 -0
  127. package/dist/compressors/config.js +183 -0
  128. package/dist/compressors/conversation.d.ts +109 -0
  129. package/dist/compressors/conversation.d.ts.map +1 -0
  130. package/dist/compressors/conversation.js +404 -0
  131. package/dist/compressors/diff.d.ts +35 -0
  132. package/dist/compressors/diff.d.ts.map +1 -0
  133. package/dist/compressors/diff.js +389 -0
  134. package/dist/compressors/generic.d.ts +9 -0
  135. package/dist/compressors/generic.d.ts.map +1 -0
  136. package/dist/compressors/generic.js +188 -0
  137. package/dist/compressors/index.d.ts +31 -0
  138. package/dist/compressors/index.d.ts.map +1 -0
  139. package/dist/compressors/index.js +82 -0
  140. package/dist/compressors/logs.d.ts +9 -0
  141. package/dist/compressors/logs.d.ts.map +1 -0
  142. package/dist/compressors/logs.js +245 -0
  143. package/dist/compressors/multifile.d.ts +106 -0
  144. package/dist/compressors/multifile.d.ts.map +1 -0
  145. package/dist/compressors/multifile.js +498 -0
  146. package/dist/compressors/semantic.d.ts +33 -0
  147. package/dist/compressors/semantic.d.ts.map +1 -0
  148. package/dist/compressors/semantic.js +233 -0
  149. package/dist/compressors/stacktrace.d.ts +9 -0
  150. package/dist/compressors/stacktrace.d.ts.map +1 -0
  151. package/dist/compressors/stacktrace.js +259 -0
  152. package/dist/compressors/types.d.ts +146 -0
  153. package/dist/compressors/types.d.ts.map +1 -0
  154. package/dist/compressors/types.js +6 -0
  155. package/dist/config/output-config.d.ts +56 -0
  156. package/dist/config/output-config.d.ts.map +1 -0
  157. package/dist/config/output-config.js +78 -0
  158. package/dist/index.d.ts +21 -0
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +27 -0
  161. package/dist/middleware/chain.d.ts +49 -0
  162. package/dist/middleware/chain.d.ts.map +1 -0
  163. package/dist/middleware/chain.js +126 -0
  164. package/dist/middleware/index.d.ts +4 -0
  165. package/dist/middleware/index.d.ts.map +1 -0
  166. package/dist/middleware/index.js +3 -0
  167. package/dist/middleware/logging.d.ts +8 -0
  168. package/dist/middleware/logging.d.ts.map +1 -0
  169. package/dist/middleware/logging.js +71 -0
  170. package/dist/middleware/types.d.ts +58 -0
  171. package/dist/middleware/types.d.ts.map +1 -0
  172. package/dist/middleware/types.js +7 -0
  173. package/dist/parsers/eslint.d.ts +8 -0
  174. package/dist/parsers/eslint.d.ts.map +1 -0
  175. package/dist/parsers/eslint.js +132 -0
  176. package/dist/parsers/generic.d.ts +8 -0
  177. package/dist/parsers/generic.d.ts.map +1 -0
  178. package/dist/parsers/generic.js +234 -0
  179. package/dist/parsers/index.d.ts +34 -0
  180. package/dist/parsers/index.d.ts.map +1 -0
  181. package/dist/parsers/index.js +216 -0
  182. package/dist/parsers/types.d.ts +84 -0
  183. package/dist/parsers/types.d.ts.map +1 -0
  184. package/dist/parsers/types.js +6 -0
  185. package/dist/parsers/typescript.d.ts +8 -0
  186. package/dist/parsers/typescript.d.ts.map +1 -0
  187. package/dist/parsers/typescript.js +107 -0
  188. package/dist/pipelines/definitions.d.ts +50 -0
  189. package/dist/pipelines/definitions.d.ts.map +1 -0
  190. package/dist/pipelines/definitions.js +206 -0
  191. package/dist/sandbox/executor.d.ts +12 -0
  192. package/dist/sandbox/executor.d.ts.map +1 -0
  193. package/dist/sandbox/executor.js +191 -0
  194. package/dist/sandbox/index.d.ts +11 -0
  195. package/dist/sandbox/index.d.ts.map +1 -0
  196. package/dist/sandbox/index.js +9 -0
  197. package/dist/sandbox/sandbox.test.d.ts +7 -0
  198. package/dist/sandbox/sandbox.test.d.ts.map +1 -0
  199. package/dist/sandbox/sandbox.test.js +202 -0
  200. package/dist/sandbox/sdk/analyze.d.ts +36 -0
  201. package/dist/sandbox/sdk/analyze.d.ts.map +1 -0
  202. package/dist/sandbox/sdk/analyze.js +413 -0
  203. package/dist/sandbox/sdk/analyze.test.d.ts +7 -0
  204. package/dist/sandbox/sdk/analyze.test.d.ts.map +1 -0
  205. package/dist/sandbox/sdk/analyze.test.js +191 -0
  206. package/dist/sandbox/sdk/code.d.ts +20 -0
  207. package/dist/sandbox/sdk/code.d.ts.map +1 -0
  208. package/dist/sandbox/sdk/code.js +104 -0
  209. package/dist/sandbox/sdk/compress.d.ts +23 -0
  210. package/dist/sandbox/sdk/compress.d.ts.map +1 -0
  211. package/dist/sandbox/sdk/compress.js +107 -0
  212. package/dist/sandbox/sdk/conversation.d.ts +148 -0
  213. package/dist/sandbox/sdk/conversation.d.ts.map +1 -0
  214. package/dist/sandbox/sdk/conversation.js +177 -0
  215. package/dist/sandbox/sdk/files.d.ts +29 -0
  216. package/dist/sandbox/sdk/files.d.ts.map +1 -0
  217. package/dist/sandbox/sdk/files.js +41 -0
  218. package/dist/sandbox/sdk/git.d.ts +37 -0
  219. package/dist/sandbox/sdk/git.d.ts.map +1 -0
  220. package/dist/sandbox/sdk/git.js +313 -0
  221. package/dist/sandbox/sdk/git.test.d.ts +8 -0
  222. package/dist/sandbox/sdk/git.test.d.ts.map +1 -0
  223. package/dist/sandbox/sdk/git.test.js +160 -0
  224. package/dist/sandbox/sdk/index.d.ts +16 -0
  225. package/dist/sandbox/sdk/index.d.ts.map +1 -0
  226. package/dist/sandbox/sdk/index.js +15 -0
  227. package/dist/sandbox/sdk/multifile.d.ts +63 -0
  228. package/dist/sandbox/sdk/multifile.d.ts.map +1 -0
  229. package/dist/sandbox/sdk/multifile.js +130 -0
  230. package/dist/sandbox/sdk/pipeline.d.ts +16 -0
  231. package/dist/sandbox/sdk/pipeline.d.ts.map +1 -0
  232. package/dist/sandbox/sdk/pipeline.js +454 -0
  233. package/dist/sandbox/sdk/pipeline.test.d.ts +7 -0
  234. package/dist/sandbox/sdk/pipeline.test.d.ts.map +1 -0
  235. package/dist/sandbox/sdk/pipeline.test.js +197 -0
  236. package/dist/sandbox/sdk/search.d.ts +36 -0
  237. package/dist/sandbox/sdk/search.d.ts.map +1 -0
  238. package/dist/sandbox/sdk/search.js +338 -0
  239. package/dist/sandbox/sdk/search.test.d.ts +7 -0
  240. package/dist/sandbox/sdk/search.test.d.ts.map +1 -0
  241. package/dist/sandbox/sdk/search.test.js +183 -0
  242. package/dist/sandbox/sdk/utils.d.ts +18 -0
  243. package/dist/sandbox/sdk/utils.d.ts.map +1 -0
  244. package/dist/sandbox/sdk/utils.js +24 -0
  245. package/dist/sandbox/security/code-analyzer.d.ts +15 -0
  246. package/dist/sandbox/security/code-analyzer.d.ts.map +1 -0
  247. package/dist/sandbox/security/code-analyzer.js +87 -0
  248. package/dist/sandbox/security/index.d.ts +6 -0
  249. package/dist/sandbox/security/index.d.ts.map +1 -0
  250. package/dist/sandbox/security/index.js +5 -0
  251. package/dist/sandbox/security/path-validator.d.ts +23 -0
  252. package/dist/sandbox/security/path-validator.d.ts.map +1 -0
  253. package/dist/sandbox/security/path-validator.js +113 -0
  254. package/dist/sandbox/types.d.ts +577 -0
  255. package/dist/sandbox/types.d.ts.map +1 -0
  256. package/dist/sandbox/types.js +14 -0
  257. package/dist/server.d.ts +36 -0
  258. package/dist/server.d.ts.map +1 -0
  259. package/dist/server.js +133 -0
  260. package/dist/summarizers/build-logs.d.ts +11 -0
  261. package/dist/summarizers/build-logs.d.ts.map +1 -0
  262. package/dist/summarizers/build-logs.js +234 -0
  263. package/dist/summarizers/generic.d.ts +11 -0
  264. package/dist/summarizers/generic.d.ts.map +1 -0
  265. package/dist/summarizers/generic.js +93 -0
  266. package/dist/summarizers/index.d.ts +20 -0
  267. package/dist/summarizers/index.d.ts.map +1 -0
  268. package/dist/summarizers/index.js +43 -0
  269. package/dist/summarizers/server-logs.d.ts +11 -0
  270. package/dist/summarizers/server-logs.d.ts.map +1 -0
  271. package/dist/summarizers/server-logs.js +215 -0
  272. package/dist/summarizers/test-logs.d.ts +11 -0
  273. package/dist/summarizers/test-logs.d.ts.map +1 -0
  274. package/dist/summarizers/test-logs.js +258 -0
  275. package/dist/summarizers/types.d.ts +146 -0
  276. package/dist/summarizers/types.d.ts.map +1 -0
  277. package/dist/summarizers/types.js +21 -0
  278. package/dist/tools/analyze-build-output.d.ts +30 -0
  279. package/dist/tools/analyze-build-output.d.ts.map +1 -0
  280. package/dist/tools/analyze-build-output.js +45 -0
  281. package/dist/tools/analyze-context.d.ts +23 -0
  282. package/dist/tools/analyze-context.d.ts.map +1 -0
  283. package/dist/tools/analyze-context.js +78 -0
  284. package/dist/tools/auto-optimize.d.ts +9 -0
  285. package/dist/tools/auto-optimize.d.ts.map +1 -0
  286. package/dist/tools/auto-optimize.js +191 -0
  287. package/dist/tools/code-execute.d.ts +9 -0
  288. package/dist/tools/code-execute.d.ts.map +1 -0
  289. package/dist/tools/code-execute.js +84 -0
  290. package/dist/tools/code-skeleton.d.ts +33 -0
  291. package/dist/tools/code-skeleton.d.ts.map +1 -0
  292. package/dist/tools/code-skeleton.js +206 -0
  293. package/dist/tools/compress-context.d.ts +33 -0
  294. package/dist/tools/compress-context.d.ts.map +1 -0
  295. package/dist/tools/compress-context.js +64 -0
  296. package/dist/tools/context-budget.d.ts +43 -0
  297. package/dist/tools/context-budget.d.ts.map +1 -0
  298. package/dist/tools/context-budget.js +260 -0
  299. package/dist/tools/context-budget.test.d.ts +5 -0
  300. package/dist/tools/context-budget.test.d.ts.map +1 -0
  301. package/dist/tools/context-budget.test.js +219 -0
  302. package/dist/tools/conversation-compress.d.ts +46 -0
  303. package/dist/tools/conversation-compress.d.ts.map +1 -0
  304. package/dist/tools/conversation-compress.js +78 -0
  305. package/dist/tools/conversation-memory.d.ts +75 -0
  306. package/dist/tools/conversation-memory.d.ts.map +1 -0
  307. package/dist/tools/conversation-memory.js +289 -0
  308. package/dist/tools/deduplicate-errors.d.ts +30 -0
  309. package/dist/tools/deduplicate-errors.d.ts.map +1 -0
  310. package/dist/tools/deduplicate-errors.js +72 -0
  311. package/dist/tools/detect-retry-loop.d.ts +40 -0
  312. package/dist/tools/detect-retry-loop.d.ts.map +1 -0
  313. package/dist/tools/detect-retry-loop.js +212 -0
  314. package/dist/tools/diff-compress.d.ts +40 -0
  315. package/dist/tools/diff-compress.d.ts.map +1 -0
  316. package/dist/tools/diff-compress.js +94 -0
  317. package/dist/tools/discover-tools.d.ts +11 -0
  318. package/dist/tools/discover-tools.d.ts.map +1 -0
  319. package/dist/tools/discover-tools.js +163 -0
  320. package/dist/tools/dynamic-loader.d.ts +131 -0
  321. package/dist/tools/dynamic-loader.d.ts.map +1 -0
  322. package/dist/tools/dynamic-loader.js +378 -0
  323. package/dist/tools/dynamic-loader.test.d.ts +10 -0
  324. package/dist/tools/dynamic-loader.test.d.ts.map +1 -0
  325. package/dist/tools/dynamic-loader.test.js +164 -0
  326. package/dist/tools/lazy-mcp.d.ts +31 -0
  327. package/dist/tools/lazy-mcp.d.ts.map +1 -0
  328. package/dist/tools/lazy-mcp.js +151 -0
  329. package/dist/tools/lazy-mcp.test.d.ts +10 -0
  330. package/dist/tools/lazy-mcp.test.d.ts.map +1 -0
  331. package/dist/tools/lazy-mcp.test.js +172 -0
  332. package/dist/tools/multifile-compress.d.ts +36 -0
  333. package/dist/tools/multifile-compress.d.ts.map +1 -0
  334. package/dist/tools/multifile-compress.js +223 -0
  335. package/dist/tools/optimization-tips.d.ts +18 -0
  336. package/dist/tools/optimization-tips.d.ts.map +1 -0
  337. package/dist/tools/optimization-tips.js +133 -0
  338. package/dist/tools/registry.d.ts +70 -0
  339. package/dist/tools/registry.d.ts.map +1 -0
  340. package/dist/tools/registry.js +169 -0
  341. package/dist/tools/semantic-compress.d.ts +39 -0
  342. package/dist/tools/semantic-compress.d.ts.map +1 -0
  343. package/dist/tools/semantic-compress.js +113 -0
  344. package/dist/tools/semantic-compress.test.d.ts +5 -0
  345. package/dist/tools/semantic-compress.test.d.ts.map +1 -0
  346. package/dist/tools/semantic-compress.test.js +182 -0
  347. package/dist/tools/session-stats.d.ts +34 -0
  348. package/dist/tools/session-stats.d.ts.map +1 -0
  349. package/dist/tools/session-stats.js +194 -0
  350. package/dist/tools/set-output-config.d.ts +38 -0
  351. package/dist/tools/set-output-config.d.ts.map +1 -0
  352. package/dist/tools/set-output-config.js +122 -0
  353. package/dist/tools/smart-cache-tool.d.ts +38 -0
  354. package/dist/tools/smart-cache-tool.d.ts.map +1 -0
  355. package/dist/tools/smart-cache-tool.js +224 -0
  356. package/dist/tools/smart-file-read.d.ts +52 -0
  357. package/dist/tools/smart-file-read.d.ts.map +1 -0
  358. package/dist/tools/smart-file-read.js +481 -0
  359. package/dist/tools/smart-pipeline.d.ts +40 -0
  360. package/dist/tools/smart-pipeline.d.ts.map +1 -0
  361. package/dist/tools/smart-pipeline.js +295 -0
  362. package/dist/tools/summarize-logs.d.ts +36 -0
  363. package/dist/tools/summarize-logs.d.ts.map +1 -0
  364. package/dist/tools/summarize-logs.js +184 -0
  365. package/dist/tools/token-budget.test.d.ts +11 -0
  366. package/dist/tools/token-budget.test.d.ts.map +1 -0
  367. package/dist/tools/token-budget.test.js +275 -0
  368. package/dist/utils/bm25.d.ts +86 -0
  369. package/dist/utils/bm25.d.ts.map +1 -0
  370. package/dist/utils/bm25.js +153 -0
  371. package/dist/utils/bm25.test.d.ts +5 -0
  372. package/dist/utils/bm25.test.d.ts.map +1 -0
  373. package/dist/utils/bm25.test.js +156 -0
  374. package/dist/utils/command-normalizer.d.ts +39 -0
  375. package/dist/utils/command-normalizer.d.ts.map +1 -0
  376. package/dist/utils/command-normalizer.js +90 -0
  377. package/dist/utils/content-detector.d.ts +27 -0
  378. package/dist/utils/content-detector.d.ts.map +1 -0
  379. package/dist/utils/content-detector.js +127 -0
  380. package/dist/utils/embeddings.d.ts +54 -0
  381. package/dist/utils/embeddings.d.ts.map +1 -0
  382. package/dist/utils/embeddings.js +97 -0
  383. package/dist/utils/embeddings.test.d.ts +8 -0
  384. package/dist/utils/embeddings.test.d.ts.map +1 -0
  385. package/dist/utils/embeddings.test.js +96 -0
  386. package/dist/utils/error-normalizer.d.ts +39 -0
  387. package/dist/utils/error-normalizer.d.ts.map +1 -0
  388. package/dist/utils/error-normalizer.js +233 -0
  389. package/dist/utils/hybrid-search.d.ts +79 -0
  390. package/dist/utils/hybrid-search.d.ts.map +1 -0
  391. package/dist/utils/hybrid-search.js +146 -0
  392. package/dist/utils/hybrid-search.test.d.ts +5 -0
  393. package/dist/utils/hybrid-search.test.d.ts.map +1 -0
  394. package/dist/utils/hybrid-search.test.js +172 -0
  395. package/dist/utils/index.d.ts +13 -0
  396. package/dist/utils/index.d.ts.map +1 -0
  397. package/dist/utils/index.js +12 -0
  398. package/dist/utils/language-detector.d.ts +27 -0
  399. package/dist/utils/language-detector.d.ts.map +1 -0
  400. package/dist/utils/language-detector.js +94 -0
  401. package/dist/utils/log-parser.d.ts +46 -0
  402. package/dist/utils/log-parser.d.ts.map +1 -0
  403. package/dist/utils/log-parser.js +287 -0
  404. package/dist/utils/output-estimator.d.ts +54 -0
  405. package/dist/utils/output-estimator.d.ts.map +1 -0
  406. package/dist/utils/output-estimator.js +119 -0
  407. package/dist/utils/output-estimator.test.d.ts +5 -0
  408. package/dist/utils/output-estimator.test.d.ts.map +1 -0
  409. package/dist/utils/output-estimator.test.js +115 -0
  410. package/dist/utils/output-similarity.d.ts +48 -0
  411. package/dist/utils/output-similarity.d.ts.map +1 -0
  412. package/dist/utils/output-similarity.js +140 -0
  413. package/dist/utils/project-detector.d.ts +16 -0
  414. package/dist/utils/project-detector.d.ts.map +1 -0
  415. package/dist/utils/project-detector.js +119 -0
  416. package/dist/utils/segment-scorer.d.ts +99 -0
  417. package/dist/utils/segment-scorer.d.ts.map +1 -0
  418. package/dist/utils/segment-scorer.js +148 -0
  419. package/dist/utils/signature-grouper.d.ts +58 -0
  420. package/dist/utils/signature-grouper.d.ts.map +1 -0
  421. package/dist/utils/signature-grouper.js +185 -0
  422. package/dist/utils/tfidf.d.ts +45 -0
  423. package/dist/utils/tfidf.d.ts.map +1 -0
  424. package/dist/utils/tfidf.js +204 -0
  425. package/dist/utils/tfidf.test.d.ts +5 -0
  426. package/dist/utils/tfidf.test.d.ts.map +1 -0
  427. package/dist/utils/tfidf.test.js +115 -0
  428. package/dist/utils/token-counter.d.ts +35 -0
  429. package/dist/utils/token-counter.d.ts.map +1 -0
  430. package/dist/utils/token-counter.js +83 -0
  431. package/dist/utils/toon-serializer.d.ts +120 -0
  432. package/dist/utils/toon-serializer.d.ts.map +1 -0
  433. package/dist/utils/toon-serializer.js +472 -0
  434. package/dist/utils/toon-serializer.test.d.ts +7 -0
  435. package/dist/utils/toon-serializer.test.d.ts.map +1 -0
  436. package/dist/utils/toon-serializer.test.js +290 -0
  437. package/package.json +63 -0
  438. package/scripts/install.ps1 +133 -0
  439. package/scripts/install.sh +183 -0
  440. package/scripts/pre-commit-hook.sh +86 -0
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Error Normalizer
3
+ *
4
+ * Normalizes error lines to create consistent signatures for deduplication.
5
+ * Removes variable parts (file paths, line numbers, values) while preserving
6
+ * the error pattern.
7
+ */
8
+ /**
9
+ * Normalize an error line by replacing variable parts with placeholders.
10
+ * This creates a consistent signature for grouping similar errors.
11
+ */
12
+ export function normalizeErrorLine(line) {
13
+ return (line
14
+ // Remove file paths (Unix and Windows)
15
+ .replace(/[A-Za-z]:\\[\w\-\\\.]+\.(ts|tsx|js|jsx|py|go|rs|java|c|cpp|h|hpp)/gi, "<FILE>")
16
+ .replace(/\/[\w\-\.\/]+\.(ts|tsx|js|jsx|py|go|rs|java|c|cpp|h|hpp)/g, "<FILE>")
17
+ // Remove relative paths
18
+ .replace(/\.\.?\/[\w\-\.\/]+\.(ts|tsx|js|jsx|py|go|rs|java|c|cpp|h|hpp)/g, "<FILE>")
19
+ // Remove line:column patterns
20
+ .replace(/:\d+:\d+/g, ":<LINE>")
21
+ .replace(/\(\d+,\s*\d+\)/g, "(<LINE>)")
22
+ .replace(/\[\d+,\s*\d+\]/g, "[<LINE>]")
23
+ .replace(/line\s+\d+/gi, "line <LINE>")
24
+ .replace(/col(?:umn)?\s+\d+/gi, "col <LINE>")
25
+ // Remove quoted values (but preserve the quotes for structure)
26
+ .replace(/'[^']*'/g, "'<VALUE>'")
27
+ .replace(/"[^"]*"/g, '"<VALUE>"')
28
+ .replace(/`[^`]*`/g, "`<VALUE>`")
29
+ // Remove timestamps
30
+ .replace(/\d{4}-\d{2}-\d{2}[\sT]\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}:?\d{2}|Z)?/g, "<TIMESTAMP>")
31
+ .replace(/\d{2}\/\d{2}\/\d{4}\s+\d{2}:\d{2}:\d{2}/g, "<TIMESTAMP>")
32
+ // Remove numeric IDs and hashes
33
+ .replace(/\b[0-9a-f]{32,}\b/gi, "<HASH>")
34
+ .replace(/\b\d{5,}\b/g, "<ID>")
35
+ // Normalize whitespace
36
+ .replace(/\s+/g, " ")
37
+ .trim());
38
+ }
39
+ /**
40
+ * Common error patterns for different tools
41
+ */
42
+ const ERROR_PATTERNS = [
43
+ // TypeScript: src/file.ts(12,5): error TS2304: Cannot find name 'foo'.
44
+ {
45
+ name: "typescript",
46
+ regex: /^(.+?)\((\d+),(\d+)\):\s*(error|warning)\s+(TS\d+):\s*(.+)$/,
47
+ extract: (match) => ({
48
+ file: match[1] ?? "",
49
+ line: parseInt(match[2] ?? "0", 10),
50
+ column: parseInt(match[3] ?? "0", 10),
51
+ code: match[5] ?? "",
52
+ message: match[6] ?? "",
53
+ raw: match[0] ?? "",
54
+ }),
55
+ },
56
+ // ESLint: src/file.ts:12:5 - error rule-name: Message
57
+ {
58
+ name: "eslint",
59
+ regex: /^(.+?):(\d+):(\d+)\s*-?\s*(error|warning|info)\s+([a-z\-@\/]+):\s*(.+)$/i,
60
+ extract: (match) => ({
61
+ file: match[1] ?? "",
62
+ line: parseInt(match[2] ?? "0", 10),
63
+ column: parseInt(match[3] ?? "0", 10),
64
+ code: match[5] ?? "",
65
+ message: match[6] ?? "",
66
+ raw: match[0] ?? "",
67
+ }),
68
+ },
69
+ // GCC/Clang: file.c:12:5: error: message
70
+ {
71
+ name: "gcc",
72
+ regex: /^(.+?):(\d+):(\d+):\s*(error|warning|note):\s*(.+)$/,
73
+ extract: (match) => ({
74
+ file: match[1] ?? "",
75
+ line: parseInt(match[2] ?? "0", 10),
76
+ column: parseInt(match[3] ?? "0", 10),
77
+ code: match[4] ?? "",
78
+ message: match[5] ?? "",
79
+ raw: match[0] ?? "",
80
+ }),
81
+ },
82
+ // Python: File "file.py", line 12, in function
83
+ {
84
+ name: "python",
85
+ regex: /^File "(.+?)", line (\d+)(?:, in .+)?$/,
86
+ extract: (match) => ({
87
+ file: match[1] ?? "",
88
+ line: parseInt(match[2] ?? "0", 10),
89
+ message: match[0] ?? "",
90
+ raw: match[0] ?? "",
91
+ }),
92
+ },
93
+ // Python error: ErrorType: message
94
+ {
95
+ name: "python-error",
96
+ regex: /^([A-Z][a-zA-Z]+Error):\s*(.+)$/,
97
+ extract: (match) => ({
98
+ code: match[1] ?? "",
99
+ message: match[2] ?? "",
100
+ raw: match[0] ?? "",
101
+ }),
102
+ },
103
+ // Go: file.go:12:5: message
104
+ {
105
+ name: "go",
106
+ regex: /^(.+?\.go):(\d+):(\d+):\s*(.+)$/,
107
+ extract: (match) => ({
108
+ file: match[1] ?? "",
109
+ line: parseInt(match[2] ?? "0", 10),
110
+ column: parseInt(match[3] ?? "0", 10),
111
+ message: match[4] ?? "",
112
+ raw: match[0] ?? "",
113
+ }),
114
+ },
115
+ // Rust: error[E0425]: cannot find value `x` in this scope
116
+ {
117
+ name: "rust",
118
+ regex: /^(error|warning)\[(E\d+)\]:\s*(.+)$/,
119
+ extract: (match) => ({
120
+ code: match[2] ?? "",
121
+ message: match[3] ?? "",
122
+ raw: match[0] ?? "",
123
+ }),
124
+ },
125
+ // Rust location: --> file.rs:12:5
126
+ {
127
+ name: "rust-location",
128
+ regex: /^\s*-->\s*(.+?):(\d+):(\d+)$/,
129
+ extract: (match) => ({
130
+ file: match[1] ?? "",
131
+ line: parseInt(match[2] ?? "0", 10),
132
+ column: parseInt(match[3] ?? "0", 10),
133
+ message: match[0] ?? "",
134
+ raw: match[0] ?? "",
135
+ }),
136
+ },
137
+ // Generic: [ERROR] message or ERROR: message
138
+ {
139
+ name: "generic-bracket",
140
+ regex: /^\[(ERROR|WARN(?:ING)?|INFO)\]\s*(.+)$/i,
141
+ extract: (match) => ({
142
+ code: (match[1] ?? "").toUpperCase(),
143
+ message: match[2] ?? "",
144
+ raw: match[0] ?? "",
145
+ }),
146
+ },
147
+ // Generic colon format
148
+ {
149
+ name: "generic-colon",
150
+ regex: /^(ERROR|WARN(?:ING)?|FATAL):\s*(.+)$/i,
151
+ extract: (match) => ({
152
+ code: (match[1] ?? "").toUpperCase(),
153
+ message: match[2] ?? "",
154
+ raw: match[0] ?? "",
155
+ }),
156
+ },
157
+ ];
158
+ /**
159
+ * Extract structured parts from an error line.
160
+ * Returns null if the line doesn't match any known error pattern.
161
+ */
162
+ export function extractErrorParts(line) {
163
+ const trimmed = line.trim();
164
+ if (!trimmed)
165
+ return null;
166
+ for (const pattern of ERROR_PATTERNS) {
167
+ const match = trimmed.match(pattern.regex);
168
+ if (match) {
169
+ return pattern.extract(match);
170
+ }
171
+ }
172
+ // If no pattern matches but line looks like an error
173
+ if (isLikelyError(trimmed)) {
174
+ return {
175
+ message: trimmed,
176
+ raw: trimmed,
177
+ };
178
+ }
179
+ return null;
180
+ }
181
+ /**
182
+ * Check if a line is likely an error message
183
+ */
184
+ export function isLikelyError(line) {
185
+ const errorIndicators = [
186
+ /\berror\b/i,
187
+ /\bfailed\b/i,
188
+ /\bfailure\b/i,
189
+ /\bexception\b/i,
190
+ /\bcannot\b/i,
191
+ /\bunable\b/i,
192
+ /\binvalid\b/i,
193
+ /\bunexpected\b/i,
194
+ /\bmissing\b/i,
195
+ /\bundefined\b/i,
196
+ /\bnot found\b/i,
197
+ /\bdoes not exist\b/i,
198
+ /\bnot defined\b/i,
199
+ /\btype mismatch\b/i,
200
+ /\bsyntax error\b/i,
201
+ /^\s*\^+\s*$/, // Error pointer line (^^^)
202
+ ];
203
+ return errorIndicators.some((pattern) => pattern.test(line));
204
+ }
205
+ /**
206
+ * Create a signature from error parts for grouping.
207
+ * The signature represents the "type" of error, ignoring location.
208
+ */
209
+ export function createSignature(parts) {
210
+ const components = [];
211
+ if (parts.code) {
212
+ components.push(parts.code);
213
+ }
214
+ // Normalize the message
215
+ const normalizedMessage = normalizeErrorLine(parts.message);
216
+ components.push(normalizedMessage);
217
+ return components.join(": ");
218
+ }
219
+ /**
220
+ * Extract file location from error parts
221
+ */
222
+ export function formatLocation(parts) {
223
+ if (!parts.file)
224
+ return "";
225
+ let location = parts.file;
226
+ if (parts.line !== undefined) {
227
+ location += `:${parts.line}`;
228
+ if (parts.column !== undefined) {
229
+ location += `:${parts.column}`;
230
+ }
231
+ }
232
+ return location;
233
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Hybrid Search combining BM25 (lexical) and Semantic Similarity
3
+ *
4
+ * Uses a weighted combination of:
5
+ * - BM25 for exact/partial keyword matches (40%)
6
+ * - Cosine similarity on embeddings for semantic matches (60%)
7
+ *
8
+ * This allows finding tools even when the query uses different
9
+ * words than the tool description (e.g., "shrink output" → compress).
10
+ */
11
+ import { type BM25Result } from "./bm25.js";
12
+ /**
13
+ * Configuration options for hybrid search
14
+ */
15
+ export interface HybridSearchOptions {
16
+ /** Weight for BM25 lexical matching (default: 0.4) */
17
+ bm25Weight?: number;
18
+ /** Weight for semantic similarity (default: 0.6) */
19
+ semanticWeight?: number;
20
+ /** Minimum semantic similarity for semantic-only matches (default: 0.5) */
21
+ semanticThreshold?: number;
22
+ }
23
+ /**
24
+ * Result from hybrid search with both scores
25
+ */
26
+ export interface HybridSearchResult<T> {
27
+ /** The matched item */
28
+ item: T;
29
+ /** Combined score (weighted BM25 + semantic) */
30
+ score: number;
31
+ /** Raw BM25 score */
32
+ bm25Score: number;
33
+ /** Semantic similarity score (0-1) */
34
+ semanticScore: number;
35
+ /** Terms that matched in BM25 */
36
+ matchedTerms: string[];
37
+ }
38
+ /**
39
+ * Hybrid search index interface
40
+ */
41
+ export interface HybridSearchIndex<T> {
42
+ /** Search using hybrid BM25 + semantic */
43
+ search: (query: string) => Promise<HybridSearchResult<T>[]>;
44
+ /** Search using BM25 only (synchronous, always available) */
45
+ searchBM25Only: (query: string) => BM25Result<T>[];
46
+ /** Precompute embeddings for all items (call during idle time) */
47
+ precomputeEmbeddings: () => Promise<void>;
48
+ /** Check if semantic search is ready */
49
+ isSemanticReady: () => boolean;
50
+ }
51
+ /**
52
+ * Create a hybrid search index combining BM25 and semantic similarity
53
+ *
54
+ * @param items - Array of items to index
55
+ * @param getSearchableText - Function to extract text from each item
56
+ * @param options - Search configuration options
57
+ * @returns Hybrid search index
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const tools = [
62
+ * { name: "compress", description: "Compress and reduce output" },
63
+ * { name: "analyze", description: "Analyze build errors" }
64
+ * ];
65
+ *
66
+ * const index = createHybridSearchIndex(
67
+ * tools,
68
+ * (tool) => `${tool.name} ${tool.description}`
69
+ * );
70
+ *
71
+ * // BM25 match
72
+ * await index.search("compress"); // finds "compress" tool
73
+ *
74
+ * // Semantic match (no keyword overlap)
75
+ * await index.search("shrink output"); // also finds "compress" tool!
76
+ * ```
77
+ */
78
+ export declare function createHybridSearchIndex<T>(items: T[], getSearchableText: (item: T) => string, options?: HybridSearchOptions): HybridSearchIndex<T>;
79
+ //# sourceMappingURL=hybrid-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../../src/utils/hybrid-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAO7D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,uBAAuB;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,0CAA0C;IAC1C,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,6DAA6D;IAC7D,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,kEAAkE;IAClE,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,wCAAwC;IACxC,eAAe,EAAE,MAAM,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,CAAC,EAAE,EACV,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EACtC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,iBAAiB,CAAC,CAAC,CAAC,CA4HtB"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Hybrid Search combining BM25 (lexical) and Semantic Similarity
3
+ *
4
+ * Uses a weighted combination of:
5
+ * - BM25 for exact/partial keyword matches (40%)
6
+ * - Cosine similarity on embeddings for semantic matches (60%)
7
+ *
8
+ * This allows finding tools even when the query uses different
9
+ * words than the tool description (e.g., "shrink output" → compress).
10
+ */
11
+ import { createBM25Index } from "./bm25.js";
12
+ import { computeEmbedding, computeEmbeddings, cosineSimilarity, } from "./embeddings.js";
13
+ /**
14
+ * Create a hybrid search index combining BM25 and semantic similarity
15
+ *
16
+ * @param items - Array of items to index
17
+ * @param getSearchableText - Function to extract text from each item
18
+ * @param options - Search configuration options
19
+ * @returns Hybrid search index
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const tools = [
24
+ * { name: "compress", description: "Compress and reduce output" },
25
+ * { name: "analyze", description: "Analyze build errors" }
26
+ * ];
27
+ *
28
+ * const index = createHybridSearchIndex(
29
+ * tools,
30
+ * (tool) => `${tool.name} ${tool.description}`
31
+ * );
32
+ *
33
+ * // BM25 match
34
+ * await index.search("compress"); // finds "compress" tool
35
+ *
36
+ * // Semantic match (no keyword overlap)
37
+ * await index.search("shrink output"); // also finds "compress" tool!
38
+ * ```
39
+ */
40
+ export function createHybridSearchIndex(items, getSearchableText, options) {
41
+ const bm25Weight = options?.bm25Weight ?? 0.4;
42
+ const semanticWeight = options?.semanticWeight ?? 0.6;
43
+ const semanticThreshold = options?.semanticThreshold ?? 0.5;
44
+ // BM25 index (synchronous, always available)
45
+ const bm25Index = createBM25Index(items, getSearchableText);
46
+ // Item embeddings (lazy computed)
47
+ let itemEmbeddings = null;
48
+ let embeddingsPromise = null;
49
+ /**
50
+ * Ensure embeddings are computed
51
+ */
52
+ async function ensureEmbeddings() {
53
+ if (itemEmbeddings)
54
+ return itemEmbeddings;
55
+ if (!embeddingsPromise) {
56
+ embeddingsPromise = (async () => {
57
+ const texts = items.map(getSearchableText);
58
+ itemEmbeddings = await computeEmbeddings(texts);
59
+ })();
60
+ }
61
+ await embeddingsPromise;
62
+ return itemEmbeddings;
63
+ }
64
+ return {
65
+ async search(query) {
66
+ // Get BM25 results first (always available)
67
+ const bm25Results = bm25Index.search(query);
68
+ // Try to compute semantic scores
69
+ let queryEmbedding = null;
70
+ let embeddings = null;
71
+ try {
72
+ embeddings = await ensureEmbeddings();
73
+ queryEmbedding = await computeEmbedding(query);
74
+ }
75
+ catch {
76
+ // Semantic search failed, fall back to BM25 only
77
+ return bm25Results.map((r) => ({
78
+ item: r.item,
79
+ score: r.score,
80
+ bm25Score: r.score,
81
+ semanticScore: 0,
82
+ matchedTerms: r.matchedTerms,
83
+ }));
84
+ }
85
+ // Build item index map for O(1) lookup
86
+ const itemIndexMap = new Map();
87
+ items.forEach((item, idx) => itemIndexMap.set(item, idx));
88
+ // Normalize BM25 scores to 0-1 range
89
+ const maxBM25 = Math.max(...bm25Results.map((r) => r.score), 0.001);
90
+ // Combine BM25 results with semantic scores
91
+ const results = [];
92
+ const processedItems = new Set();
93
+ for (const bm25Result of bm25Results) {
94
+ const idx = itemIndexMap.get(bm25Result.item);
95
+ if (idx === undefined || !embeddings || !queryEmbedding)
96
+ continue;
97
+ const itemEmbedding = embeddings[idx];
98
+ if (!itemEmbedding)
99
+ continue;
100
+ const semanticScore = cosineSimilarity(queryEmbedding, itemEmbedding);
101
+ const normalizedBM25 = bm25Result.score / maxBM25;
102
+ results.push({
103
+ item: bm25Result.item,
104
+ score: normalizedBM25 * bm25Weight + semanticScore * semanticWeight,
105
+ bm25Score: bm25Result.score,
106
+ semanticScore,
107
+ matchedTerms: bm25Result.matchedTerms,
108
+ });
109
+ processedItems.add(bm25Result.item);
110
+ }
111
+ // Add items that only match semantically (no BM25 match)
112
+ if (embeddings && queryEmbedding) {
113
+ for (let i = 0; i < items.length; i++) {
114
+ const item = items[i];
115
+ if (!item || processedItems.has(item))
116
+ continue;
117
+ const itemEmbedding = embeddings[i];
118
+ if (!itemEmbedding)
119
+ continue;
120
+ const similarity = cosineSimilarity(queryEmbedding, itemEmbedding);
121
+ // Only include if above semantic threshold
122
+ if (similarity >= semanticThreshold) {
123
+ results.push({
124
+ item,
125
+ score: similarity * semanticWeight,
126
+ bm25Score: 0,
127
+ semanticScore: similarity,
128
+ matchedTerms: [],
129
+ });
130
+ }
131
+ }
132
+ }
133
+ // Sort by combined score (highest first)
134
+ return results.sort((a, b) => b.score - a.score);
135
+ },
136
+ searchBM25Only(query) {
137
+ return bm25Index.search(query);
138
+ },
139
+ async precomputeEmbeddings() {
140
+ await ensureEmbeddings();
141
+ },
142
+ isSemanticReady() {
143
+ return itemEmbeddings !== null;
144
+ },
145
+ };
146
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Hybrid Search Tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=hybrid-search.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybrid-search.test.d.ts","sourceRoot":"","sources":["../../src/utils/hybrid-search.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Hybrid Search Tests
3
+ */
4
+ import { describe, it, expect, vi, beforeEach } from "vitest";
5
+ import { createHybridSearchIndex } from "./hybrid-search.js";
6
+ // Mock the embeddings module for fast tests
7
+ vi.mock("./embeddings.js", () => {
8
+ // Simple mock embeddings based on word overlap
9
+ const mockEmbedding = (text) => {
10
+ const words = text.toLowerCase().split(/\s+/);
11
+ const dim = 384;
12
+ const embedding = new Array(dim).fill(0);
13
+ // Create deterministic embedding based on words
14
+ for (const word of words) {
15
+ for (let i = 0; i < word.length; i++) {
16
+ const idx = (word.charCodeAt(i) * (i + 1)) % dim;
17
+ embedding[idx] += 0.1;
18
+ }
19
+ }
20
+ // Normalize
21
+ const magnitude = Math.sqrt(embedding.reduce((sum, x) => sum + x * x, 0));
22
+ if (magnitude > 0) {
23
+ for (let i = 0; i < dim; i++) {
24
+ embedding[i] /= magnitude;
25
+ }
26
+ }
27
+ return embedding;
28
+ };
29
+ return {
30
+ computeEmbedding: vi.fn(async (text) => mockEmbedding(text)),
31
+ computeEmbeddings: vi.fn(async (texts) => texts.map((t) => mockEmbedding(t))),
32
+ cosineSimilarity: vi.fn((a, b) => {
33
+ if (a.length !== b.length)
34
+ return 0;
35
+ let dot = 0;
36
+ for (let i = 0; i < a.length; i++) {
37
+ dot += (a[i] ?? 0) * (b[i] ?? 0);
38
+ }
39
+ return dot;
40
+ }),
41
+ };
42
+ });
43
+ describe("Hybrid Search", () => {
44
+ const testItems = [
45
+ { name: "compress", description: "Compress and reduce output size" },
46
+ { name: "analyze", description: "Analyze build errors and warnings" },
47
+ { name: "summarize", description: "Summarize log files" },
48
+ { name: "optimize", description: "Optimize token usage" },
49
+ ];
50
+ const getSearchableText = (item) => `${item.name} ${item.description}`;
51
+ beforeEach(() => {
52
+ vi.clearAllMocks();
53
+ });
54
+ describe("createHybridSearchIndex", () => {
55
+ it("should create an index with all methods", () => {
56
+ const index = createHybridSearchIndex(testItems, getSearchableText);
57
+ expect(index.search).toBeDefined();
58
+ expect(index.searchBM25Only).toBeDefined();
59
+ expect(index.precomputeEmbeddings).toBeDefined();
60
+ expect(index.isSemanticReady).toBeDefined();
61
+ });
62
+ it("should start with semantic not ready", () => {
63
+ const index = createHybridSearchIndex(testItems, getSearchableText);
64
+ expect(index.isSemanticReady()).toBe(false);
65
+ });
66
+ });
67
+ describe("searchBM25Only", () => {
68
+ it("should return BM25 results synchronously", () => {
69
+ const index = createHybridSearchIndex(testItems, getSearchableText);
70
+ const results = index.searchBM25Only("compress");
71
+ expect(results.length).toBeGreaterThan(0);
72
+ expect(results[0].item.name).toBe("compress");
73
+ });
74
+ it("should return empty array for no matches", () => {
75
+ const index = createHybridSearchIndex(testItems, getSearchableText);
76
+ const results = index.searchBM25Only("nonexistent");
77
+ expect(results).toHaveLength(0);
78
+ });
79
+ });
80
+ describe("search (hybrid)", () => {
81
+ it("should return results with both BM25 and semantic scores", async () => {
82
+ const index = createHybridSearchIndex(testItems, getSearchableText);
83
+ const results = await index.search("compress output");
84
+ expect(results.length).toBeGreaterThan(0);
85
+ expect(results[0]).toHaveProperty("bm25Score");
86
+ expect(results[0]).toHaveProperty("semanticScore");
87
+ expect(results[0]).toHaveProperty("score");
88
+ expect(results[0]).toHaveProperty("matchedTerms");
89
+ });
90
+ it("should find exact keyword matches", async () => {
91
+ const index = createHybridSearchIndex(testItems, getSearchableText);
92
+ const results = await index.search("compress");
93
+ expect(results.length).toBeGreaterThan(0);
94
+ expect(results[0].item.name).toBe("compress");
95
+ expect(results[0].bm25Score).toBeGreaterThan(0);
96
+ });
97
+ it("should sort results by combined score", async () => {
98
+ const index = createHybridSearchIndex(testItems, getSearchableText);
99
+ const results = await index.search("compress reduce");
100
+ for (let i = 1; i < results.length; i++) {
101
+ expect(results[i - 1].score).toBeGreaterThanOrEqual(results[i].score);
102
+ }
103
+ });
104
+ it("should handle empty query", async () => {
105
+ const index = createHybridSearchIndex(testItems, getSearchableText);
106
+ const results = await index.search("");
107
+ // Empty query might return all items with semantic similarity
108
+ // or no results depending on implementation
109
+ expect(Array.isArray(results)).toBe(true);
110
+ });
111
+ it("should use custom weights", async () => {
112
+ const index = createHybridSearchIndex(testItems, getSearchableText, {
113
+ bm25Weight: 0.8,
114
+ semanticWeight: 0.2,
115
+ });
116
+ const results = await index.search("compress");
117
+ expect(results.length).toBeGreaterThan(0);
118
+ });
119
+ });
120
+ describe("precomputeEmbeddings", () => {
121
+ it("should mark semantic as ready after precomputing", async () => {
122
+ const index = createHybridSearchIndex(testItems, getSearchableText);
123
+ expect(index.isSemanticReady()).toBe(false);
124
+ await index.precomputeEmbeddings();
125
+ expect(index.isSemanticReady()).toBe(true);
126
+ });
127
+ it("should only compute embeddings once", async () => {
128
+ const { computeEmbeddings } = await import("./embeddings.js");
129
+ const index = createHybridSearchIndex(testItems, getSearchableText);
130
+ await index.precomputeEmbeddings();
131
+ await index.precomputeEmbeddings();
132
+ expect(computeEmbeddings).toHaveBeenCalledTimes(1);
133
+ });
134
+ });
135
+ describe("edge cases", () => {
136
+ it("should handle empty items array", async () => {
137
+ const index = createHybridSearchIndex([], getSearchableText);
138
+ const bm25Results = index.searchBM25Only("test");
139
+ expect(bm25Results).toHaveLength(0);
140
+ const hybridResults = await index.search("test");
141
+ expect(hybridResults).toHaveLength(0);
142
+ });
143
+ it("should handle single item", async () => {
144
+ const singleItem = [{ name: "test", description: "Test item" }];
145
+ const index = createHybridSearchIndex(singleItem, getSearchableText);
146
+ const results = await index.search("test");
147
+ expect(results.length).toBeLessThanOrEqual(1);
148
+ });
149
+ });
150
+ describe("score composition", () => {
151
+ it("should combine BM25 and semantic scores", async () => {
152
+ const index = createHybridSearchIndex(testItems, getSearchableText, {
153
+ bm25Weight: 0.4,
154
+ semanticWeight: 0.6,
155
+ });
156
+ const results = await index.search("compress");
157
+ const firstResult = results[0];
158
+ if (firstResult && firstResult.bm25Score > 0) {
159
+ // If there's a BM25 match, score should be combination
160
+ expect(firstResult.score).toBeGreaterThan(0);
161
+ }
162
+ });
163
+ it("should include matched terms from BM25", async () => {
164
+ const index = createHybridSearchIndex(testItems, getSearchableText);
165
+ const results = await index.search("compress output");
166
+ const compressResult = results.find((r) => r.item.name === "compress");
167
+ if (compressResult) {
168
+ expect(compressResult.matchedTerms.length).toBeGreaterThan(0);
169
+ }
170
+ });
171
+ });
172
+ });
@@ -0,0 +1,13 @@
1
+ export * from "./project-detector.js";
2
+ export * from "./command-normalizer.js";
3
+ export * from "./output-similarity.js";
4
+ export * from "./content-detector.js";
5
+ export * from "./language-detector.js";
6
+ export * from "./error-normalizer.js";
7
+ export * from "./signature-grouper.js";
8
+ export * from "./log-parser.js";
9
+ export * from "./token-counter.js";
10
+ export * from "./bm25.js";
11
+ export * from "./embeddings.js";
12
+ export * from "./hybrid-search.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export * from "./project-detector.js";
2
+ export * from "./command-normalizer.js";
3
+ export * from "./output-similarity.js";
4
+ export * from "./content-detector.js";
5
+ export * from "./language-detector.js";
6
+ export * from "./error-normalizer.js";
7
+ export * from "./signature-grouper.js";
8
+ export * from "./log-parser.js";
9
+ export * from "./token-counter.js";
10
+ export * from "./bm25.js";
11
+ export * from "./embeddings.js";
12
+ export * from "./hybrid-search.js";