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,451 @@
1
+ /**
2
+ * Config Precedence Chain
3
+ *
4
+ * Composes ConfigProviders to establish the standard CLI config precedence:
5
+ *
6
+ * ```
7
+ * CLI Flags (highest priority)
8
+ * ↓
9
+ * Environment Variables (MDCONTEXT_*)
10
+ * ↓
11
+ * Config File (mdcontext.config.ts/json)
12
+ * ↓
13
+ * Defaults (lowest priority)
14
+ * ```
15
+ *
16
+ * Uses a flattened Map approach to avoid memory issues with deep orElse chains.
17
+ *
18
+ * ## Usage
19
+ *
20
+ * ```typescript
21
+ * import { createConfigProvider, ConfigProviderOptions } from './config/precedence.js'
22
+ * import { Effect } from 'effect'
23
+ *
24
+ * const options: ConfigProviderOptions = {
25
+ * cliOverrides: { index: { maxDepth: 5 } }, // From CLI flags
26
+ * configPath: './custom.config.json', // Optional explicit path
27
+ * workingDir: process.cwd(), // For config file search
28
+ * }
29
+ *
30
+ * const provider = await Effect.runPromise(createConfigProvider(options))
31
+ * // Use provider with Effect.withConfigProvider
32
+ * ```
33
+ */
34
+
35
+ import { ConfigProvider, Effect } from 'effect'
36
+ import type { ConfigError } from '../errors/index.js'
37
+ import { loadConfigFile, loadConfigFromPath } from './file-provider.js'
38
+ import type { PartialMdContextConfig } from './service.js'
39
+
40
+ // ============================================================================
41
+ // Types
42
+ // ============================================================================
43
+
44
+ /**
45
+ * Options for creating the config provider chain
46
+ */
47
+ export interface ConfigProviderOptions {
48
+ /**
49
+ * CLI flag overrides (highest priority)
50
+ * These values take precedence over all other sources
51
+ */
52
+ cliOverrides?: PartialMdContextConfig
53
+
54
+ /**
55
+ * Explicit path to config file
56
+ * If provided, this file is used instead of searching
57
+ */
58
+ configPath?: string
59
+
60
+ /**
61
+ * Working directory for config file search
62
+ * Defaults to process.cwd()
63
+ */
64
+ workingDir?: string
65
+
66
+ /**
67
+ * Environment variable prefix
68
+ * Defaults to 'MDCONTEXT'
69
+ * Variables are expected in format: MDCONTEXT_INDEX_MAXDEPTH
70
+ */
71
+ envPrefix?: string
72
+
73
+ /**
74
+ * Skip loading config file entirely
75
+ * Useful for testing or when only using env/CLI config
76
+ */
77
+ skipConfigFile?: boolean
78
+
79
+ /**
80
+ * Skip environment variable provider
81
+ * Useful for testing
82
+ */
83
+ skipEnv?: boolean
84
+ }
85
+
86
+ // ============================================================================
87
+ // Flattening Utilities
88
+ // ============================================================================
89
+
90
+ /**
91
+ * Flatten a nested config object into dot-separated key-value pairs.
92
+ *
93
+ * Example:
94
+ * ```
95
+ * { index: { maxDepth: 5 } } -> Map([['index.maxDepth', '5']])
96
+ * ```
97
+ */
98
+ export const flattenConfig = (
99
+ config: PartialMdContextConfig,
100
+ prefix = '',
101
+ ): Map<string, string> => {
102
+ const result = new Map<string, string>()
103
+
104
+ const flatten = (obj: unknown, currentPrefix: string): void => {
105
+ if (obj === null || obj === undefined) {
106
+ return
107
+ }
108
+
109
+ if (Array.isArray(obj)) {
110
+ // Convert arrays to comma-separated strings
111
+ result.set(currentPrefix, obj.join(','))
112
+ return
113
+ }
114
+
115
+ if (typeof obj === 'object') {
116
+ for (const [key, value] of Object.entries(obj)) {
117
+ const newKey = currentPrefix ? `${currentPrefix}.${key}` : key
118
+ flatten(value, newKey)
119
+ }
120
+ return
121
+ }
122
+
123
+ // Primitive values
124
+ result.set(currentPrefix, String(obj))
125
+ }
126
+
127
+ flatten(config, prefix)
128
+ return result
129
+ }
130
+
131
+ // ============================================================================
132
+ // Environment Variable Mapping
133
+ // ============================================================================
134
+
135
+ /**
136
+ * Sequence delimiter for array values in environment variables.
137
+ * MDCONTEXT_INDEX_EXCLUDEPATTERNS=node_modules,dist
138
+ */
139
+ const ENV_SEQ_DELIM = ','
140
+
141
+ // ============================================================================
142
+ // Programmatic ENV_KEY_MAPPING Generation
143
+ // ============================================================================
144
+
145
+ /**
146
+ * Configuration schema structure defining all keys for each section.
147
+ * This is the single source of truth for configuration keys.
148
+ *
149
+ * Adding a new config key:
150
+ * 1. Add it to the appropriate section here
151
+ * 2. Add it to the schema in schema.ts
152
+ * 3. The ENV_KEY_MAPPING is automatically generated
153
+ */
154
+ export const CONFIG_SCHEMA_KEYS = {
155
+ index: [
156
+ 'maxDepth',
157
+ 'excludePatterns',
158
+ 'fileExtensions',
159
+ 'followSymlinks',
160
+ 'indexDir',
161
+ ],
162
+ search: [
163
+ 'defaultLimit',
164
+ 'maxLimit',
165
+ 'minSimilarity',
166
+ 'includeSnippets',
167
+ 'snippetLength',
168
+ 'autoIndexThreshold',
169
+ ],
170
+ embeddings: [
171
+ 'provider',
172
+ 'baseURL',
173
+ 'model',
174
+ 'dimensions',
175
+ 'batchSize',
176
+ 'maxRetries',
177
+ 'retryDelayMs',
178
+ 'timeoutMs',
179
+ 'apiKey',
180
+ ],
181
+ summarization: [
182
+ 'briefTokenBudget',
183
+ 'summaryTokenBudget',
184
+ 'compressionRatio',
185
+ 'minSectionTokens',
186
+ 'maxTopics',
187
+ 'minPartialBudget',
188
+ ],
189
+ output: ['format', 'color', 'prettyJson', 'verbose', 'debug'],
190
+ paths: ['root', 'configFile', 'cacheDir'],
191
+ } as const
192
+
193
+ /**
194
+ * Generate the ENV_KEY_MAPPING from the schema definition.
195
+ *
196
+ * ENV format: MDCONTEXT_SECTION_KEY (all lowercase)
197
+ * Config format: section.key (camelCase preserved)
198
+ */
199
+ const generateEnvKeyMapping = (): Record<string, string> => {
200
+ const mapping: Record<string, string> = {}
201
+ for (const [section, keys] of Object.entries(CONFIG_SCHEMA_KEYS)) {
202
+ for (const key of keys) {
203
+ const envKey = `${section}_${key}`.toLowerCase()
204
+ const configKey = `${section}.${key}`
205
+ mapping[envKey] = configKey
206
+ }
207
+ }
208
+ return mapping
209
+ }
210
+
211
+ /**
212
+ * Known config keys for case mapping.
213
+ * Generated programmatically from CONFIG_SCHEMA_KEYS.
214
+ */
215
+ const ENV_KEY_MAPPING: Record<string, string> = generateEnvKeyMapping()
216
+
217
+ // Type-level completeness check
218
+ type ConfigSchemaKey = {
219
+ [S in keyof typeof CONFIG_SCHEMA_KEYS]: `${S}.${(typeof CONFIG_SCHEMA_KEYS)[S][number]}`
220
+ }[keyof typeof CONFIG_SCHEMA_KEYS]
221
+
222
+ type _MissingMappings = Exclude<
223
+ ConfigSchemaKey,
224
+ (typeof ENV_KEY_MAPPING)[string]
225
+ >
226
+
227
+ // Pure type-level assertion: will fail to compile if any mappings are missing
228
+ type AssertTrue<T extends true> = T
229
+ // @ts-expect-error - Type-level assertion, intentionally unused
230
+ type _CompletenessCheck = AssertTrue<
231
+ _MissingMappings extends never ? true : false
232
+ >
233
+ /**
234
+ * Read environment variables with the given prefix and map them to config keys.
235
+ *
236
+ * @param prefix - Environment variable prefix (default: 'MDCONTEXT')
237
+ * @returns Map of config keys to values
238
+ */
239
+ export const readEnvConfig = (prefix = 'MDCONTEXT'): Map<string, string> => {
240
+ const result = new Map<string, string>()
241
+ const prefixWithUnderscore = `${prefix}_`
242
+
243
+ for (const [key, value] of Object.entries(process.env)) {
244
+ if (key.startsWith(prefixWithUnderscore) && value !== undefined) {
245
+ const envKey = key.slice(prefixWithUnderscore.length).toLowerCase()
246
+ const configKey = ENV_KEY_MAPPING[envKey]
247
+
248
+ if (configKey) {
249
+ result.set(configKey, value)
250
+ }
251
+ }
252
+ }
253
+
254
+ return result
255
+ }
256
+
257
+ /**
258
+ * Create a ConfigProvider from environment variables with the given prefix.
259
+ * Kept for backwards compatibility.
260
+ *
261
+ * @param prefix - Environment variable prefix (default: 'MDCONTEXT')
262
+ * @returns ConfigProvider that reads from environment
263
+ */
264
+ export const createEnvConfigProvider = (
265
+ prefix = 'MDCONTEXT',
266
+ ): ConfigProvider.ConfigProvider => {
267
+ const envMap = readEnvConfig(prefix)
268
+ return ConfigProvider.fromMap(envMap, {
269
+ pathDelim: '.',
270
+ seqDelim: ENV_SEQ_DELIM,
271
+ })
272
+ }
273
+
274
+ // ============================================================================
275
+ // Combined Provider
276
+ // ============================================================================
277
+
278
+ /**
279
+ * Create the full config provider chain with proper precedence.
280
+ *
281
+ * Precedence (highest to lowest):
282
+ * 1. CLI flags (if provided)
283
+ * 2. Environment variables (MDCONTEXT_*)
284
+ * 3. Config file (if found)
285
+ * 4. Built-in defaults (handled by Config schema)
286
+ *
287
+ * @param options - Configuration options
288
+ * @returns Effect yielding the composed ConfigProvider
289
+ */
290
+ export const createConfigProvider = (
291
+ options: ConfigProviderOptions = {},
292
+ ): Effect.Effect<ConfigProvider.ConfigProvider, ConfigError> =>
293
+ Effect.gen(function* () {
294
+ const {
295
+ cliOverrides,
296
+ configPath,
297
+ workingDir = process.cwd(),
298
+ envPrefix = 'MDCONTEXT',
299
+ skipConfigFile = false,
300
+ skipEnv = false,
301
+ } = options
302
+
303
+ // Build merged config map with precedence (lowest to highest)
304
+ const mergedMap = new Map<string, string>()
305
+
306
+ // 1. File config (lowest priority)
307
+ if (!skipConfigFile) {
308
+ let fileConfig: PartialMdContextConfig | undefined
309
+
310
+ if (configPath) {
311
+ fileConfig = yield* loadConfigFromPath(configPath)
312
+ } else {
313
+ const result = yield* loadConfigFile(workingDir)
314
+ if (result.found) {
315
+ fileConfig = result.config
316
+ }
317
+ }
318
+
319
+ if (fileConfig) {
320
+ const flattened = flattenConfig(fileConfig)
321
+ for (const [k, v] of flattened) {
322
+ mergedMap.set(k, v)
323
+ }
324
+ }
325
+ }
326
+
327
+ // 2. Environment variables (higher priority - overwrites file config)
328
+ if (!skipEnv) {
329
+ const envConfig = readEnvConfig(envPrefix)
330
+ for (const [k, v] of envConfig) {
331
+ mergedMap.set(k, v)
332
+ }
333
+ }
334
+
335
+ // 3. CLI overrides (highest priority - overwrites everything)
336
+ if (cliOverrides && Object.keys(cliOverrides).length > 0) {
337
+ const flattened = flattenConfig(cliOverrides)
338
+ for (const [k, v] of flattened) {
339
+ mergedMap.set(k, v)
340
+ }
341
+ }
342
+
343
+ return ConfigProvider.fromMap(mergedMap, {
344
+ pathDelim: '.',
345
+ seqDelim: ENV_SEQ_DELIM,
346
+ })
347
+ })
348
+
349
+ /**
350
+ * Create a ConfigProvider chain synchronously (when you don't need file loading).
351
+ *
352
+ * Useful when:
353
+ * - You already have the config file content
354
+ * - You only want env vars and CLI overrides
355
+ * - Testing without file I/O
356
+ *
357
+ * @param options - Configuration options
358
+ * @returns The composed ConfigProvider
359
+ */
360
+ export const createConfigProviderSync = (
361
+ options: Omit<ConfigProviderOptions, 'configPath' | 'workingDir'> & {
362
+ fileConfig?: PartialMdContextConfig
363
+ } = {},
364
+ ): ConfigProvider.ConfigProvider => {
365
+ const {
366
+ cliOverrides,
367
+ fileConfig,
368
+ envPrefix = 'MDCONTEXT',
369
+ skipConfigFile = false,
370
+ skipEnv = false,
371
+ } = options
372
+
373
+ // Build merged config map with precedence (lowest to highest)
374
+ const mergedMap = new Map<string, string>()
375
+
376
+ // 1. File config (lowest priority)
377
+ if (!skipConfigFile && fileConfig) {
378
+ const flattened = flattenConfig(fileConfig)
379
+ for (const [k, v] of flattened) {
380
+ mergedMap.set(k, v)
381
+ }
382
+ }
383
+
384
+ // 2. Environment variables (higher priority)
385
+ if (!skipEnv) {
386
+ const envConfig = readEnvConfig(envPrefix)
387
+ for (const [k, v] of envConfig) {
388
+ mergedMap.set(k, v)
389
+ }
390
+ }
391
+
392
+ // 3. CLI overrides (highest priority)
393
+ if (cliOverrides && Object.keys(cliOverrides).length > 0) {
394
+ const flattened = flattenConfig(cliOverrides)
395
+ for (const [k, v] of flattened) {
396
+ mergedMap.set(k, v)
397
+ }
398
+ }
399
+
400
+ return ConfigProvider.fromMap(mergedMap, {
401
+ pathDelim: '.',
402
+ seqDelim: ENV_SEQ_DELIM,
403
+ })
404
+ }
405
+
406
+ // ============================================================================
407
+ // Convenience Functions
408
+ // ============================================================================
409
+
410
+ /**
411
+ * Create a minimal ConfigProvider for testing.
412
+ *
413
+ * Includes only CLI overrides and optionally file config.
414
+ * No environment variables are read.
415
+ *
416
+ * @param cliOverrides - CLI flag overrides
417
+ * @param fileConfig - Optional file config values
418
+ * @returns ConfigProvider for testing
419
+ */
420
+ export const createTestConfigProvider = (
421
+ cliOverrides?: PartialMdContextConfig,
422
+ fileConfig?: PartialMdContextConfig,
423
+ ): ConfigProvider.ConfigProvider => {
424
+ const options: Parameters<typeof createConfigProviderSync>[0] = {
425
+ skipEnv: true,
426
+ }
427
+ if (cliOverrides !== undefined) {
428
+ options.cliOverrides = cliOverrides
429
+ }
430
+ if (fileConfig !== undefined) {
431
+ options.fileConfig = fileConfig
432
+ }
433
+ return createConfigProviderSync(options)
434
+ }
435
+
436
+ /**
437
+ * Create a ConfigProvider from CLI flag overrides.
438
+ * Kept for backwards compatibility.
439
+ *
440
+ * @param overrides - Partial config from CLI flags
441
+ * @returns ConfigProvider that provides CLI values
442
+ */
443
+ export const createCliConfigProvider = (
444
+ overrides: PartialMdContextConfig,
445
+ ): ConfigProvider.ConfigProvider => {
446
+ const flattened = flattenConfig(overrides)
447
+ return ConfigProvider.fromMap(flattened, {
448
+ pathDelim: '.',
449
+ seqDelim: ENV_SEQ_DELIM,
450
+ })
451
+ }