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.
- package/.changeset/config.json +9 -9
- package/.claude/settings.local.json +25 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +85 -0
- package/CONTRIBUTING.md +186 -0
- package/NOTES/NOTES +44 -0
- package/README.md +206 -3
- package/biome.json +1 -1
- package/dist/chunk-23UPXDNL.js +3044 -0
- package/dist/chunk-2W7MO2DL.js +1366 -0
- package/dist/chunk-3NUAZGMA.js +1689 -0
- package/dist/chunk-7TOWB2XB.js +366 -0
- package/dist/chunk-7XOTOADQ.js +3065 -0
- package/dist/chunk-AH2PDM2K.js +3042 -0
- package/dist/chunk-BNXWSZ63.js +3742 -0
- package/dist/chunk-BTL5DJVU.js +3222 -0
- package/dist/chunk-HDHYG7E4.js +104 -0
- package/dist/chunk-HLR4KZBP.js +3234 -0
- package/dist/chunk-IP3FRFEB.js +1045 -0
- package/dist/chunk-KHU56VDO.js +3042 -0
- package/dist/chunk-KRYIFLQR.js +85 -89
- package/dist/chunk-LBSDNLEM.js +287 -0
- package/dist/chunk-MNTQ7HCP.js +2643 -0
- package/dist/chunk-MUJELQQ6.js +1387 -0
- package/dist/chunk-MXJGMSLV.js +2199 -0
- package/dist/chunk-N6QJGC3Z.js +2636 -0
- package/dist/chunk-OBELGBPM.js +1713 -0
- package/dist/chunk-OT7R5XTA.js +3192 -0
- package/dist/chunk-P7X4RA2T.js +106 -0
- package/dist/chunk-PIDUQNC2.js +3185 -0
- package/dist/chunk-POGCDIH4.js +3187 -0
- package/dist/chunk-PSIEOQGZ.js +3043 -0
- package/dist/chunk-PVRT3IHA.js +3238 -0
- package/dist/chunk-QNN4TT23.js +1430 -0
- package/dist/chunk-RE3R45RJ.js +3042 -0
- package/dist/chunk-S7E6TFX6.js +718 -657
- package/dist/chunk-SG6GLU4U.js +1378 -0
- package/dist/chunk-SJCDV2ST.js +274 -0
- package/dist/chunk-SYE5XLF3.js +104 -0
- package/dist/chunk-T5VLYBZD.js +103 -0
- package/dist/chunk-TOQB7VWU.js +3238 -0
- package/dist/chunk-VFNMZ4ZQ.js +3228 -0
- package/dist/chunk-VVTGZNBT.js +1533 -1423
- package/dist/chunk-W7Q4RFEV.js +104 -0
- package/dist/chunk-XTYYVRLO.js +3190 -0
- package/dist/chunk-Y6MDYVJD.js +3063 -0
- package/dist/cli/main.js +4072 -629
- package/dist/index.d.ts +420 -33
- package/dist/index.js +8 -15
- package/dist/mcp/server.js +103 -7
- package/dist/schema-BAWSG7KY.js +22 -0
- package/dist/schema-E3QUPL26.js +20 -0
- package/dist/schema-EHL7WUT6.js +20 -0
- package/docs/019-USAGE.md +44 -5
- package/docs/020-current-implementation.md +8 -8
- package/docs/021-DOGFOODING-FINDINGS.md +1 -1
- package/docs/CONFIG.md +1123 -0
- package/docs/ERRORS.md +383 -0
- package/docs/summarization.md +320 -0
- package/justfile +40 -0
- package/package.json +39 -33
- package/research/INDEX.md +315 -0
- package/research/code-review/README.md +90 -0
- package/research/code-review/cli-error-handling-review.md +979 -0
- package/research/code-review/code-review-validation-report.md +464 -0
- package/research/code-review/main-ts-review.md +1128 -0
- package/research/config-docs/SUMMARY.md +357 -0
- package/research/config-docs/TEST-RESULTS.md +776 -0
- package/research/config-docs/TODO.md +542 -0
- package/research/config-docs/analysis.md +744 -0
- package/research/config-docs/fix-validation.md +502 -0
- package/research/config-docs/help-audit.md +264 -0
- package/research/config-docs/help-system-analysis.md +890 -0
- package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
- package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
- package/research/issue-review.md +603 -0
- package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
- package/research/llm-summarization/alternative-providers-2026.md +1428 -0
- package/research/llm-summarization/anthropic-2026.md +367 -0
- package/research/llm-summarization/claude-cli-integration.md +1706 -0
- package/research/llm-summarization/cli-integration-patterns.md +3155 -0
- package/research/llm-summarization/openai-2026.md +473 -0
- package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
- package/research/llm-summarization/opencode-cli-integration.md +1552 -0
- package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
- package/research/llm-summarization/prototype-results.md +56 -0
- package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
- package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
- package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
- package/research/mdcontext-pudding/01-index-embed.md +956 -0
- package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
- package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
- package/research/mdcontext-pudding/02-search.md +970 -0
- package/research/mdcontext-pudding/03-context.md +779 -0
- package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
- package/research/mdcontext-pudding/04-tree.md +704 -0
- package/research/mdcontext-pudding/05-config.md +1038 -0
- package/research/mdcontext-pudding/06-links-summary.txt +87 -0
- package/research/mdcontext-pudding/06-links.md +679 -0
- package/research/mdcontext-pudding/07-stats.md +693 -0
- package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
- package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
- package/research/mdcontext-pudding/README.md +168 -0
- package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
- package/research/research-quality-review.md +834 -0
- package/research/semantic-search/embedding-text-analysis.md +156 -0
- package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
- package/research/semantic-search/query-processing-analysis.md +207 -0
- package/research/semantic-search/root-cause-and-solution.md +114 -0
- package/research/semantic-search/threshold-validation-report.md +69 -0
- package/research/semantic-search/vector-search-analysis.md +63 -0
- package/research/test-path-issues.md +276 -0
- package/review/ALP-76/1-error-type-design.md +962 -0
- package/review/ALP-76/2-error-handling-patterns.md +906 -0
- package/review/ALP-76/3-error-presentation.md +624 -0
- package/review/ALP-76/4-test-coverage.md +625 -0
- package/review/ALP-76/5-migration-completeness.md +440 -0
- package/review/ALP-76/6-effect-best-practices.md +755 -0
- package/scripts/apply-branch-protection.sh +47 -0
- package/scripts/branch-protection-templates.json +79 -0
- package/scripts/prototype-summarization.ts +346 -0
- package/scripts/rebuild-hnswlib.js +32 -37
- package/scripts/setup-branch-protection.sh +64 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
- package/src/cli/argv-preprocessor.test.ts +2 -2
- package/src/cli/cli.test.ts +230 -33
- package/src/cli/commands/config-cmd.ts +642 -0
- package/src/cli/commands/context.ts +97 -9
- package/src/cli/commands/duplicates.ts +122 -0
- package/src/cli/commands/embeddings.ts +529 -0
- package/src/cli/commands/index-cmd.ts +210 -30
- package/src/cli/commands/index.ts +3 -0
- package/src/cli/commands/search.ts +894 -64
- package/src/cli/commands/stats.ts +3 -0
- package/src/cli/commands/tree.ts +26 -5
- package/src/cli/config-layer.ts +176 -0
- package/src/cli/error-handler.test.ts +235 -0
- package/src/cli/error-handler.ts +655 -0
- package/src/cli/flag-schemas.ts +66 -0
- package/src/cli/help.ts +209 -7
- package/src/cli/main.ts +348 -58
- package/src/cli/options.ts +10 -0
- package/src/cli/shared-error-handling.ts +199 -0
- package/src/cli/utils.ts +150 -17
- package/src/config/file-provider.test.ts +320 -0
- package/src/config/file-provider.ts +273 -0
- package/src/config/index.ts +72 -0
- package/src/config/integration.test.ts +667 -0
- package/src/config/precedence.test.ts +277 -0
- package/src/config/precedence.ts +451 -0
- package/src/config/schema.test.ts +414 -0
- package/src/config/schema.ts +603 -0
- package/src/config/service.test.ts +320 -0
- package/src/config/service.ts +243 -0
- package/src/config/testing.test.ts +264 -0
- package/src/config/testing.ts +110 -0
- package/src/core/types.ts +6 -33
- package/src/duplicates/detector.test.ts +183 -0
- package/src/duplicates/detector.ts +414 -0
- package/src/duplicates/index.ts +18 -0
- package/src/embeddings/embedding-namespace.test.ts +300 -0
- package/src/embeddings/embedding-namespace.ts +947 -0
- package/src/embeddings/heading-boost.test.ts +222 -0
- package/src/embeddings/hnsw-build-options.test.ts +198 -0
- package/src/embeddings/hyde.test.ts +272 -0
- package/src/embeddings/hyde.ts +264 -0
- package/src/embeddings/index.ts +2 -0
- package/src/embeddings/openai-provider.ts +332 -83
- package/src/embeddings/pricing.json +22 -0
- package/src/embeddings/provider-constants.ts +204 -0
- package/src/embeddings/provider-errors.test.ts +967 -0
- package/src/embeddings/provider-errors.ts +565 -0
- package/src/embeddings/provider-factory.test.ts +240 -0
- package/src/embeddings/provider-factory.ts +225 -0
- package/src/embeddings/provider-integration.test.ts +788 -0
- package/src/embeddings/query-preprocessing.test.ts +187 -0
- package/src/embeddings/semantic-search-threshold.test.ts +508 -0
- package/src/embeddings/semantic-search.ts +780 -93
- package/src/embeddings/types.ts +293 -16
- package/src/embeddings/vector-store.ts +486 -77
- package/src/embeddings/voyage-provider.ts +313 -0
- package/src/errors/errors.test.ts +845 -0
- package/src/errors/index.ts +533 -0
- package/src/index/ignore-patterns.test.ts +354 -0
- package/src/index/ignore-patterns.ts +305 -0
- package/src/index/indexer.ts +286 -48
- package/src/index/storage.ts +94 -30
- package/src/index/types.ts +40 -2
- package/src/index/watcher.ts +67 -9
- package/src/index.ts +22 -0
- package/src/integration/search-keyword.test.ts +678 -0
- package/src/mcp/server.ts +135 -6
- package/src/parser/parser.ts +18 -19
- package/src/parser/section-filter.test.ts +277 -0
- package/src/parser/section-filter.ts +125 -3
- package/src/search/__tests__/hybrid-search.test.ts +650 -0
- package/src/search/bm25-store.ts +366 -0
- package/src/search/cross-encoder.test.ts +253 -0
- package/src/search/cross-encoder.ts +406 -0
- package/src/search/fuzzy-search.test.ts +419 -0
- package/src/search/fuzzy-search.ts +273 -0
- package/src/search/hybrid-search.ts +448 -0
- package/src/search/path-matcher.test.ts +276 -0
- package/src/search/path-matcher.ts +33 -0
- package/src/search/searcher.test.ts +99 -1
- package/src/search/searcher.ts +189 -67
- package/src/search/wink-bm25.d.ts +30 -0
- package/src/summarization/cli-providers/claude.ts +202 -0
- package/src/summarization/cli-providers/detection.test.ts +273 -0
- package/src/summarization/cli-providers/detection.ts +118 -0
- package/src/summarization/cli-providers/index.ts +8 -0
- package/src/summarization/cost.test.ts +139 -0
- package/src/summarization/cost.ts +102 -0
- package/src/summarization/error-handler.test.ts +127 -0
- package/src/summarization/error-handler.ts +111 -0
- package/src/summarization/index.ts +102 -0
- package/src/summarization/pipeline.test.ts +498 -0
- package/src/summarization/pipeline.ts +231 -0
- package/src/summarization/prompts.test.ts +269 -0
- package/src/summarization/prompts.ts +133 -0
- package/src/summarization/provider-factory.test.ts +396 -0
- package/src/summarization/provider-factory.ts +178 -0
- package/src/summarization/types.ts +184 -0
- package/src/summarize/summarizer.ts +104 -35
- package/src/types/huggingface-transformers.d.ts +66 -0
- package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/indexes/documents.json +4 -4
- package/tests/fixtures/cli/.mdcontext/indexes/sections.json +14 -0
- package/tests/integration/embed-index.test.ts +712 -0
- package/tests/integration/search-context.test.ts +469 -0
- package/tests/integration/search-semantic.test.ts +522 -0
- package/vitest.config.ts +1 -6
- package/AGENTS.md +0 -46
- package/tests/fixtures/cli/.mdcontext/vectors.bin +0 -0
- 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.
|