mdcontext 0.0.1 → 0.2.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 (337) hide show
  1. package/.changeset/README.md +28 -0
  2. package/.changeset/config.json +11 -0
  3. package/.claude/settings.local.json +25 -0
  4. package/.github/workflows/ci.yml +83 -0
  5. package/.github/workflows/claude-code-review.yml +44 -0
  6. package/.github/workflows/claude.yml +85 -0
  7. package/.github/workflows/release.yml +113 -0
  8. package/.tldrignore +112 -0
  9. package/BACKLOG.md +338 -0
  10. package/CONTRIBUTING.md +186 -0
  11. package/NOTES/NOTES +44 -0
  12. package/README.md +434 -11
  13. package/biome.json +36 -0
  14. package/cspell.config.yaml +14 -0
  15. package/dist/chunk-23UPXDNL.js +3044 -0
  16. package/dist/chunk-2W7MO2DL.js +1366 -0
  17. package/dist/chunk-3NUAZGMA.js +1689 -0
  18. package/dist/chunk-7TOWB2XB.js +366 -0
  19. package/dist/chunk-7XOTOADQ.js +3065 -0
  20. package/dist/chunk-AH2PDM2K.js +3042 -0
  21. package/dist/chunk-BNXWSZ63.js +3742 -0
  22. package/dist/chunk-BTL5DJVU.js +3222 -0
  23. package/dist/chunk-HDHYG7E4.js +104 -0
  24. package/dist/chunk-HLR4KZBP.js +3234 -0
  25. package/dist/chunk-IP3FRFEB.js +1045 -0
  26. package/dist/chunk-KHU56VDO.js +3042 -0
  27. package/dist/chunk-KRYIFLQR.js +88 -0
  28. package/dist/chunk-LBSDNLEM.js +287 -0
  29. package/dist/chunk-MNTQ7HCP.js +2643 -0
  30. package/dist/chunk-MUJELQQ6.js +1387 -0
  31. package/dist/chunk-MXJGMSLV.js +2199 -0
  32. package/dist/chunk-N6QJGC3Z.js +2636 -0
  33. package/dist/chunk-OBELGBPM.js +1713 -0
  34. package/dist/chunk-OT7R5XTA.js +3192 -0
  35. package/dist/chunk-P7X4RA2T.js +106 -0
  36. package/dist/chunk-PIDUQNC2.js +3185 -0
  37. package/dist/chunk-POGCDIH4.js +3187 -0
  38. package/dist/chunk-PSIEOQGZ.js +3043 -0
  39. package/dist/chunk-PVRT3IHA.js +3238 -0
  40. package/dist/chunk-QNN4TT23.js +1430 -0
  41. package/dist/chunk-RE3R45RJ.js +3042 -0
  42. package/dist/chunk-S7E6TFX6.js +803 -0
  43. package/dist/chunk-SG6GLU4U.js +1378 -0
  44. package/dist/chunk-SJCDV2ST.js +274 -0
  45. package/dist/chunk-SYE5XLF3.js +104 -0
  46. package/dist/chunk-T5VLYBZD.js +103 -0
  47. package/dist/chunk-TOQB7VWU.js +3238 -0
  48. package/dist/chunk-VFNMZ4ZQ.js +3228 -0
  49. package/dist/chunk-VVTGZNBT.js +1629 -0
  50. package/dist/chunk-W7Q4RFEV.js +104 -0
  51. package/dist/chunk-XTYYVRLO.js +3190 -0
  52. package/dist/chunk-Y6MDYVJD.js +3063 -0
  53. package/dist/cli/main.d.ts +1 -0
  54. package/dist/cli/main.js +5458 -0
  55. package/dist/index.d.ts +653 -0
  56. package/dist/index.js +79 -0
  57. package/dist/mcp/server.d.ts +1 -0
  58. package/dist/mcp/server.js +472 -0
  59. package/dist/schema-BAWSG7KY.js +22 -0
  60. package/dist/schema-E3QUPL26.js +20 -0
  61. package/dist/schema-EHL7WUT6.js +20 -0
  62. package/docs/019-USAGE.md +625 -0
  63. package/docs/020-current-implementation.md +364 -0
  64. package/docs/021-DOGFOODING-FINDINGS.md +175 -0
  65. package/docs/BACKLOG.md +80 -0
  66. package/docs/CONFIG.md +1123 -0
  67. package/docs/DESIGN.md +439 -0
  68. package/docs/ERRORS.md +383 -0
  69. package/docs/PROJECT.md +88 -0
  70. package/docs/ROADMAP.md +407 -0
  71. package/docs/summarization.md +320 -0
  72. package/docs/test-links.md +9 -0
  73. package/justfile +40 -0
  74. package/package.json +74 -9
  75. package/pnpm-workspace.yaml +5 -0
  76. package/research/INDEX.md +315 -0
  77. package/research/code-review/README.md +90 -0
  78. package/research/code-review/cli-error-handling-review.md +979 -0
  79. package/research/code-review/code-review-validation-report.md +464 -0
  80. package/research/code-review/main-ts-review.md +1128 -0
  81. package/research/config-analysis/01-current-implementation.md +470 -0
  82. package/research/config-analysis/02-strategy-recommendation.md +428 -0
  83. package/research/config-analysis/03-task-candidates.md +715 -0
  84. package/research/config-analysis/033-research-configuration-management.md +828 -0
  85. package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
  86. package/research/config-analysis/04-consolidated-task-candidates.md +277 -0
  87. package/research/config-docs/SUMMARY.md +357 -0
  88. package/research/config-docs/TEST-RESULTS.md +776 -0
  89. package/research/config-docs/TODO.md +542 -0
  90. package/research/config-docs/analysis.md +744 -0
  91. package/research/config-docs/fix-validation.md +502 -0
  92. package/research/config-docs/help-audit.md +264 -0
  93. package/research/config-docs/help-system-analysis.md +890 -0
  94. package/research/dogfood/consolidated-tool-evaluation.md +373 -0
  95. package/research/dogfood/strategy-a/a-synthesis.md +184 -0
  96. package/research/dogfood/strategy-a/a1-docs.md +226 -0
  97. package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
  98. package/research/dogfood/strategy-a/a3-llm.md +164 -0
  99. package/research/dogfood/strategy-b/b-synthesis.md +228 -0
  100. package/research/dogfood/strategy-b/b1-architecture.md +207 -0
  101. package/research/dogfood/strategy-b/b2-gaps.md +258 -0
  102. package/research/dogfood/strategy-b/b3-workflows.md +250 -0
  103. package/research/dogfood/strategy-c/c-synthesis.md +451 -0
  104. package/research/dogfood/strategy-c/c1-explorer.md +192 -0
  105. package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
  106. package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
  107. package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
  108. package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
  109. package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
  110. package/research/effect-cli-error-handling.md +845 -0
  111. package/research/effect-errors-as-values.md +943 -0
  112. package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
  113. package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
  114. package/research/errors-task-analysis/embeddings-analysis.md +709 -0
  115. package/research/errors-task-analysis/index-search-analysis.md +812 -0
  116. package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
  117. package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
  118. package/research/issue-review.md +603 -0
  119. package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
  120. package/research/llm-summarization/alternative-providers-2026.md +1428 -0
  121. package/research/llm-summarization/anthropic-2026.md +367 -0
  122. package/research/llm-summarization/claude-cli-integration.md +1706 -0
  123. package/research/llm-summarization/cli-integration-patterns.md +3155 -0
  124. package/research/llm-summarization/openai-2026.md +473 -0
  125. package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
  126. package/research/llm-summarization/opencode-cli-integration.md +1552 -0
  127. package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
  128. package/research/llm-summarization/prototype-results.md +56 -0
  129. package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
  130. package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
  131. package/research/mdcontext-error-analysis.md +521 -0
  132. package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
  133. package/research/mdcontext-pudding/01-index-embed.md +956 -0
  134. package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
  135. package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
  136. package/research/mdcontext-pudding/02-search.md +970 -0
  137. package/research/mdcontext-pudding/03-context.md +779 -0
  138. package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
  139. package/research/mdcontext-pudding/04-tree.md +704 -0
  140. package/research/mdcontext-pudding/05-config.md +1038 -0
  141. package/research/mdcontext-pudding/06-links-summary.txt +87 -0
  142. package/research/mdcontext-pudding/06-links.md +679 -0
  143. package/research/mdcontext-pudding/07-stats.md +693 -0
  144. package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
  145. package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
  146. package/research/mdcontext-pudding/README.md +168 -0
  147. package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
  148. package/research/npm_publish/011-npm-workflow-research-agent2.md +792 -0
  149. package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
  150. package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
  151. package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
  152. package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
  153. package/research/research-quality-review.md +834 -0
  154. package/research/semantic-search/002-research-embedding-models.md +490 -0
  155. package/research/semantic-search/003-research-rag-alternatives.md +523 -0
  156. package/research/semantic-search/004-research-vector-search.md +841 -0
  157. package/research/semantic-search/032-research-semantic-search.md +427 -0
  158. package/research/semantic-search/embedding-text-analysis.md +156 -0
  159. package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
  160. package/research/semantic-search/query-processing-analysis.md +207 -0
  161. package/research/semantic-search/root-cause-and-solution.md +114 -0
  162. package/research/semantic-search/threshold-validation-report.md +69 -0
  163. package/research/semantic-search/vector-search-analysis.md +63 -0
  164. package/research/task-management-2026/00-synthesis-recommendations.md +295 -0
  165. package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
  166. package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
  167. package/research/task-management-2026/03-lightweight-file-based.md +567 -0
  168. package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
  169. package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
  170. package/research/task-management-2026/linear/02-api-integrations.md +930 -0
  171. package/research/task-management-2026/linear/03-ai-features.md +368 -0
  172. package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
  173. package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -0
  174. package/research/test-path-issues.md +276 -0
  175. package/review/ALP-76/1-error-type-design.md +962 -0
  176. package/review/ALP-76/2-error-handling-patterns.md +906 -0
  177. package/review/ALP-76/3-error-presentation.md +624 -0
  178. package/review/ALP-76/4-test-coverage.md +625 -0
  179. package/review/ALP-76/5-migration-completeness.md +440 -0
  180. package/review/ALP-76/6-effect-best-practices.md +755 -0
  181. package/scripts/apply-branch-protection.sh +47 -0
  182. package/scripts/branch-protection-templates.json +79 -0
  183. package/scripts/prototype-summarization.ts +346 -0
  184. package/scripts/rebuild-hnswlib.js +58 -0
  185. package/scripts/setup-branch-protection.sh +64 -0
  186. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
  187. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
  188. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
  189. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
  190. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  191. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  192. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
  193. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
  194. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
  195. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
  196. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
  197. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
  198. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
  199. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
  200. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
  201. package/src/cli/argv-preprocessor.test.ts +210 -0
  202. package/src/cli/argv-preprocessor.ts +202 -0
  203. package/src/cli/cli.test.ts +627 -0
  204. package/src/cli/commands/backlinks.ts +54 -0
  205. package/src/cli/commands/config-cmd.ts +642 -0
  206. package/src/cli/commands/context.ts +285 -0
  207. package/src/cli/commands/duplicates.ts +122 -0
  208. package/src/cli/commands/embeddings.ts +529 -0
  209. package/src/cli/commands/index-cmd.ts +480 -0
  210. package/src/cli/commands/index.ts +16 -0
  211. package/src/cli/commands/links.ts +52 -0
  212. package/src/cli/commands/search.ts +1281 -0
  213. package/src/cli/commands/stats.ts +149 -0
  214. package/src/cli/commands/tree.ts +128 -0
  215. package/src/cli/config-layer.ts +176 -0
  216. package/src/cli/error-handler.test.ts +235 -0
  217. package/src/cli/error-handler.ts +655 -0
  218. package/src/cli/flag-schemas.ts +341 -0
  219. package/src/cli/help.ts +588 -0
  220. package/src/cli/index.ts +9 -0
  221. package/src/cli/main.ts +435 -0
  222. package/src/cli/options.ts +41 -0
  223. package/src/cli/shared-error-handling.ts +199 -0
  224. package/src/cli/typo-suggester.test.ts +105 -0
  225. package/src/cli/typo-suggester.ts +130 -0
  226. package/src/cli/utils.ts +259 -0
  227. package/src/config/file-provider.test.ts +320 -0
  228. package/src/config/file-provider.ts +273 -0
  229. package/src/config/index.ts +72 -0
  230. package/src/config/integration.test.ts +667 -0
  231. package/src/config/precedence.test.ts +277 -0
  232. package/src/config/precedence.ts +451 -0
  233. package/src/config/schema.test.ts +414 -0
  234. package/src/config/schema.ts +603 -0
  235. package/src/config/service.test.ts +320 -0
  236. package/src/config/service.ts +243 -0
  237. package/src/config/testing.test.ts +264 -0
  238. package/src/config/testing.ts +110 -0
  239. package/src/core/index.ts +1 -0
  240. package/src/core/types.ts +113 -0
  241. package/src/duplicates/detector.test.ts +183 -0
  242. package/src/duplicates/detector.ts +414 -0
  243. package/src/duplicates/index.ts +18 -0
  244. package/src/embeddings/embedding-namespace.test.ts +300 -0
  245. package/src/embeddings/embedding-namespace.ts +947 -0
  246. package/src/embeddings/heading-boost.test.ts +222 -0
  247. package/src/embeddings/hnsw-build-options.test.ts +198 -0
  248. package/src/embeddings/hyde.test.ts +272 -0
  249. package/src/embeddings/hyde.ts +264 -0
  250. package/src/embeddings/index.ts +10 -0
  251. package/src/embeddings/openai-provider.ts +414 -0
  252. package/src/embeddings/pricing.json +22 -0
  253. package/src/embeddings/provider-constants.ts +204 -0
  254. package/src/embeddings/provider-errors.test.ts +967 -0
  255. package/src/embeddings/provider-errors.ts +565 -0
  256. package/src/embeddings/provider-factory.test.ts +240 -0
  257. package/src/embeddings/provider-factory.ts +225 -0
  258. package/src/embeddings/provider-integration.test.ts +788 -0
  259. package/src/embeddings/query-preprocessing.test.ts +187 -0
  260. package/src/embeddings/semantic-search-threshold.test.ts +508 -0
  261. package/src/embeddings/semantic-search.ts +1270 -0
  262. package/src/embeddings/types.ts +359 -0
  263. package/src/embeddings/vector-store.ts +708 -0
  264. package/src/embeddings/voyage-provider.ts +313 -0
  265. package/src/errors/errors.test.ts +845 -0
  266. package/src/errors/index.ts +533 -0
  267. package/src/index/ignore-patterns.test.ts +354 -0
  268. package/src/index/ignore-patterns.ts +305 -0
  269. package/src/index/index.ts +4 -0
  270. package/src/index/indexer.ts +684 -0
  271. package/src/index/storage.ts +260 -0
  272. package/src/index/types.ts +147 -0
  273. package/src/index/watcher.ts +189 -0
  274. package/src/index.ts +30 -0
  275. package/src/integration/search-keyword.test.ts +678 -0
  276. package/src/mcp/server.ts +612 -0
  277. package/src/parser/index.ts +1 -0
  278. package/src/parser/parser.test.ts +291 -0
  279. package/src/parser/parser.ts +394 -0
  280. package/src/parser/section-filter.test.ts +277 -0
  281. package/src/parser/section-filter.ts +392 -0
  282. package/src/search/__tests__/hybrid-search.test.ts +650 -0
  283. package/src/search/bm25-store.ts +366 -0
  284. package/src/search/cross-encoder.test.ts +253 -0
  285. package/src/search/cross-encoder.ts +406 -0
  286. package/src/search/fuzzy-search.test.ts +419 -0
  287. package/src/search/fuzzy-search.ts +273 -0
  288. package/src/search/hybrid-search.ts +448 -0
  289. package/src/search/path-matcher.test.ts +276 -0
  290. package/src/search/path-matcher.ts +33 -0
  291. package/src/search/query-parser.test.ts +260 -0
  292. package/src/search/query-parser.ts +319 -0
  293. package/src/search/searcher.test.ts +280 -0
  294. package/src/search/searcher.ts +724 -0
  295. package/src/search/wink-bm25.d.ts +30 -0
  296. package/src/summarization/cli-providers/claude.ts +202 -0
  297. package/src/summarization/cli-providers/detection.test.ts +273 -0
  298. package/src/summarization/cli-providers/detection.ts +118 -0
  299. package/src/summarization/cli-providers/index.ts +8 -0
  300. package/src/summarization/cost.test.ts +139 -0
  301. package/src/summarization/cost.ts +102 -0
  302. package/src/summarization/error-handler.test.ts +127 -0
  303. package/src/summarization/error-handler.ts +111 -0
  304. package/src/summarization/index.ts +102 -0
  305. package/src/summarization/pipeline.test.ts +498 -0
  306. package/src/summarization/pipeline.ts +231 -0
  307. package/src/summarization/prompts.test.ts +269 -0
  308. package/src/summarization/prompts.ts +133 -0
  309. package/src/summarization/provider-factory.test.ts +396 -0
  310. package/src/summarization/provider-factory.ts +178 -0
  311. package/src/summarization/types.ts +184 -0
  312. package/src/summarize/budget-bugs.test.ts +620 -0
  313. package/src/summarize/formatters.ts +419 -0
  314. package/src/summarize/index.ts +20 -0
  315. package/src/summarize/summarizer.test.ts +275 -0
  316. package/src/summarize/summarizer.ts +597 -0
  317. package/src/summarize/verify-bugs.test.ts +238 -0
  318. package/src/types/huggingface-transformers.d.ts +66 -0
  319. package/src/utils/index.ts +1 -0
  320. package/src/utils/tokens.test.ts +142 -0
  321. package/src/utils/tokens.ts +186 -0
  322. package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
  323. package/tests/fixtures/cli/.mdcontext/config.json +8 -0
  324. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  325. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  326. package/tests/fixtures/cli/.mdcontext/indexes/documents.json +33 -0
  327. package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
  328. package/tests/fixtures/cli/.mdcontext/indexes/sections.json +247 -0
  329. package/tests/fixtures/cli/README.md +9 -0
  330. package/tests/fixtures/cli/api-reference.md +11 -0
  331. package/tests/fixtures/cli/getting-started.md +11 -0
  332. package/tests/integration/embed-index.test.ts +712 -0
  333. package/tests/integration/search-context.test.ts +469 -0
  334. package/tests/integration/search-semantic.test.ts +522 -0
  335. package/tsconfig.json +26 -0
  336. package/vitest.config.ts +16 -0
  337. package/vitest.setup.ts +12 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Heading Match Boost Tests
3
+ *
4
+ * Tests for heading boost functionality that improves search results
5
+ * when query terms appear in section headings.
6
+ */
7
+
8
+ import { describe, expect, it } from 'vitest'
9
+ import {
10
+ calculateFileImportanceBoost,
11
+ calculateHeadingBoost,
12
+ calculateRankingBoost,
13
+ type SemanticSearchOptions,
14
+ } from './types.js'
15
+
16
+ describe('Heading Match Boost', () => {
17
+ describe('calculateHeadingBoost function', () => {
18
+ it('should return 0 for no matches', () => {
19
+ expect(
20
+ calculateHeadingBoost('Installation Guide', 'authentication'),
21
+ ).toBe(0)
22
+ })
23
+
24
+ it('should return boost for single term match', () => {
25
+ expect(calculateHeadingBoost('Installation Guide', 'installation')).toBe(
26
+ 0.05,
27
+ )
28
+ })
29
+
30
+ it('should return higher boost for multiple term matches', () => {
31
+ expect(
32
+ calculateHeadingBoost('Installation Guide', 'installation guide'),
33
+ ).toBe(0.1)
34
+ })
35
+
36
+ it('should be case-insensitive', () => {
37
+ expect(
38
+ calculateHeadingBoost('INSTALLATION GUIDE', 'installation guide'),
39
+ ).toBe(0.1)
40
+ expect(
41
+ calculateHeadingBoost('Installation Guide', 'INSTALLATION GUIDE'),
42
+ ).toBe(0.1)
43
+ })
44
+
45
+ it('should handle partial term matches', () => {
46
+ // "install" is contained in "Installation"
47
+ expect(calculateHeadingBoost('Installation Guide', 'install')).toBe(0.05)
48
+ })
49
+
50
+ it('should handle empty query', () => {
51
+ expect(calculateHeadingBoost('Installation Guide', '')).toBe(0)
52
+ })
53
+
54
+ it('should handle empty heading', () => {
55
+ expect(calculateHeadingBoost('', 'installation')).toBe(0)
56
+ })
57
+
58
+ it('should handle whitespace-only query', () => {
59
+ expect(calculateHeadingBoost('Installation Guide', ' ')).toBe(0)
60
+ })
61
+
62
+ it('should boost navigation queries', () => {
63
+ // Common navigation patterns
64
+ expect(calculateHeadingBoost('API Reference', 'api reference')).toBe(0.1)
65
+ expect(calculateHeadingBoost('Getting Started', 'getting started')).toBe(
66
+ 0.1,
67
+ )
68
+ expect(calculateHeadingBoost('Configuration', 'config')).toBe(0.05)
69
+ })
70
+
71
+ it('should count each matching term only once', () => {
72
+ // Query with repeated terms - each "auth" matches "authentication"
73
+ expect(
74
+ calculateHeadingBoost('Authentication', 'auth auth auth'),
75
+ ).toBeCloseTo(0.15)
76
+ })
77
+ })
78
+
79
+ describe('SemanticSearchOptions headingBoost', () => {
80
+ it('should accept headingBoost option', () => {
81
+ const options: SemanticSearchOptions = {
82
+ headingBoost: true,
83
+ }
84
+ expect(options.headingBoost).toBe(true)
85
+ })
86
+
87
+ it('should accept headingBoost=false to disable', () => {
88
+ const options: SemanticSearchOptions = {
89
+ headingBoost: false,
90
+ }
91
+ expect(options.headingBoost).toBe(false)
92
+ })
93
+
94
+ it('should default to undefined (enabled)', () => {
95
+ const options: SemanticSearchOptions = {}
96
+ expect(options.headingBoost).toBeUndefined()
97
+ })
98
+
99
+ it('should work with other options', () => {
100
+ const options: SemanticSearchOptions = {
101
+ limit: 10,
102
+ threshold: 0.35,
103
+ headingBoost: true,
104
+ skipPreprocessing: false,
105
+ }
106
+ expect(options.headingBoost).toBe(true)
107
+ expect(options.limit).toBe(10)
108
+ })
109
+ })
110
+ })
111
+
112
+ describe('File Importance Boost', () => {
113
+ describe('calculateFileImportanceBoost function', () => {
114
+ it('should return boost for README files', () => {
115
+ expect(calculateFileImportanceBoost('README.md')).toBe(0.03)
116
+ expect(calculateFileImportanceBoost('docs/README.md')).toBe(0.03)
117
+ expect(calculateFileImportanceBoost('readme.md')).toBe(0.03)
118
+ })
119
+
120
+ it('should return boost for index files', () => {
121
+ expect(calculateFileImportanceBoost('index.md')).toBe(0.03)
122
+ expect(calculateFileImportanceBoost('docs/index.md')).toBe(0.03)
123
+ })
124
+
125
+ it('should return boost for getting started guides', () => {
126
+ expect(calculateFileImportanceBoost('getting-started.md')).toBe(0.03)
127
+ expect(calculateFileImportanceBoost('Getting-Started.md')).toBe(0.03)
128
+ expect(calculateFileImportanceBoost('gettingstarted.md')).toBe(0.03)
129
+ })
130
+
131
+ it('should return boost for introduction files', () => {
132
+ expect(calculateFileImportanceBoost('introduction.md')).toBe(0.03)
133
+ expect(calculateFileImportanceBoost('docs/introduction.md')).toBe(0.03)
134
+ })
135
+
136
+ it('should return boost for overview files', () => {
137
+ expect(calculateFileImportanceBoost('overview.md')).toBe(0.03)
138
+ expect(calculateFileImportanceBoost('docs/overview.md')).toBe(0.03)
139
+ })
140
+
141
+ it('should return boost for quickstart guides', () => {
142
+ expect(calculateFileImportanceBoost('quickstart.md')).toBe(0.03)
143
+ expect(calculateFileImportanceBoost('Quickstart.md')).toBe(0.03)
144
+ })
145
+
146
+ it('should return boost for changelog files', () => {
147
+ expect(calculateFileImportanceBoost('CHANGELOG.md')).toBe(0.03)
148
+ expect(calculateFileImportanceBoost('changelog.md')).toBe(0.03)
149
+ })
150
+
151
+ it('should return 0 for regular files', () => {
152
+ expect(calculateFileImportanceBoost('api.md')).toBe(0)
153
+ expect(calculateFileImportanceBoost('docs/configuration.md')).toBe(0)
154
+ expect(calculateFileImportanceBoost('src/utils.md')).toBe(0)
155
+ })
156
+ })
157
+
158
+ describe('calculateRankingBoost combined function', () => {
159
+ it('should combine heading and file importance boosts', () => {
160
+ // README with matching heading
161
+ const boost = calculateRankingBoost(
162
+ 'Installation Guide',
163
+ 'installation',
164
+ 'README.md',
165
+ )
166
+ expect(boost).toBe(0.08) // 0.05 (heading) + 0.03 (file)
167
+ })
168
+
169
+ it('should return only file boost when heading does not match', () => {
170
+ const boost = calculateRankingBoost(
171
+ 'API Reference',
172
+ 'authentication',
173
+ 'README.md',
174
+ )
175
+ expect(boost).toBe(0.03) // 0.00 (heading) + 0.03 (file)
176
+ })
177
+
178
+ it('should return only heading boost for regular files', () => {
179
+ const boost = calculateRankingBoost(
180
+ 'Installation Guide',
181
+ 'installation',
182
+ 'docs/install.md',
183
+ )
184
+ expect(boost).toBe(0.05) // 0.05 (heading) + 0.00 (file)
185
+ })
186
+
187
+ it('should return 0 when nothing matches', () => {
188
+ const boost = calculateRankingBoost(
189
+ 'API Reference',
190
+ 'authentication',
191
+ 'docs/api.md',
192
+ )
193
+ expect(boost).toBe(0)
194
+ })
195
+ })
196
+ })
197
+
198
+ describe('Export verification', () => {
199
+ it('should export calculateHeadingBoost from types module', async () => {
200
+ const { calculateHeadingBoost } = await import('./types.js')
201
+ expect(calculateHeadingBoost).toBeDefined()
202
+ expect(typeof calculateHeadingBoost).toBe('function')
203
+ })
204
+
205
+ it('should export calculateHeadingBoost from main embeddings module', async () => {
206
+ const { calculateHeadingBoost } = await import('./index.js')
207
+ expect(calculateHeadingBoost).toBeDefined()
208
+ expect(typeof calculateHeadingBoost).toBe('function')
209
+ })
210
+
211
+ it('should export calculateFileImportanceBoost from types module', async () => {
212
+ const { calculateFileImportanceBoost } = await import('./types.js')
213
+ expect(calculateFileImportanceBoost).toBeDefined()
214
+ expect(typeof calculateFileImportanceBoost).toBe('function')
215
+ })
216
+
217
+ it('should export calculateFileImportanceBoost from main embeddings module', async () => {
218
+ const { calculateFileImportanceBoost } = await import('./index.js')
219
+ expect(calculateFileImportanceBoost).toBeDefined()
220
+ expect(typeof calculateFileImportanceBoost).toBe('function')
221
+ })
222
+ })
@@ -0,0 +1,198 @@
1
+ /**
2
+ * HNSW Build Options Tests
3
+ *
4
+ * Tests for configurable HNSW index build parameters:
5
+ * - M: maximum connections per node (affects recall and index size)
6
+ * - efConstruction: construction-time search width (affects quality and build time)
7
+ *
8
+ * These parameters control the vector index structure and require index rebuild when changed.
9
+ */
10
+
11
+ import * as path from 'node:path'
12
+ import { Effect } from 'effect'
13
+ import { describe, expect, it } from 'vitest'
14
+ import {
15
+ createNamespacedVectorStore,
16
+ createVectorStore,
17
+ type HnswBuildOptions,
18
+ } from './vector-store.js'
19
+
20
+ // Path to test corpus with pre-built embeddings
21
+ const TEST_CORPUS_PATH = path.join(
22
+ __dirname,
23
+ '../__tests__/fixtures/semantic-search/multi-word-corpus',
24
+ )
25
+
26
+ // Test corpus uses 512 dimensions (text-embedding-3-small with Matryoshka reduction)
27
+ const TEST_CORPUS_DIMENSIONS = 512
28
+ const TEST_CORPUS_PROVIDER = 'openai'
29
+ const TEST_CORPUS_MODEL = 'text-embedding-3-small'
30
+
31
+ // Helper to create the namespaced vector store for test corpus
32
+ const createTestVectorStore = (hnswOptions?: HnswBuildOptions) =>
33
+ createNamespacedVectorStore(
34
+ TEST_CORPUS_PATH,
35
+ TEST_CORPUS_PROVIDER,
36
+ TEST_CORPUS_MODEL,
37
+ TEST_CORPUS_DIMENSIONS,
38
+ hnswOptions,
39
+ )
40
+
41
+ describe('HNSW Build Options', () => {
42
+ describe('HnswBuildOptions interface', () => {
43
+ it('should accept M parameter', () => {
44
+ const options: HnswBuildOptions = { m: 24 }
45
+ expect(options.m).toBe(24)
46
+ })
47
+
48
+ it('should accept efConstruction parameter', () => {
49
+ const options: HnswBuildOptions = { efConstruction: 256 }
50
+ expect(options.efConstruction).toBe(256)
51
+ })
52
+
53
+ it('should accept both parameters', () => {
54
+ const options: HnswBuildOptions = { m: 24, efConstruction: 256 }
55
+ expect(options.m).toBe(24)
56
+ expect(options.efConstruction).toBe(256)
57
+ })
58
+
59
+ it('should allow undefined parameters for defaults', () => {
60
+ const options: HnswBuildOptions = {}
61
+ expect(options.m).toBeUndefined()
62
+ expect(options.efConstruction).toBeUndefined()
63
+ })
64
+ })
65
+
66
+ describe('createVectorStore with HNSW options', () => {
67
+ it('should create vector store without HNSW options (defaults)', () => {
68
+ const vectorStore = createVectorStore(
69
+ TEST_CORPUS_PATH,
70
+ TEST_CORPUS_DIMENSIONS,
71
+ )
72
+ expect(vectorStore).toBeDefined()
73
+ expect(vectorStore.dimensions).toBe(TEST_CORPUS_DIMENSIONS)
74
+ })
75
+
76
+ it('should create vector store with custom M parameter', () => {
77
+ const vectorStore = createVectorStore(
78
+ TEST_CORPUS_PATH,
79
+ TEST_CORPUS_DIMENSIONS,
80
+ { m: 24 },
81
+ )
82
+ expect(vectorStore).toBeDefined()
83
+ expect(vectorStore.dimensions).toBe(TEST_CORPUS_DIMENSIONS)
84
+ })
85
+
86
+ it('should create vector store with custom efConstruction parameter', () => {
87
+ const vectorStore = createVectorStore(
88
+ TEST_CORPUS_PATH,
89
+ TEST_CORPUS_DIMENSIONS,
90
+ { efConstruction: 256 },
91
+ )
92
+ expect(vectorStore).toBeDefined()
93
+ expect(vectorStore.dimensions).toBe(TEST_CORPUS_DIMENSIONS)
94
+ })
95
+
96
+ it('should create vector store with both custom parameters', () => {
97
+ const vectorStore = createVectorStore(
98
+ TEST_CORPUS_PATH,
99
+ TEST_CORPUS_DIMENSIONS,
100
+ { m: 24, efConstruction: 256 },
101
+ )
102
+ expect(vectorStore).toBeDefined()
103
+ expect(vectorStore.dimensions).toBe(TEST_CORPUS_DIMENSIONS)
104
+ })
105
+ })
106
+
107
+ describe('Recommended configurations', () => {
108
+ it('should support speed-focused config (M=12, efConstruction=128)', () => {
109
+ const speedOptions: HnswBuildOptions = { m: 12, efConstruction: 128 }
110
+ const vectorStore = createVectorStore(
111
+ TEST_CORPUS_PATH,
112
+ TEST_CORPUS_DIMENSIONS,
113
+ speedOptions,
114
+ )
115
+ expect(vectorStore).toBeDefined()
116
+ })
117
+
118
+ it('should support balanced config (M=16, efConstruction=200) - defaults', () => {
119
+ // Default config - no options passed
120
+ const vectorStore = createVectorStore(
121
+ TEST_CORPUS_PATH,
122
+ TEST_CORPUS_DIMENSIONS,
123
+ )
124
+ expect(vectorStore).toBeDefined()
125
+ })
126
+
127
+ it('should support quality-focused config (M=24, efConstruction=256)', () => {
128
+ const qualityOptions: HnswBuildOptions = { m: 24, efConstruction: 256 }
129
+ const vectorStore = createVectorStore(
130
+ TEST_CORPUS_PATH,
131
+ TEST_CORPUS_DIMENSIONS,
132
+ qualityOptions,
133
+ )
134
+ expect(vectorStore).toBeDefined()
135
+ })
136
+ })
137
+
138
+ describe('Vector store functionality with custom options', () => {
139
+ it('should load existing index regardless of HNSW options', async () => {
140
+ // HNSW options only affect index creation, not loading
141
+ const vectorStore = createTestVectorStore({ m: 24, efConstruction: 256 })
142
+ const loadResult = await Effect.runPromise(vectorStore.load())
143
+ expect(loadResult.loaded).toBe(true)
144
+
145
+ const stats = vectorStore.getStats()
146
+ expect(stats.count).toBeGreaterThan(0)
147
+ })
148
+
149
+ it('should search after loading with custom options', async () => {
150
+ const vectorStore = createTestVectorStore({ m: 12, efConstruction: 128 })
151
+ await Effect.runPromise(vectorStore.load())
152
+
153
+ const results = await Effect.runPromise(
154
+ vectorStore.search(new Array(TEST_CORPUS_DIMENSIONS).fill(0.1), 10, 0),
155
+ )
156
+
157
+ expect(results.length).toBeGreaterThan(0)
158
+ })
159
+ })
160
+
161
+ describe('Config schema HNSW defaults', () => {
162
+ it('should have hnswM default of 16 in config schema', async () => {
163
+ const { defaultConfig } = await import('../config/schema.js')
164
+ expect(defaultConfig.embeddings.hnswM).toBe(16)
165
+ })
166
+
167
+ it('should have hnswEfConstruction default of 200 in config schema', async () => {
168
+ const { defaultConfig } = await import('../config/schema.js')
169
+ expect(defaultConfig.embeddings.hnswEfConstruction).toBe(200)
170
+ })
171
+ })
172
+ })
173
+
174
+ describe('BuildEmbeddingsOptions HNSW support', () => {
175
+ it('should export BuildEmbeddingsOptions with hnswOptions field', async () => {
176
+ const { buildEmbeddings } = await import('./semantic-search.js')
177
+ expect(buildEmbeddings).toBeDefined()
178
+ expect(typeof buildEmbeddings).toBe('function')
179
+ })
180
+
181
+ it('should accept hnswOptions in BuildEmbeddingsOptions interface', async () => {
182
+ // Type-level test: if this compiles, the interface has the field
183
+ type BuildEmbeddingsOptions =
184
+ typeof import('./semantic-search.js').buildEmbeddings extends (
185
+ path: string,
186
+ options?: infer O,
187
+ ) => unknown
188
+ ? O
189
+ : never
190
+
191
+ // This verifies the type accepts hnswOptions
192
+ const options: BuildEmbeddingsOptions = {
193
+ hnswOptions: { m: 24, efConstruction: 256 },
194
+ }
195
+ expect(options.hnswOptions?.m).toBe(24)
196
+ expect(options.hnswOptions?.efConstruction).toBe(256)
197
+ })
198
+ })
@@ -0,0 +1,272 @@
1
+ /**
2
+ * HyDE (Hypothetical Document Embeddings) Tests
3
+ *
4
+ * Tests for HyDE query expansion functionality.
5
+ */
6
+
7
+ import { Effect } from 'effect'
8
+ import { describe, expect, it } from 'vitest'
9
+ import {
10
+ generateHypotheticalDocument,
11
+ type HydeOptions,
12
+ type HydeResult,
13
+ isHydeAvailable,
14
+ shouldUseHyde,
15
+ } from './hyde.js'
16
+ import type { SemanticSearchOptions } from './types.js'
17
+
18
+ describe('HyDE Query Expansion', () => {
19
+ describe('shouldUseHyde detection', () => {
20
+ it('should recommend HyDE for question queries', () => {
21
+ expect(shouldUseHyde('How do I configure authentication?')).toBe(true)
22
+ expect(shouldUseHyde('What is the best way to handle errors?')).toBe(true)
23
+ expect(shouldUseHyde('Why is my build failing?')).toBe(true)
24
+ expect(shouldUseHyde('When should I use caching?')).toBe(true)
25
+ expect(shouldUseHyde('Where are the configuration files?')).toBe(true)
26
+ })
27
+
28
+ it('should recommend HyDE for procedural queries', () => {
29
+ expect(shouldUseHyde('setup react project with typescript')).toBe(true)
30
+ expect(shouldUseHyde('install dependencies for the project')).toBe(true)
31
+ expect(shouldUseHyde('configure webpack for production')).toBe(true)
32
+ expect(shouldUseHyde('implement user authentication flow')).toBe(true)
33
+ })
34
+
35
+ it('should recommend HyDE for longer queries (6+ words)', () => {
36
+ expect(
37
+ shouldUseHyde('user login flow with oauth and refresh tokens'),
38
+ ).toBe(true)
39
+ expect(
40
+ shouldUseHyde(
41
+ 'database connection pooling configuration options for mysql',
42
+ ),
43
+ ).toBe(true)
44
+ })
45
+
46
+ it('should not recommend HyDE for short queries', () => {
47
+ expect(shouldUseHyde('api')).toBe(false)
48
+ expect(shouldUseHyde('config')).toBe(false)
49
+ expect(shouldUseHyde('user auth')).toBe(false)
50
+ })
51
+
52
+ it('should not recommend HyDE for exact phrase searches', () => {
53
+ expect(shouldUseHyde('"exact phrase match"')).toBe(false)
54
+ })
55
+
56
+ it('should recommend HyDE for queries ending with question mark', () => {
57
+ expect(shouldUseHyde('database configuration options?')).toBe(true)
58
+ })
59
+
60
+ it('should handle edge cases gracefully', () => {
61
+ expect(shouldUseHyde('')).toBe(false)
62
+ expect(shouldUseHyde(' ')).toBe(false)
63
+ expect(shouldUseHyde('a')).toBe(false)
64
+ })
65
+ })
66
+
67
+ describe('isHydeAvailable', () => {
68
+ it('should check if OPENAI_API_KEY is set', () => {
69
+ // This test reflects the actual environment state
70
+ const result = isHydeAvailable()
71
+ expect(typeof result).toBe('boolean')
72
+ })
73
+ })
74
+
75
+ describe('HydeOptions interface', () => {
76
+ it('should accept all configuration options', () => {
77
+ const options: HydeOptions = {
78
+ apiKey: 'test-key',
79
+ model: 'gpt-4o-mini',
80
+ maxTokens: 256,
81
+ temperature: 0.3,
82
+ systemPrompt: 'Custom prompt',
83
+ baseURL: 'http://localhost:1234/v1',
84
+ }
85
+
86
+ expect(options.apiKey).toBe('test-key')
87
+ expect(options.model).toBe('gpt-4o-mini')
88
+ expect(options.maxTokens).toBe(256)
89
+ expect(options.temperature).toBe(0.3)
90
+ expect(options.systemPrompt).toBe('Custom prompt')
91
+ expect(options.baseURL).toBe('http://localhost:1234/v1')
92
+ })
93
+
94
+ it('should allow partial options', () => {
95
+ const options: HydeOptions = {
96
+ model: 'gpt-4o',
97
+ }
98
+ expect(options.model).toBe('gpt-4o')
99
+ expect(options.apiKey).toBeUndefined()
100
+ })
101
+
102
+ it('should allow empty options', () => {
103
+ const options: HydeOptions = {}
104
+ expect(options).toEqual({})
105
+ })
106
+ })
107
+
108
+ describe('HydeResult interface', () => {
109
+ it('should have required fields', () => {
110
+ const result: HydeResult = {
111
+ hypotheticalDocument: 'Generated content about authentication...',
112
+ originalQuery: 'How do I configure authentication?',
113
+ model: 'gpt-4o-mini',
114
+ tokensUsed: 150,
115
+ cost: 0.00003,
116
+ }
117
+
118
+ expect(result.hypotheticalDocument).toBeDefined()
119
+ expect(result.originalQuery).toBeDefined()
120
+ expect(result.model).toBeDefined()
121
+ expect(result.tokensUsed).toBeDefined()
122
+ expect(result.cost).toBeDefined()
123
+ })
124
+ })
125
+
126
+ describe('SemanticSearchOptions hyde integration', () => {
127
+ it('should accept hyde option in SemanticSearchOptions', () => {
128
+ const options: SemanticSearchOptions = {
129
+ hyde: true,
130
+ }
131
+ expect(options.hyde).toBe(true)
132
+ })
133
+
134
+ it('should default to undefined (HyDE disabled)', () => {
135
+ const options: SemanticSearchOptions = {}
136
+ expect(options.hyde).toBeUndefined()
137
+ })
138
+
139
+ it('should accept hydeOptions when hyde is enabled', () => {
140
+ const options: SemanticSearchOptions = {
141
+ hyde: true,
142
+ hydeOptions: {
143
+ model: 'gpt-4o',
144
+ maxTokens: 512,
145
+ temperature: 0.5,
146
+ },
147
+ }
148
+ expect(options.hyde).toBe(true)
149
+ expect(options.hydeOptions?.model).toBe('gpt-4o')
150
+ expect(options.hydeOptions?.maxTokens).toBe(512)
151
+ expect(options.hydeOptions?.temperature).toBe(0.5)
152
+ })
153
+
154
+ it('should accept hyde with other search options', () => {
155
+ const options: SemanticSearchOptions = {
156
+ limit: 10,
157
+ threshold: 0.35,
158
+ quality: 'thorough',
159
+ hyde: true,
160
+ hydeOptions: {
161
+ model: 'gpt-4o-mini',
162
+ },
163
+ }
164
+ expect(options.limit).toBe(10)
165
+ expect(options.threshold).toBe(0.35)
166
+ expect(options.quality).toBe('thorough')
167
+ expect(options.hyde).toBe(true)
168
+ })
169
+ })
170
+
171
+ describe('generateHypotheticalDocument error handling', () => {
172
+ it('should fail with ApiKeyMissingError when no API key', async () => {
173
+ // Save and clear the environment variable
174
+ const originalKey = process.env.OPENAI_API_KEY
175
+ delete process.env.OPENAI_API_KEY
176
+
177
+ try {
178
+ const result = await Effect.runPromise(
179
+ generateHypotheticalDocument('test query').pipe(Effect.either),
180
+ )
181
+
182
+ expect(result._tag).toBe('Left')
183
+ if (result._tag === 'Left') {
184
+ expect(result.left._tag).toBe('ApiKeyMissingError')
185
+ }
186
+ } finally {
187
+ // Restore the environment variable
188
+ if (originalKey) {
189
+ process.env.OPENAI_API_KEY = originalKey
190
+ }
191
+ }
192
+ })
193
+ })
194
+
195
+ describe('Query pattern detection', () => {
196
+ describe('question patterns', () => {
197
+ it('should detect "how" questions', () => {
198
+ expect(shouldUseHyde('how to implement feature X')).toBe(true)
199
+ expect(shouldUseHyde('how does the build system work')).toBe(true)
200
+ })
201
+
202
+ it('should detect "what" questions', () => {
203
+ expect(shouldUseHyde('what is the recommended approach')).toBe(true)
204
+ expect(shouldUseHyde('what are the configuration options')).toBe(true)
205
+ })
206
+
207
+ it('should detect "can/could/should" questions', () => {
208
+ expect(shouldUseHyde('can I use custom validators here')).toBe(true)
209
+ expect(shouldUseHyde('should I enable caching for this')).toBe(true)
210
+ })
211
+
212
+ it('should detect "is/are/does/do" questions', () => {
213
+ expect(shouldUseHyde('is there a way to override this')).toBe(true)
214
+ expect(shouldUseHyde('are there any known issues with')).toBe(true)
215
+ expect(shouldUseHyde('does the API support pagination')).toBe(true)
216
+ })
217
+ })
218
+
219
+ describe('procedural patterns', () => {
220
+ it('should detect setup/install queries', () => {
221
+ expect(shouldUseHyde('setup local development environment')).toBe(true)
222
+ expect(shouldUseHyde('install required dependencies for testing')).toBe(
223
+ true,
224
+ )
225
+ })
226
+
227
+ it('should detect configure/implement queries', () => {
228
+ expect(shouldUseHyde('configure database connection pooling')).toBe(
229
+ true,
230
+ )
231
+ expect(shouldUseHyde('implement user session management')).toBe(true)
232
+ })
233
+
234
+ it('should detect fix/debug/resolve queries', () => {
235
+ expect(shouldUseHyde('fix the authentication issue with tokens')).toBe(
236
+ true,
237
+ )
238
+ expect(shouldUseHyde('debug memory leak in the application')).toBe(true)
239
+ expect(shouldUseHyde('resolve dependency conflicts in package')).toBe(
240
+ true,
241
+ )
242
+ })
243
+
244
+ it('should detect guide/tutorial/example queries', () => {
245
+ expect(shouldUseHyde('guide for setting up CI CD')).toBe(true)
246
+ expect(shouldUseHyde('tutorial for building REST APIs')).toBe(true)
247
+ expect(shouldUseHyde('example of using custom hooks')).toBe(true)
248
+ })
249
+ })
250
+ })
251
+ })
252
+
253
+ describe('Export verification', () => {
254
+ it('should export HyDE functions from types module', async () => {
255
+ const { generateHypotheticalDocument, isHydeAvailable, shouldUseHyde } =
256
+ await import('./hyde.js')
257
+ expect(generateHypotheticalDocument).toBeDefined()
258
+ expect(typeof generateHypotheticalDocument).toBe('function')
259
+ expect(isHydeAvailable).toBeDefined()
260
+ expect(typeof isHydeAvailable).toBe('function')
261
+ expect(shouldUseHyde).toBeDefined()
262
+ expect(typeof shouldUseHyde).toBe('function')
263
+ })
264
+
265
+ it('should export HyDE functions from main embeddings module', async () => {
266
+ const { generateHypotheticalDocument, isHydeAvailable, shouldUseHyde } =
267
+ await import('./index.js')
268
+ expect(generateHypotheticalDocument).toBeDefined()
269
+ expect(isHydeAvailable).toBeDefined()
270
+ expect(shouldUseHyde).toBeDefined()
271
+ })
272
+ })