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,979 @@
1
+ # CLI Error Handling Review
2
+
3
+ **Date:** 2026-01-24
4
+ **Last Validated:** 2026-01-24 06:38:24 UTC
5
+ **Validation Commit:** `07c9e72ba01cda840046b96a1be4743a85e3d4c5`
6
+ **Scope:** All CLI command files and error handling infrastructure
7
+ **Reviewer:** Claude Sonnet 4.5
8
+
9
+ ---
10
+
11
+ ## Validation Summary
12
+
13
+ **✓ All Issues Verified**: All 11 issues remain valid and accurately documented.
14
+
15
+ ### Resolution Status
16
+ - **✓ VALID:** 10 issues (91%)
17
+ - **📍 MOVED:** 1 issue (9%)
18
+ - **✅ RESOLVED:** 0 issues (0%)
19
+
20
+ See `/research/code-review/code-review-validation-report.md` for detailed validation results.
21
+
22
+ ---
23
+
24
+ ## Executive Summary
25
+
26
+ The CLI codebase demonstrates a **well-architected error handling system** using Effect's tagged error pattern. The centralized error handler (`src/cli/error-handler.ts`) provides consistent formatting and exit codes. However, there are **inconsistencies in error propagation** between commands, with some using graceful degradation while others let errors propagate to the CLI boundary.
27
+
28
+ **Overall Grade: B+**
29
+
30
+ ### Strengths
31
+ - Centralized error handler with comprehensive error mapping
32
+ - Type-safe tagged errors using Effect's Data.TaggedError pattern
33
+ - Consistent exit code strategy (0=success, 1=user error, 2=system error, 3=API error)
34
+ - Rich error context with actionable suggestions
35
+ - Clear separation between technical error messages and user-facing formatting
36
+
37
+ ### Areas for Improvement
38
+ - Inconsistent error handling strategies across commands (some catch locally, some propagate)
39
+ - Multiple `process.exit()` calls scattered across CLI files
40
+ - Mixed error handling patterns (Effect.catchTags vs Effect.try)
41
+ - Some commands silently degrade on errors without proper logging
42
+ - Legacy error handling code for @effect/cli validation errors
43
+
44
+ ---
45
+
46
+ ## Error Handling Architecture
47
+
48
+ ### Centralized Error Handler (`src/cli/error-handler.ts`)
49
+
50
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/error-handler.ts`
51
+
52
+ The error handler is well-designed with:
53
+
54
+ 1. **Exit Code Constants** (Lines 45-52)
55
+ ```typescript
56
+ export const EXIT_CODE = {
57
+ SUCCESS: 0,
58
+ USER_ERROR: 1,
59
+ SYSTEM_ERROR: 2,
60
+ API_ERROR: 3,
61
+ } as const
62
+ ```
63
+
64
+ 2. **Formatted Error Interface** (Lines 58-64)
65
+ - Provides structured error output with code, message, details, suggestions, and exit code
66
+ - Enables consistent formatting across all error types
67
+
68
+ 3. **Exhaustive Error Formatting** (Lines 129-335)
69
+ - Uses Effect's `Match.value()` pattern matching for type-safe error handling
70
+ - Each error type mapped to user-friendly message with actionable suggestions
71
+ - Special handling for ConfigError with enhanced context
72
+
73
+ 4. **Error Display Functions**
74
+ - `displayError()`: Standard error output to stderr
75
+ - `displayErrorDebug()`: Enhanced output with stack traces for debugging
76
+ - Clean separation of concerns
77
+
78
+ ### Error Type System (`src/errors/index.ts`)
79
+
80
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/errors/index.ts`
81
+
82
+ Excellent error taxonomy with:
83
+ - **Error Codes** (E1xx-E9xx): Stable, machine-readable identifiers
84
+ - **Tagged Errors**: Type-safe discriminated unions using Effect's Data.TaggedError
85
+ - **Clear Documentation**: Each error type includes purpose and usage examples
86
+ - **Rich Context**: Errors carry path, message, cause, and domain-specific metadata
87
+
88
+ **Error Categories:**
89
+ - E1xx: File system errors (FileReadError, FileWriteError, etc.)
90
+ - E2xx: Parse errors
91
+ - E3xx: API/authentication errors
92
+ - E4xx: Index errors
93
+ - E5xx: Search errors
94
+ - E6xx: Vector store errors
95
+ - E7xx: Config errors
96
+ - E8xx: Watch errors
97
+ - E9xx: CLI validation errors
98
+
99
+ ---
100
+
101
+ ## Command-by-Command Analysis
102
+
103
+ ### 1. index-cmd.ts
104
+
105
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/index-cmd.ts`
106
+
107
+ **Pattern:** **Graceful Degradation with Local Error Catching**
108
+
109
+ #### Good Practices ✅
110
+
111
+ 1. **Strategic Error Catching** (Lines 256-276, 308-360)
112
+ - Uses `Effect.catchTags()` to handle expected errors gracefully
113
+ - Distinguishes between critical errors (index build) and optional operations (embeddings)
114
+ - Continues execution when embeddings fail, preserving main index functionality
115
+
116
+ 2. **Context-Aware Error Handling**
117
+ ```typescript
118
+ estimateEmbeddingCost(resolvedDir).pipe(
119
+ Effect.catchTags({
120
+ IndexNotFoundError: () => Effect.succeed(null),
121
+ FileReadError: (e) => {
122
+ Effect.runSync(Effect.logWarning(`Could not read index files: ${e.message}`))
123
+ return Effect.succeed(null)
124
+ },
125
+ // ... more error cases
126
+ }),
127
+ )
128
+ ```
129
+
130
+ 3. **User-Friendly Degradation**
131
+ - Shows informative messages when embeddings fail
132
+ - Doesn't crash the entire operation if optional features fail
133
+
134
+ #### Issues ⚠️
135
+
136
+ 1. **Inconsistent Process Exit** (Line 117) ✓ VALID
137
+ ```typescript
138
+ process.on('SIGINT', () => {
139
+ watcher.stop()
140
+ console.log('\nStopped watching.')
141
+ process.exit(0) // Direct exit instead of Effect-based termination
142
+ })
143
+ ```
144
+ - **Impact:** Bypasses Effect's cleanup and error handling
145
+ - **Recommendation:** Use Effect's interrupt mechanism
146
+
147
+ 2. **Effect.runSync in Error Handlers** (Lines 261-262, 268-269, 320, 324, 332-333, 337-338, 347-348, 354-355) ✓ VALID
148
+ ```typescript
149
+ Effect.runSync(Console.error(`\n${e.message}`))
150
+ ```
151
+ - **Issue:** Running effects synchronously within effect chains can cause issues
152
+ - **Impact:** Potential for unhandled errors if Console.error fails
153
+ - **Recommendation:** Return effect-wrapped logging operations
154
+
155
+ 3. **Duplicated Error Handling Code** (Lines 256-276 and 308-360) ✓ VALID
156
+ - Identical `Effect.catchTags()` blocks in two places
157
+ - **Impact:** Maintenance burden, potential for divergence
158
+ - **Recommendation:** Extract to reusable function
159
+
160
+ ### 2. search.ts
161
+
162
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/search.ts`
163
+
164
+ **Pattern:** **Mixed - Graceful Degradation for Missing Index, Propagation for Search Errors**
165
+
166
+ #### Good Practices ✅
167
+
168
+ 1. **Early Return for Missing Index** (Lines 134-140)
169
+ ```typescript
170
+ if (!indexInfo.exists && !json) {
171
+ yield* Console.log('No index found.')
172
+ yield* Console.log('')
173
+ yield* Console.log('Run: mdcontext index /path/to/docs')
174
+ yield* Console.log(' Add --embed for semantic search capabilities')
175
+ return
176
+ }
177
+ ```
178
+ - User-friendly message with clear next steps
179
+ - Graceful handling of expected "no index" state
180
+
181
+ 2. **Auto-Index Feature with Error Handling** (Lines 155-165, 359-580)
182
+ - Proactively creates semantic index if missing and under threshold
183
+ - Gracefully falls back to keyword search on embedding errors
184
+ - Good UX design
185
+
186
+ 3. **Helpful Tips** (Lines 310-314, 349)
187
+ - Contextual suggestions based on current state
188
+ - Educates users about available features
189
+
190
+ #### Issues ⚠️
191
+
192
+ 1. **Triple-Duplicated Error Handling** (Lines 368-386, 416-461, 513-559) ✓ VALID
193
+ - Same `Effect.catchTags()` block appears **three times** in `handleMissingEmbeddings()`
194
+ - **Impact:** High maintenance burden, 150+ lines of duplicated code
195
+ - **Recommendation:** Extract to shared utility function
196
+
197
+ 2. **Silent Error Suppression** (Lines 418-421) ✓ VALID
198
+ ```typescript
199
+ ApiKeyMissingError: (e) => {
200
+ if (!json) {
201
+ Effect.runSync(Console.error(`\n${e.message}`))
202
+ }
203
+ return Effect.succeed(null as BuildEmbeddingsResult | null)
204
+ }
205
+ ```
206
+ - Errors are logged but operation continues
207
+ - Users may miss critical configuration issues
208
+ - **Recommendation:** Consider accumulating errors and displaying summary
209
+
210
+ 3. **Inconsistent Error Propagation** ✓ VALID
211
+ - Semantic search errors propagate (Line 318: `yield* semanticSearch(...)`)
212
+ - Embedding errors are caught and suppressed
213
+ - **Impact:** Confusing for users - why do some operations fail hard, others silently?
214
+
215
+ ### 3. context.ts
216
+
217
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/context.ts`
218
+
219
+ **Pattern:** **Error Propagation to CLI Boundary**
220
+
221
+ #### Good Practices ✅
222
+
223
+ 1. **Clean Error Propagation**
224
+ - Most errors are allowed to propagate naturally
225
+ - Minimal local error handling
226
+ - Consistent with Effect's error handling philosophy
227
+
228
+ 2. **Explicit Validation** (Lines 74-82)
229
+ ```typescript
230
+ if (fileList.length === 0) {
231
+ yield* Effect.fail(
232
+ new CliValidationError({
233
+ message: 'At least one file is required. Usage: mdcontext context <file> [files...]',
234
+ argument: 'files',
235
+ }),
236
+ )
237
+ }
238
+ ```
239
+ - Uses typed errors for validation failures
240
+ - Clear, actionable error messages
241
+
242
+ 3. **Error Mapping** (Lines 93-105)
243
+ ```typescript
244
+ yield* parseFile(filePath).pipe(
245
+ Effect.mapError((e) =>
246
+ e._tag === 'ParseError'
247
+ ? new ParseError({ ... })
248
+ : new FileReadError({ ... })
249
+ ),
250
+ )
251
+ ```
252
+ - Properly maps internal errors to CLI error types
253
+ - Preserves error context (path, line, column)
254
+
255
+ #### Issues ⚠️
256
+
257
+ 1. **Continue on Error** (Line 161) 📍 MOVED (Still at line 161, verified)
258
+ ```typescript
259
+ if (extractedSections.length === 0) {
260
+ yield* Console.error(`No sections found matching "${sectionSelector}" in ${file}`)
261
+ yield* Console.error('Use --sections to list available sections.')
262
+ continue // Continues to next file instead of failing
263
+ }
264
+ ```
265
+ - **Issue:** Silently continues when section not found
266
+ - **Impact:** User may not notice if one of many files failed
267
+ - **Recommendation:** Collect errors and report summary, or fail fast
268
+
269
+ ### 4. tree.ts
270
+
271
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/tree.ts`
272
+
273
+ **Pattern:** **Error Propagation with Effect.try**
274
+
275
+ #### Good Practices ✅
276
+
277
+ 1. **Effect.try for File System Operations** (Lines 32-40)
278
+ ```typescript
279
+ const stat = yield* Effect.try({
280
+ try: () => fs.statSync(resolvedPath),
281
+ catch: (e) =>
282
+ new FileReadError({
283
+ path: resolvedPath,
284
+ message: `Cannot access path: ${e instanceof Error ? e.message : String(e)}`,
285
+ cause: e,
286
+ }),
287
+ })
288
+ ```
289
+ - Proper error wrapping with typed errors
290
+ - Preserves original error as cause
291
+ - Good error message construction
292
+
293
+ 2. **Consistent Error Mapping** (Lines 44-58)
294
+ - Same pattern as context.ts for parseFile errors
295
+ - Maps internal errors to CLI error types
296
+
297
+ #### Issues ⚠️
298
+
299
+ None identified. This is a good example of clean error handling.
300
+
301
+ ### 5. links.ts & backlinks.ts
302
+
303
+ **Location:**
304
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/links.ts`
305
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/backlinks.ts`
306
+
307
+ **Pattern:** **Pure Error Propagation**
308
+
309
+ #### Good Practices ✅
310
+
311
+ 1. **Minimal Error Handling**
312
+ - No try/catch blocks
313
+ - Errors propagate naturally
314
+ - Relies on centralized error handler
315
+
316
+ 2. **Clean Command Implementation**
317
+ - Simple, focused logic
318
+ - No defensive error handling
319
+ - Trusts underlying functions to return proper errors
320
+
321
+ #### Issues ⚠️
322
+
323
+ None identified. These are excellent examples of letting errors propagate.
324
+
325
+ ### 6. stats.ts
326
+
327
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/stats.ts`
328
+
329
+ **Pattern:** **Graceful Degradation for Missing Index**
330
+
331
+ #### Good Practices ✅
332
+
333
+ 1. **Null Check for Missing Index** (Lines 52-60)
334
+ ```typescript
335
+ if (!docIndex || !sectionIndex) {
336
+ if (json) {
337
+ yield* Console.log(formatJson({ error: 'No index found' }, pretty))
338
+ } else {
339
+ yield* Console.log('No index found.')
340
+ yield* Console.log("Run 'mdcontext index <path>' to create an index.")
341
+ }
342
+ return
343
+ }
344
+ ```
345
+ - Handles expected "no index" case gracefully
346
+ - Different output for JSON vs text mode
347
+ - Clear user guidance
348
+
349
+ #### Issues ⚠️
350
+
351
+ 1. **No Error Propagation from loadDocumentIndex** (Line 48)
352
+ ```typescript
353
+ const docIndex = yield* loadDocumentIndex(storage)
354
+ const sectionIndex = yield* loadSectionIndex(storage)
355
+ ```
356
+ - Assumes these functions return `null` on error
357
+ - **Issue:** If these functions throw different errors (corruption, permission issues), they won't be caught
358
+ - **Recommendation:** Verify these functions handle errors internally or add error handling
359
+
360
+ ### 7. config-cmd.ts
361
+
362
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/config-cmd.ts`
363
+
364
+ **Pattern:** **Mixed - Effect.try for File Operations, catchTag for Config Errors**
365
+
366
+ #### Good Practices ✅
367
+
368
+ 1. **Effect.try for File Operations** (Lines 249-252)
369
+ ```typescript
370
+ yield* Effect.try({
371
+ try: () => fs.writeFileSync(filepath, content, 'utf-8'),
372
+ catch: (e) => new Error(`Failed to write config file: ${e}`),
373
+ })
374
+ ```
375
+ - Wraps sync file operations properly
376
+ - Good error message
377
+
378
+ 2. **catchTag for Expected Errors** (Lines 527-531)
379
+ ```typescript
380
+ const configResult = yield* loadConfigFile(cwd).pipe(
381
+ Effect.catchTag('ConfigError', (e) => {
382
+ errors.push(e.message)
383
+ return Effect.succeed({ found: false, searched: [] } as const)
384
+ }),
385
+ )
386
+ ```
387
+ - Catches expected config errors
388
+ - Accumulates errors for reporting
389
+ - Graceful degradation
390
+
391
+ #### Issues ⚠️
392
+
393
+ None identified. Good example of mixing patterns appropriately.
394
+
395
+ ---
396
+
397
+ ## Cross-Cutting Concerns
398
+
399
+ ### 1. Process Exit Calls ✓ VALID
400
+
401
+ **Issue:** Direct `process.exit()` calls bypass Effect's cleanup mechanism
402
+
403
+ **Locations:** (All verified as of commit 07c9e72)
404
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/main.ts` (Lines 98, 128, 138, 150, 154, 181, 193, 319)
405
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/commands/index-cmd.ts` (Line 117)
406
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/help.ts` (Lines 291, 404, 427)
407
+ - `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/argv-preprocessor.ts` (Line 93)
408
+
409
+ **Impact:**
410
+ - Resource cleanup may not execute
411
+ - Effect finalizers are bypassed
412
+ - Potential for leaked resources (file handles, network connections)
413
+
414
+ **Recommendation:**
415
+ ```typescript
416
+ // Instead of:
417
+ process.exit(1)
418
+
419
+ // Use Effect-based failure:
420
+ yield* Effect.fail(new CliValidationError({ message: '...' }))
421
+
422
+ // Or for success:
423
+ yield* Effect.succeed(void 0)
424
+ ```
425
+
426
+ ### 2. Effect.runSync in Error Handlers ✓ VALID
427
+
428
+ **Issue:** Running effects synchronously within effect chains
429
+
430
+ **Pattern:**
431
+ ```typescript
432
+ ApiKeyMissingError: (e) => {
433
+ Effect.runSync(Console.error(`\n${e.message}`))
434
+ return Effect.succeed(null)
435
+ }
436
+ ```
437
+
438
+ **Locations:** (All verified as of commit 07c9e72)
439
+ - `index-cmd.ts`: Lines 261-262, 268-269, 320, 324, 332-333, 337-338, 347-348, 354-355
440
+ - `search.ts`: Lines 373-374, 418-419, 424-425, 433-434, 440-441, 448-449, 454-455
441
+
442
+ **Impact:**
443
+ - Potential for unhandled errors if Console.error fails
444
+ - Breaks Effect's composition model
445
+ - Can't be tested or mocked easily
446
+
447
+ **Recommendation:**
448
+ ```typescript
449
+ // Instead of Effect.runSync:
450
+ ApiKeyMissingError: (e) =>
451
+ Console.error(`\n${e.message}`).pipe(
452
+ Effect.flatMap(() => Effect.succeed(null))
453
+ )
454
+ ```
455
+
456
+ ### 3. Duplicated Error Handling Code ✓ VALID
457
+
458
+ **Issue:** Same error handling blocks repeated multiple times
459
+
460
+ **Examples:** (All verified as of commit 07c9e72)
461
+ 1. **search.ts**: `handleMissingEmbeddings()` has identical catchTags blocks 3 times at lines 368-386, 416-461, 513-559 (150+ lines)
462
+ 2. **index-cmd.ts**: Embedding error handling duplicated 2 times at lines 256-276 and 308-360 (100+ lines)
463
+
464
+ **Impact:**
465
+ - Maintenance burden
466
+ - Risk of bugs when updating one instance but not others
467
+ - Code bloat
468
+
469
+ **Recommendation:**
470
+ ```typescript
471
+ // Extract shared error handler:
472
+ const handleEmbeddingErrors = (json: boolean) => ({
473
+ ApiKeyMissingError: (e: ApiKeyMissingError) =>
474
+ Console.error(`\n${e.message}`).pipe(
475
+ Effect.when(() => !json),
476
+ Effect.flatMap(() => Effect.succeed(null as BuildEmbeddingsResult | null))
477
+ ),
478
+ // ... other error handlers
479
+ })
480
+
481
+ // Use it:
482
+ buildEmbeddings(resolvedDir, { ... }).pipe(
483
+ Effect.catchTags(handleEmbeddingErrors(json))
484
+ )
485
+ ```
486
+
487
+ ### 4. Legacy Error Handling ✓ VALID
488
+
489
+ **Location:** `/Users/alphab/Dev/LLM/DEV/mdcontext/worktrees/nancy-ALP-139/src/cli/error-handler.ts` (Lines 446-491)
490
+
491
+ **Issue:** Code for handling @effect/cli validation errors (Verified at commit 07c9e72)
492
+
493
+ ```typescript
494
+ export const isEffectCliValidationError = (error: unknown): boolean => {
495
+ // ... legacy error checking
496
+ }
497
+ ```
498
+
499
+ **Impact:**
500
+ - Technical debt
501
+ - Suggests migration in progress
502
+ - Code complexity
503
+
504
+ **Recommendation:**
505
+ - If migration to custom error types is complete, remove this code
506
+ - If still needed, add comment explaining why
507
+ - Consider deprecation timeline
508
+
509
+ ### 5. Inconsistent Error Messages ✓ VALID
510
+
511
+ **Issue:** Some commands use console.error directly, others use Console.error
512
+
513
+ **Examples:**
514
+ ```typescript
515
+ // Direct console usage (bypasses Effect)
516
+ console.error(`Watch error: ${error.message}`) // index-cmd.ts:109
517
+
518
+ // Effect-based (proper)
519
+ yield* Console.error('No index found.') // stats.ts:56
520
+ ```
521
+
522
+ **Impact:**
523
+ - Inconsistent error output
524
+ - Can't intercept/test direct console calls
525
+ - Mixed paradigms
526
+
527
+ **Recommendation:** Always use Effect's Console for consistency
528
+
529
+ ---
530
+
531
+ ## Error Message Quality
532
+
533
+ ### Good Examples ✅
534
+
535
+ 1. **Actionable Suggestions**
536
+ ```typescript
537
+ suggestions: [
538
+ "Run 'mdcontext index' first to build the index",
539
+ ]
540
+ ```
541
+
542
+ 2. **Context-Rich Messages**
543
+ ```typescript
544
+ message: `Cannot read file: ${e.path}`,
545
+ details: e.message, // Technical details
546
+ suggestions: [
547
+ 'Check that the file exists',
548
+ 'Check file permissions',
549
+ ]
550
+ ```
551
+
552
+ 3. **Progressive Disclosure**
553
+ - Brief message for common cases
554
+ - Details available with --debug flag
555
+
556
+ ### Areas for Improvement ⚠️
557
+
558
+ 1. **Vague Error Messages** (stats.ts:54)
559
+ ```typescript
560
+ yield* Console.log(formatJson({ error: 'No index found' }, pretty))
561
+ ```
562
+ - **Issue:** Generic message, no path information
563
+ - **Better:** `{ error: 'No index found', path: resolvedRoot, suggestion: 'Run mdcontext index' }`
564
+
565
+ 2. **Missing Error Codes in Some Messages**
566
+ - Some errors logged without error codes
567
+ - Inconsistent with centralized error handler
568
+
569
+ ---
570
+
571
+ ## Exit Code Correctness
572
+
573
+ ### ✅ Correct Usage
574
+
575
+ **Centralized Exit Codes** (error-handler.ts:45-52)
576
+ ```typescript
577
+ export const EXIT_CODE = {
578
+ SUCCESS: 0, // Successful operation
579
+ USER_ERROR: 1, // Invalid arguments, missing config
580
+ SYSTEM_ERROR: 2, // File system, network errors
581
+ API_ERROR: 3, // Authentication, rate limits
582
+ } as const
583
+ ```
584
+
585
+ **Proper Mapping:**
586
+ - File system errors → SYSTEM_ERROR (2)
587
+ - API key errors → API_ERROR (3)
588
+ - Validation errors → USER_ERROR (1)
589
+
590
+ ### ⚠️ Issues
591
+
592
+ 1. **Direct Exit Calls Without Proper Codes**
593
+ ```typescript
594
+ process.exit(0) // OK for success
595
+ process.exit(1) // Generic error, loses context
596
+ ```
597
+ - Should use centralized exit code constants
598
+ - Should route through error handler
599
+
600
+ 2. **Main.ts Exit Strategy** (Lines 291-302)
601
+ ```typescript
602
+ Effect.catchAll((error) =>
603
+ Effect.sync(() => {
604
+ if (isEffectCliValidationError(error)) {
605
+ const message = formatEffectCliError(error)
606
+ console.error(`\nError: ${message}`)
607
+ console.error('\nRun "mdcontext --help" for usage information.')
608
+ process.exit(1) // Always exit 1 for validation errors
609
+ }
610
+ throw error // Re-throw for other errors
611
+ }),
612
+ )
613
+ ```
614
+ - **Issue:** Hardcoded exit code 1
615
+ - **Better:** Map to EXIT_CODE.USER_ERROR for clarity
616
+
617
+ ---
618
+
619
+ ## Unhandled Promise Rejections
620
+
621
+ ### ✅ Good Practices
622
+
623
+ All async operations are properly wrapped in Effect:
624
+ - `Effect.promise()` for user prompts (index-cmd.ts:286, search.ts:492)
625
+ - `Effect.try()` for file operations (tree.ts:32, config-cmd.ts:249)
626
+ - No naked promises in command handlers
627
+
628
+ ### ⚠️ Potential Issues
629
+
630
+ 1. **SIGINT Handler** (index-cmd.ts:113-119)
631
+ ```typescript
632
+ yield* Effect.async<never, never>(() => {
633
+ process.on('SIGINT', () => {
634
+ watcher.stop()
635
+ console.log('\nStopped watching.')
636
+ process.exit(0)
637
+ })
638
+ })
639
+ ```
640
+ - **Issue:** If `watcher.stop()` throws, it won't be caught
641
+ - **Recommendation:** Wrap in try/catch or Effect.try
642
+
643
+ 2. **Dynamic Import in main.ts** (Lines 309-320)
644
+ ```typescript
645
+ (async () => {
646
+ try {
647
+ const configLayer = await loadConfigAsync(customConfigPath!)
648
+ runCli(configLayer)
649
+ } catch (error) {
650
+ console.error(`\nError: Failed to load config`)
651
+ if (error instanceof Error) {
652
+ console.error(` ${error.message}`)
653
+ }
654
+ process.exit(1)
655
+ }
656
+ })()
657
+ ```
658
+ - **Issue:** IIFE async function - rejection not attached to process
659
+ - **Better:** Add `.catch()` or use top-level await
660
+
661
+ ---
662
+
663
+ ## Pattern Recommendations
664
+
665
+ ### Ideal Error Handling Pattern for This Codebase
666
+
667
+ Based on the analysis, here's the recommended pattern:
668
+
669
+ ```typescript
670
+ /**
671
+ * Recommended Error Handling Pattern for mdcontext CLI Commands
672
+ */
673
+
674
+ // 1. Let critical errors propagate to CLI boundary
675
+ // The centralized error handler will format and display them
676
+ export const myCommand = Command.make('my-command', options, (args) =>
677
+ Effect.gen(function* () {
678
+ // Critical operation - let errors propagate
679
+ const result = yield* criticalOperation(args)
680
+
681
+ // ... use result
682
+ })
683
+ )
684
+
685
+ // 2. For optional operations, use graceful degradation
686
+ export const myCommandWithOptional = Command.make('my-command', options, (args) =>
687
+ Effect.gen(function* () {
688
+ // Critical operation
689
+ const result = yield* criticalOperation(args)
690
+
691
+ // Optional operation - catch and continue
692
+ const optional = yield* optionalOperation(args).pipe(
693
+ Effect.catchTags({
694
+ ExpectedError: (e) =>
695
+ Console.log(`Note: ${e.message}`).pipe(
696
+ Effect.map(() => null)
697
+ )
698
+ })
699
+ )
700
+
701
+ // Use both results
702
+ displayResults(result, optional)
703
+ })
704
+ )
705
+
706
+ // 3. For batch operations, accumulate errors
707
+ export const myBatchCommand = Command.make('my-command', options, (args) =>
708
+ Effect.gen(function* () {
709
+ const errors: Error[] = []
710
+ const results: Result[] = []
711
+
712
+ for (const item of args.items) {
713
+ const result = yield* processItem(item).pipe(
714
+ Effect.catchAll((e) =>
715
+ Effect.sync(() => {
716
+ errors.push(e)
717
+ return null
718
+ })
719
+ )
720
+ )
721
+ if (result) results.push(result)
722
+ }
723
+
724
+ // Report summary
725
+ if (errors.length > 0) {
726
+ yield* Console.log(`Completed with ${errors.length} errors:`)
727
+ for (const error of errors) {
728
+ yield* Console.error(` - ${error.message}`)
729
+ }
730
+ }
731
+
732
+ return results
733
+ })
734
+ )
735
+
736
+ // 4. Extract shared error handlers for reuse
737
+ const createEmbeddingErrorHandler = (json: boolean) => ({
738
+ ApiKeyMissingError: (e: ApiKeyMissingError) =>
739
+ Console.error(e.message).pipe(
740
+ Effect.when(() => !json),
741
+ Effect.map(() => null as BuildEmbeddingsResult | null)
742
+ ),
743
+
744
+ ApiKeyInvalidError: (e: ApiKeyInvalidError) =>
745
+ Console.error(e.message).pipe(
746
+ Effect.when(() => !json),
747
+ Effect.map(() => null as BuildEmbeddingsResult | null)
748
+ ),
749
+
750
+ // ... other handlers
751
+ })
752
+
753
+ // Use shared handler
754
+ buildEmbeddings(path, options).pipe(
755
+ Effect.catchTags(createEmbeddingErrorHandler(json))
756
+ )
757
+
758
+ // 5. Use Effect.try for all external/sync operations
759
+ const stat = yield* Effect.try({
760
+ try: () => fs.statSync(path),
761
+ catch: (e) => new FileReadError({
762
+ path,
763
+ message: e instanceof Error ? e.message : String(e),
764
+ cause: e,
765
+ })
766
+ })
767
+
768
+ // 6. Map errors to domain types
769
+ const document = yield* parseFile(path).pipe(
770
+ Effect.mapError((e) =>
771
+ e._tag === 'ParseError'
772
+ ? new ParseError({ message: e.message, path, line: e.line })
773
+ : new FileReadError({ path: e.path, message: e.message })
774
+ )
775
+ )
776
+
777
+ // 7. Never use process.exit() in command handlers
778
+ // Instead, fail with typed errors:
779
+ yield* Effect.fail(
780
+ new CliValidationError({
781
+ message: 'Invalid argument',
782
+ argument: 'path',
783
+ expected: 'directory',
784
+ received: typeof args.path,
785
+ })
786
+ )
787
+ ```
788
+
789
+ ### Anti-Patterns to Avoid
790
+
791
+ ```typescript
792
+ // ❌ DON'T: Use process.exit() in command handlers
793
+ process.exit(1)
794
+
795
+ // ✅ DO: Fail with typed errors
796
+ yield* Effect.fail(new CliValidationError({ message: '...' }))
797
+
798
+ // ❌ DON'T: Use Effect.runSync in error handlers
799
+ Effect.runSync(Console.error('message'))
800
+
801
+ // ✅ DO: Return effect-wrapped operations
802
+ Console.error('message').pipe(Effect.map(() => null))
803
+
804
+ // ❌ DON'T: Catch errors and silently continue without logging
805
+ .pipe(Effect.catchAll(() => Effect.succeed(null)))
806
+
807
+ // ✅ DO: Log before continuing
808
+ .pipe(
809
+ Effect.catchAll((e) =>
810
+ Console.log(`Note: Operation failed: ${e.message}`).pipe(
811
+ Effect.map(() => null)
812
+ )
813
+ )
814
+ )
815
+
816
+ // ❌ DON'T: Duplicate error handling code
817
+ // (see index-cmd.ts and search.ts for examples)
818
+
819
+ // ✅ DO: Extract to shared functions
820
+ const handleEmbeddingErrors = createEmbeddingErrorHandler(json)
821
+
822
+ // ❌ DON'T: Mix paradigms
823
+ console.error('error') // Direct console
824
+ yield* Console.error('error') // Effect-based
825
+
826
+ // ✅ DO: Use Effect consistently
827
+ yield* Console.error('error')
828
+ ```
829
+
830
+ ---
831
+
832
+ ## Specific Issues with File Paths and Line Numbers
833
+
834
+ ### Critical Issues
835
+
836
+ 1. **index-cmd.ts:117** - Direct process.exit in SIGINT handler
837
+ - Priority: Medium
838
+ - Fix: Use Effect interrupt mechanism
839
+
840
+ 2. **index-cmd.ts:262, 269, 320, etc.** - Effect.runSync in error handlers (15 occurrences)
841
+ - Priority: High
842
+ - Fix: Replace with Effect.flatMap chains
843
+
844
+ 3. **search.ts:368-580** - Triple-duplicated error handling (150+ lines)
845
+ - Priority: High
846
+ - Fix: Extract to shared function
847
+
848
+ 4. **main.ts:163, 175, 196, 297, 318** - Multiple process.exit calls
849
+ - Priority: Medium
850
+ - Fix: Route through error handler or use typed errors
851
+
852
+ ### Medium Priority Issues
853
+
854
+ 5. **context.ts:161** - Silent continue on section not found
855
+ - Priority: Medium
856
+ - Fix: Accumulate errors and report summary
857
+
858
+ 6. **stats.ts:48** - No error handling for loadDocumentIndex
859
+ - Priority: Medium
860
+ - Fix: Add catchTag or verify function handles errors internally
861
+
862
+ 7. **error-handler.ts:453-491** - Legacy error handling code
863
+ - Priority: Low
864
+ - Fix: Add deprecation comment or remove if no longer needed
865
+
866
+ ### Low Priority Issues
867
+
868
+ 8. **All commands** - Inconsistent use of console.error vs Console.error
869
+ - Priority: Low
870
+ - Fix: Standardize on Effect's Console
871
+
872
+ 9. **main.ts:309** - IIFE async without top-level await
873
+ - Priority: Low
874
+ - Fix: Add .catch() handler or use top-level await (Node 14.8+)
875
+
876
+ ---
877
+
878
+ ## Testing Recommendations
879
+
880
+ 1. **Error Path Testing**
881
+ - Add tests for each error type in each command
882
+ - Verify correct exit codes
883
+ - Test error message formatting
884
+
885
+ 2. **Error Handler Testing**
886
+ - Unit tests for formatError()
887
+ - Verify all error tags are handled
888
+ - Test debug mode output
889
+
890
+ 3. **Integration Tests**
891
+ - Test full error flow from command to exit
892
+ - Verify cleanup on errors
893
+ - Test interrupt handling
894
+
895
+ 4. **Example Test Structure**
896
+ ```typescript
897
+ describe('index command error handling', () => {
898
+ it('should exit with code 1 when index not found', async () => {
899
+ const result = await runCommand(['index', '/nonexistent'])
900
+ expect(result.exitCode).toBe(EXIT_CODE.USER_ERROR)
901
+ expect(result.stderr).toContain('Index not found')
902
+ })
903
+
904
+ it('should exit with code 2 on file system error', async () => {
905
+ const result = await runCommand(['index', '/no-permission'])
906
+ expect(result.exitCode).toBe(EXIT_CODE.SYSTEM_ERROR)
907
+ expect(result.stderr).toContain('permissions')
908
+ })
909
+ })
910
+ ```
911
+
912
+ ---
913
+
914
+ ## Migration Path
915
+
916
+ ### Phase 1: Quick Wins (1-2 days)
917
+
918
+ 1. Extract duplicated error handlers to shared functions
919
+ - `createEmbeddingErrorHandler()` in shared utilities
920
+ - Reduces 250+ lines of duplication
921
+
922
+ 2. Replace Effect.runSync with proper Effect chains
923
+ - Search and replace pattern
924
+ - Low risk, high value
925
+
926
+ 3. Document legacy error handling
927
+ - Add comments explaining migration status
928
+ - Set deprecation timeline
929
+
930
+ ### Phase 2: Consistency Improvements (2-3 days)
931
+
932
+ 1. Standardize on Effect's Console throughout
933
+ - Replace all console.error with Console.error
934
+ - Consistent error output
935
+
936
+ 2. Remove direct process.exit() calls
937
+ - Replace with typed errors where possible
938
+ - Use Effect.interrupt for signal handling
939
+
940
+ 3. Add error accumulation to batch operations
941
+ - context command with multiple files
942
+ - Better user feedback
943
+
944
+ ### Phase 3: Structural Improvements (3-5 days)
945
+
946
+ 1. Refactor error handling strategy
947
+ - Document when to catch vs propagate
948
+ - Add guidelines to contributing docs
949
+
950
+ 2. Improve error messages
951
+ - Add context to generic errors
952
+ - Ensure all errors have actionable suggestions
953
+
954
+ 3. Add comprehensive error tests
955
+ - Cover all error types
956
+ - Verify exit codes
957
+ - Test error message formatting
958
+
959
+ ---
960
+
961
+ ## Conclusion
962
+
963
+ The mdcontext CLI has a **solid foundation** for error handling with its centralized error handler and typed error system. The main issues are:
964
+
965
+ 1. **Inconsistent application** of error handling patterns across commands
966
+ 2. **Code duplication** in error handlers (250+ lines)
967
+ 3. **Mixed paradigms** (Effect vs direct console/process.exit)
968
+ 4. **Graceful degradation without proper logging** in some commands
969
+
970
+ Addressing these issues will result in a **more maintainable, consistent, and user-friendly** CLI with clear error messages and proper exit codes.
971
+
972
+ **Recommended Priority:**
973
+ 1. Extract duplicated error handlers (high impact, low effort)
974
+ 2. Replace Effect.runSync calls (high impact, medium effort)
975
+ 3. Document error handling strategy (medium impact, low effort)
976
+ 4. Remove process.exit() calls (medium impact, medium effort)
977
+ 5. Add error tests (high value, high effort)
978
+
979
+ Total estimated effort: **1-2 weeks** for complete implementation with tests.