mdcontext 0.0.1 → 0.1.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/.github/workflows/ci.yml +83 -0
- package/.github/workflows/release.yml +113 -0
- package/.tldrignore +112 -0
- package/AGENTS.md +46 -0
- package/BACKLOG.md +338 -0
- package/README.md +231 -11
- package/biome.json +36 -0
- package/cspell.config.yaml +14 -0
- package/dist/chunk-KRYIFLQR.js +92 -0
- package/dist/chunk-S7E6TFX6.js +742 -0
- package/dist/chunk-VVTGZNBT.js +1519 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +2015 -0
- package/dist/index.d.ts +266 -0
- package/dist/index.js +86 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +376 -0
- package/docs/019-USAGE.md +586 -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/DESIGN.md +439 -0
- package/docs/PROJECT.md +88 -0
- package/docs/ROADMAP.md +407 -0
- package/docs/test-links.md +9 -0
- package/package.json +69 -10
- package/pnpm-workspace.yaml +5 -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/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/mdcontext-error-analysis.md +521 -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/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/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/scripts/rebuild-hnswlib.js +63 -0
- package/src/cli/argv-preprocessor.test.ts +210 -0
- package/src/cli/argv-preprocessor.ts +202 -0
- package/src/cli/cli.test.ts +430 -0
- package/src/cli/commands/backlinks.ts +54 -0
- package/src/cli/commands/context.ts +197 -0
- package/src/cli/commands/index-cmd.ts +300 -0
- package/src/cli/commands/index.ts +13 -0
- package/src/cli/commands/links.ts +52 -0
- package/src/cli/commands/search.ts +451 -0
- package/src/cli/commands/stats.ts +146 -0
- package/src/cli/commands/tree.ts +107 -0
- package/src/cli/flag-schemas.ts +275 -0
- package/src/cli/help.ts +386 -0
- package/src/cli/index.ts +9 -0
- package/src/cli/main.ts +145 -0
- package/src/cli/options.ts +31 -0
- package/src/cli/typo-suggester.test.ts +105 -0
- package/src/cli/typo-suggester.ts +130 -0
- package/src/cli/utils.ts +126 -0
- package/src/core/index.ts +1 -0
- package/src/core/types.ts +140 -0
- package/src/embeddings/index.ts +8 -0
- package/src/embeddings/openai-provider.ts +165 -0
- package/src/embeddings/semantic-search.ts +583 -0
- package/src/embeddings/types.ts +82 -0
- package/src/embeddings/vector-store.ts +299 -0
- package/src/index/index.ts +4 -0
- package/src/index/indexer.ts +446 -0
- package/src/index/storage.ts +196 -0
- package/src/index/types.ts +109 -0
- package/src/index/watcher.ts +131 -0
- package/src/index.ts +8 -0
- package/src/mcp/server.ts +483 -0
- package/src/parser/index.ts +1 -0
- package/src/parser/parser.test.ts +291 -0
- package/src/parser/parser.ts +395 -0
- package/src/parser/section-filter.ts +270 -0
- package/src/search/query-parser.test.ts +260 -0
- package/src/search/query-parser.ts +319 -0
- package/src/search/searcher.test.ts +182 -0
- package/src/search/searcher.ts +602 -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 +528 -0
- package/src/summarize/verify-bugs.test.ts +238 -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/config.json +8 -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 +233 -0
- package/tests/fixtures/cli/.mdcontext/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/vectors.meta.json +1264 -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/tsconfig.json +26 -0
- package/vitest.config.ts +21 -0
- package/vitest.setup.ts +12 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI embedding provider
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Console, Effect } from 'effect'
|
|
6
|
+
import OpenAI from 'openai'
|
|
7
|
+
import type { EmbeddingProvider, EmbeddingResult } from './types.js'
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Cost Constants
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
// Prices per 1M tokens (as of 2024)
|
|
14
|
+
const PRICING: Record<string, number> = {
|
|
15
|
+
'text-embedding-3-small': 0.02,
|
|
16
|
+
'text-embedding-3-large': 0.13,
|
|
17
|
+
'text-embedding-ada-002': 0.1,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Error Classes
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export class MissingApiKeyError extends Error {
|
|
25
|
+
constructor() {
|
|
26
|
+
super('OPENAI_API_KEY not set')
|
|
27
|
+
this.name = 'MissingApiKeyError'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class InvalidApiKeyError extends Error {
|
|
32
|
+
constructor(message?: string) {
|
|
33
|
+
super(message ?? 'Invalid OPENAI_API_KEY')
|
|
34
|
+
this.name = 'InvalidApiKeyError'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// OpenAI Provider
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
export interface OpenAIProviderOptions {
|
|
43
|
+
readonly apiKey?: string | undefined
|
|
44
|
+
readonly model?: string | undefined
|
|
45
|
+
readonly batchSize?: number | undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class OpenAIProvider implements EmbeddingProvider {
|
|
49
|
+
readonly name: string
|
|
50
|
+
readonly dimensions: number
|
|
51
|
+
|
|
52
|
+
private readonly client: OpenAI
|
|
53
|
+
private readonly model: string
|
|
54
|
+
private readonly batchSize: number
|
|
55
|
+
|
|
56
|
+
constructor(options: OpenAIProviderOptions = {}) {
|
|
57
|
+
const apiKey = options.apiKey ?? process.env.OPENAI_API_KEY
|
|
58
|
+
if (!apiKey) {
|
|
59
|
+
throw new MissingApiKeyError()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.client = new OpenAI({ apiKey })
|
|
63
|
+
this.model = options.model ?? 'text-embedding-3-small'
|
|
64
|
+
this.batchSize = options.batchSize ?? 100
|
|
65
|
+
this.name = `openai:${this.model}`
|
|
66
|
+
this.dimensions = 512
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async embed(texts: string[]): Promise<EmbeddingResult> {
|
|
70
|
+
if (texts.length === 0) {
|
|
71
|
+
return { embeddings: [], tokensUsed: 0, cost: 0 }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const allEmbeddings: number[][] = []
|
|
75
|
+
let totalTokens = 0
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Process in batches
|
|
79
|
+
for (let i = 0; i < texts.length; i += this.batchSize) {
|
|
80
|
+
const batch = texts.slice(i, i + this.batchSize)
|
|
81
|
+
|
|
82
|
+
const response = await this.client.embeddings.create({
|
|
83
|
+
model: this.model,
|
|
84
|
+
input: batch,
|
|
85
|
+
dimensions: 512, // Ensure consistent dimensions
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
for (const item of response.data) {
|
|
89
|
+
allEmbeddings.push(item.embedding)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
totalTokens += response.usage?.total_tokens ?? 0
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
// Check for authentication errors (401 Unauthorized, invalid API key)
|
|
96
|
+
if (error instanceof OpenAI.AuthenticationError) {
|
|
97
|
+
throw new InvalidApiKeyError(error.message)
|
|
98
|
+
}
|
|
99
|
+
throw error
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Calculate cost
|
|
103
|
+
const pricePerMillion = PRICING[this.model] ?? 0.02
|
|
104
|
+
const cost = (totalTokens / 1_000_000) * pricePerMillion
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
embeddings: allEmbeddings,
|
|
108
|
+
tokensUsed: totalTokens,
|
|
109
|
+
cost,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Factory
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
export const createOpenAIProvider = (
|
|
119
|
+
options?: OpenAIProviderOptions,
|
|
120
|
+
): EmbeddingProvider => new OpenAIProvider(options)
|
|
121
|
+
|
|
122
|
+
// ============================================================================
|
|
123
|
+
// Error Handler Utility
|
|
124
|
+
// ============================================================================
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Catches OpenAI API key errors and displays helpful messages.
|
|
128
|
+
* Use with Effect.pipe after operations that may throw MissingApiKeyError or InvalidApiKeyError.
|
|
129
|
+
*/
|
|
130
|
+
export const handleApiKeyError = <A, E>(
|
|
131
|
+
effect: Effect.Effect<A, E | MissingApiKeyError | InvalidApiKeyError>,
|
|
132
|
+
): Effect.Effect<A, E | Error> =>
|
|
133
|
+
effect.pipe(
|
|
134
|
+
Effect.catchIf(
|
|
135
|
+
(e): e is MissingApiKeyError => e instanceof MissingApiKeyError,
|
|
136
|
+
() =>
|
|
137
|
+
Effect.gen(function* () {
|
|
138
|
+
yield* Console.error('')
|
|
139
|
+
yield* Console.error('Error: OPENAI_API_KEY not set')
|
|
140
|
+
yield* Console.error('')
|
|
141
|
+
yield* Console.error(
|
|
142
|
+
'To use semantic search, set your OpenAI API key:',
|
|
143
|
+
)
|
|
144
|
+
yield* Console.error(' export OPENAI_API_KEY=sk-...')
|
|
145
|
+
yield* Console.error('')
|
|
146
|
+
yield* Console.error('Or add to .env file in project root.')
|
|
147
|
+
return yield* Effect.fail(new Error('Missing API key'))
|
|
148
|
+
}),
|
|
149
|
+
),
|
|
150
|
+
Effect.catchIf(
|
|
151
|
+
(e): e is InvalidApiKeyError => e instanceof InvalidApiKeyError,
|
|
152
|
+
(e) =>
|
|
153
|
+
Effect.gen(function* () {
|
|
154
|
+
yield* Console.error('')
|
|
155
|
+
yield* Console.error('Error: Invalid OPENAI_API_KEY')
|
|
156
|
+
yield* Console.error('')
|
|
157
|
+
yield* Console.error('The provided API key was rejected by OpenAI.')
|
|
158
|
+
yield* Console.error('Please check your API key is correct:')
|
|
159
|
+
yield* Console.error(' export OPENAI_API_KEY=sk-...')
|
|
160
|
+
yield* Console.error('')
|
|
161
|
+
yield* Console.error(`Details: ${e.message}`)
|
|
162
|
+
return yield* Effect.fail(new Error('Invalid API key'))
|
|
163
|
+
}),
|
|
164
|
+
),
|
|
165
|
+
)
|