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,521 @@
1
+ # mdcontext Error Handling Analysis
2
+
3
+ ## Executive Summary
4
+
5
+ The mdcontext codebase has a mixed error handling strategy. While it defines typed errors in `core/types.ts` (ParseError, IoError, IndexError) and uses Effect for error management, the actual implementation frequently loses type information by converting typed errors to generic `Error` objects. This document catalogs the current state and proposes a unified approach.
6
+
7
+ ---
8
+
9
+ ## 1. Current Error Handling Audit
10
+
11
+ ### 1.1 Custom Error Classes
12
+
13
+ **Location: `/src/embeddings/openai-provider.ts`**
14
+
15
+ ```typescript
16
+ export class MissingApiKeyError extends Error {
17
+ constructor() {
18
+ super("OPENAI_API_KEY not set");
19
+ this.name = "MissingApiKeyError";
20
+ }
21
+ }
22
+
23
+ export class InvalidApiKeyError extends Error {
24
+ constructor(message?: string) {
25
+ super(message ?? "Invalid OPENAI_API_KEY");
26
+ this.name = "InvalidApiKeyError";
27
+ }
28
+ }
29
+ ```
30
+
31
+ **Location: `/src/core/types.ts`** (Tagged unions - Effect style)
32
+
33
+ ```typescript
34
+ export interface ParseError {
35
+ readonly _tag: "ParseError";
36
+ readonly message: string;
37
+ readonly line?: number | undefined;
38
+ readonly column?: number | undefined;
39
+ }
40
+
41
+ export interface IoError {
42
+ readonly _tag: "IoError";
43
+ readonly message: string;
44
+ readonly path: string;
45
+ readonly cause?: unknown;
46
+ }
47
+
48
+ export interface IndexError {
49
+ readonly _tag: "IndexError";
50
+ readonly cause: "DiskFull" | "Permission" | "Corrupted" | "Unknown";
51
+ readonly message: string;
52
+ }
53
+ ```
54
+
55
+ ### 1.2 The `handleApiKeyError` Utility
56
+
57
+ **Location: `/src/embeddings/openai-provider.ts:130-165`**
58
+
59
+ This is a key pattern in the codebase that demonstrates the problem:
60
+
61
+ ```typescript
62
+ export const handleApiKeyError = <A, E>(
63
+ effect: Effect.Effect<A, E | MissingApiKeyError | InvalidApiKeyError>,
64
+ ): Effect.Effect<A, E | Error> =>
65
+ effect.pipe(
66
+ Effect.catchIf(
67
+ (e): e is MissingApiKeyError => e instanceof MissingApiKeyError,
68
+ () =>
69
+ Effect.gen(function* () {
70
+ yield* Console.error("");
71
+ yield* Console.error("Error: OPENAI_API_KEY not set");
72
+ // ... more Console.error calls ...
73
+ return yield* Effect.fail(new Error("Missing API key")); // <-- Type lost here
74
+ }),
75
+ ),
76
+ Effect.catchIf(
77
+ (e): e is InvalidApiKeyError => e instanceof InvalidApiKeyError,
78
+ (e) =>
79
+ Effect.gen(function* () {
80
+ // ... Console.error calls ...
81
+ return yield* Effect.fail(new Error("Invalid API key")); // <-- Type lost here
82
+ }),
83
+ ),
84
+ );
85
+ ```
86
+
87
+ **Problems:**
88
+
89
+ 1. Catches typed errors (`MissingApiKeyError`, `InvalidApiKeyError`)
90
+ 2. Prints messages via `Console.error`
91
+ 3. Converts to generic `Error` - losing type information for callers
92
+ 4. Mixes error handling with error display (violates separation of concerns)
93
+
94
+ ### 1.3 CLI Command Error Handling
95
+
96
+ **`/src/cli/commands/search.ts`**
97
+
98
+ Uses `handleApiKeyError` for semantic search operations:
99
+
100
+ ```typescript
101
+ const results =
102
+ yield *
103
+ semanticSearch(resolvedDir, query, {
104
+ limit,
105
+ threshold,
106
+ }).pipe(handleApiKeyError);
107
+ ```
108
+
109
+ Also uses `Effect.catchAll(() => Effect.succeed(null))` pattern to swallow errors:
110
+
111
+ ```typescript
112
+ const estimate =
113
+ yield *
114
+ estimateEmbeddingCost(resolvedDir).pipe(
115
+ Effect.catchAll(() => Effect.succeed(null)),
116
+ );
117
+ ```
118
+
119
+ **`/src/cli/commands/index-cmd.ts`**
120
+
121
+ Same patterns - uses `handleApiKeyError` and swallows errors with `catchAll`:
122
+
123
+ ```typescript
124
+ const embedResult =
125
+ yield *
126
+ buildEmbeddings(resolvedDir, {
127
+ // ...
128
+ }).pipe(
129
+ handleApiKeyError,
130
+ Effect.catchAll(() => Effect.succeed(null)),
131
+ );
132
+ ```
133
+
134
+ Watch mode uses callbacks for error handling (escapes Effect):
135
+
136
+ ```typescript
137
+ const watcher =
138
+ yield *
139
+ watchDirectory(resolvedRoot, {
140
+ onError: (error) => {
141
+ console.error(`Watch error: ${error.message}`); // <-- Direct console.error
142
+ },
143
+ });
144
+ ```
145
+
146
+ **`/src/cli/main.ts`**
147
+
148
+ Top-level error handling for CLI validation errors:
149
+
150
+ ```typescript
151
+ Effect.catchAll((error) =>
152
+ Effect.sync(() => {
153
+ if (isValidationError(error)) {
154
+ const message = formatCliError(error);
155
+ console.error(`\nError: ${message}`); // <-- Direct console.error
156
+ console.error('\nRun "mdcontext --help" for usage information.');
157
+ process.exit(1);
158
+ }
159
+ throw error; // <-- Re-throws, escapes Effect
160
+ }),
161
+ );
162
+ ```
163
+
164
+ ---
165
+
166
+ ## 2. Identified Problems
167
+
168
+ ### 2.1 Type Information Loss
169
+
170
+ | Location | Original Error | Converted To |
171
+ | ------------------------ | -------------------- | ---------------------------------------------- |
172
+ | `openai-provider.ts:147` | `MissingApiKeyError` | `new Error('Missing API key')` |
173
+ | `openai-provider.ts:162` | `InvalidApiKeyError` | `new Error('Invalid API key')` |
174
+ | `storage.ts:25` | Unknown | `new Error(\`Failed to create directory...\`)` |
175
+ | `storage.ts:38` | Unknown | `new Error(\`Failed to read...\`)` |
176
+ | `storage.ts:50` | Unknown | `new Error(\`Failed to write...\`)` |
177
+ | `context.ts:86` | `ParseError` | `new Error(\`${e.\_tag}: ${e.message}\`)` |
178
+ | `tree.ts:36` | `ParseError` | `new Error(\`${e.\_tag}: ${e.message}\`)` |
179
+ | `mcp/server.ts:260` | Various | `new Error(\`${e.\_tag}: ${e.message}\`)` |
180
+ | `semantic-search.ts:371` | `InvalidApiKeyError` | `new Error(\`Embedding failed: ...\`)` |
181
+
182
+ ### 2.2 Direct `console.error` / `console.log` Usage
183
+
184
+ | Location | Context |
185
+ | ---------------------------- | ----------------------- |
186
+ | `main.ts:136-137` | CLI validation errors |
187
+ | `index-cmd.ts:94-102` | Watch mode logging |
188
+ | `help.ts:258-292` | Help display |
189
+ | `argv-preprocessor.ts:91-92` | Argument parsing errors |
190
+ | `mcp/server.ts:481` | Fatal server errors |
191
+
192
+ ### 2.3 Error Swallowing with `Effect.catchAll`
193
+
194
+ The pattern `Effect.catchAll(() => Effect.succeed(null))` is used in multiple places, silently swallowing errors:
195
+
196
+ - `search.ts:348` - Cost estimation
197
+ - `search.ts:376` - Embedding building
198
+ - `search.ts:424` - Embedding building (retry)
199
+ - `index-cmd.ts:232` - Cost estimation prompt
200
+ - `index-cmd.ts:272` - Embedding building
201
+ - `summarizer.ts:505` - File parsing
202
+
203
+ ### 2.4 Errors Escaping Effect System
204
+
205
+ | Location | Pattern |
206
+ | -------------------------- | ----------------------------------------------------------------------------- |
207
+ | `openai-provider.ts:59` | `throw new MissingApiKeyError()` in constructor |
208
+ | `openai-provider.ts:97-99` | `throw new InvalidApiKeyError(error.message)` / `throw error` in async method |
209
+ | `main.ts:141` | `throw error` to re-throw unhandled errors |
210
+ | `watcher.ts:71-81` | `Effect.runPromise` with try/catch for callback |
211
+
212
+ ### 2.5 Mixed Error Paradigms
213
+
214
+ The codebase uses three different error paradigms:
215
+
216
+ 1. **Effect tagged unions** (`ParseError`, `IoError`, `IndexError` in `core/types.ts`)
217
+ 2. **JavaScript Error subclasses** (`MissingApiKeyError`, `InvalidApiKeyError`)
218
+ 3. **Generic Error objects** (`new Error(...)` throughout)
219
+
220
+ ---
221
+
222
+ ## 3. Complete Error Type Catalog
223
+
224
+ ### 3.1 Defined Error Types (Effect style)
225
+
226
+ | Type | Location | Fields |
227
+ | ------------ | --------------- | ------------------------------------- |
228
+ | `ParseError` | `core/types.ts` | `_tag`, `message`, `line?`, `column?` |
229
+ | `IoError` | `core/types.ts` | `_tag`, `message`, `path`, `cause?` |
230
+ | `IndexError` | `core/types.ts` | `_tag`, `cause`, `message` |
231
+
232
+ ### 3.2 Defined Error Classes (JavaScript style)
233
+
234
+ | Class | Location | Purpose |
235
+ | -------------------- | ------------------------------- | ---------------- |
236
+ | `MissingApiKeyError` | `embeddings/openai-provider.ts` | No API key set |
237
+ | `InvalidApiKeyError` | `embeddings/openai-provider.ts` | API key rejected |
238
+
239
+ ### 3.3 Ad-hoc Error Messages (Generic Error)
240
+
241
+ | Message Pattern | Location | Count |
242
+ | -------------------------------------- | ----------------------------------- | ----- |
243
+ | `"Index not found..."` | `semantic-search.ts`, `searcher.ts` | 3 |
244
+ | `"Embeddings not found..."` | `semantic-search.ts` | 1 |
245
+ | `"Document not found in index..."` | `searcher.ts` | 1 |
246
+ | `"Failed to create/read/write..."` | `storage.ts` | 4 |
247
+ | `"Failed to walk directory..."` | `indexer.ts` | 1 |
248
+ | `"Parse error in..."` | `indexer.ts` | 1 |
249
+ | `"Embedding failed..."` | `semantic-search.ts` | 1 |
250
+ | `"Query embedding failed..."` | `semantic-search.ts` | 1 |
251
+ | `"Failed to generate query embedding"` | `semantic-search.ts` | 1 |
252
+ | `"At least one file is required..."` | `context.ts` | 1 |
253
+
254
+ ---
255
+
256
+ ## 4. Proposed Error Architecture
257
+
258
+ ### 4.1 Unified Error Type Hierarchy
259
+
260
+ All errors should follow the Effect tagged union pattern:
261
+
262
+ ```typescript
263
+ // Base error interface
264
+ interface MdContextError {
265
+ readonly _tag: string;
266
+ readonly message: string;
267
+ }
268
+
269
+ // File system errors
270
+ interface IoError extends MdContextError {
271
+ readonly _tag: "IoError";
272
+ readonly path: string;
273
+ readonly operation: "read" | "write" | "stat" | "mkdir" | "walk";
274
+ readonly cause?: unknown;
275
+ }
276
+
277
+ // Parsing errors
278
+ interface ParseError extends MdContextError {
279
+ readonly _tag: "ParseError";
280
+ readonly path?: string;
281
+ readonly line?: number;
282
+ readonly column?: number;
283
+ }
284
+
285
+ // Index errors
286
+ interface IndexError extends MdContextError {
287
+ readonly _tag: "IndexError";
288
+ readonly kind: "NotFound" | "Corrupted" | "VersionMismatch";
289
+ readonly path: string;
290
+ }
291
+
292
+ // API errors
293
+ interface ApiKeyError extends MdContextError {
294
+ readonly _tag: "ApiKeyError";
295
+ readonly kind: "Missing" | "Invalid";
296
+ readonly provider: string;
297
+ }
298
+
299
+ interface EmbeddingError extends MdContextError {
300
+ readonly _tag: "EmbeddingError";
301
+ readonly kind: "GenerationFailed" | "RateLimited" | "QuotaExceeded";
302
+ readonly cause?: unknown;
303
+ }
304
+
305
+ // Search errors
306
+ interface SearchError extends MdContextError {
307
+ readonly _tag: "SearchError";
308
+ readonly kind: "NoIndex" | "NoEmbeddings" | "DocumentNotFound";
309
+ readonly path?: string;
310
+ }
311
+
312
+ // CLI errors
313
+ interface CliError extends MdContextError {
314
+ readonly _tag: "CliError";
315
+ readonly kind: "ValidationError" | "MissingArgument" | "InvalidOption";
316
+ readonly details?: Record<string, unknown>;
317
+ }
318
+
319
+ // Union type for all errors
320
+ type MdContextErrors =
321
+ | IoError
322
+ | ParseError
323
+ | IndexError
324
+ | ApiKeyError
325
+ | EmbeddingError
326
+ | SearchError
327
+ | CliError;
328
+ ```
329
+
330
+ ### 4.2 Error Constructor Functions
331
+
332
+ Following Effect conventions:
333
+
334
+ ```typescript
335
+ // constructors/errors.ts
336
+ export const IoError = (
337
+ operation: IoError["operation"],
338
+ path: string,
339
+ message: string,
340
+ cause?: unknown,
341
+ ): IoError => ({
342
+ _tag: "IoError",
343
+ operation,
344
+ path,
345
+ message,
346
+ cause,
347
+ });
348
+
349
+ export const ApiKeyError = (
350
+ kind: ApiKeyError["kind"],
351
+ provider: string,
352
+ message?: string,
353
+ ): ApiKeyError => ({
354
+ _tag: "ApiKeyError",
355
+ kind,
356
+ provider,
357
+ message:
358
+ message ??
359
+ (kind === "Missing"
360
+ ? `${provider} API key not set`
361
+ : `Invalid ${provider} API key`),
362
+ });
363
+
364
+ // etc.
365
+ ```
366
+
367
+ ### 4.3 Error Handling Flow
368
+
369
+ ```
370
+ ┌──────────────────────────────────────────────────────────────┐
371
+ │ Effect Pipeline │
372
+ ├──────────────────────────────────────────────────────────────┤
373
+ │ │
374
+ │ Service Layer (returns typed Effect errors) │
375
+ │ ┌─────────────────────────────────────────────────────────┐ │
376
+ │ │ embeddings/openai-provider.ts │ │
377
+ │ │ → Effect.Effect<Result, ApiKeyError | EmbeddingError> │ │
378
+ │ └─────────────────────────────────────────────────────────┘ │
379
+ │ │ │
380
+ │ ▼ │
381
+ │ Business Logic (propagates or handles errors) │
382
+ │ ┌─────────────────────────────────────────────────────────┐ │
383
+ │ │ search/semantic-search.ts │ │
384
+ │ │ → Effect.Effect<Results, SearchError | ApiKeyError> │ │
385
+ │ └─────────────────────────────────────────────────────────┘ │
386
+ │ │ │
387
+ │ ▼ │
388
+ │ CLI Layer (formats errors for display) │
389
+ │ ┌─────────────────────────────────────────────────────────┐ │
390
+ │ │ cli/error-renderer.ts │ │
391
+ │ │ formatError(error: MdContextErrors): FormattedOutput │ │
392
+ │ │ - User-friendly messages │ │
393
+ │ │ - Actionable suggestions │ │
394
+ │ │ - Exit codes │ │
395
+ │ └─────────────────────────────────────────────────────────┘ │
396
+ │ │
397
+ └──────────────────────────────────────────────────────────────┘
398
+ ```
399
+
400
+ ### 4.4 Error Renderer (Separation of Concerns)
401
+
402
+ ```typescript
403
+ // cli/error-renderer.ts
404
+
405
+ interface FormattedError {
406
+ readonly message: string;
407
+ readonly details?: string;
408
+ readonly suggestions?: readonly string[];
409
+ readonly exitCode: number;
410
+ }
411
+
412
+ const formatError = (error: MdContextErrors): FormattedError => {
413
+ switch (error._tag) {
414
+ case "ApiKeyError":
415
+ return {
416
+ message:
417
+ error.kind === "Missing"
418
+ ? "OPENAI_API_KEY not set"
419
+ : "Invalid OPENAI_API_KEY",
420
+ suggestions: [
421
+ "export OPENAI_API_KEY=sk-...",
422
+ "Or add to .env file in project root.",
423
+ ],
424
+ exitCode: 1,
425
+ };
426
+
427
+ case "SearchError":
428
+ if (error.kind === "NoIndex") {
429
+ return {
430
+ message: "No index found.",
431
+ suggestions: [
432
+ "Run: mdcontext index /path/to/docs",
433
+ "Add --embed for semantic search capabilities",
434
+ ],
435
+ exitCode: 1,
436
+ };
437
+ }
438
+ // ... more cases
439
+
440
+ // ... other error types
441
+ }
442
+ };
443
+
444
+ const renderError = (error: FormattedError): Effect.Effect<never> =>
445
+ Effect.gen(function* () {
446
+ yield* Console.error("");
447
+ yield* Console.error(`Error: ${error.message}`);
448
+ if (error.details) {
449
+ yield* Console.error(`Details: ${error.details}`);
450
+ }
451
+ if (error.suggestions?.length) {
452
+ yield* Console.error("");
453
+ for (const suggestion of error.suggestions) {
454
+ yield* Console.error(` ${suggestion}`);
455
+ }
456
+ }
457
+ yield* Console.error("");
458
+ return yield* Effect.fail(error); // Keep as Effect failure for exit code
459
+ });
460
+ ```
461
+
462
+ ### 4.5 Migration Strategy
463
+
464
+ 1. **Phase 1: Define all error types** in `src/errors/types.ts`
465
+ 2. **Phase 2: Create constructors** in `src/errors/constructors.ts`
466
+ 3. **Phase 3: Create error renderer** in `src/cli/error-renderer.ts`
467
+ 4. **Phase 4: Migrate openai-provider.ts** - replace Error classes with tagged unions
468
+ 5. **Phase 5: Migrate storage.ts** - use IoError constructors
469
+ 6. **Phase 6: Migrate semantic-search.ts** - use SearchError/EmbeddingError
470
+ 7. **Phase 7: Migrate CLI commands** - use error renderer at top level
471
+ 8. **Phase 8: Remove handleApiKeyError** - no longer needed
472
+
473
+ ### 4.6 Key Principles
474
+
475
+ 1. **Never lose type information** - Use tagged unions throughout
476
+ 2. **Separate error definition from display** - Errors carry data, renderers format it
477
+ 3. **Single point of error formatting** - All user-facing error output goes through renderer
478
+ 4. **Effect-native errors** - Use `_tag` discriminators, not `instanceof`
479
+ 5. **Actionable errors** - Include suggestions where possible
480
+ 6. **Structured for logging** - JSON-serializable for debugging
481
+
482
+ ---
483
+
484
+ ## 5. Files Requiring Changes
485
+
486
+ | File | Changes Needed |
487
+ | ----------------------------------- | ----------------------------------------------- |
488
+ | `src/core/types.ts` | Expand error types or move to dedicated module |
489
+ | `src/embeddings/openai-provider.ts` | Replace Error classes, remove handleApiKeyError |
490
+ | `src/embeddings/semantic-search.ts` | Use typed errors instead of generic Error |
491
+ | `src/index/storage.ts` | Use IoError constructor |
492
+ | `src/index/indexer.ts` | Use typed errors |
493
+ | `src/index/watcher.ts` | Use typed errors in callbacks |
494
+ | `src/search/searcher.ts` | Use SearchError |
495
+ | `src/cli/commands/search.ts` | Use error renderer |
496
+ | `src/cli/commands/index-cmd.ts` | Use error renderer |
497
+ | `src/cli/commands/context.ts` | Use error renderer |
498
+ | `src/cli/main.ts` | Centralize error handling |
499
+ | `src/mcp/server.ts` | Use typed errors |
500
+ | `src/summarize/summarizer.ts` | Propagate typed errors |
501
+
502
+ ---
503
+
504
+ ## 6. Implementation Notes
505
+
506
+ ### Don't Do
507
+
508
+ - Don't use `new Error(...)` for known error conditions
509
+ - Don't mix `console.error` into business logic
510
+ - Don't swallow errors silently with `Effect.catchAll(() => Effect.succeed(null))`
511
+ - Don't convert typed errors to generic errors
512
+ - Don't use JavaScript Error subclasses (use tagged unions)
513
+
514
+ ### Do
515
+
516
+ - Define all possible errors as tagged unions
517
+ - Use constructor functions for consistent error creation
518
+ - Keep error handling separate from error display
519
+ - Provide actionable suggestions in error messages
520
+ - Use Effect's type system to track possible errors
521
+ - Log full error context for debugging while showing friendly messages to users