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
|
@@ -7,15 +7,24 @@
|
|
|
7
7
|
import * as path from 'node:path'
|
|
8
8
|
import * as readline from 'node:readline'
|
|
9
9
|
import { Args, Command, Options } from '@effect/cli'
|
|
10
|
-
import { Console, Effect } from 'effect'
|
|
11
|
-
import {
|
|
10
|
+
import { Console, Effect, Option } from 'effect'
|
|
11
|
+
import type {
|
|
12
|
+
BuildEmbeddingsResult,
|
|
13
|
+
EmbeddingEstimate,
|
|
14
|
+
} from '../../embeddings/semantic-search.js'
|
|
12
15
|
import {
|
|
13
16
|
buildEmbeddings,
|
|
17
|
+
checkPricingFreshness,
|
|
14
18
|
estimateEmbeddingCost,
|
|
19
|
+
getPricingDate,
|
|
15
20
|
} from '../../embeddings/semantic-search.js'
|
|
16
21
|
import { buildIndex } from '../../index/indexer.js'
|
|
17
22
|
import { watchDirectory } from '../../index/watcher.js'
|
|
18
23
|
import { forceOption, jsonOption, prettyOption } from '../options.js'
|
|
24
|
+
import {
|
|
25
|
+
createCostEstimateErrorHandler,
|
|
26
|
+
createEmbeddingErrorHandler,
|
|
27
|
+
} from '../shared-error-handling.js'
|
|
19
28
|
import { formatJson, hasEmbeddings } from '../utils.js'
|
|
20
29
|
|
|
21
30
|
const promptUser = (message: string): Promise<string> => {
|
|
@@ -50,7 +59,50 @@ export const indexCommand = Command.make(
|
|
|
50
59
|
exclude: Options.text('exclude').pipe(
|
|
51
60
|
Options.withAlias('x'),
|
|
52
61
|
Options.withDescription(
|
|
53
|
-
'
|
|
62
|
+
'Additional patterns to exclude (comma-separated). Patterns from .gitignore and .mdcontextignore are honored automatically.',
|
|
63
|
+
),
|
|
64
|
+
Options.optional,
|
|
65
|
+
),
|
|
66
|
+
noGitignore: Options.boolean('no-gitignore').pipe(
|
|
67
|
+
Options.withDescription('Ignore .gitignore file'),
|
|
68
|
+
Options.withDefault(false),
|
|
69
|
+
),
|
|
70
|
+
provider: Options.choice('provider', [
|
|
71
|
+
'openai',
|
|
72
|
+
'ollama',
|
|
73
|
+
'lm-studio',
|
|
74
|
+
'openrouter',
|
|
75
|
+
'voyage',
|
|
76
|
+
]).pipe(
|
|
77
|
+
Options.withDescription(
|
|
78
|
+
'Embedding provider: openai, ollama, lm-studio, openrouter, or voyage',
|
|
79
|
+
),
|
|
80
|
+
Options.optional,
|
|
81
|
+
),
|
|
82
|
+
providerBaseUrl: Options.text('provider-base-url').pipe(
|
|
83
|
+
Options.withDescription('Custom provider API base URL'),
|
|
84
|
+
Options.optional,
|
|
85
|
+
),
|
|
86
|
+
providerModel: Options.text('provider-model').pipe(
|
|
87
|
+
Options.withDescription('Embedding model to use'),
|
|
88
|
+
Options.optional,
|
|
89
|
+
),
|
|
90
|
+
hnswM: Options.integer('hnsw-m').pipe(
|
|
91
|
+
Options.withDescription(
|
|
92
|
+
'HNSW M parameter: max connections per node. Higher = better recall, larger index. Recommended: 12 (speed), 16 (balanced, default), 24 (quality)',
|
|
93
|
+
),
|
|
94
|
+
Options.optional,
|
|
95
|
+
),
|
|
96
|
+
hnswEfConstruction: Options.integer('hnsw-ef-construction').pipe(
|
|
97
|
+
Options.withDescription(
|
|
98
|
+
'HNSW efConstruction: construction-time search width. Higher = better quality, slower builds. Recommended: 128 (speed), 200 (balanced, default), 256 (quality)',
|
|
99
|
+
),
|
|
100
|
+
Options.optional,
|
|
101
|
+
),
|
|
102
|
+
timeout: Options.integer('timeout').pipe(
|
|
103
|
+
Options.withAlias('t'),
|
|
104
|
+
Options.withDescription(
|
|
105
|
+
'Request timeout in milliseconds for embedding API calls (default: 30000)',
|
|
54
106
|
),
|
|
55
107
|
Options.optional,
|
|
56
108
|
),
|
|
@@ -68,6 +120,13 @@ export const indexCommand = Command.make(
|
|
|
68
120
|
embed,
|
|
69
121
|
noEmbed,
|
|
70
122
|
exclude,
|
|
123
|
+
noGitignore,
|
|
124
|
+
provider,
|
|
125
|
+
providerBaseUrl,
|
|
126
|
+
providerModel,
|
|
127
|
+
hnswM,
|
|
128
|
+
hnswEfConstruction,
|
|
129
|
+
timeout,
|
|
71
130
|
watch: watchMode,
|
|
72
131
|
force,
|
|
73
132
|
json,
|
|
@@ -76,8 +135,9 @@ export const indexCommand = Command.make(
|
|
|
76
135
|
Effect.gen(function* () {
|
|
77
136
|
const resolvedDir = path.resolve(dirPath)
|
|
78
137
|
|
|
79
|
-
// Parse exclude patterns
|
|
80
|
-
|
|
138
|
+
// Parse exclude patterns - CLI adds to ignore files
|
|
139
|
+
// Note: buildIndex now honors .gitignore and .mdcontextignore by default
|
|
140
|
+
const cliExcludePatterns =
|
|
81
141
|
exclude._tag === 'Some'
|
|
82
142
|
? exclude.value.split(',').map((p) => p.trim())
|
|
83
143
|
: undefined
|
|
@@ -89,6 +149,8 @@ export const indexCommand = Command.make(
|
|
|
89
149
|
|
|
90
150
|
const watcher = yield* watchDirectory(resolvedDir, {
|
|
91
151
|
force,
|
|
152
|
+
exclude: cliExcludePatterns,
|
|
153
|
+
honorGitignore: !noGitignore,
|
|
92
154
|
onIndex: (result) => {
|
|
93
155
|
if (json) {
|
|
94
156
|
console.log(formatJson(result, pretty))
|
|
@@ -113,7 +175,22 @@ export const indexCommand = Command.make(
|
|
|
113
175
|
} else {
|
|
114
176
|
yield* Console.log(`Indexing ${resolvedDir}...`)
|
|
115
177
|
|
|
116
|
-
const result = yield* buildIndex(resolvedDir, {
|
|
178
|
+
const result = yield* buildIndex(resolvedDir, {
|
|
179
|
+
force,
|
|
180
|
+
exclude: cliExcludePatterns,
|
|
181
|
+
honorGitignore: !noGitignore,
|
|
182
|
+
onProgress: (progress) => {
|
|
183
|
+
if (!json) {
|
|
184
|
+
const progressMsg = ` [${progress.current}/${progress.total}] ${progress.filePath}`
|
|
185
|
+
process.stdout.write(`\x1b[2K\r${progressMsg}`)
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Clear the progress line after indexing completes
|
|
191
|
+
if (!json) {
|
|
192
|
+
process.stdout.write('\x1b[2K\r')
|
|
193
|
+
}
|
|
117
194
|
|
|
118
195
|
if (!json) {
|
|
119
196
|
yield* Console.log('')
|
|
@@ -129,6 +206,21 @@ export const indexCommand = Command.make(
|
|
|
129
206
|
yield* Console.log(` Links: ${result.totalLinks}`)
|
|
130
207
|
yield* Console.log(` Duration: ${result.duration}ms`)
|
|
131
208
|
|
|
209
|
+
// Show skip summary if any files were skipped
|
|
210
|
+
if (result.skipped.total > 0) {
|
|
211
|
+
const skipParts: string[] = []
|
|
212
|
+
if (result.skipped.unchanged > 0) {
|
|
213
|
+
skipParts.push(`${result.skipped.unchanged} unchanged`)
|
|
214
|
+
}
|
|
215
|
+
if (result.skipped.hidden > 0) {
|
|
216
|
+
skipParts.push(`${result.skipped.hidden} hidden`)
|
|
217
|
+
}
|
|
218
|
+
if (result.skipped.excluded > 0) {
|
|
219
|
+
skipParts.push(`${result.skipped.excluded} excluded`)
|
|
220
|
+
}
|
|
221
|
+
yield* Console.log(` Skipped: ${skipParts.join(', ')}`)
|
|
222
|
+
}
|
|
223
|
+
|
|
132
224
|
if (result.errors.length > 0) {
|
|
133
225
|
yield* Console.log('')
|
|
134
226
|
yield* Console.log(`Errors (${result.errors.length}):`)
|
|
@@ -147,10 +239,10 @@ export const indexCommand = Command.make(
|
|
|
147
239
|
if (embed) {
|
|
148
240
|
yield* Console.log('')
|
|
149
241
|
|
|
150
|
-
// Show cost estimate first
|
|
242
|
+
// Show cost estimate first - errors propagate to CLI boundary
|
|
151
243
|
const estimate = yield* estimateEmbeddingCost(resolvedDir, {
|
|
152
|
-
excludePatterns,
|
|
153
|
-
})
|
|
244
|
+
excludePatterns: cliExcludePatterns,
|
|
245
|
+
})
|
|
154
246
|
|
|
155
247
|
if (!json) {
|
|
156
248
|
yield* Console.log(`Found ${estimate.totalFiles} files to embed:`)
|
|
@@ -165,8 +257,14 @@ export const indexCommand = Command.make(
|
|
|
165
257
|
}
|
|
166
258
|
yield* Console.log('')
|
|
167
259
|
yield* Console.log(
|
|
168
|
-
`Total: ~${estimate.totalTokens.toLocaleString()} tokens, ~$${estimate.totalCost.toFixed(4)}, ~${estimate.estimatedTimeSeconds}s`,
|
|
260
|
+
`Total: ~${estimate.totalTokens.toLocaleString()} tokens, ~$${estimate.totalCost.toFixed(4)} (pricing as of ${getPricingDate()}), ~${estimate.estimatedTimeSeconds}s`,
|
|
169
261
|
)
|
|
262
|
+
|
|
263
|
+
// Check for stale pricing data
|
|
264
|
+
const stalenessWarning = checkPricingFreshness()
|
|
265
|
+
if (stalenessWarning) {
|
|
266
|
+
yield* Console.log(` Warning: ${stalenessWarning}`)
|
|
267
|
+
}
|
|
170
268
|
yield* Console.log('')
|
|
171
269
|
}
|
|
172
270
|
|
|
@@ -176,21 +274,56 @@ export const indexCommand = Command.make(
|
|
|
176
274
|
yield* Console.log('Rebuilding embeddings (--force specified)...')
|
|
177
275
|
}
|
|
178
276
|
|
|
277
|
+
// Build provider config from CLI flags if specified
|
|
278
|
+
const cliTimeout = Option.getOrUndefined(timeout)
|
|
279
|
+
const providerConfig = Option.isSome(provider)
|
|
280
|
+
? {
|
|
281
|
+
provider: provider.value as
|
|
282
|
+
| 'openai'
|
|
283
|
+
| 'ollama'
|
|
284
|
+
| 'lm-studio'
|
|
285
|
+
| 'openrouter'
|
|
286
|
+
| 'voyage',
|
|
287
|
+
baseURL: Option.getOrUndefined(providerBaseUrl),
|
|
288
|
+
model: Option.getOrUndefined(providerModel),
|
|
289
|
+
timeout: cliTimeout,
|
|
290
|
+
}
|
|
291
|
+
: cliTimeout !== undefined
|
|
292
|
+
? { provider: 'openai' as const, timeout: cliTimeout }
|
|
293
|
+
: undefined
|
|
294
|
+
|
|
295
|
+
// Build HNSW options from CLI flags if specified
|
|
296
|
+
const hnswOptions =
|
|
297
|
+
Option.isSome(hnswM) || Option.isSome(hnswEfConstruction)
|
|
298
|
+
? {
|
|
299
|
+
m: Option.getOrUndefined(hnswM),
|
|
300
|
+
efConstruction: Option.getOrUndefined(hnswEfConstruction),
|
|
301
|
+
}
|
|
302
|
+
: undefined
|
|
303
|
+
|
|
304
|
+
// Build embeddings - errors propagate to CLI boundary
|
|
179
305
|
const embedResult = yield* buildEmbeddings(resolvedDir, {
|
|
180
306
|
force,
|
|
181
|
-
excludePatterns,
|
|
307
|
+
excludePatterns: cliExcludePatterns,
|
|
308
|
+
providerConfig,
|
|
309
|
+
hnswOptions,
|
|
182
310
|
onFileProgress: (progress) => {
|
|
183
311
|
if (!json) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
312
|
+
const progressMsg = ` [${progress.fileIndex}/${progress.totalFiles}] ${progress.filePath} (${progress.sectionCount} sections)...`
|
|
313
|
+
process.stdout.write(`\x1b[2K\r${progressMsg}`)
|
|
187
314
|
}
|
|
188
315
|
},
|
|
189
|
-
|
|
316
|
+
onBatchProgress: (progress) => {
|
|
317
|
+
if (!json) {
|
|
318
|
+
const progressMsg = ` Embedding [${progress.processedSections}/${progress.totalSections}] sections (batch ${progress.batchIndex}/${progress.totalBatches})...`
|
|
319
|
+
process.stdout.write(`\x1b[2K\r${progressMsg}`)
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
})
|
|
190
323
|
|
|
191
324
|
if (!json) {
|
|
192
|
-
// Clear the progress line
|
|
193
|
-
process.stdout.write(`\r${' '.repeat(
|
|
325
|
+
// Clear the progress line completely
|
|
326
|
+
process.stdout.write(`\r${' '.repeat(120)}\r`)
|
|
194
327
|
yield* Console.log('')
|
|
195
328
|
|
|
196
329
|
if (embedResult.cacheHit) {
|
|
@@ -228,8 +361,11 @@ export const indexCommand = Command.make(
|
|
|
228
361
|
yield* Console.log('')
|
|
229
362
|
|
|
230
363
|
// Get cost estimate for the prompt
|
|
364
|
+
// Note: We gracefully handle errors here since this is optional information
|
|
365
|
+
// for the user prompt. IndexNotFoundError is expected if index doesn't exist.
|
|
231
366
|
const estimate = yield* estimateEmbeddingCost(resolvedDir).pipe(
|
|
232
|
-
Effect.
|
|
367
|
+
Effect.map((r): EmbeddingEstimate | null => r),
|
|
368
|
+
Effect.catchTags(createCostEstimateErrorHandler()),
|
|
233
369
|
)
|
|
234
370
|
|
|
235
371
|
if (estimate) {
|
|
@@ -237,7 +373,21 @@ export const indexCommand = Command.make(
|
|
|
237
373
|
`Cost: ~$${estimate.totalCost.toFixed(4)} for this corpus (~${estimate.estimatedTimeSeconds}s)`,
|
|
238
374
|
)
|
|
239
375
|
}
|
|
240
|
-
yield* Console.log('Requires
|
|
376
|
+
yield* Console.log('Requires an embedding provider. Options:')
|
|
377
|
+
yield* Console.log(
|
|
378
|
+
' - OpenAI (cloud): Set OPENAI_API_KEY environment variable',
|
|
379
|
+
)
|
|
380
|
+
yield* Console.log(
|
|
381
|
+
' - Ollama (free, local): Run "ollama serve" - no API key needed',
|
|
382
|
+
)
|
|
383
|
+
yield* Console.log(
|
|
384
|
+
' - LM Studio (free, local): Start the server - no API key needed',
|
|
385
|
+
)
|
|
386
|
+
yield* Console.log(
|
|
387
|
+
' - OpenRouter (cloud): Set OPENROUTER_API_KEY environment variable',
|
|
388
|
+
)
|
|
389
|
+
yield* Console.log('')
|
|
390
|
+
yield* Console.log('See CONFIG.md for detailed setup instructions.')
|
|
241
391
|
yield* Console.log('')
|
|
242
392
|
|
|
243
393
|
const answer = yield* Effect.promise(() =>
|
|
@@ -245,36 +395,66 @@ export const indexCommand = Command.make(
|
|
|
245
395
|
)
|
|
246
396
|
|
|
247
397
|
if (answer === 'y' || answer === 'yes') {
|
|
248
|
-
// Check for API key
|
|
398
|
+
// Check for API key (only required for cloud providers)
|
|
399
|
+
// Note: When no provider is configured, we default to OpenAI which needs a key
|
|
400
|
+
// Local providers (Ollama, LM Studio) don't need API keys
|
|
249
401
|
if (!process.env.OPENAI_API_KEY) {
|
|
250
402
|
yield* Console.log('')
|
|
251
|
-
yield* Console.log('
|
|
403
|
+
yield* Console.log('No embedding provider configured.')
|
|
404
|
+
yield* Console.log('')
|
|
405
|
+
yield* Console.log('Choose a provider:')
|
|
252
406
|
yield* Console.log('')
|
|
407
|
+
yield* Console.log(' Cloud (requires API key):')
|
|
408
|
+
yield* Console.log(' export OPENAI_API_KEY=sk-...')
|
|
409
|
+
yield* Console.log(' export OPENROUTER_API_KEY=sk-...')
|
|
410
|
+
yield* Console.log('')
|
|
411
|
+
yield* Console.log(' Local (free, no API key needed):')
|
|
253
412
|
yield* Console.log(
|
|
254
|
-
'
|
|
413
|
+
' Ollama: ollama serve && ollama pull nomic-embed-text',
|
|
255
414
|
)
|
|
256
|
-
yield* Console.log('
|
|
415
|
+
yield* Console.log(' LM Studio: Start the server GUI')
|
|
257
416
|
yield* Console.log('')
|
|
258
|
-
yield* Console.log(
|
|
417
|
+
yield* Console.log(
|
|
418
|
+
'Then run: mdcontext index --embed [--provider <name>]',
|
|
419
|
+
)
|
|
420
|
+
yield* Console.log('See CONFIG.md for detailed setup.')
|
|
259
421
|
} else {
|
|
260
422
|
yield* Console.log('')
|
|
261
423
|
yield* Console.log('Building embeddings...')
|
|
262
424
|
|
|
425
|
+
// Build HNSW options from CLI flags if specified
|
|
426
|
+
const hnswOptionsPrompt =
|
|
427
|
+
Option.isSome(hnswM) || Option.isSome(hnswEfConstruction)
|
|
428
|
+
? {
|
|
429
|
+
m: Option.getOrUndefined(hnswM),
|
|
430
|
+
efConstruction: Option.getOrUndefined(hnswEfConstruction),
|
|
431
|
+
}
|
|
432
|
+
: undefined
|
|
433
|
+
|
|
434
|
+
// Build provider config if timeout specified
|
|
435
|
+
const promptTimeout = Option.getOrUndefined(timeout)
|
|
436
|
+
const providerConfigPrompt =
|
|
437
|
+
promptTimeout !== undefined
|
|
438
|
+
? { provider: 'openai' as const, timeout: promptTimeout }
|
|
439
|
+
: undefined
|
|
440
|
+
|
|
441
|
+
// Note: We gracefully handle errors here since embedding failure
|
|
442
|
+
// shouldn't block the main index operation. Errors are logged for debugging.
|
|
263
443
|
const embedResult = yield* buildEmbeddings(resolvedDir, {
|
|
264
444
|
force: false,
|
|
445
|
+
hnswOptions: hnswOptionsPrompt,
|
|
446
|
+
providerConfig: providerConfigPrompt,
|
|
265
447
|
onFileProgress: (progress) => {
|
|
266
|
-
|
|
267
|
-
|
|
448
|
+
console.log(
|
|
449
|
+
` [${progress.fileIndex}/${progress.totalFiles}] ${progress.filePath}`,
|
|
268
450
|
)
|
|
269
451
|
},
|
|
270
452
|
}).pipe(
|
|
271
|
-
|
|
272
|
-
Effect.
|
|
453
|
+
Effect.map((r): BuildEmbeddingsResult | null => r),
|
|
454
|
+
Effect.catchTags(createEmbeddingErrorHandler()),
|
|
273
455
|
)
|
|
274
456
|
|
|
275
457
|
if (embedResult) {
|
|
276
|
-
// Clear the progress line
|
|
277
|
-
process.stdout.write(`\r${' '.repeat(80)}\r`)
|
|
278
458
|
yield* Console.log('')
|
|
279
459
|
yield* Console.log(
|
|
280
460
|
`Completed in ${(embedResult.duration / 1000).toFixed(1)}s`,
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export { backlinksCommand } from './backlinks.js'
|
|
8
|
+
export { configCommand } from './config-cmd.js'
|
|
8
9
|
export { contextCommand } from './context.js'
|
|
10
|
+
export { duplicatesCommand } from './duplicates.js'
|
|
11
|
+
export { embeddingsCommand } from './embeddings.js'
|
|
9
12
|
export { indexCommand } from './index-cmd.js'
|
|
10
13
|
export { linksCommand } from './links.js'
|
|
11
14
|
export { searchCommand } from './search.js'
|