mdcontext 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/README.md +28 -0
- package/.changeset/config.json +11 -0
- package/.claude/settings.local.json +25 -0
- package/.github/workflows/ci.yml +83 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +85 -0
- package/.github/workflows/release.yml +113 -0
- package/.tldrignore +112 -0
- package/BACKLOG.md +338 -0
- package/CONTRIBUTING.md +186 -0
- package/NOTES/NOTES +44 -0
- package/README.md +434 -11
- package/biome.json +36 -0
- package/cspell.config.yaml +14 -0
- 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 +88 -0
- 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 +803 -0
- 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 +1629 -0
- 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.d.ts +1 -0
- package/dist/cli/main.js +5458 -0
- package/dist/index.d.ts +653 -0
- package/dist/index.js +79 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +472 -0
- 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 +625 -0
- package/docs/020-current-implementation.md +364 -0
- package/docs/021-DOGFOODING-FINDINGS.md +175 -0
- package/docs/BACKLOG.md +80 -0
- package/docs/CONFIG.md +1123 -0
- package/docs/DESIGN.md +439 -0
- package/docs/ERRORS.md +383 -0
- package/docs/PROJECT.md +88 -0
- package/docs/ROADMAP.md +407 -0
- package/docs/summarization.md +320 -0
- package/docs/test-links.md +9 -0
- package/justfile +40 -0
- package/package.json +74 -9
- package/pnpm-workspace.yaml +5 -0
- 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-analysis/01-current-implementation.md +470 -0
- package/research/config-analysis/02-strategy-recommendation.md +428 -0
- package/research/config-analysis/03-task-candidates.md +715 -0
- package/research/config-analysis/033-research-configuration-management.md +828 -0
- package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
- package/research/config-analysis/04-consolidated-task-candidates.md +277 -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/dogfood/consolidated-tool-evaluation.md +373 -0
- package/research/dogfood/strategy-a/a-synthesis.md +184 -0
- package/research/dogfood/strategy-a/a1-docs.md +226 -0
- package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
- package/research/dogfood/strategy-a/a3-llm.md +164 -0
- package/research/dogfood/strategy-b/b-synthesis.md +228 -0
- package/research/dogfood/strategy-b/b1-architecture.md +207 -0
- package/research/dogfood/strategy-b/b2-gaps.md +258 -0
- package/research/dogfood/strategy-b/b3-workflows.md +250 -0
- package/research/dogfood/strategy-c/c-synthesis.md +451 -0
- package/research/dogfood/strategy-c/c1-explorer.md +192 -0
- package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
- package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
- package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
- package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
- package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
- package/research/effect-cli-error-handling.md +845 -0
- package/research/effect-errors-as-values.md +943 -0
- package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
- package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
- package/research/errors-task-analysis/embeddings-analysis.md +709 -0
- package/research/errors-task-analysis/index-search-analysis.md +812 -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-error-analysis.md +521 -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/npm_publish/011-npm-workflow-research-agent2.md +792 -0
- package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
- package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
- package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
- package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
- package/research/research-quality-review.md +834 -0
- package/research/semantic-search/002-research-embedding-models.md +490 -0
- package/research/semantic-search/003-research-rag-alternatives.md +523 -0
- package/research/semantic-search/004-research-vector-search.md +841 -0
- package/research/semantic-search/032-research-semantic-search.md +427 -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/task-management-2026/00-synthesis-recommendations.md +295 -0
- package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
- package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
- package/research/task-management-2026/03-lightweight-file-based.md +567 -0
- package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
- package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
- package/research/task-management-2026/linear/02-api-integrations.md +930 -0
- package/research/task-management-2026/linear/03-ai-features.md +368 -0
- package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
- package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -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 +58 -0
- 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 +210 -0
- package/src/cli/argv-preprocessor.ts +202 -0
- package/src/cli/cli.test.ts +627 -0
- package/src/cli/commands/backlinks.ts +54 -0
- package/src/cli/commands/config-cmd.ts +642 -0
- package/src/cli/commands/context.ts +285 -0
- package/src/cli/commands/duplicates.ts +122 -0
- package/src/cli/commands/embeddings.ts +529 -0
- package/src/cli/commands/index-cmd.ts +480 -0
- package/src/cli/commands/index.ts +16 -0
- package/src/cli/commands/links.ts +52 -0
- package/src/cli/commands/search.ts +1281 -0
- package/src/cli/commands/stats.ts +149 -0
- package/src/cli/commands/tree.ts +128 -0
- 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 +341 -0
- package/src/cli/help.ts +588 -0
- package/src/cli/index.ts +9 -0
- package/src/cli/main.ts +435 -0
- package/src/cli/options.ts +41 -0
- package/src/cli/shared-error-handling.ts +199 -0
- package/src/cli/typo-suggester.test.ts +105 -0
- package/src/cli/typo-suggester.ts +130 -0
- package/src/cli/utils.ts +259 -0
- 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/index.ts +1 -0
- package/src/core/types.ts +113 -0
- 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 +10 -0
- package/src/embeddings/openai-provider.ts +414 -0
- 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 +1270 -0
- package/src/embeddings/types.ts +359 -0
- package/src/embeddings/vector-store.ts +708 -0
- 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/index.ts +4 -0
- package/src/index/indexer.ts +684 -0
- package/src/index/storage.ts +260 -0
- package/src/index/types.ts +147 -0
- package/src/index/watcher.ts +189 -0
- package/src/index.ts +30 -0
- package/src/integration/search-keyword.test.ts +678 -0
- package/src/mcp/server.ts +612 -0
- package/src/parser/index.ts +1 -0
- package/src/parser/parser.test.ts +291 -0
- package/src/parser/parser.ts +394 -0
- package/src/parser/section-filter.test.ts +277 -0
- package/src/parser/section-filter.ts +392 -0
- 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/query-parser.test.ts +260 -0
- package/src/search/query-parser.ts +319 -0
- package/src/search/searcher.test.ts +280 -0
- package/src/search/searcher.ts +724 -0
- 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/budget-bugs.test.ts +620 -0
- package/src/summarize/formatters.ts +419 -0
- package/src/summarize/index.ts +20 -0
- package/src/summarize/summarizer.test.ts +275 -0
- package/src/summarize/summarizer.ts +597 -0
- package/src/summarize/verify-bugs.test.ts +238 -0
- package/src/types/huggingface-transformers.d.ts +66 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tokens.test.ts +142 -0
- package/src/utils/tokens.ts +186 -0
- package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
- package/tests/fixtures/cli/.mdcontext/config.json +8 -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 +33 -0
- package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
- package/tests/fixtures/cli/.mdcontext/indexes/sections.json +247 -0
- package/tests/fixtures/cli/README.md +9 -0
- package/tests/fixtures/cli/api-reference.md +11 -0
- package/tests/fixtures/cli/getting-started.md +11 -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/tsconfig.json +26 -0
- package/vitest.config.ts +16 -0
- package/vitest.setup.ts +12 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based ConfigProvider Unit Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for loading configuration from files and creating ConfigProviders.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from 'node:fs'
|
|
8
|
+
import * as os from 'node:os'
|
|
9
|
+
import * as path from 'node:path'
|
|
10
|
+
import { Effect } from 'effect'
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
12
|
+
import {
|
|
13
|
+
CONFIG_FILE_NAMES,
|
|
14
|
+
createFileConfigProvider,
|
|
15
|
+
findConfigFile,
|
|
16
|
+
loadConfigFile,
|
|
17
|
+
loadConfigFromPath,
|
|
18
|
+
loadFileConfigProvider,
|
|
19
|
+
} from './file-provider.js'
|
|
20
|
+
import { MdContextConfig } from './schema.js'
|
|
21
|
+
|
|
22
|
+
describe('File-based ConfigProvider', () => {
|
|
23
|
+
let tempDir: string
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mdcontext-test-'))
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
fs.rmSync(tempDir, { recursive: true, force: true })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('CONFIG_FILE_NAMES', () => {
|
|
34
|
+
it('should have the expected file names in order of precedence', () => {
|
|
35
|
+
expect(CONFIG_FILE_NAMES).toEqual([
|
|
36
|
+
'mdcontext.config.ts',
|
|
37
|
+
'mdcontext.config.js',
|
|
38
|
+
'mdcontext.config.mjs',
|
|
39
|
+
'mdcontext.config.json',
|
|
40
|
+
'.mdcontextrc',
|
|
41
|
+
'.mdcontextrc.json',
|
|
42
|
+
])
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('findConfigFile', () => {
|
|
47
|
+
it('should return null when no config file exists', () => {
|
|
48
|
+
const result = findConfigFile(tempDir)
|
|
49
|
+
expect(result).toBeNull()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should find mdcontext.config.json', () => {
|
|
53
|
+
const configPath = path.join(tempDir, 'mdcontext.config.json')
|
|
54
|
+
fs.writeFileSync(configPath, '{}')
|
|
55
|
+
|
|
56
|
+
const result = findConfigFile(tempDir)
|
|
57
|
+
expect(result).not.toBeNull()
|
|
58
|
+
expect(result?.path).toBe(configPath)
|
|
59
|
+
expect(result?.format).toBe('json')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should find .mdcontextrc', () => {
|
|
63
|
+
const configPath = path.join(tempDir, '.mdcontextrc')
|
|
64
|
+
fs.writeFileSync(configPath, '{}')
|
|
65
|
+
|
|
66
|
+
const result = findConfigFile(tempDir)
|
|
67
|
+
expect(result).not.toBeNull()
|
|
68
|
+
expect(result?.path).toBe(configPath)
|
|
69
|
+
expect(result?.format).toBe('json')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('should find config in parent directory', () => {
|
|
73
|
+
const subDir = path.join(tempDir, 'subdir')
|
|
74
|
+
fs.mkdirSync(subDir)
|
|
75
|
+
const configPath = path.join(tempDir, 'mdcontext.config.json')
|
|
76
|
+
fs.writeFileSync(configPath, '{}')
|
|
77
|
+
|
|
78
|
+
const result = findConfigFile(subDir)
|
|
79
|
+
expect(result).not.toBeNull()
|
|
80
|
+
expect(result?.path).toBe(configPath)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('should prefer higher precedence files', () => {
|
|
84
|
+
// Create both .ts and .json files
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
path.join(tempDir, 'mdcontext.config.ts'),
|
|
87
|
+
'export default {}',
|
|
88
|
+
)
|
|
89
|
+
fs.writeFileSync(path.join(tempDir, 'mdcontext.config.json'), '{}')
|
|
90
|
+
|
|
91
|
+
const result = findConfigFile(tempDir)
|
|
92
|
+
expect(result).not.toBeNull()
|
|
93
|
+
expect(result?.path).toBe(path.join(tempDir, 'mdcontext.config.ts'))
|
|
94
|
+
expect(result?.format).toBe('ts')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('should identify .js format correctly', () => {
|
|
98
|
+
const configPath = path.join(tempDir, 'mdcontext.config.js')
|
|
99
|
+
fs.writeFileSync(configPath, 'module.exports = {}')
|
|
100
|
+
|
|
101
|
+
const result = findConfigFile(tempDir)
|
|
102
|
+
expect(result?.format).toBe('js')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should identify .mjs format correctly', () => {
|
|
106
|
+
const configPath = path.join(tempDir, 'mdcontext.config.mjs')
|
|
107
|
+
fs.writeFileSync(configPath, 'export default {}')
|
|
108
|
+
|
|
109
|
+
const result = findConfigFile(tempDir)
|
|
110
|
+
expect(result?.format).toBe('js')
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
describe('loadConfigFile', () => {
|
|
115
|
+
it('should return found: false when no config exists', async () => {
|
|
116
|
+
const result = await Effect.runPromise(loadConfigFile(tempDir))
|
|
117
|
+
expect(result.found).toBe(false)
|
|
118
|
+
if (!result.found) {
|
|
119
|
+
expect(result.searched.length).toBeGreaterThan(0)
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('should load JSON config file', async () => {
|
|
124
|
+
const config = {
|
|
125
|
+
index: { maxDepth: 5 },
|
|
126
|
+
output: { verbose: true },
|
|
127
|
+
}
|
|
128
|
+
fs.writeFileSync(
|
|
129
|
+
path.join(tempDir, 'mdcontext.config.json'),
|
|
130
|
+
JSON.stringify(config),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const result = await Effect.runPromise(loadConfigFile(tempDir))
|
|
134
|
+
expect(result.found).toBe(true)
|
|
135
|
+
if (result.found) {
|
|
136
|
+
expect(result.config).toEqual(config)
|
|
137
|
+
expect(result.path).toContain('mdcontext.config.json')
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should load .mdcontextrc file', async () => {
|
|
142
|
+
const config = { search: { defaultLimit: 20 } }
|
|
143
|
+
fs.writeFileSync(
|
|
144
|
+
path.join(tempDir, '.mdcontextrc'),
|
|
145
|
+
JSON.stringify(config),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const result = await Effect.runPromise(loadConfigFile(tempDir))
|
|
149
|
+
expect(result.found).toBe(true)
|
|
150
|
+
if (result.found) {
|
|
151
|
+
expect(result.config).toEqual(config)
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('should fail with ConfigError for invalid JSON', async () => {
|
|
156
|
+
fs.writeFileSync(
|
|
157
|
+
path.join(tempDir, 'mdcontext.config.json'),
|
|
158
|
+
'not valid json',
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
const result = await Effect.runPromiseExit(loadConfigFile(tempDir))
|
|
162
|
+
expect(result._tag).toBe('Failure')
|
|
163
|
+
if (result._tag === 'Failure') {
|
|
164
|
+
const error = result.cause
|
|
165
|
+
expect(String(error)).toContain('ConfigError')
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
describe('loadConfigFromPath', () => {
|
|
171
|
+
it('should load config from explicit path', async () => {
|
|
172
|
+
const configPath = path.join(tempDir, 'custom.json')
|
|
173
|
+
const config = { index: { maxDepth: 15 } }
|
|
174
|
+
fs.writeFileSync(configPath, JSON.stringify(config))
|
|
175
|
+
|
|
176
|
+
const result = await Effect.runPromise(loadConfigFromPath(configPath))
|
|
177
|
+
expect(result).toEqual(config)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('should fail with ConfigError when file does not exist', async () => {
|
|
181
|
+
const configPath = path.join(tempDir, 'nonexistent.json')
|
|
182
|
+
|
|
183
|
+
const result = await Effect.runPromiseExit(loadConfigFromPath(configPath))
|
|
184
|
+
expect(result._tag).toBe('Failure')
|
|
185
|
+
if (result._tag === 'Failure') {
|
|
186
|
+
const error = String(result.cause)
|
|
187
|
+
expect(error).toContain('ConfigError')
|
|
188
|
+
expect(error).toContain('not found')
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('should fail with ConfigError for invalid JSON', async () => {
|
|
193
|
+
const configPath = path.join(tempDir, 'invalid.json')
|
|
194
|
+
fs.writeFileSync(configPath, 'invalid json content')
|
|
195
|
+
|
|
196
|
+
const result = await Effect.runPromiseExit(loadConfigFromPath(configPath))
|
|
197
|
+
expect(result._tag).toBe('Failure')
|
|
198
|
+
if (result._tag === 'Failure') {
|
|
199
|
+
expect(String(result.cause)).toContain('ConfigError')
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
describe('createFileConfigProvider', () => {
|
|
205
|
+
it('should create a ConfigProvider from partial config', async () => {
|
|
206
|
+
const config = {
|
|
207
|
+
index: { maxDepth: 25 },
|
|
208
|
+
search: { minSimilarity: 0.8 },
|
|
209
|
+
}
|
|
210
|
+
const provider = createFileConfigProvider(config)
|
|
211
|
+
|
|
212
|
+
const program = Effect.gen(function* () {
|
|
213
|
+
return yield* MdContextConfig
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
const result = await Effect.runPromise(
|
|
217
|
+
Effect.withConfigProvider(program, provider),
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
expect(result.index.maxDepth).toBe(25)
|
|
221
|
+
expect(result.search.minSimilarity).toBe(0.8)
|
|
222
|
+
// Defaults should be used for unspecified values
|
|
223
|
+
expect(result.output.format).toBe('text')
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('should work with nested config structure', async () => {
|
|
227
|
+
const config = {
|
|
228
|
+
embeddings: {
|
|
229
|
+
model: 'text-embedding-3-large',
|
|
230
|
+
batchSize: 50,
|
|
231
|
+
},
|
|
232
|
+
paths: {
|
|
233
|
+
cacheDir: '/custom/cache',
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
const provider = createFileConfigProvider(config)
|
|
237
|
+
|
|
238
|
+
const program = Effect.gen(function* () {
|
|
239
|
+
return yield* MdContextConfig
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
const result = await Effect.runPromise(
|
|
243
|
+
Effect.withConfigProvider(program, provider),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
expect(result.embeddings.model).toBe('text-embedding-3-large')
|
|
247
|
+
expect(result.embeddings.batchSize).toBe(50)
|
|
248
|
+
expect(result.paths.cacheDir).toBe('/custom/cache')
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
describe('loadFileConfigProvider', () => {
|
|
253
|
+
it('should return empty provider when no config file exists', async () => {
|
|
254
|
+
const provider = await Effect.runPromise(loadFileConfigProvider(tempDir))
|
|
255
|
+
|
|
256
|
+
// Provider should exist but provide no overrides
|
|
257
|
+
const program = Effect.gen(function* () {
|
|
258
|
+
return yield* MdContextConfig
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
const result = await Effect.runPromise(
|
|
262
|
+
Effect.withConfigProvider(program, provider),
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
// All defaults should be used
|
|
266
|
+
expect(result.index.maxDepth).toBe(10)
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('should load config and create provider in one step', async () => {
|
|
270
|
+
const config = {
|
|
271
|
+
index: { maxDepth: 30 },
|
|
272
|
+
output: { debug: true },
|
|
273
|
+
}
|
|
274
|
+
fs.writeFileSync(
|
|
275
|
+
path.join(tempDir, 'mdcontext.config.json'),
|
|
276
|
+
JSON.stringify(config),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
const provider = await Effect.runPromise(loadFileConfigProvider(tempDir))
|
|
280
|
+
|
|
281
|
+
const program = Effect.gen(function* () {
|
|
282
|
+
return yield* MdContextConfig
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
const result = await Effect.runPromise(
|
|
286
|
+
Effect.withConfigProvider(program, provider),
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
expect(result.index.maxDepth).toBe(30)
|
|
290
|
+
expect(result.output.debug).toBe(true)
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
describe('JavaScript/TypeScript config loading', () => {
|
|
295
|
+
it('should load .mjs config with default export', async () => {
|
|
296
|
+
const configPath = path.join(tempDir, 'mdcontext.config.mjs')
|
|
297
|
+
fs.writeFileSync(configPath, `export default { index: { maxDepth: 42 } }`)
|
|
298
|
+
|
|
299
|
+
const result = await Effect.runPromise(loadConfigFile(tempDir))
|
|
300
|
+
expect(result.found).toBe(true)
|
|
301
|
+
if (result.found) {
|
|
302
|
+
expect(result.config.index?.maxDepth).toBe(42)
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should load .mjs config with named export', async () => {
|
|
307
|
+
const configPath = path.join(tempDir, 'mdcontext.config.mjs')
|
|
308
|
+
fs.writeFileSync(
|
|
309
|
+
configPath,
|
|
310
|
+
`export const config = { search: { defaultLimit: 50 } }`,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
const result = await Effect.runPromise(loadConfigFile(tempDir))
|
|
314
|
+
expect(result.found).toBe(true)
|
|
315
|
+
if (result.found) {
|
|
316
|
+
expect(result.config.search?.defaultLimit).toBe(50)
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
})
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based ConfigProvider
|
|
3
|
+
*
|
|
4
|
+
* Creates a custom ConfigProvider that reads from config files:
|
|
5
|
+
* - mdcontext.config.ts (TypeScript - dynamic import)
|
|
6
|
+
* - mdcontext.config.js (JavaScript - dynamic import)
|
|
7
|
+
* - mdcontext.config.json (JSON - file read)
|
|
8
|
+
* - .mdcontextrc (JSON - file read)
|
|
9
|
+
* - .mdcontextrc.json (JSON - file read)
|
|
10
|
+
*
|
|
11
|
+
* ## Usage
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { loadConfigFile, createFileConfigProvider } from './config/file-provider.js'
|
|
15
|
+
* import { Effect, ConfigProvider } from 'effect'
|
|
16
|
+
*
|
|
17
|
+
* // Load config and create provider
|
|
18
|
+
* const result = await loadConfigFile('/path/to/project')
|
|
19
|
+
* if (result.found) {
|
|
20
|
+
* const provider = createFileConfigProvider(result.config)
|
|
21
|
+
* // Use with Effect.withConfigProvider
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import * as fs from 'node:fs'
|
|
27
|
+
import * as path from 'node:path'
|
|
28
|
+
import { ConfigProvider, Effect } from 'effect'
|
|
29
|
+
import { ConfigError } from '../errors/index.js'
|
|
30
|
+
import type { PartialMdContextConfig } from './service.js'
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Types
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Supported config file names in order of precedence
|
|
38
|
+
*/
|
|
39
|
+
export const CONFIG_FILE_NAMES = [
|
|
40
|
+
'mdcontext.config.ts',
|
|
41
|
+
'mdcontext.config.js',
|
|
42
|
+
'mdcontext.config.mjs',
|
|
43
|
+
'mdcontext.config.json',
|
|
44
|
+
'.mdcontextrc',
|
|
45
|
+
'.mdcontextrc.json',
|
|
46
|
+
] as const
|
|
47
|
+
|
|
48
|
+
export type ConfigFileName = (typeof CONFIG_FILE_NAMES)[number]
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Result of loading a config file
|
|
52
|
+
*/
|
|
53
|
+
export type LoadConfigResult =
|
|
54
|
+
| { found: true; path: string; config: PartialMdContextConfig }
|
|
55
|
+
| { found: false; searched: string[] }
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Config file format
|
|
59
|
+
*/
|
|
60
|
+
export type ConfigFileFormat = 'ts' | 'js' | 'json'
|
|
61
|
+
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// File Detection
|
|
64
|
+
// ============================================================================
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Find a config file starting from the given directory.
|
|
68
|
+
* Searches up the directory tree until a config file is found or root is reached.
|
|
69
|
+
*
|
|
70
|
+
* @param startDir - Directory to start searching from
|
|
71
|
+
* @returns The path to the config file if found, or null
|
|
72
|
+
*/
|
|
73
|
+
export const findConfigFile = (
|
|
74
|
+
startDir: string,
|
|
75
|
+
): { path: string; format: ConfigFileFormat } | null => {
|
|
76
|
+
let currentDir = path.resolve(startDir)
|
|
77
|
+
const root = path.parse(currentDir).root
|
|
78
|
+
|
|
79
|
+
while (currentDir !== root) {
|
|
80
|
+
for (const fileName of CONFIG_FILE_NAMES) {
|
|
81
|
+
const configPath = path.join(currentDir, fileName)
|
|
82
|
+
if (fs.existsSync(configPath)) {
|
|
83
|
+
const format = getConfigFormat(fileName)
|
|
84
|
+
return { path: configPath, format }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const parentDir = path.dirname(currentDir)
|
|
88
|
+
if (parentDir === currentDir) break
|
|
89
|
+
currentDir = parentDir
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the format of a config file based on its name
|
|
97
|
+
*/
|
|
98
|
+
const getConfigFormat = (fileName: string): ConfigFileFormat => {
|
|
99
|
+
if (fileName.endsWith('.ts')) return 'ts'
|
|
100
|
+
if (fileName.endsWith('.js') || fileName.endsWith('.mjs')) return 'js'
|
|
101
|
+
return 'json'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// File Loading
|
|
106
|
+
// ============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Load configuration from a JSON file
|
|
110
|
+
*/
|
|
111
|
+
const loadJsonConfig = (
|
|
112
|
+
filePath: string,
|
|
113
|
+
): Effect.Effect<PartialMdContextConfig, ConfigError> =>
|
|
114
|
+
Effect.try({
|
|
115
|
+
try: () => {
|
|
116
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
117
|
+
return JSON.parse(content) as PartialMdContextConfig
|
|
118
|
+
},
|
|
119
|
+
catch: (error) =>
|
|
120
|
+
new ConfigError({
|
|
121
|
+
field: 'configFile',
|
|
122
|
+
message: `Failed to load config from ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
123
|
+
cause: error,
|
|
124
|
+
}),
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Load configuration from a JavaScript/TypeScript file using dynamic import
|
|
129
|
+
*/
|
|
130
|
+
const loadJsConfig = (
|
|
131
|
+
filePath: string,
|
|
132
|
+
): Effect.Effect<PartialMdContextConfig, ConfigError> =>
|
|
133
|
+
Effect.tryPromise({
|
|
134
|
+
try: async () => {
|
|
135
|
+
// Convert to file URL for dynamic import
|
|
136
|
+
const fileUrl = `file://${filePath}`
|
|
137
|
+
const module = await import(fileUrl)
|
|
138
|
+
// Support both default export and named 'config' export
|
|
139
|
+
const config = module.default ?? module.config
|
|
140
|
+
if (!config || typeof config !== 'object') {
|
|
141
|
+
throw new Error(
|
|
142
|
+
'Config file must export a default object or named "config" export',
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
return config as PartialMdContextConfig
|
|
146
|
+
},
|
|
147
|
+
catch: (error) =>
|
|
148
|
+
new ConfigError({
|
|
149
|
+
field: 'configFile',
|
|
150
|
+
message: `Failed to load config from ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
151
|
+
cause: error,
|
|
152
|
+
}),
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Load configuration from a file based on its format
|
|
157
|
+
*/
|
|
158
|
+
export const loadConfigFromFile = (
|
|
159
|
+
filePath: string,
|
|
160
|
+
format: ConfigFileFormat,
|
|
161
|
+
): Effect.Effect<PartialMdContextConfig, ConfigError> => {
|
|
162
|
+
switch (format) {
|
|
163
|
+
case 'json':
|
|
164
|
+
return loadJsonConfig(filePath)
|
|
165
|
+
case 'ts':
|
|
166
|
+
case 'js':
|
|
167
|
+
return loadJsConfig(filePath)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Search for and load a config file starting from the given directory.
|
|
173
|
+
*
|
|
174
|
+
* @param startDir - Directory to start searching from
|
|
175
|
+
* @returns LoadConfigResult indicating whether a config was found
|
|
176
|
+
*/
|
|
177
|
+
export const loadConfigFile = (
|
|
178
|
+
startDir: string,
|
|
179
|
+
): Effect.Effect<LoadConfigResult, ConfigError> =>
|
|
180
|
+
Effect.gen(function* () {
|
|
181
|
+
const found = findConfigFile(startDir)
|
|
182
|
+
|
|
183
|
+
if (!found) {
|
|
184
|
+
return {
|
|
185
|
+
found: false,
|
|
186
|
+
searched: CONFIG_FILE_NAMES.map((name) => path.join(startDir, name)),
|
|
187
|
+
} as LoadConfigResult
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const config = yield* loadConfigFromFile(found.path, found.format)
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
found: true,
|
|
194
|
+
path: found.path,
|
|
195
|
+
config,
|
|
196
|
+
} as LoadConfigResult
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Load a config file from a specific path (not searching up directories)
|
|
201
|
+
*
|
|
202
|
+
* @param configPath - Explicit path to the config file
|
|
203
|
+
* @returns The loaded configuration
|
|
204
|
+
*/
|
|
205
|
+
export const loadConfigFromPath = (
|
|
206
|
+
configPath: string,
|
|
207
|
+
): Effect.Effect<PartialMdContextConfig, ConfigError> =>
|
|
208
|
+
Effect.gen(function* () {
|
|
209
|
+
const resolvedPath = path.resolve(configPath)
|
|
210
|
+
|
|
211
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
212
|
+
return yield* Effect.fail(
|
|
213
|
+
new ConfigError({
|
|
214
|
+
field: 'configFile',
|
|
215
|
+
message: `Config file not found: ${resolvedPath}`,
|
|
216
|
+
}),
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const format = getConfigFormat(path.basename(configPath))
|
|
221
|
+
return yield* loadConfigFromFile(resolvedPath, format)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// ConfigProvider Creation
|
|
226
|
+
// ============================================================================
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Create a ConfigProvider from a partial configuration object.
|
|
230
|
+
*
|
|
231
|
+
* The provider uses ConfigProvider.fromJson to map the nested config
|
|
232
|
+
* structure to Effect's config namespace.
|
|
233
|
+
*
|
|
234
|
+
* @param config - Partial configuration object
|
|
235
|
+
* @returns A ConfigProvider that provides the config values
|
|
236
|
+
*/
|
|
237
|
+
export const createFileConfigProvider = (
|
|
238
|
+
config: PartialMdContextConfig,
|
|
239
|
+
): ConfigProvider.ConfigProvider => ConfigProvider.fromJson(config)
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Load config file and create a ConfigProvider in one step.
|
|
243
|
+
*
|
|
244
|
+
* If no config file is found, returns a ConfigProvider that provides no values
|
|
245
|
+
* (Effect will use defaults from the Config schema).
|
|
246
|
+
*
|
|
247
|
+
* @param startDir - Directory to start searching for config files
|
|
248
|
+
* @returns Effect yielding a ConfigProvider
|
|
249
|
+
*/
|
|
250
|
+
export const loadFileConfigProvider = (
|
|
251
|
+
startDir: string,
|
|
252
|
+
): Effect.Effect<ConfigProvider.ConfigProvider, ConfigError> =>
|
|
253
|
+
Effect.gen(function* () {
|
|
254
|
+
const result = yield* loadConfigFile(startDir)
|
|
255
|
+
|
|
256
|
+
if (!result.found) {
|
|
257
|
+
// Return empty provider - defaults will be used
|
|
258
|
+
return ConfigProvider.fromMap(new Map())
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return createFileConfigProvider(result.config)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Load config from a specific file and create a ConfigProvider.
|
|
266
|
+
*
|
|
267
|
+
* @param configPath - Path to the config file
|
|
268
|
+
* @returns Effect yielding a ConfigProvider
|
|
269
|
+
*/
|
|
270
|
+
export const loadFileConfigProviderFromPath = (
|
|
271
|
+
configPath: string,
|
|
272
|
+
): Effect.Effect<ConfigProvider.ConfigProvider, ConfigError> =>
|
|
273
|
+
Effect.map(loadConfigFromPath(configPath), createFileConfigProvider)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Exports all configuration-related types, schemas, and utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
// File detection
|
|
9
|
+
CONFIG_FILE_NAMES,
|
|
10
|
+
type ConfigFileFormat,
|
|
11
|
+
type ConfigFileName,
|
|
12
|
+
// Provider creation
|
|
13
|
+
createFileConfigProvider,
|
|
14
|
+
findConfigFile,
|
|
15
|
+
type LoadConfigResult,
|
|
16
|
+
// File loading
|
|
17
|
+
loadConfigFile,
|
|
18
|
+
loadConfigFromPath,
|
|
19
|
+
loadFileConfigProvider,
|
|
20
|
+
loadFileConfigProviderFromPath,
|
|
21
|
+
} from './file-provider.js'
|
|
22
|
+
export {
|
|
23
|
+
// Precedence chain
|
|
24
|
+
type ConfigProviderOptions,
|
|
25
|
+
createCliConfigProvider,
|
|
26
|
+
createConfigProvider,
|
|
27
|
+
createConfigProviderSync,
|
|
28
|
+
createEnvConfigProvider,
|
|
29
|
+
createTestConfigProvider,
|
|
30
|
+
// Utilities
|
|
31
|
+
flattenConfig,
|
|
32
|
+
readEnvConfig,
|
|
33
|
+
} from './precedence.js'
|
|
34
|
+
export {
|
|
35
|
+
// Default values
|
|
36
|
+
defaultConfig,
|
|
37
|
+
// Types
|
|
38
|
+
type EmbeddingProvider,
|
|
39
|
+
EmbeddingsConfig,
|
|
40
|
+
// Config schemas
|
|
41
|
+
IndexConfig,
|
|
42
|
+
MdContextConfig,
|
|
43
|
+
type OpenAIEmbeddingModel,
|
|
44
|
+
OutputConfig,
|
|
45
|
+
type OutputFormat,
|
|
46
|
+
PathsConfig,
|
|
47
|
+
SearchConfig,
|
|
48
|
+
SummarizationConfig,
|
|
49
|
+
} from './schema.js'
|
|
50
|
+
export {
|
|
51
|
+
// Service
|
|
52
|
+
ConfigService,
|
|
53
|
+
ConfigServiceDefault,
|
|
54
|
+
ConfigServiceLive,
|
|
55
|
+
// Helper functions
|
|
56
|
+
getConfig,
|
|
57
|
+
getConfigSection,
|
|
58
|
+
getConfigValue,
|
|
59
|
+
// Layer utilities
|
|
60
|
+
makeConfigLayer,
|
|
61
|
+
makeConfigLayerPartial,
|
|
62
|
+
// Merge utilities
|
|
63
|
+
mergeWithDefaults,
|
|
64
|
+
type PartialMdContextConfig,
|
|
65
|
+
} from './service.js'
|
|
66
|
+
export {
|
|
67
|
+
// Testing utilities
|
|
68
|
+
runWithConfig,
|
|
69
|
+
runWithConfigSync,
|
|
70
|
+
TestConfigLayer,
|
|
71
|
+
withTestConfig,
|
|
72
|
+
} from './testing.js'
|