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,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-Command Flag Schemas
|
|
3
|
+
*
|
|
4
|
+
* Defines the valid flags for each CLI command to enable:
|
|
5
|
+
* - Unknown flag detection
|
|
6
|
+
* - Typo suggestions
|
|
7
|
+
* - Accurate flag/value parsing in the preprocessor
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type of flag
|
|
12
|
+
*/
|
|
13
|
+
export type FlagType = 'boolean' | 'string'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Flag specification
|
|
17
|
+
*/
|
|
18
|
+
export interface FlagSpec {
|
|
19
|
+
/** Flag name without leading dashes (e.g., 'json') */
|
|
20
|
+
name: string
|
|
21
|
+
/** Flag type: boolean (no value) or string (takes value) */
|
|
22
|
+
type: FlagType
|
|
23
|
+
/** Short alias without leading dash (e.g., 'n' for --limit) */
|
|
24
|
+
alias?: string
|
|
25
|
+
/** Description for error messages */
|
|
26
|
+
description?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Command flag schema
|
|
31
|
+
*/
|
|
32
|
+
export interface CommandSchema {
|
|
33
|
+
/** Command name */
|
|
34
|
+
name: string
|
|
35
|
+
/** Valid flags for this command */
|
|
36
|
+
flags: FlagSpec[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Shared Flags (used by multiple commands)
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
const jsonFlag: FlagSpec = {
|
|
44
|
+
name: 'json',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
description: 'Output as JSON',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const prettyFlag: FlagSpec = {
|
|
50
|
+
name: 'pretty',
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
description: 'Pretty-print JSON output',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const forceFlag: FlagSpec = {
|
|
56
|
+
name: 'force',
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
description: 'Force full rebuild',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const rootFlag: FlagSpec = {
|
|
62
|
+
name: 'root',
|
|
63
|
+
type: 'string',
|
|
64
|
+
alias: 'r',
|
|
65
|
+
description: 'Root directory',
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Per-Command Schemas
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
export const indexSchema: CommandSchema = {
|
|
73
|
+
name: 'index',
|
|
74
|
+
flags: [
|
|
75
|
+
{
|
|
76
|
+
name: 'embed',
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
alias: 'e',
|
|
79
|
+
description: 'Build semantic embeddings',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'no-embed',
|
|
83
|
+
type: 'boolean',
|
|
84
|
+
description: 'Skip semantic search prompt',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'watch',
|
|
88
|
+
type: 'boolean',
|
|
89
|
+
alias: 'w',
|
|
90
|
+
description: 'Watch for changes',
|
|
91
|
+
},
|
|
92
|
+
forceFlag,
|
|
93
|
+
jsonFlag,
|
|
94
|
+
prettyFlag,
|
|
95
|
+
],
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const searchSchema: CommandSchema = {
|
|
99
|
+
name: 'search',
|
|
100
|
+
flags: [
|
|
101
|
+
{
|
|
102
|
+
name: 'keyword',
|
|
103
|
+
type: 'boolean',
|
|
104
|
+
alias: 'k',
|
|
105
|
+
description: 'Force keyword search',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'heading-only',
|
|
109
|
+
type: 'boolean',
|
|
110
|
+
alias: 'H',
|
|
111
|
+
description: 'Search headings only',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'mode',
|
|
115
|
+
type: 'string',
|
|
116
|
+
alias: 'm',
|
|
117
|
+
description: 'Force search mode (semantic or keyword)',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'limit',
|
|
121
|
+
type: 'string',
|
|
122
|
+
alias: 'n',
|
|
123
|
+
description: 'Maximum results',
|
|
124
|
+
},
|
|
125
|
+
{ name: 'threshold', type: 'string', description: 'Similarity threshold' },
|
|
126
|
+
{
|
|
127
|
+
name: 'context',
|
|
128
|
+
type: 'string',
|
|
129
|
+
alias: 'C',
|
|
130
|
+
description: 'Lines of context around matches (like grep -C)',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'before-context',
|
|
134
|
+
type: 'string',
|
|
135
|
+
alias: 'B',
|
|
136
|
+
description: 'Lines of context before matches (like grep -B)',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'after-context',
|
|
140
|
+
type: 'string',
|
|
141
|
+
alias: 'A',
|
|
142
|
+
description: 'Lines of context after matches (like grep -A)',
|
|
143
|
+
},
|
|
144
|
+
jsonFlag,
|
|
145
|
+
prettyFlag,
|
|
146
|
+
],
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const contextSchema: CommandSchema = {
|
|
150
|
+
name: 'context',
|
|
151
|
+
flags: [
|
|
152
|
+
{ name: 'tokens', type: 'string', alias: 't', description: 'Token budget' },
|
|
153
|
+
{ name: 'brief', type: 'boolean', description: 'Minimal output' },
|
|
154
|
+
{ name: 'full', type: 'boolean', description: 'Include full content' },
|
|
155
|
+
{
|
|
156
|
+
name: 'section',
|
|
157
|
+
type: 'string',
|
|
158
|
+
alias: 'S',
|
|
159
|
+
description: 'Filter by section name, number, or glob pattern',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'sections',
|
|
163
|
+
type: 'boolean',
|
|
164
|
+
description: 'List available sections',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'shallow',
|
|
168
|
+
type: 'boolean',
|
|
169
|
+
description: 'Exclude nested subsections when filtering',
|
|
170
|
+
},
|
|
171
|
+
jsonFlag,
|
|
172
|
+
prettyFlag,
|
|
173
|
+
],
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export const treeSchema: CommandSchema = {
|
|
177
|
+
name: 'tree',
|
|
178
|
+
flags: [jsonFlag, prettyFlag],
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export const linksSchema: CommandSchema = {
|
|
182
|
+
name: 'links',
|
|
183
|
+
flags: [rootFlag, jsonFlag, prettyFlag],
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export const backlinksSchema: CommandSchema = {
|
|
187
|
+
name: 'backlinks',
|
|
188
|
+
flags: [rootFlag, jsonFlag, prettyFlag],
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const statsSchema: CommandSchema = {
|
|
192
|
+
name: 'stats',
|
|
193
|
+
flags: [jsonFlag, prettyFlag],
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ============================================================================
|
|
197
|
+
// Schema Registry
|
|
198
|
+
// ============================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* All command schemas indexed by command name
|
|
202
|
+
*/
|
|
203
|
+
export const commandSchemas: Record<string, CommandSchema> = {
|
|
204
|
+
index: indexSchema,
|
|
205
|
+
search: searchSchema,
|
|
206
|
+
context: contextSchema,
|
|
207
|
+
tree: treeSchema,
|
|
208
|
+
links: linksSchema,
|
|
209
|
+
backlinks: backlinksSchema,
|
|
210
|
+
stats: statsSchema,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get schema for a command
|
|
215
|
+
*/
|
|
216
|
+
export const getCommandSchema = (
|
|
217
|
+
commandName: string,
|
|
218
|
+
): CommandSchema | undefined => {
|
|
219
|
+
return commandSchemas[commandName]
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get all valid flag names for a command (both long and short forms)
|
|
224
|
+
*/
|
|
225
|
+
export const getValidFlags = (schema: CommandSchema): Set<string> => {
|
|
226
|
+
const flags = new Set<string>()
|
|
227
|
+
for (const spec of schema.flags) {
|
|
228
|
+
flags.add(`--${spec.name}`)
|
|
229
|
+
if (spec.alias) {
|
|
230
|
+
flags.add(`-${spec.alias}`)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return flags
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check if a flag takes a value for a given command
|
|
238
|
+
*/
|
|
239
|
+
export const flagTakesValue = (
|
|
240
|
+
schema: CommandSchema,
|
|
241
|
+
flag: string,
|
|
242
|
+
): boolean => {
|
|
243
|
+
// Handle --flag=value syntax
|
|
244
|
+
if (flag.includes('=')) {
|
|
245
|
+
return false // Value is already embedded
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (const spec of schema.flags) {
|
|
249
|
+
if (
|
|
250
|
+
flag === `--${spec.name}` ||
|
|
251
|
+
(spec.alias && flag === `-${spec.alias}`)
|
|
252
|
+
) {
|
|
253
|
+
return spec.type === 'string'
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return false
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Find the canonical name for a flag (for suggestions)
|
|
261
|
+
*/
|
|
262
|
+
export const getCanonicalFlagName = (
|
|
263
|
+
schema: CommandSchema,
|
|
264
|
+
flag: string,
|
|
265
|
+
): string | undefined => {
|
|
266
|
+
for (const spec of schema.flags) {
|
|
267
|
+
if (
|
|
268
|
+
flag === `--${spec.name}` ||
|
|
269
|
+
(spec.alias && flag === `-${spec.alias}`)
|
|
270
|
+
) {
|
|
271
|
+
return `--${spec.name}`
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return undefined
|
|
275
|
+
}
|
package/src/cli/help.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom help system for mdcontext CLI
|
|
3
|
+
*
|
|
4
|
+
* Provides beautiful, useful help output that matches the quality of
|
|
5
|
+
* professional CLI tools like git and gh.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Types
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
interface CommandHelp {
|
|
13
|
+
description: string
|
|
14
|
+
usage: string
|
|
15
|
+
examples: string[]
|
|
16
|
+
options: { name: string; description: string }[]
|
|
17
|
+
notes?: string[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Help Content
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export const helpContent: Record<string, CommandHelp> = {
|
|
25
|
+
index: {
|
|
26
|
+
description: 'Index markdown files for fast searching',
|
|
27
|
+
usage: 'mdcontext index [path] [options]',
|
|
28
|
+
examples: [
|
|
29
|
+
'mdcontext index # Index current directory',
|
|
30
|
+
'mdcontext index docs/ # Index specific directory',
|
|
31
|
+
'mdcontext index --embed # Include semantic embeddings',
|
|
32
|
+
'mdcontext index --watch # Watch for file changes',
|
|
33
|
+
'mdcontext index --embed --watch # Full setup with live updates',
|
|
34
|
+
'mdcontext index --force # Rebuild from scratch',
|
|
35
|
+
],
|
|
36
|
+
options: [
|
|
37
|
+
{
|
|
38
|
+
name: '-e, --embed',
|
|
39
|
+
description: 'Build semantic embeddings (enables AI-powered search)',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: '--no-embed',
|
|
43
|
+
description: 'Skip the prompt to enable semantic search',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: '-w, --watch',
|
|
47
|
+
description: 'Watch for changes and re-index automatically',
|
|
48
|
+
},
|
|
49
|
+
{ name: '--force', description: 'Rebuild from scratch, ignoring cache' },
|
|
50
|
+
{ name: '--json', description: 'Output results as JSON' },
|
|
51
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
52
|
+
],
|
|
53
|
+
notes: [
|
|
54
|
+
'After indexing, prompts to enable semantic search (use --no-embed to skip).',
|
|
55
|
+
'Embedding requires OPENAI_API_KEY environment variable.',
|
|
56
|
+
'Index is stored in .mdcontext/ directory.',
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
search: {
|
|
60
|
+
description: 'Search markdown content by meaning or heading pattern',
|
|
61
|
+
usage: 'mdcontext search [options] <query> [path]',
|
|
62
|
+
examples: [
|
|
63
|
+
'mdcontext search "auth" # Simple term search',
|
|
64
|
+
'mdcontext search "auth AND deploy" # Both terms required',
|
|
65
|
+
'mdcontext search "error OR bug" # Either term matches',
|
|
66
|
+
'mdcontext search "impl NOT test" # Exclude "test"',
|
|
67
|
+
'mdcontext search "auth AND (error OR bug)" # Grouped expressions',
|
|
68
|
+
'mdcontext search \'"exact phrase"\' # Exact phrase match',
|
|
69
|
+
'mdcontext search \'"context resumption" AND drift\' # Phrase + boolean',
|
|
70
|
+
'mdcontext search -H "API.*" # Regex on headings only',
|
|
71
|
+
'mdcontext search --mode keyword "auth" # Force keyword mode',
|
|
72
|
+
'mdcontext search --mode semantic "auth" # Force semantic mode',
|
|
73
|
+
'mdcontext search -n 5 "setup" # Limit to 5 results',
|
|
74
|
+
'mdcontext search "config" docs/ # Search in specific directory',
|
|
75
|
+
'',
|
|
76
|
+
'# Context lines (like grep):',
|
|
77
|
+
'mdcontext search "checkpoint" -C 3 # 3 lines before AND after',
|
|
78
|
+
'mdcontext search "error" -B 2 -A 5 # 2 before, 5 after',
|
|
79
|
+
],
|
|
80
|
+
options: [
|
|
81
|
+
{
|
|
82
|
+
name: '-k, --keyword',
|
|
83
|
+
description: 'Force keyword search (content text match)',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: '-H, --heading-only',
|
|
87
|
+
description: 'Search headings only (not content)',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: '-m, --mode <mode>',
|
|
91
|
+
description: 'Force search mode: semantic or keyword',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: '-n, --limit <n>',
|
|
95
|
+
description: 'Maximum number of results (default: 10)',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: '-C <n>',
|
|
99
|
+
description: 'Show N context lines before AND after each match',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: '-B <n>',
|
|
103
|
+
description: 'Show N context lines before each match',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: '-A <n>',
|
|
107
|
+
description: 'Show N context lines after each match',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: '--threshold <n>',
|
|
111
|
+
description:
|
|
112
|
+
'Similarity threshold 0-1 for semantic search (default: 0.5)',
|
|
113
|
+
},
|
|
114
|
+
{ name: '--json', description: 'Output results as JSON' },
|
|
115
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
116
|
+
],
|
|
117
|
+
notes: [
|
|
118
|
+
'Auto-detects mode: semantic if embeddings exist, keyword otherwise.',
|
|
119
|
+
'Boolean operators: AND, OR, NOT (case-insensitive).',
|
|
120
|
+
'Quoted phrases match exactly: "context resumption".',
|
|
121
|
+
'Regex patterns (e.g., "API.*") always use keyword search.',
|
|
122
|
+
'Run "mdcontext index --embed" first for semantic search.',
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
context: {
|
|
126
|
+
description: 'Get LLM-ready summary of markdown files',
|
|
127
|
+
usage: 'mdcontext context [options] <files>...',
|
|
128
|
+
examples: [
|
|
129
|
+
'mdcontext context README.md # Summarize single file',
|
|
130
|
+
'mdcontext context *.md # Summarize all markdown files',
|
|
131
|
+
'mdcontext context -t 1000 *.md # Fit within 1000 token budget',
|
|
132
|
+
'mdcontext context --brief *.md # Minimal output (headings only)',
|
|
133
|
+
'mdcontext context --full doc.md # Include full content',
|
|
134
|
+
'mdcontext context *.md | pbcopy # Copy to clipboard (macOS)',
|
|
135
|
+
'',
|
|
136
|
+
'# Section filtering:',
|
|
137
|
+
'mdcontext context doc.md --sections # List available sections',
|
|
138
|
+
'mdcontext context doc.md --section "Setup" # Extract by section name',
|
|
139
|
+
'mdcontext context doc.md --section "2.1" # Extract by section number',
|
|
140
|
+
'mdcontext context doc.md --section "API*" # Glob pattern matching',
|
|
141
|
+
'mdcontext context doc.md --section "Config" --shallow # Top-level only',
|
|
142
|
+
],
|
|
143
|
+
options: [
|
|
144
|
+
{
|
|
145
|
+
name: '-t, --tokens <n>',
|
|
146
|
+
description: 'Token budget for output (default: 2000)',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: '--brief',
|
|
150
|
+
description: 'Minimal output (headings and key points only)',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: '--full',
|
|
154
|
+
description: 'Include full content (no summarization)',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: '--section <name>',
|
|
158
|
+
description:
|
|
159
|
+
'Extract specific section by name, number, or glob pattern',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: '--sections',
|
|
163
|
+
description: 'List available sections with numbers and token counts',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: '--shallow',
|
|
167
|
+
description: 'Exclude nested subsections when using --section',
|
|
168
|
+
},
|
|
169
|
+
{ name: '--json', description: 'Output as JSON' },
|
|
170
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
171
|
+
],
|
|
172
|
+
notes: [
|
|
173
|
+
'Token budget controls how much content is included.',
|
|
174
|
+
'Lower tokens = more aggressive summarization.',
|
|
175
|
+
'Output is formatted for direct use in LLM prompts.',
|
|
176
|
+
'Use --sections to discover section names before filtering.',
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
tree: {
|
|
180
|
+
description: 'Show file tree or document outline',
|
|
181
|
+
usage: 'mdcontext tree [path] [options]',
|
|
182
|
+
examples: [
|
|
183
|
+
'mdcontext tree # List markdown files in current dir',
|
|
184
|
+
'mdcontext tree docs/ # List files in specific directory',
|
|
185
|
+
'mdcontext tree README.md # Show document outline (headings)',
|
|
186
|
+
'mdcontext tree doc.md --json # Outline as JSON',
|
|
187
|
+
],
|
|
188
|
+
options: [
|
|
189
|
+
{ name: '--json', description: 'Output as JSON' },
|
|
190
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
191
|
+
],
|
|
192
|
+
notes: [
|
|
193
|
+
'Pass a directory to list markdown files.',
|
|
194
|
+
'Pass a file to show its heading structure with token counts.',
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
links: {
|
|
198
|
+
description: 'Show what a file links to (outgoing links)',
|
|
199
|
+
usage: 'mdcontext links <file> [options]',
|
|
200
|
+
examples: [
|
|
201
|
+
'mdcontext links README.md # Show outgoing links',
|
|
202
|
+
'mdcontext links doc.md --json # Output as JSON',
|
|
203
|
+
'mdcontext links doc.md -r docs/ # Resolve links relative to docs/',
|
|
204
|
+
],
|
|
205
|
+
options: [
|
|
206
|
+
{
|
|
207
|
+
name: '-r, --root <dir>',
|
|
208
|
+
description: 'Root directory for resolving relative links',
|
|
209
|
+
},
|
|
210
|
+
{ name: '--json', description: 'Output as JSON' },
|
|
211
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
backlinks: {
|
|
215
|
+
description: 'Show what links to a file (incoming links)',
|
|
216
|
+
usage: 'mdcontext backlinks <file> [options]',
|
|
217
|
+
examples: [
|
|
218
|
+
'mdcontext backlinks api.md # What links to api.md?',
|
|
219
|
+
'mdcontext backlinks doc.md --json # Output as JSON',
|
|
220
|
+
'mdcontext backlinks doc.md -r ./ # Resolve from current directory',
|
|
221
|
+
],
|
|
222
|
+
options: [
|
|
223
|
+
{
|
|
224
|
+
name: '-r, --root <dir>',
|
|
225
|
+
description: 'Root directory for resolving relative links',
|
|
226
|
+
},
|
|
227
|
+
{ name: '--json', description: 'Output as JSON' },
|
|
228
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
229
|
+
],
|
|
230
|
+
notes: ['Requires index to exist. Run "mdcontext index" first.'],
|
|
231
|
+
},
|
|
232
|
+
stats: {
|
|
233
|
+
description: 'Show index statistics',
|
|
234
|
+
usage: 'mdcontext stats [path] [options]',
|
|
235
|
+
examples: [
|
|
236
|
+
'mdcontext stats # Show stats for current directory',
|
|
237
|
+
'mdcontext stats docs/ # Show stats for specific directory',
|
|
238
|
+
'mdcontext stats --json # Output as JSON',
|
|
239
|
+
],
|
|
240
|
+
options: [
|
|
241
|
+
{ name: '--json', description: 'Output as JSON' },
|
|
242
|
+
{ name: '--pretty', description: 'Pretty-print JSON output' },
|
|
243
|
+
],
|
|
244
|
+
notes: ['Shows embedding count, dimensions, and cost if embeddings exist.'],
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ============================================================================
|
|
249
|
+
// Help Rendering
|
|
250
|
+
// ============================================================================
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Render beautiful subcommand help
|
|
254
|
+
*/
|
|
255
|
+
export const showSubcommandHelp = (command: string): void => {
|
|
256
|
+
const help = helpContent[command]
|
|
257
|
+
if (!help) {
|
|
258
|
+
console.log(`Unknown command: ${command}`)
|
|
259
|
+
console.log('Run "mdcontext --help" for available commands.')
|
|
260
|
+
process.exit(1)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Header
|
|
264
|
+
console.log(`\n\x1b[1mmdcontext ${command}\x1b[0m - ${help.description}`)
|
|
265
|
+
|
|
266
|
+
// Usage
|
|
267
|
+
console.log(`\n\x1b[33mUSAGE\x1b[0m`)
|
|
268
|
+
console.log(` ${help.usage}`)
|
|
269
|
+
|
|
270
|
+
// Examples
|
|
271
|
+
console.log(`\n\x1b[33mEXAMPLES\x1b[0m`)
|
|
272
|
+
for (const example of help.examples) {
|
|
273
|
+
console.log(` ${example}`)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Options
|
|
277
|
+
console.log(`\n\x1b[33mOPTIONS\x1b[0m`)
|
|
278
|
+
for (const opt of help.options) {
|
|
279
|
+
// Pad option name to 24 chars for alignment
|
|
280
|
+
const paddedName = opt.name.padEnd(24)
|
|
281
|
+
console.log(` ${paddedName}${opt.description}`)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Notes (if any)
|
|
285
|
+
if (help.notes && help.notes.length > 0) {
|
|
286
|
+
console.log(`\n\x1b[33mNOTES\x1b[0m`)
|
|
287
|
+
for (const note of help.notes) {
|
|
288
|
+
console.log(` ${note}`)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
console.log('')
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Custom help output for main command - beautiful and useful
|
|
297
|
+
*/
|
|
298
|
+
export const showMainHelp = (): void => {
|
|
299
|
+
const help = `
|
|
300
|
+
\x1b[1mmdcontext\x1b[0m - Token-efficient markdown analysis for LLMs
|
|
301
|
+
|
|
302
|
+
\x1b[33mCOMMANDS\x1b[0m
|
|
303
|
+
index [path] Index markdown files (default: .)
|
|
304
|
+
search <query> [path] Search by meaning or structure
|
|
305
|
+
context <files>... Get LLM-ready summary
|
|
306
|
+
tree [path] Show files or document outline
|
|
307
|
+
links <file> Show outgoing links
|
|
308
|
+
backlinks <file> Show incoming links
|
|
309
|
+
stats [path] Index statistics
|
|
310
|
+
|
|
311
|
+
\x1b[33mEXAMPLES\x1b[0m
|
|
312
|
+
mdcontext tree # List all markdown files
|
|
313
|
+
mdcontext tree README.md # Show document outline
|
|
314
|
+
mdcontext index # Index current directory
|
|
315
|
+
mdcontext index --embed # Index with semantic embeddings
|
|
316
|
+
mdcontext search "auth" # Simple term search
|
|
317
|
+
mdcontext search "auth AND deploy" # Boolean AND (both required)
|
|
318
|
+
mdcontext search "error OR bug" # Boolean OR (either matches)
|
|
319
|
+
mdcontext search '"exact phrase"' # Quoted phrase (exact match)
|
|
320
|
+
mdcontext search "how to deploy" # Semantic search (if embeddings exist)
|
|
321
|
+
mdcontext context README.md # Summarize a file
|
|
322
|
+
mdcontext context *.md -t 2000 # Multi-file with token budget
|
|
323
|
+
|
|
324
|
+
\x1b[33mWORKFLOWS\x1b[0m
|
|
325
|
+
\x1b[2m# Quick context for LLM\x1b[0m
|
|
326
|
+
mdcontext context README.md docs/*.md | pbcopy
|
|
327
|
+
|
|
328
|
+
\x1b[2m# Find relevant documentation\x1b[0m
|
|
329
|
+
mdcontext search "error handling"
|
|
330
|
+
|
|
331
|
+
\x1b[2m# Complex queries with boolean operators\x1b[0m
|
|
332
|
+
mdcontext search "auth AND (error OR exception) NOT test"
|
|
333
|
+
|
|
334
|
+
\x1b[2m# Explore a new codebase\x1b[0m
|
|
335
|
+
mdcontext tree && mdcontext stats
|
|
336
|
+
|
|
337
|
+
\x1b[2m# Build semantic search\x1b[0m
|
|
338
|
+
mdcontext index --embed && mdcontext search "authentication flow"
|
|
339
|
+
|
|
340
|
+
\x1b[33mGLOBAL OPTIONS\x1b[0m
|
|
341
|
+
--json Output as JSON
|
|
342
|
+
--pretty Pretty-print JSON
|
|
343
|
+
--help, -h Show help
|
|
344
|
+
--version, -v Show version
|
|
345
|
+
|
|
346
|
+
Run \x1b[36mmdcontext <command> --help\x1b[0m for command-specific options.
|
|
347
|
+
`
|
|
348
|
+
console.log(help)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ============================================================================
|
|
352
|
+
// Help Detection
|
|
353
|
+
// ============================================================================
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Check for subcommand help pattern: mdcontext <cmd> --help or mdcontext <cmd> -h
|
|
357
|
+
* Returns true if help was shown and we should exit
|
|
358
|
+
*/
|
|
359
|
+
export const checkSubcommandHelp = (): boolean => {
|
|
360
|
+
const args = process.argv.slice(2)
|
|
361
|
+
if (args.length < 2) return false
|
|
362
|
+
|
|
363
|
+
const command = args[0]
|
|
364
|
+
const hasHelpFlag = args.includes('--help') || args.includes('-h')
|
|
365
|
+
|
|
366
|
+
if (hasHelpFlag && command && helpContent[command]) {
|
|
367
|
+
showSubcommandHelp(command)
|
|
368
|
+
process.exit(0)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return false
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Check if we should show main help
|
|
376
|
+
*/
|
|
377
|
+
export const shouldShowMainHelp = (): boolean => {
|
|
378
|
+
const args = process.argv.slice(2)
|
|
379
|
+
const showHelp =
|
|
380
|
+
args.length === 0 ||
|
|
381
|
+
args.includes('--help') ||
|
|
382
|
+
args.includes('-h') ||
|
|
383
|
+
(args.length === 1 && args[0] === 'help')
|
|
384
|
+
|
|
385
|
+
return showHelp && !args.some((a) => !a.startsWith('-') && a !== 'help')
|
|
386
|
+
}
|
package/src/cli/index.ts
ADDED