mdcontext 0.1.0 → 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 (251) hide show
  1. package/.changeset/config.json +9 -9
  2. package/.claude/settings.local.json +25 -0
  3. package/.github/workflows/claude-code-review.yml +44 -0
  4. package/.github/workflows/claude.yml +85 -0
  5. package/CONTRIBUTING.md +186 -0
  6. package/NOTES/NOTES +44 -0
  7. package/README.md +206 -3
  8. package/biome.json +1 -1
  9. package/dist/chunk-23UPXDNL.js +3044 -0
  10. package/dist/chunk-2W7MO2DL.js +1366 -0
  11. package/dist/chunk-3NUAZGMA.js +1689 -0
  12. package/dist/chunk-7TOWB2XB.js +366 -0
  13. package/dist/chunk-7XOTOADQ.js +3065 -0
  14. package/dist/chunk-AH2PDM2K.js +3042 -0
  15. package/dist/chunk-BNXWSZ63.js +3742 -0
  16. package/dist/chunk-BTL5DJVU.js +3222 -0
  17. package/dist/chunk-HDHYG7E4.js +104 -0
  18. package/dist/chunk-HLR4KZBP.js +3234 -0
  19. package/dist/chunk-IP3FRFEB.js +1045 -0
  20. package/dist/chunk-KHU56VDO.js +3042 -0
  21. package/dist/chunk-KRYIFLQR.js +85 -89
  22. package/dist/chunk-LBSDNLEM.js +287 -0
  23. package/dist/chunk-MNTQ7HCP.js +2643 -0
  24. package/dist/chunk-MUJELQQ6.js +1387 -0
  25. package/dist/chunk-MXJGMSLV.js +2199 -0
  26. package/dist/chunk-N6QJGC3Z.js +2636 -0
  27. package/dist/chunk-OBELGBPM.js +1713 -0
  28. package/dist/chunk-OT7R5XTA.js +3192 -0
  29. package/dist/chunk-P7X4RA2T.js +106 -0
  30. package/dist/chunk-PIDUQNC2.js +3185 -0
  31. package/dist/chunk-POGCDIH4.js +3187 -0
  32. package/dist/chunk-PSIEOQGZ.js +3043 -0
  33. package/dist/chunk-PVRT3IHA.js +3238 -0
  34. package/dist/chunk-QNN4TT23.js +1430 -0
  35. package/dist/chunk-RE3R45RJ.js +3042 -0
  36. package/dist/chunk-S7E6TFX6.js +718 -657
  37. package/dist/chunk-SG6GLU4U.js +1378 -0
  38. package/dist/chunk-SJCDV2ST.js +274 -0
  39. package/dist/chunk-SYE5XLF3.js +104 -0
  40. package/dist/chunk-T5VLYBZD.js +103 -0
  41. package/dist/chunk-TOQB7VWU.js +3238 -0
  42. package/dist/chunk-VFNMZ4ZQ.js +3228 -0
  43. package/dist/chunk-VVTGZNBT.js +1533 -1423
  44. package/dist/chunk-W7Q4RFEV.js +104 -0
  45. package/dist/chunk-XTYYVRLO.js +3190 -0
  46. package/dist/chunk-Y6MDYVJD.js +3063 -0
  47. package/dist/cli/main.js +4072 -629
  48. package/dist/index.d.ts +420 -33
  49. package/dist/index.js +8 -15
  50. package/dist/mcp/server.js +103 -7
  51. package/dist/schema-BAWSG7KY.js +22 -0
  52. package/dist/schema-E3QUPL26.js +20 -0
  53. package/dist/schema-EHL7WUT6.js +20 -0
  54. package/docs/019-USAGE.md +44 -5
  55. package/docs/020-current-implementation.md +8 -8
  56. package/docs/021-DOGFOODING-FINDINGS.md +1 -1
  57. package/docs/CONFIG.md +1123 -0
  58. package/docs/ERRORS.md +383 -0
  59. package/docs/summarization.md +320 -0
  60. package/justfile +40 -0
  61. package/package.json +39 -33
  62. package/research/INDEX.md +315 -0
  63. package/research/code-review/README.md +90 -0
  64. package/research/code-review/cli-error-handling-review.md +979 -0
  65. package/research/code-review/code-review-validation-report.md +464 -0
  66. package/research/code-review/main-ts-review.md +1128 -0
  67. package/research/config-docs/SUMMARY.md +357 -0
  68. package/research/config-docs/TEST-RESULTS.md +776 -0
  69. package/research/config-docs/TODO.md +542 -0
  70. package/research/config-docs/analysis.md +744 -0
  71. package/research/config-docs/fix-validation.md +502 -0
  72. package/research/config-docs/help-audit.md +264 -0
  73. package/research/config-docs/help-system-analysis.md +890 -0
  74. package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
  75. package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
  76. package/research/issue-review.md +603 -0
  77. package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
  78. package/research/llm-summarization/alternative-providers-2026.md +1428 -0
  79. package/research/llm-summarization/anthropic-2026.md +367 -0
  80. package/research/llm-summarization/claude-cli-integration.md +1706 -0
  81. package/research/llm-summarization/cli-integration-patterns.md +3155 -0
  82. package/research/llm-summarization/openai-2026.md +473 -0
  83. package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
  84. package/research/llm-summarization/opencode-cli-integration.md +1552 -0
  85. package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
  86. package/research/llm-summarization/prototype-results.md +56 -0
  87. package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
  88. package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
  89. package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
  90. package/research/mdcontext-pudding/01-index-embed.md +956 -0
  91. package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
  92. package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
  93. package/research/mdcontext-pudding/02-search.md +970 -0
  94. package/research/mdcontext-pudding/03-context.md +779 -0
  95. package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
  96. package/research/mdcontext-pudding/04-tree.md +704 -0
  97. package/research/mdcontext-pudding/05-config.md +1038 -0
  98. package/research/mdcontext-pudding/06-links-summary.txt +87 -0
  99. package/research/mdcontext-pudding/06-links.md +679 -0
  100. package/research/mdcontext-pudding/07-stats.md +693 -0
  101. package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
  102. package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
  103. package/research/mdcontext-pudding/README.md +168 -0
  104. package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
  105. package/research/research-quality-review.md +834 -0
  106. package/research/semantic-search/embedding-text-analysis.md +156 -0
  107. package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
  108. package/research/semantic-search/query-processing-analysis.md +207 -0
  109. package/research/semantic-search/root-cause-and-solution.md +114 -0
  110. package/research/semantic-search/threshold-validation-report.md +69 -0
  111. package/research/semantic-search/vector-search-analysis.md +63 -0
  112. package/research/test-path-issues.md +276 -0
  113. package/review/ALP-76/1-error-type-design.md +962 -0
  114. package/review/ALP-76/2-error-handling-patterns.md +906 -0
  115. package/review/ALP-76/3-error-presentation.md +624 -0
  116. package/review/ALP-76/4-test-coverage.md +625 -0
  117. package/review/ALP-76/5-migration-completeness.md +440 -0
  118. package/review/ALP-76/6-effect-best-practices.md +755 -0
  119. package/scripts/apply-branch-protection.sh +47 -0
  120. package/scripts/branch-protection-templates.json +79 -0
  121. package/scripts/prototype-summarization.ts +346 -0
  122. package/scripts/rebuild-hnswlib.js +32 -37
  123. package/scripts/setup-branch-protection.sh +64 -0
  124. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
  125. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
  126. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
  127. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
  128. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  129. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  130. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
  131. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
  132. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
  133. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
  134. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
  135. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
  136. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
  137. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
  138. package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
  139. package/src/cli/argv-preprocessor.test.ts +2 -2
  140. package/src/cli/cli.test.ts +230 -33
  141. package/src/cli/commands/config-cmd.ts +642 -0
  142. package/src/cli/commands/context.ts +97 -9
  143. package/src/cli/commands/duplicates.ts +122 -0
  144. package/src/cli/commands/embeddings.ts +529 -0
  145. package/src/cli/commands/index-cmd.ts +210 -30
  146. package/src/cli/commands/index.ts +3 -0
  147. package/src/cli/commands/search.ts +894 -64
  148. package/src/cli/commands/stats.ts +3 -0
  149. package/src/cli/commands/tree.ts +26 -5
  150. package/src/cli/config-layer.ts +176 -0
  151. package/src/cli/error-handler.test.ts +235 -0
  152. package/src/cli/error-handler.ts +655 -0
  153. package/src/cli/flag-schemas.ts +66 -0
  154. package/src/cli/help.ts +209 -7
  155. package/src/cli/main.ts +348 -58
  156. package/src/cli/options.ts +10 -0
  157. package/src/cli/shared-error-handling.ts +199 -0
  158. package/src/cli/utils.ts +150 -17
  159. package/src/config/file-provider.test.ts +320 -0
  160. package/src/config/file-provider.ts +273 -0
  161. package/src/config/index.ts +72 -0
  162. package/src/config/integration.test.ts +667 -0
  163. package/src/config/precedence.test.ts +277 -0
  164. package/src/config/precedence.ts +451 -0
  165. package/src/config/schema.test.ts +414 -0
  166. package/src/config/schema.ts +603 -0
  167. package/src/config/service.test.ts +320 -0
  168. package/src/config/service.ts +243 -0
  169. package/src/config/testing.test.ts +264 -0
  170. package/src/config/testing.ts +110 -0
  171. package/src/core/types.ts +6 -33
  172. package/src/duplicates/detector.test.ts +183 -0
  173. package/src/duplicates/detector.ts +414 -0
  174. package/src/duplicates/index.ts +18 -0
  175. package/src/embeddings/embedding-namespace.test.ts +300 -0
  176. package/src/embeddings/embedding-namespace.ts +947 -0
  177. package/src/embeddings/heading-boost.test.ts +222 -0
  178. package/src/embeddings/hnsw-build-options.test.ts +198 -0
  179. package/src/embeddings/hyde.test.ts +272 -0
  180. package/src/embeddings/hyde.ts +264 -0
  181. package/src/embeddings/index.ts +2 -0
  182. package/src/embeddings/openai-provider.ts +332 -83
  183. package/src/embeddings/pricing.json +22 -0
  184. package/src/embeddings/provider-constants.ts +204 -0
  185. package/src/embeddings/provider-errors.test.ts +967 -0
  186. package/src/embeddings/provider-errors.ts +565 -0
  187. package/src/embeddings/provider-factory.test.ts +240 -0
  188. package/src/embeddings/provider-factory.ts +225 -0
  189. package/src/embeddings/provider-integration.test.ts +788 -0
  190. package/src/embeddings/query-preprocessing.test.ts +187 -0
  191. package/src/embeddings/semantic-search-threshold.test.ts +508 -0
  192. package/src/embeddings/semantic-search.ts +780 -93
  193. package/src/embeddings/types.ts +293 -16
  194. package/src/embeddings/vector-store.ts +486 -77
  195. package/src/embeddings/voyage-provider.ts +313 -0
  196. package/src/errors/errors.test.ts +845 -0
  197. package/src/errors/index.ts +533 -0
  198. package/src/index/ignore-patterns.test.ts +354 -0
  199. package/src/index/ignore-patterns.ts +305 -0
  200. package/src/index/indexer.ts +286 -48
  201. package/src/index/storage.ts +94 -30
  202. package/src/index/types.ts +40 -2
  203. package/src/index/watcher.ts +67 -9
  204. package/src/index.ts +22 -0
  205. package/src/integration/search-keyword.test.ts +678 -0
  206. package/src/mcp/server.ts +135 -6
  207. package/src/parser/parser.ts +18 -19
  208. package/src/parser/section-filter.test.ts +277 -0
  209. package/src/parser/section-filter.ts +125 -3
  210. package/src/search/__tests__/hybrid-search.test.ts +650 -0
  211. package/src/search/bm25-store.ts +366 -0
  212. package/src/search/cross-encoder.test.ts +253 -0
  213. package/src/search/cross-encoder.ts +406 -0
  214. package/src/search/fuzzy-search.test.ts +419 -0
  215. package/src/search/fuzzy-search.ts +273 -0
  216. package/src/search/hybrid-search.ts +448 -0
  217. package/src/search/path-matcher.test.ts +276 -0
  218. package/src/search/path-matcher.ts +33 -0
  219. package/src/search/searcher.test.ts +99 -1
  220. package/src/search/searcher.ts +189 -67
  221. package/src/search/wink-bm25.d.ts +30 -0
  222. package/src/summarization/cli-providers/claude.ts +202 -0
  223. package/src/summarization/cli-providers/detection.test.ts +273 -0
  224. package/src/summarization/cli-providers/detection.ts +118 -0
  225. package/src/summarization/cli-providers/index.ts +8 -0
  226. package/src/summarization/cost.test.ts +139 -0
  227. package/src/summarization/cost.ts +102 -0
  228. package/src/summarization/error-handler.test.ts +127 -0
  229. package/src/summarization/error-handler.ts +111 -0
  230. package/src/summarization/index.ts +102 -0
  231. package/src/summarization/pipeline.test.ts +498 -0
  232. package/src/summarization/pipeline.ts +231 -0
  233. package/src/summarization/prompts.test.ts +269 -0
  234. package/src/summarization/prompts.ts +133 -0
  235. package/src/summarization/provider-factory.test.ts +396 -0
  236. package/src/summarization/provider-factory.ts +178 -0
  237. package/src/summarization/types.ts +184 -0
  238. package/src/summarize/summarizer.ts +104 -35
  239. package/src/types/huggingface-transformers.d.ts +66 -0
  240. package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
  241. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
  242. package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
  243. package/tests/fixtures/cli/.mdcontext/indexes/documents.json +4 -4
  244. package/tests/fixtures/cli/.mdcontext/indexes/sections.json +14 -0
  245. package/tests/integration/embed-index.test.ts +712 -0
  246. package/tests/integration/search-context.test.ts +469 -0
  247. package/tests/integration/search-semantic.test.ts +522 -0
  248. package/vitest.config.ts +1 -6
  249. package/AGENTS.md +0 -46
  250. package/tests/fixtures/cli/.mdcontext/vectors.bin +0 -0
  251. package/tests/fixtures/cli/.mdcontext/vectors.meta.json +0 -1264
@@ -0,0 +1,624 @@
1
+ # ALP-76 Error Presentation & CLI Boundary Review
2
+
3
+ **Reviewer:** Claude Sonnet 4.5
4
+ **Date:** 2026-01-24
5
+ **Worktree:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76`
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ **Overall Assessment:** ✅ **PASS with Minor Concerns**
12
+
13
+ The ALP-76 refactoring successfully establishes clear separation between error presentation and business logic. Error formatting is properly isolated at the CLI boundary, domain errors contain technical data (not user messages), and the error handler provides comprehensive user-friendly formatting. There are a few minor areas where presentation concerns leak into business logic, but these are edge cases that don't compromise the overall architecture.
14
+
15
+ ### Acceptance Criteria Status
16
+
17
+ | Criterion | Status | Notes |
18
+ |-----------|--------|-------|
19
+ | Error formatting only at CLI entry points | ✅ PASS | Centralized in `error-handler.ts` |
20
+ | Clear separation between domain errors and user messages | ✅ PASS | Domain errors use technical fields, presentation in handler |
21
+ | No presentation logic in core modules | ⚠️ MOSTLY | One console.warn in parser, graceful degradation messages in commands |
22
+ | Consistent formatting and tone | ✅ PASS | Standardized message structure across all error types |
23
+ | Appropriate detail level for users | ✅ PASS | Technical details separated from actionable suggestions |
24
+
25
+ ---
26
+
27
+ ## 1. CLI Boundary Analysis
28
+
29
+ ### 1.1 Centralized Error Handler
30
+
31
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/cli/error-handler.ts`
32
+
33
+ The error handler provides excellent separation of concerns:
34
+
35
+ ✅ **Strengths:**
36
+ - Single `formatError()` function handles all error types using exhaustive pattern matching
37
+ - Uses `Match.exhaustive` to ensure all error types are covered at compile time
38
+ - Returns structured `FormattedError` objects with consistent shape
39
+ - Separate display functions for normal and debug modes
40
+ - Exit codes mapped to error categories (user error, system error, API error)
41
+
42
+ **Key Pattern (lines 74-287):**
43
+ ```typescript
44
+ export const formatError = (error: MdContextError): FormattedError =>
45
+ Match.value(error).pipe(
46
+ Match.tag('FileReadError', (e) => ({
47
+ code: e.code,
48
+ message: `Cannot read file: ${e.path}`,
49
+ details: e.message,
50
+ suggestions: [
51
+ 'Check that the file exists',
52
+ 'Check file permissions',
53
+ ] as const,
54
+ exitCode: EXIT_CODE.SYSTEM_ERROR,
55
+ })),
56
+ // ... all other error types
57
+ Match.exhaustive,
58
+ )
59
+ ```
60
+
61
+ ✅ **User Message Quality:**
62
+ - Primary message is user-friendly: "Cannot read file: /path/to/file"
63
+ - Technical details preserved in `details` field: "ENOENT: no such file or directory"
64
+ - Actionable suggestions provided for each error type
65
+ - Error codes included for scripting/automation
66
+
67
+ ### 1.2 Command-Level Error Handling
68
+
69
+ Commands properly propagate typed errors to the CLI boundary without formatting them:
70
+
71
+ **Example: context.ts (lines 92-106)**
72
+ ```typescript
73
+ const document = yield* parseFile(filePath).pipe(
74
+ Effect.mapError((e) =>
75
+ e._tag === 'ParseError'
76
+ ? new ParseError({
77
+ message: e.message,
78
+ path: filePath,
79
+ ...(e.line !== undefined && { line: e.line }),
80
+ ...(e.column !== undefined && { column: e.column }),
81
+ })
82
+ : new FileReadError({
83
+ path: e.path,
84
+ message: e.message,
85
+ }),
86
+ ),
87
+ )
88
+ ```
89
+
90
+ ✅ The command:
91
+ - Preserves technical error data (message, path, line, column)
92
+ - Does NOT format error messages for users
93
+ - Allows errors to propagate to CLI boundary for formatting
94
+
95
+ ### 1.3 Main Entry Point
96
+
97
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/cli/main.ts`
98
+
99
+ The main CLI file handles legacy Effect CLI validation errors during the transition period:
100
+
101
+ **Lines 95-106:**
102
+ ```typescript
103
+ Effect.catchAll((error) =>
104
+ Effect.sync(() => {
105
+ // Only show friendly error for Effect CLI validation errors
106
+ if (isEffectCliValidationError(error)) {
107
+ const message = formatEffectCliError(error)
108
+ console.error(`\nError: ${message}`)
109
+ console.error('\nRun "mdcontext --help" for usage information.')
110
+ process.exit(1)
111
+ }
112
+ // Re-throw other errors to be handled normally
113
+ throw error
114
+ }),
115
+ )
116
+ ```
117
+
118
+ ✅ This is appropriate for the transition period but should be documented as temporary.
119
+
120
+ ---
121
+
122
+ ## 2. Domain Error Separation
123
+
124
+ ### 2.1 Error Definition Convention
125
+
126
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/errors/index.ts`
127
+
128
+ Excellent documentation of the error message convention (lines 10-37):
129
+
130
+ ```typescript
131
+ /**
132
+ * ## Error Message Convention
133
+ *
134
+ * The `message` field in errors should contain **technical details** from the
135
+ * underlying operation, NOT user-facing formatted messages.
136
+ *
137
+ * **Good (technical):**
138
+ * ```typescript
139
+ * new FileReadError({
140
+ * path: '/path/to/file',
141
+ * message: e.message, // e.g., "ENOENT: no such file or directory"
142
+ * cause: e,
143
+ * })
144
+ * ```
145
+ *
146
+ * **Bad (user-facing):**
147
+ * ```typescript
148
+ * new FileReadError({
149
+ * path: '/path/to/file',
150
+ * message: 'Cannot read file. Please check permissions.', // NO!
151
+ * })
152
+ * ```
153
+ */
154
+ ```
155
+
156
+ ✅ This establishes clear expectations for error construction throughout the codebase.
157
+
158
+ ### 2.2 Error Construction in Core Modules
159
+
160
+ **Indexer (indexer.ts:295-302):**
161
+ ```typescript
162
+ Effect.mapError(
163
+ (e) =>
164
+ new ParseError({
165
+ message: e.message,
166
+ path: relativePath,
167
+ ...(e.line !== undefined && { line: e.line }),
168
+ ...(e.column !== undefined && { column: e.column }),
169
+ }),
170
+ )
171
+ ```
172
+
173
+ ✅ Preserves technical error message from underlying parser.
174
+
175
+ **OpenAI Provider (openai-provider.ts:96-103):**
176
+ ```typescript
177
+ if (error instanceof OpenAI.AuthenticationError) {
178
+ throw new ApiKeyInvalidError({
179
+ provider: 'OpenAI',
180
+ details: error.message, // Technical error from API
181
+ })
182
+ }
183
+ ```
184
+
185
+ ✅ Uses API error message as technical details, not user presentation.
186
+
187
+ **Semantic Search (semantic-search.ts:500-507):**
188
+ ```typescript
189
+ if (!queryVector) {
190
+ return yield* Effect.fail(
191
+ new EmbeddingError({
192
+ reason: 'Unknown',
193
+ message: 'Failed to generate query embedding', // Technical description
194
+ provider: 'OpenAI',
195
+ }),
196
+ )
197
+ }
198
+ ```
199
+
200
+ ✅ Technical description of what went wrong, not user instructions.
201
+
202
+ ### 2.3 Dynamic Message Generation
203
+
204
+ Some errors generate user-friendly messages dynamically via getters:
205
+
206
+ **ApiKeyMissingError (errors/index.ts:224-227):**
207
+ ```typescript
208
+ get message(): string {
209
+ return `${this.envVar} not set`
210
+ }
211
+ ```
212
+
213
+ **EmbeddingsNotFoundError (errors/index.ts:399-401):**
214
+ ```typescript
215
+ get message(): string {
216
+ return `Embeddings not found at ${this.path}. Run 'mdcontext index --embed' first.`
217
+ }
218
+ ```
219
+
220
+ ⚠️ **Minor Concern:** These messages include user instructions ("Run 'mdcontext index --embed' first"). While not ideal, the error handler overrides these in `formatError()`, so the impact is minimal. However, it creates duplication and potential inconsistency.
221
+
222
+ **Recommendation:** Consider removing user instructions from error class getters and keeping only technical descriptions. Let the error handler provide all user guidance.
223
+
224
+ ---
225
+
226
+ ## 3. User Experience Assessment
227
+
228
+ ### 3.1 Error Message Quality
229
+
230
+ The error handler provides excellent user-facing messages across all error types:
231
+
232
+ **File System Errors (error-handler.ts:77-117):**
233
+ ```typescript
234
+ Match.tag('FileReadError', (e) => ({
235
+ code: e.code,
236
+ message: `Cannot read file: ${e.path}`,
237
+ details: e.message,
238
+ suggestions: [
239
+ 'Check that the file exists',
240
+ 'Check file permissions',
241
+ ],
242
+ exitCode: EXIT_CODE.SYSTEM_ERROR,
243
+ }))
244
+ ```
245
+
246
+ ✅ **Strengths:**
247
+ - Clear primary message identifies the problem
248
+ - Technical details available but separate
249
+ - Actionable suggestions for remediation
250
+ - Appropriate exit code for error category
251
+
252
+ **API Errors (error-handler.ts:131-192):**
253
+ ```typescript
254
+ Match.tag('ApiKeyMissingError', (e) => ({
255
+ code: e.code,
256
+ message: `${e.envVar} not set`,
257
+ suggestions: [
258
+ `export ${e.envVar}=your-api-key`,
259
+ 'Or add to .env file in project root',
260
+ ],
261
+ exitCode: EXIT_CODE.API_ERROR,
262
+ }))
263
+ ```
264
+
265
+ ✅ Provides concrete setup instructions with example commands.
266
+
267
+ **Embedding Error Nuance (error-handler.ts:153-192):**
268
+ ```typescript
269
+ Match.tag('EmbeddingError', (e) =>
270
+ Match.value(e.reason).pipe(
271
+ Match.when('RateLimit', () => ({
272
+ code: e.code,
273
+ message: 'Rate limit exceeded',
274
+ details: e.message,
275
+ suggestions: [
276
+ 'Wait a few minutes and try again',
277
+ 'Consider using a smaller batch size',
278
+ ],
279
+ exitCode: EXIT_CODE.API_ERROR,
280
+ })),
281
+ Match.when('QuotaExceeded', () => ({
282
+ // Different message and suggestions
283
+ })),
284
+ Match.when('Network', () => ({
285
+ // Network-specific guidance
286
+ })),
287
+ // ...
288
+ ),
289
+ )
290
+ ```
291
+
292
+ ✅ **Excellent:** Different error reasons within the same type get tailored messages and suggestions.
293
+
294
+ ### 3.2 Message Consistency
295
+
296
+ All error messages follow a consistent structure:
297
+
298
+ 1. **Code:** Machine-readable error code (e.g., "E100", "E300")
299
+ 2. **Message:** User-friendly description of what went wrong
300
+ 3. **Details:** Technical information from the underlying error (optional)
301
+ 4. **Suggestions:** Actionable steps to resolve (1-3 items)
302
+ 5. **Exit Code:** Appropriate exit code for scripting
303
+
304
+ **Display Format (error-handler.ts:297-316):**
305
+ ```typescript
306
+ export const displayError = (formatted: FormattedError): Effect.Effect<void, never> =>
307
+ Effect.gen(function* () {
308
+ yield* Console.error('')
309
+ yield* Console.error(`Error [${formatted.code}]: ${formatted.message}`)
310
+
311
+ if (formatted.details) {
312
+ yield* Console.error(` ${formatted.details}`)
313
+ }
314
+
315
+ if (formatted.suggestions && formatted.suggestions.length > 0) {
316
+ yield* Console.error('')
317
+ for (const suggestion of formatted.suggestions) {
318
+ yield* Console.error(` ${suggestion}`)
319
+ }
320
+ }
321
+
322
+ yield* Console.error('')
323
+ })
324
+ ```
325
+
326
+ ✅ Clean, consistent format across all error types.
327
+
328
+ ### 3.3 Debug Mode Support
329
+
330
+ **Lines 321-340:**
331
+ ```typescript
332
+ export const displayErrorDebug = (
333
+ error: MdContextError,
334
+ formatted: FormattedError,
335
+ ): Effect.Effect<void, never> =>
336
+ Effect.gen(function* () {
337
+ yield* displayError(formatted)
338
+
339
+ yield* Console.error('--- Debug Info ---')
340
+ yield* Console.error(`Code: ${formatted.code}`)
341
+ yield* Console.error(`Tag: ${error._tag}`)
342
+ yield* Console.error(`Error: ${JSON.stringify(error, null, 2)}`)
343
+
344
+ // Show cause/stack if available
345
+ if ('cause' in error && error.cause) {
346
+ yield* Console.error(`Cause: ${String(error.cause)}`)
347
+ if (error.cause instanceof Error && error.cause.stack) {
348
+ yield* Console.error(`Stack: ${error.cause.stack}`)
349
+ }
350
+ }
351
+ })
352
+ ```
353
+
354
+ ✅ **Excellent:** Debug mode preserves all technical details including:
355
+ - Full error object as JSON
356
+ - Error tag for type identification
357
+ - Cause chain with stack traces
358
+ - User-friendly message still shown first
359
+
360
+ ---
361
+
362
+ ## 4. Separation of Concerns Evaluation
363
+
364
+ ### 4.1 Presentation Leaks in Core Modules
365
+
366
+ #### ⚠️ Issue #1: Parser Warning Message
367
+
368
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/parser/parser.ts:311-313`
369
+
370
+ ```typescript
371
+ console.warn(
372
+ `Warning: Malformed frontmatter in ${path}, skipping: ${msg.split('\n')[0]}`,
373
+ )
374
+ ```
375
+
376
+ **Concern:** Direct console output in a core parsing module bypasses the error handling system.
377
+
378
+ **Impact:** Low - This is a warning for malformed YAML frontmatter that doesn't prevent parsing. The parser gracefully continues.
379
+
380
+ **Recommendation:** Consider using `Effect.logWarning()` instead of `console.warn()` to integrate with Effect's logging system.
381
+
382
+ #### ⚠️ Issue #2: Graceful Degradation Messages in Commands
383
+
384
+ **Location:** Multiple command files show this pattern for optional features.
385
+
386
+ **Example: search.ts (lines 393-411):**
387
+ ```typescript
388
+ Effect.catchTags({
389
+ ApiKeyMissingError: (e) => {
390
+ if (!json) {
391
+ Effect.runSync(Console.error(`\n${e.message}`))
392
+ }
393
+ return Effect.succeed(null)
394
+ },
395
+ ApiKeyInvalidError: (e) => {
396
+ if (!json) {
397
+ Effect.runSync(Console.error(`\n${e.message}`))
398
+ }
399
+ return Effect.succeed(null)
400
+ },
401
+ // ...
402
+ })
403
+ ```
404
+
405
+ **Analysis:** This is graceful degradation for optional embedding features. The command catches errors and displays them inline rather than failing the entire operation.
406
+
407
+ **Is this presentation logic?** Debatable:
408
+ - ✅ Pro: These are informational messages for optional features, not error formatting
409
+ - ⚠️ Con: Direct console output bypasses the centralized error handler
410
+ - ✅ Pro: Allows the main operation to continue despite embedding failures
411
+ - ⚠️ Con: Creates duplicate error display logic
412
+
413
+ **Recommendation:** Consider creating a helper function like `displayInlineWarning(error)` that maintains consistent formatting while allowing graceful degradation.
414
+
415
+ #### ⚠️ Issue #3: MCP Server Fatal Error
416
+
417
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/mcp/server.ts:487`
418
+
419
+ ```typescript
420
+ console.error('Fatal error:', error)
421
+ ```
422
+
423
+ **Context:** This is in the MCP server's fatal error handler, separate from the CLI.
424
+
425
+ **Impact:** Minimal - MCP server has different presentation requirements than CLI.
426
+
427
+ ✅ **Acceptable:** Different entry points (CLI vs MCP server) may have different error presentation needs.
428
+
429
+ ### 4.2 Business Logic Cleanliness
430
+
431
+ Core business logic modules are clean of presentation concerns:
432
+
433
+ **Indexer (indexer.ts:389-400):**
434
+ ```typescript
435
+ Effect.catchAll((error) => {
436
+ // Extract message from typed errors or generic errors
437
+ const message =
438
+ 'message' in error && typeof error.message === 'string'
439
+ ? error.message
440
+ : String(error)
441
+ errors.push({
442
+ path: relativePath,
443
+ message,
444
+ })
445
+ return Effect.void
446
+ })
447
+ ```
448
+
449
+ ✅ Collects error data without formatting or displaying it.
450
+
451
+ **Semantic Search (semantic-search.ts:367-374):**
452
+ ```typescript
453
+ Effect.catchAll(() =>
454
+ Effect.succeed({ ok: false as const, content: '' }),
455
+ )
456
+ ```
457
+
458
+ ✅ Returns error state without logging or displaying.
459
+
460
+ **Vector Store - Not reviewed in detail but no console output detected in grep.**
461
+
462
+ ---
463
+
464
+ ## 5. Logging vs Presentation
465
+
466
+ ### 5.1 Technical Logging
467
+
468
+ The codebase uses `Effect.logWarning()` appropriately for technical logging:
469
+
470
+ **Semantic Search (semantic-search.ts:377):**
471
+ ```typescript
472
+ yield* Effect.logWarning(`Skipping file (cannot read): ${docPath}`)
473
+ ```
474
+
475
+ **Search Command (search.ts:355-360):**
476
+ ```typescript
477
+ Effect.runSync(
478
+ Effect.logWarning(
479
+ `Could not estimate embedding cost: ${e instanceof Error ? e.message : String(e)}`,
480
+ ),
481
+ )
482
+ ```
483
+
484
+ ✅ **Appropriate:** These are debug/operational logs, not user-facing error messages.
485
+
486
+ ### 5.2 Stack Traces
487
+
488
+ Stack traces are only shown in debug mode:
489
+
490
+ **error-handler.ts:334-339:**
491
+ ```typescript
492
+ if ('cause' in error && error.cause) {
493
+ yield* Console.error(`Cause: ${String(error.cause)}`)
494
+ if (error.cause instanceof Error && error.cause.stack) {
495
+ yield* Console.error(`Stack: ${error.cause.stack}`)
496
+ }
497
+ }
498
+ ```
499
+
500
+ ✅ **Excellent:** Normal users see friendly messages; debug mode shows full technical details.
501
+
502
+ ---
503
+
504
+ ## 6. Test Coverage
505
+
506
+ The error handling is well-tested:
507
+
508
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-76/src/errors/errors.test.ts`
509
+
510
+ ✅ **Comprehensive Tests:**
511
+ - Error construction with correct `_tag` (lines 42-88)
512
+ - Error code getters return correct values (lines 50-56)
513
+ - Error data field access (lines 59-65)
514
+ - Cause chain preservation (lines 68-76)
515
+ - `catchTag` pattern matching (lines 78-88)
516
+ - Dynamic message generation (lines 186-231)
517
+ - Multiple error handling with `catchTags` (lines 522-553)
518
+ - Error code uniqueness and format (lines 560-609)
519
+
520
+ ⚠️ **Missing:** Tests for the error handler's `formatError()` and `displayError()` functions.
521
+
522
+ **Recommendation:** Add tests for `error-handler.ts` to verify:
523
+ - Correct formatting for each error type
524
+ - Exhaustive matching (all error types handled)
525
+ - Exit code mapping
526
+ - Debug mode output
527
+
528
+ ---
529
+
530
+ ## 7. Code References
531
+
532
+ ### Well-Separated Components
533
+
534
+ | Component | Path | Lines | Assessment |
535
+ |-----------|------|-------|------------|
536
+ | Error Definitions | `src/errors/index.ts` | 1-484 | ✅ Clean domain errors |
537
+ | Error Formatter | `src/cli/error-handler.ts` | 74-287 | ✅ Centralized presentation |
538
+ | Error Display | `src/cli/error-handler.ts` | 297-340 | ✅ Consistent output |
539
+ | Error Handler Factory | `src/cli/error-handler.ts` | 376-395 | ✅ Type-safe handlers |
540
+ | Main CLI | `src/cli/main.ts` | 93-109 | ✅ Proper error routing |
541
+
542
+ ### Areas Needing Attention
543
+
544
+ | Issue | Location | Lines | Severity |
545
+ |-------|----------|-------|----------|
546
+ | Parser console.warn | `src/parser/parser.ts` | 311-313 | Minor |
547
+ | Graceful degradation messages | `src/cli/commands/search.ts` | 393-411 | Minor |
548
+ | Graceful degradation messages | `src/cli/commands/index-cmd.ts` | 294-333 | Minor |
549
+ | Dynamic user messages in errors | `src/errors/index.ts` | 399-401 | Minor |
550
+ | MCP server console.error | `src/mcp/server.ts` | 487 | Acceptable |
551
+
552
+ ---
553
+
554
+ ## 8. Recommendations
555
+
556
+ ### High Priority
557
+
558
+ 1. **Add Error Handler Tests**
559
+ - Test `formatError()` for all error types
560
+ - Verify exhaustive matching
561
+ - Test exit code mapping
562
+ - Test debug mode output
563
+
564
+ ### Medium Priority
565
+
566
+ 2. **Remove User Instructions from Error Classes**
567
+ - Move instructions from `EmbeddingsNotFoundError.message` getter to error handler
568
+ - Keep error class messages purely technical
569
+ - Eliminates duplication and potential inconsistency
570
+
571
+ 3. **Replace console.warn in Parser**
572
+ ```typescript
573
+ // Replace:
574
+ console.warn(`Warning: Malformed frontmatter in ${path}, skipping: ${msg.split('\n')[0]}`)
575
+
576
+ // With:
577
+ yield* Effect.logWarning(`Malformed frontmatter in ${path}, skipping: ${msg.split('\n')[0]}`)
578
+ ```
579
+
580
+ 4. **Create Graceful Degradation Helper**
581
+ ```typescript
582
+ // In cli/utils.ts:
583
+ export const displayInlineWarning = (error: MdContextError, json: boolean): void => {
584
+ if (json) return
585
+ const formatted = formatError(error)
586
+ console.error(`\nWarning: ${formatted.message}`)
587
+ if (formatted.suggestions?.length > 0) {
588
+ console.error(` ${formatted.suggestions[0]}`)
589
+ }
590
+ }
591
+ ```
592
+
593
+ ### Low Priority
594
+
595
+ 5. **Document Temporary Legacy Error Handling**
596
+ - Add comment explaining Effect CLI validation error handling is transitional
597
+ - Track removal in issue/backlog
598
+
599
+ 6. **Consider Error Logging Hook**
600
+ - Allow attaching logger to error handler for observability
601
+ - Separate from user presentation
602
+
603
+ ---
604
+
605
+ ## 9. Conclusion
606
+
607
+ The ALP-76 error handling refactoring successfully achieves its goal of separating error presentation from business logic. The implementation demonstrates:
608
+
609
+ ✅ **Strengths:**
610
+ - Centralized error formatting at CLI boundary
611
+ - Domain errors contain technical data, not user messages
612
+ - Comprehensive error coverage with exhaustive matching
613
+ - Excellent user experience with actionable suggestions
614
+ - Debug mode preserves technical details
615
+ - Clean separation in core modules
616
+
617
+ ⚠️ **Minor Issues:**
618
+ - One console.warn in parser (easily fixed)
619
+ - Graceful degradation messages bypass error handler (design trade-off)
620
+ - Some dynamic user messages in error classes (minor duplication)
621
+
622
+ The architecture is solid and maintainable. The minor issues are edge cases that don't compromise the overall design. The error handling system provides a strong foundation for consistent, user-friendly error presentation across the application.
623
+
624
+ **Final Verdict:** ✅ **PASS** - Acceptance criteria met with minor improvement opportunities.