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.
Files changed (140) hide show
  1. package/.changeset/README.md +28 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/workflows/ci.yml +83 -0
  4. package/.github/workflows/release.yml +113 -0
  5. package/.tldrignore +112 -0
  6. package/AGENTS.md +46 -0
  7. package/BACKLOG.md +338 -0
  8. package/README.md +231 -11
  9. package/biome.json +36 -0
  10. package/cspell.config.yaml +14 -0
  11. package/dist/chunk-KRYIFLQR.js +92 -0
  12. package/dist/chunk-S7E6TFX6.js +742 -0
  13. package/dist/chunk-VVTGZNBT.js +1519 -0
  14. package/dist/cli/main.d.ts +1 -0
  15. package/dist/cli/main.js +2015 -0
  16. package/dist/index.d.ts +266 -0
  17. package/dist/index.js +86 -0
  18. package/dist/mcp/server.d.ts +1 -0
  19. package/dist/mcp/server.js +376 -0
  20. package/docs/019-USAGE.md +586 -0
  21. package/docs/020-current-implementation.md +364 -0
  22. package/docs/021-DOGFOODING-FINDINGS.md +175 -0
  23. package/docs/BACKLOG.md +80 -0
  24. package/docs/DESIGN.md +439 -0
  25. package/docs/PROJECT.md +88 -0
  26. package/docs/ROADMAP.md +407 -0
  27. package/docs/test-links.md +9 -0
  28. package/package.json +69 -10
  29. package/pnpm-workspace.yaml +5 -0
  30. package/research/config-analysis/01-current-implementation.md +470 -0
  31. package/research/config-analysis/02-strategy-recommendation.md +428 -0
  32. package/research/config-analysis/03-task-candidates.md +715 -0
  33. package/research/config-analysis/033-research-configuration-management.md +828 -0
  34. package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
  35. package/research/config-analysis/04-consolidated-task-candidates.md +277 -0
  36. package/research/dogfood/consolidated-tool-evaluation.md +373 -0
  37. package/research/dogfood/strategy-a/a-synthesis.md +184 -0
  38. package/research/dogfood/strategy-a/a1-docs.md +226 -0
  39. package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
  40. package/research/dogfood/strategy-a/a3-llm.md +164 -0
  41. package/research/dogfood/strategy-b/b-synthesis.md +228 -0
  42. package/research/dogfood/strategy-b/b1-architecture.md +207 -0
  43. package/research/dogfood/strategy-b/b2-gaps.md +258 -0
  44. package/research/dogfood/strategy-b/b3-workflows.md +250 -0
  45. package/research/dogfood/strategy-c/c-synthesis.md +451 -0
  46. package/research/dogfood/strategy-c/c1-explorer.md +192 -0
  47. package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
  48. package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
  49. package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
  50. package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
  51. package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
  52. package/research/effect-cli-error-handling.md +845 -0
  53. package/research/effect-errors-as-values.md +943 -0
  54. package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
  55. package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
  56. package/research/errors-task-analysis/embeddings-analysis.md +709 -0
  57. package/research/errors-task-analysis/index-search-analysis.md +812 -0
  58. package/research/mdcontext-error-analysis.md +521 -0
  59. package/research/npm_publish/011-npm-workflow-research-agent2.md +792 -0
  60. package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
  61. package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
  62. package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
  63. package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
  64. package/research/semantic-search/002-research-embedding-models.md +490 -0
  65. package/research/semantic-search/003-research-rag-alternatives.md +523 -0
  66. package/research/semantic-search/004-research-vector-search.md +841 -0
  67. package/research/semantic-search/032-research-semantic-search.md +427 -0
  68. package/research/task-management-2026/00-synthesis-recommendations.md +295 -0
  69. package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
  70. package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
  71. package/research/task-management-2026/03-lightweight-file-based.md +567 -0
  72. package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
  73. package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
  74. package/research/task-management-2026/linear/02-api-integrations.md +930 -0
  75. package/research/task-management-2026/linear/03-ai-features.md +368 -0
  76. package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
  77. package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -0
  78. package/scripts/rebuild-hnswlib.js +63 -0
  79. package/src/cli/argv-preprocessor.test.ts +210 -0
  80. package/src/cli/argv-preprocessor.ts +202 -0
  81. package/src/cli/cli.test.ts +430 -0
  82. package/src/cli/commands/backlinks.ts +54 -0
  83. package/src/cli/commands/context.ts +197 -0
  84. package/src/cli/commands/index-cmd.ts +300 -0
  85. package/src/cli/commands/index.ts +13 -0
  86. package/src/cli/commands/links.ts +52 -0
  87. package/src/cli/commands/search.ts +451 -0
  88. package/src/cli/commands/stats.ts +146 -0
  89. package/src/cli/commands/tree.ts +107 -0
  90. package/src/cli/flag-schemas.ts +275 -0
  91. package/src/cli/help.ts +386 -0
  92. package/src/cli/index.ts +9 -0
  93. package/src/cli/main.ts +145 -0
  94. package/src/cli/options.ts +31 -0
  95. package/src/cli/typo-suggester.test.ts +105 -0
  96. package/src/cli/typo-suggester.ts +130 -0
  97. package/src/cli/utils.ts +126 -0
  98. package/src/core/index.ts +1 -0
  99. package/src/core/types.ts +140 -0
  100. package/src/embeddings/index.ts +8 -0
  101. package/src/embeddings/openai-provider.ts +165 -0
  102. package/src/embeddings/semantic-search.ts +583 -0
  103. package/src/embeddings/types.ts +82 -0
  104. package/src/embeddings/vector-store.ts +299 -0
  105. package/src/index/index.ts +4 -0
  106. package/src/index/indexer.ts +446 -0
  107. package/src/index/storage.ts +196 -0
  108. package/src/index/types.ts +109 -0
  109. package/src/index/watcher.ts +131 -0
  110. package/src/index.ts +8 -0
  111. package/src/mcp/server.ts +483 -0
  112. package/src/parser/index.ts +1 -0
  113. package/src/parser/parser.test.ts +291 -0
  114. package/src/parser/parser.ts +395 -0
  115. package/src/parser/section-filter.ts +270 -0
  116. package/src/search/query-parser.test.ts +260 -0
  117. package/src/search/query-parser.ts +319 -0
  118. package/src/search/searcher.test.ts +182 -0
  119. package/src/search/searcher.ts +602 -0
  120. package/src/summarize/budget-bugs.test.ts +620 -0
  121. package/src/summarize/formatters.ts +419 -0
  122. package/src/summarize/index.ts +20 -0
  123. package/src/summarize/summarizer.test.ts +275 -0
  124. package/src/summarize/summarizer.ts +528 -0
  125. package/src/summarize/verify-bugs.test.ts +238 -0
  126. package/src/utils/index.ts +1 -0
  127. package/src/utils/tokens.test.ts +142 -0
  128. package/src/utils/tokens.ts +186 -0
  129. package/tests/fixtures/cli/.mdcontext/config.json +8 -0
  130. package/tests/fixtures/cli/.mdcontext/indexes/documents.json +33 -0
  131. package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
  132. package/tests/fixtures/cli/.mdcontext/indexes/sections.json +233 -0
  133. package/tests/fixtures/cli/.mdcontext/vectors.bin +0 -0
  134. package/tests/fixtures/cli/.mdcontext/vectors.meta.json +1264 -0
  135. package/tests/fixtures/cli/README.md +9 -0
  136. package/tests/fixtures/cli/api-reference.md +11 -0
  137. package/tests/fixtures/cli/getting-started.md +11 -0
  138. package/tsconfig.json +26 -0
  139. package/vitest.config.ts +21 -0
  140. 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
+ )