viberag 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 (151) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +219 -0
  3. package/dist/cli/__tests__/mcp-setup.test.d.ts +6 -0
  4. package/dist/cli/__tests__/mcp-setup.test.js +597 -0
  5. package/dist/cli/app.d.ts +2 -0
  6. package/dist/cli/app.js +238 -0
  7. package/dist/cli/commands/handlers.d.ts +57 -0
  8. package/dist/cli/commands/handlers.js +231 -0
  9. package/dist/cli/commands/index.d.ts +2 -0
  10. package/dist/cli/commands/index.js +2 -0
  11. package/dist/cli/commands/mcp-setup.d.ts +107 -0
  12. package/dist/cli/commands/mcp-setup.js +509 -0
  13. package/dist/cli/commands/useRagCommands.d.ts +23 -0
  14. package/dist/cli/commands/useRagCommands.js +180 -0
  15. package/dist/cli/components/CleanWizard.d.ts +17 -0
  16. package/dist/cli/components/CleanWizard.js +169 -0
  17. package/dist/cli/components/InitWizard.d.ts +20 -0
  18. package/dist/cli/components/InitWizard.js +370 -0
  19. package/dist/cli/components/McpSetupWizard.d.ts +37 -0
  20. package/dist/cli/components/McpSetupWizard.js +387 -0
  21. package/dist/cli/components/SearchResultsDisplay.d.ts +13 -0
  22. package/dist/cli/components/SearchResultsDisplay.js +130 -0
  23. package/dist/cli/components/WelcomeBanner.d.ts +10 -0
  24. package/dist/cli/components/WelcomeBanner.js +26 -0
  25. package/dist/cli/components/index.d.ts +1 -0
  26. package/dist/cli/components/index.js +1 -0
  27. package/dist/cli/data/mcp-editors.d.ts +80 -0
  28. package/dist/cli/data/mcp-editors.js +270 -0
  29. package/dist/cli/index.d.ts +2 -0
  30. package/dist/cli/index.js +26 -0
  31. package/dist/cli-bundle.cjs +5269 -0
  32. package/dist/common/commands/terminalSetup.d.ts +2 -0
  33. package/dist/common/commands/terminalSetup.js +144 -0
  34. package/dist/common/components/CommandSuggestions.d.ts +9 -0
  35. package/dist/common/components/CommandSuggestions.js +20 -0
  36. package/dist/common/components/StaticWithResize.d.ts +23 -0
  37. package/dist/common/components/StaticWithResize.js +62 -0
  38. package/dist/common/components/StatusBar.d.ts +8 -0
  39. package/dist/common/components/StatusBar.js +64 -0
  40. package/dist/common/components/TextInput.d.ts +12 -0
  41. package/dist/common/components/TextInput.js +239 -0
  42. package/dist/common/components/index.d.ts +3 -0
  43. package/dist/common/components/index.js +3 -0
  44. package/dist/common/hooks/index.d.ts +4 -0
  45. package/dist/common/hooks/index.js +4 -0
  46. package/dist/common/hooks/useCommandHistory.d.ts +7 -0
  47. package/dist/common/hooks/useCommandHistory.js +51 -0
  48. package/dist/common/hooks/useCtrlC.d.ts +9 -0
  49. package/dist/common/hooks/useCtrlC.js +40 -0
  50. package/dist/common/hooks/useKittyKeyboard.d.ts +10 -0
  51. package/dist/common/hooks/useKittyKeyboard.js +26 -0
  52. package/dist/common/hooks/useStaticOutputBuffer.d.ts +31 -0
  53. package/dist/common/hooks/useStaticOutputBuffer.js +58 -0
  54. package/dist/common/hooks/useTerminalResize.d.ts +28 -0
  55. package/dist/common/hooks/useTerminalResize.js +51 -0
  56. package/dist/common/hooks/useTextBuffer.d.ts +13 -0
  57. package/dist/common/hooks/useTextBuffer.js +165 -0
  58. package/dist/common/index.d.ts +13 -0
  59. package/dist/common/index.js +17 -0
  60. package/dist/common/types.d.ts +162 -0
  61. package/dist/common/types.js +1 -0
  62. package/dist/mcp/index.d.ts +12 -0
  63. package/dist/mcp/index.js +66 -0
  64. package/dist/mcp/server.d.ts +25 -0
  65. package/dist/mcp/server.js +837 -0
  66. package/dist/mcp/watcher.d.ts +86 -0
  67. package/dist/mcp/watcher.js +334 -0
  68. package/dist/rag/__tests__/grammar-smoke.test.d.ts +9 -0
  69. package/dist/rag/__tests__/grammar-smoke.test.js +161 -0
  70. package/dist/rag/__tests__/helpers.d.ts +30 -0
  71. package/dist/rag/__tests__/helpers.js +67 -0
  72. package/dist/rag/__tests__/merkle.test.d.ts +5 -0
  73. package/dist/rag/__tests__/merkle.test.js +161 -0
  74. package/dist/rag/__tests__/metadata-extraction.test.d.ts +10 -0
  75. package/dist/rag/__tests__/metadata-extraction.test.js +202 -0
  76. package/dist/rag/__tests__/multi-language.test.d.ts +13 -0
  77. package/dist/rag/__tests__/multi-language.test.js +535 -0
  78. package/dist/rag/__tests__/rag.test.d.ts +10 -0
  79. package/dist/rag/__tests__/rag.test.js +311 -0
  80. package/dist/rag/__tests__/search-exhaustive.test.d.ts +9 -0
  81. package/dist/rag/__tests__/search-exhaustive.test.js +87 -0
  82. package/dist/rag/__tests__/search-filters.test.d.ts +10 -0
  83. package/dist/rag/__tests__/search-filters.test.js +250 -0
  84. package/dist/rag/__tests__/search-modes.test.d.ts +8 -0
  85. package/dist/rag/__tests__/search-modes.test.js +133 -0
  86. package/dist/rag/config/index.d.ts +61 -0
  87. package/dist/rag/config/index.js +111 -0
  88. package/dist/rag/constants.d.ts +41 -0
  89. package/dist/rag/constants.js +57 -0
  90. package/dist/rag/embeddings/fastembed.d.ts +62 -0
  91. package/dist/rag/embeddings/fastembed.js +124 -0
  92. package/dist/rag/embeddings/gemini.d.ts +26 -0
  93. package/dist/rag/embeddings/gemini.js +116 -0
  94. package/dist/rag/embeddings/index.d.ts +10 -0
  95. package/dist/rag/embeddings/index.js +9 -0
  96. package/dist/rag/embeddings/local-4b.d.ts +28 -0
  97. package/dist/rag/embeddings/local-4b.js +51 -0
  98. package/dist/rag/embeddings/local.d.ts +29 -0
  99. package/dist/rag/embeddings/local.js +119 -0
  100. package/dist/rag/embeddings/mistral.d.ts +22 -0
  101. package/dist/rag/embeddings/mistral.js +85 -0
  102. package/dist/rag/embeddings/openai.d.ts +22 -0
  103. package/dist/rag/embeddings/openai.js +85 -0
  104. package/dist/rag/embeddings/types.d.ts +37 -0
  105. package/dist/rag/embeddings/types.js +1 -0
  106. package/dist/rag/gitignore/index.d.ts +57 -0
  107. package/dist/rag/gitignore/index.js +178 -0
  108. package/dist/rag/index.d.ts +15 -0
  109. package/dist/rag/index.js +25 -0
  110. package/dist/rag/indexer/chunker.d.ts +129 -0
  111. package/dist/rag/indexer/chunker.js +1352 -0
  112. package/dist/rag/indexer/index.d.ts +6 -0
  113. package/dist/rag/indexer/index.js +6 -0
  114. package/dist/rag/indexer/indexer.d.ts +73 -0
  115. package/dist/rag/indexer/indexer.js +356 -0
  116. package/dist/rag/indexer/types.d.ts +68 -0
  117. package/dist/rag/indexer/types.js +47 -0
  118. package/dist/rag/logger/index.d.ts +20 -0
  119. package/dist/rag/logger/index.js +75 -0
  120. package/dist/rag/manifest/index.d.ts +50 -0
  121. package/dist/rag/manifest/index.js +97 -0
  122. package/dist/rag/merkle/diff.d.ts +26 -0
  123. package/dist/rag/merkle/diff.js +95 -0
  124. package/dist/rag/merkle/hash.d.ts +34 -0
  125. package/dist/rag/merkle/hash.js +165 -0
  126. package/dist/rag/merkle/index.d.ts +68 -0
  127. package/dist/rag/merkle/index.js +298 -0
  128. package/dist/rag/merkle/node.d.ts +51 -0
  129. package/dist/rag/merkle/node.js +69 -0
  130. package/dist/rag/search/filters.d.ts +21 -0
  131. package/dist/rag/search/filters.js +100 -0
  132. package/dist/rag/search/fts.d.ts +32 -0
  133. package/dist/rag/search/fts.js +61 -0
  134. package/dist/rag/search/hybrid.d.ts +17 -0
  135. package/dist/rag/search/hybrid.js +58 -0
  136. package/dist/rag/search/index.d.ts +89 -0
  137. package/dist/rag/search/index.js +367 -0
  138. package/dist/rag/search/types.d.ts +130 -0
  139. package/dist/rag/search/types.js +4 -0
  140. package/dist/rag/search/vector.d.ts +25 -0
  141. package/dist/rag/search/vector.js +44 -0
  142. package/dist/rag/storage/index.d.ts +92 -0
  143. package/dist/rag/storage/index.js +287 -0
  144. package/dist/rag/storage/lancedb-native.d.ts +7 -0
  145. package/dist/rag/storage/lancedb-native.js +10 -0
  146. package/dist/rag/storage/schema.d.ts +23 -0
  147. package/dist/rag/storage/schema.js +50 -0
  148. package/dist/rag/storage/types.d.ts +100 -0
  149. package/dist/rag/storage/types.js +68 -0
  150. package/package.json +67 -0
  151. package/scripts/check-node-version.js +37 -0
@@ -0,0 +1,387 @@
1
+ /**
2
+ * MCP Setup Wizard Component
3
+ *
4
+ * Multi-step wizard for configuring VibeRAG's MCP server
5
+ * across various AI coding tools.
6
+ */
7
+ import React, { useState, useCallback, useEffect } from 'react';
8
+ import { Box, Text, useInput } from 'ink';
9
+ import SelectInput from 'ink-select-input';
10
+ import { EDITORS } from '../data/mcp-editors.js';
11
+ import { writeMcpConfig, getManualInstructions, isAlreadyConfigured, addToGitignore, getProjectConfigPaths, } from '../commands/mcp-setup.js';
12
+ /**
13
+ * Prompt items for post-init flow.
14
+ */
15
+ const PROMPT_ITEMS = [
16
+ { label: 'Yes, configure now', value: 'yes' },
17
+ { label: 'Skip (run /mcp-setup later)', value: 'skip' },
18
+ ];
19
+ /**
20
+ * Action items for each editor.
21
+ */
22
+ const PROJECT_ACTION_ITEMS = [
23
+ { label: 'Auto-configure (Recommended)', value: 'auto' },
24
+ { label: 'Show manual instructions', value: 'manual' },
25
+ { label: 'Skip this editor', value: 'skip' },
26
+ ];
27
+ const GLOBAL_ACTION_ITEMS = [
28
+ { label: 'Auto-update config (Recommended)', value: 'auto' },
29
+ { label: 'Show config to copy manually', value: 'manual' },
30
+ { label: 'Skip this editor', value: 'skip' },
31
+ ];
32
+ const UI_ACTION_ITEMS = [
33
+ { label: 'Show setup instructions', value: 'manual' },
34
+ { label: 'Skip this editor', value: 'skip' },
35
+ ];
36
+ /**
37
+ * Multi-select checkbox list component.
38
+ */
39
+ function MultiSelect({ items, selected, onToggle, onSubmit, highlightIndex, onHighlightChange, disabledItems, }) {
40
+ useInput((input, key) => {
41
+ if (key.upArrow) {
42
+ onHighlightChange(Math.max(0, highlightIndex - 1));
43
+ }
44
+ else if (key.downArrow) {
45
+ onHighlightChange(Math.min(items.length - 1, highlightIndex + 1));
46
+ }
47
+ else if (input === ' ') {
48
+ const item = items[highlightIndex];
49
+ if (item && !disabledItems?.has(item.id)) {
50
+ onToggle(item.id);
51
+ }
52
+ }
53
+ else if (key.return) {
54
+ onSubmit();
55
+ }
56
+ });
57
+ return (React.createElement(Box, { flexDirection: "column" }, items.map((item, index) => {
58
+ const isSelected = selected.has(item.id);
59
+ const isHighlighted = index === highlightIndex;
60
+ const isDisabled = disabledItems?.has(item.id);
61
+ const checkbox = isSelected ? '[x]' : '[ ]';
62
+ return (React.createElement(Box, { key: item.id },
63
+ React.createElement(Text, { color: isDisabled ? 'gray' : isHighlighted ? 'cyan' : undefined, bold: isHighlighted, dimColor: isDisabled },
64
+ isHighlighted ? '> ' : ' ',
65
+ checkbox,
66
+ " ",
67
+ item.label,
68
+ React.createElement(Text, { dimColor: true },
69
+ " (",
70
+ item.description,
71
+ ")"),
72
+ isDisabled ? (React.createElement(Text, { color: "yellow" }, " (already configured)")) : null)));
73
+ })));
74
+ }
75
+ /**
76
+ * MCP Setup Wizard main component.
77
+ */
78
+ export function McpSetupWizard({ step, config, projectRoot, showPrompt, onStepChange, onComplete, onCancel, addOutput, }) {
79
+ // Multi-select state
80
+ const [selected, setSelected] = useState(new Set(config.selectedEditors ?? []));
81
+ const [highlightIndex, setHighlightIndex] = useState(0);
82
+ const [configuredEditors, setConfiguredEditors] = useState(new Set());
83
+ // Per-editor configuration state
84
+ const [currentEditorIndex, setCurrentEditorIndex] = useState(0);
85
+ const [results, setResults] = useState(config.results ?? []);
86
+ const [isProcessing, setIsProcessing] = useState(false);
87
+ // Gitignore prompt state
88
+ const [gitignoreHandled, setGitignoreHandled] = useState(false);
89
+ const [gitignoreAdded, setGitignoreAdded] = useState([]);
90
+ // Check which editors are already configured
91
+ useEffect(() => {
92
+ const checkConfigured = async () => {
93
+ const configured = new Set();
94
+ for (const editor of EDITORS) {
95
+ const isConfigured = await isAlreadyConfigured(editor, projectRoot);
96
+ if (isConfigured) {
97
+ configured.add(editor.id);
98
+ }
99
+ }
100
+ setConfiguredEditors(configured);
101
+ };
102
+ checkConfigured();
103
+ }, [projectRoot]);
104
+ // Handle Escape to cancel
105
+ useInput((input, key) => {
106
+ if (key.escape || (key.ctrl && input === 'c')) {
107
+ onCancel();
108
+ }
109
+ });
110
+ // Toggle selection
111
+ const handleToggle = useCallback((id) => {
112
+ setSelected(prev => {
113
+ const next = new Set(prev);
114
+ if (next.has(id)) {
115
+ next.delete(id);
116
+ }
117
+ else {
118
+ next.add(id);
119
+ }
120
+ return next;
121
+ });
122
+ }, []);
123
+ // Submit selection
124
+ const handleSubmitSelection = useCallback(() => {
125
+ if (selected.size === 0) {
126
+ onCancel();
127
+ return;
128
+ }
129
+ onStepChange('configure', { selectedEditors: Array.from(selected) });
130
+ setCurrentEditorIndex(0);
131
+ }, [selected, onStepChange, onCancel]);
132
+ // Get current editor being configured
133
+ const selectedEditorIds = config.selectedEditors ?? [];
134
+ const currentEditorId = selectedEditorIds[currentEditorIndex];
135
+ const currentEditor = EDITORS.find(e => e.id === currentEditorId);
136
+ // Handle editor action
137
+ const handleEditorAction = useCallback(async (action) => {
138
+ if (!currentEditor)
139
+ return;
140
+ setIsProcessing(true);
141
+ let result;
142
+ if (action === 'skip') {
143
+ result = {
144
+ success: false,
145
+ editor: currentEditor.id,
146
+ method: 'instructions-shown',
147
+ error: 'Skipped',
148
+ };
149
+ }
150
+ else if (action === 'manual') {
151
+ // Show manual instructions
152
+ const instructions = getManualInstructions(currentEditor, projectRoot);
153
+ if (addOutput) {
154
+ addOutput('system', instructions);
155
+ }
156
+ result = {
157
+ success: true,
158
+ editor: currentEditor.id,
159
+ method: 'instructions-shown',
160
+ };
161
+ }
162
+ else {
163
+ // Auto setup
164
+ result = await writeMcpConfig(currentEditor, projectRoot);
165
+ }
166
+ const newResults = [...results, result];
167
+ setResults(newResults);
168
+ // Move to next editor or summary
169
+ if (currentEditorIndex < selectedEditorIds.length - 1) {
170
+ setCurrentEditorIndex(currentEditorIndex + 1);
171
+ }
172
+ else {
173
+ onStepChange('summary', { results: newResults });
174
+ }
175
+ setIsProcessing(false);
176
+ }, [
177
+ currentEditor,
178
+ projectRoot,
179
+ results,
180
+ currentEditorIndex,
181
+ selectedEditorIds.length,
182
+ onStepChange,
183
+ addOutput,
184
+ ]);
185
+ // Build editor items for multi-select
186
+ const editorItems = EDITORS.map(editor => ({
187
+ id: editor.id,
188
+ label: editor.name,
189
+ description: editor.description,
190
+ }));
191
+ // Get project-scope configs for gitignore prompt (computed from results)
192
+ // NOTE: This must be before early returns to maintain consistent hook order
193
+ const projectConfigs = getProjectConfigPaths(results);
194
+ // Handle gitignore action
195
+ const handleGitignore = useCallback(async (action) => {
196
+ if (action === 'yes') {
197
+ const added = [];
198
+ for (const configPath of projectConfigs) {
199
+ const success = await addToGitignore(projectRoot, configPath);
200
+ if (success) {
201
+ added.push(configPath);
202
+ }
203
+ }
204
+ setGitignoreAdded(added);
205
+ }
206
+ setGitignoreHandled(true);
207
+ }, [projectConfigs, projectRoot]);
208
+ // Gitignore action items
209
+ const gitignoreItems = [
210
+ { label: 'Yes, add to .gitignore (Recommended)', value: 'yes' },
211
+ { label: 'No, keep in version control', value: 'no' },
212
+ ];
213
+ // Step: Prompt (post-init)
214
+ if (step === 'prompt' && showPrompt) {
215
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
216
+ React.createElement(Text, { bold: true, color: "green" }, "Setup Complete"),
217
+ React.createElement(Box, { marginTop: 1 },
218
+ React.createElement(Text, null,
219
+ "Would you like to configure an AI coding tool to use",
220
+ '\n',
221
+ "VibeRAG's MCP server?")),
222
+ React.createElement(Box, { marginTop: 1 },
223
+ React.createElement(SelectInput, { items: PROMPT_ITEMS, onSelect: item => {
224
+ if (item.value === 'yes') {
225
+ onStepChange('select');
226
+ }
227
+ else {
228
+ onCancel();
229
+ }
230
+ } })),
231
+ React.createElement(Text, { dimColor: true }, "\u2191/\u2193 navigate, Enter select, Esc cancel")));
232
+ }
233
+ // Step: Multi-select editors
234
+ if (step === 'select') {
235
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
236
+ React.createElement(Text, { bold: true }, "MCP Setup Wizard"),
237
+ React.createElement(Box, { marginTop: 1 },
238
+ React.createElement(Text, null,
239
+ "Select AI coding tool(s) to configure:",
240
+ '\n',
241
+ React.createElement(Text, { dimColor: true }, "(Space to toggle, Enter to confirm)"))),
242
+ React.createElement(Box, { marginTop: 1 },
243
+ React.createElement(MultiSelect, { items: editorItems, selected: selected, onToggle: handleToggle, onSubmit: handleSubmitSelection, highlightIndex: highlightIndex, onHighlightChange: setHighlightIndex, disabledItems: configuredEditors })),
244
+ React.createElement(Box, { marginTop: 1 },
245
+ React.createElement(Text, { dimColor: true },
246
+ selected.size,
247
+ " selected | \u2191/\u2193 move, Space toggle, Enter confirm, Esc cancel"))));
248
+ }
249
+ // Step: Configure each editor
250
+ if (step === 'configure' && currentEditor) {
251
+ if (isProcessing) {
252
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
253
+ React.createElement(Text, { bold: true },
254
+ currentEditor.name,
255
+ " MCP Setup"),
256
+ React.createElement(Box, { marginTop: 1 },
257
+ React.createElement(Text, { color: "yellow" }, "Processing..."))));
258
+ }
259
+ const actionItems = currentEditor.scope === 'ui'
260
+ ? UI_ACTION_ITEMS
261
+ : currentEditor.scope === 'global'
262
+ ? GLOBAL_ACTION_ITEMS
263
+ : PROJECT_ACTION_ITEMS;
264
+ const configPathDisplay = currentEditor.scope === 'project'
265
+ ? currentEditor.configPath
266
+ : currentEditor.scope === 'global'
267
+ ? `${currentEditor.configPath}`
268
+ : 'IDE Settings';
269
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
270
+ React.createElement(Text, { bold: true },
271
+ currentEditor.name,
272
+ " MCP Setup (",
273
+ currentEditorIndex + 1,
274
+ "/",
275
+ selectedEditorIds.length,
276
+ ")"),
277
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, currentEditor.scope === 'project' ? (React.createElement(Text, null,
278
+ "VibeRAG can create or update",
279
+ ' ',
280
+ React.createElement(Text, { color: "cyan" }, configPathDisplay),
281
+ " automatically.")) : currentEditor.scope === 'global' ? (React.createElement(Text, null,
282
+ currentEditor.name,
283
+ " uses a global config at:",
284
+ '\n',
285
+ React.createElement(Text, { color: "cyan" }, configPathDisplay))) : (React.createElement(Text, null,
286
+ currentEditor.name,
287
+ " requires manual configuration in the IDE."))),
288
+ React.createElement(Box, { marginTop: 1 },
289
+ React.createElement(SelectInput, { items: actionItems, onSelect: item => {
290
+ handleEditorAction(item.value);
291
+ } })),
292
+ React.createElement(Text, { dimColor: true }, "\u2191/\u2193 navigate, Enter select, Esc cancel")));
293
+ }
294
+ // Step: Summary
295
+ if (step === 'summary') {
296
+ const successResults = results.filter(r => r.success && r.method !== 'instructions-shown');
297
+ const instructionResults = results.filter(r => r.success && r.method === 'instructions-shown');
298
+ const skippedResults = results.filter(r => !r.success);
299
+ // Show gitignore prompt if we have project configs and haven't handled yet
300
+ if (projectConfigs.length > 0 && !gitignoreHandled) {
301
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
302
+ React.createElement(Text, { bold: true, color: "yellow" }, "Add MCP configs to .gitignore?"),
303
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
304
+ React.createElement(Text, null, "These project-local MCP config files were created:"),
305
+ projectConfigs.map(p => (React.createElement(Text, { key: p, dimColor: true },
306
+ ' ',
307
+ p)))),
308
+ React.createElement(Box, { marginTop: 1 },
309
+ React.createElement(Text, { dimColor: true }, "MCP configs are typically machine-specific and should not be committed.")),
310
+ React.createElement(Box, { marginTop: 1 },
311
+ React.createElement(SelectInput, { items: gitignoreItems, onSelect: item => handleGitignore(item.value) }))));
312
+ }
313
+ return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", paddingX: 2, paddingY: 1 },
314
+ React.createElement(Text, { bold: true, color: "green" }, "MCP Setup Complete"),
315
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
316
+ successResults.map(r => {
317
+ const editor = EDITORS.find(e => e.id === r.editor);
318
+ return (React.createElement(Text, { key: r.editor },
319
+ React.createElement(Text, { color: "green" }, "\u2713"),
320
+ " ",
321
+ editor?.name ?? r.editor,
322
+ React.createElement(Text, { dimColor: true },
323
+ ' ',
324
+ r.method === 'file-created'
325
+ ? `Created ${r.configPath}`
326
+ : r.method === 'file-merged'
327
+ ? `Updated ${r.configPath}`
328
+ : 'CLI command')));
329
+ }),
330
+ instructionResults.map(r => {
331
+ const editor = EDITORS.find(e => e.id === r.editor);
332
+ return (React.createElement(Text, { key: r.editor },
333
+ React.createElement(Text, { color: "blue" }, "\u2139"),
334
+ " ",
335
+ editor?.name ?? r.editor,
336
+ React.createElement(Text, { dimColor: true }, " Instructions shown above")));
337
+ }),
338
+ skippedResults.map(r => {
339
+ const editor = EDITORS.find(e => e.id === r.editor);
340
+ return (React.createElement(Text, { key: r.editor },
341
+ React.createElement(Text, { color: "gray" }, "-"),
342
+ " ",
343
+ editor?.name ?? r.editor,
344
+ React.createElement(Text, { dimColor: true }, " Skipped")));
345
+ })),
346
+ gitignoreAdded.length > 0 && (React.createElement(Box, { marginTop: 1 },
347
+ React.createElement(Text, { color: "green" }, "\u2713"),
348
+ React.createElement(Text, { dimColor: true },
349
+ ' ',
350
+ "Added to .gitignore: ",
351
+ gitignoreAdded.join(', ')))),
352
+ successResults.length > 0 && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
353
+ React.createElement(Text, { bold: true }, "Verify setup:"),
354
+ successResults.map(r => {
355
+ const editor = EDITORS.find(e => e.id === r.editor);
356
+ if (!editor)
357
+ return null;
358
+ return (React.createElement(Box, { key: r.editor, flexDirection: "column" },
359
+ React.createElement(Text, null,
360
+ React.createElement(Text, { color: "cyan" },
361
+ editor.name,
362
+ ":"),
363
+ ' ',
364
+ editor.verificationSteps[0])));
365
+ }))),
366
+ successResults.length > 0 && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
367
+ React.createElement(Text, { bold: true }, "Next steps:"),
368
+ React.createElement(Text, null, "1. Restart your editor(s) to load the MCP server"),
369
+ React.createElement(Text, null, "2. Verify using the steps above"),
370
+ React.createElement(Text, null, "3. Test codebase_search with a code query"))),
371
+ React.createElement(Box, { marginTop: 1 },
372
+ React.createElement(Text, { dimColor: true }, "Run /mcp-setup anytime to configure more editors.")),
373
+ React.createElement(Box, { marginTop: 1 },
374
+ React.createElement(SelectInput, { items: [{ label: 'Done', value: 'done' }], onSelect: () => {
375
+ onComplete({
376
+ selectedEditors: selectedEditorIds,
377
+ results,
378
+ });
379
+ } }))));
380
+ }
381
+ // Fallback
382
+ return (React.createElement(Box, { flexDirection: "column" },
383
+ React.createElement(Text, { color: "red" },
384
+ "Unknown wizard step: ",
385
+ step)));
386
+ }
387
+ export default McpSetupWizard;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Search results display component with syntax highlighting.
3
+ */
4
+ import React from 'react';
5
+ import type { SearchResultsData } from '../../common/types.js';
6
+ type Props = {
7
+ data: SearchResultsData;
8
+ };
9
+ /**
10
+ * Search results display component.
11
+ */
12
+ export default function SearchResultsDisplay({ data }: Props): React.JSX.Element;
13
+ export {};
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Search results display component with syntax highlighting.
3
+ */
4
+ import React from 'react';
5
+ import { Box, Text, useStdout } from 'ink';
6
+ import { highlight } from 'cli-highlight';
7
+ /**
8
+ * Color mapping for chunk types.
9
+ */
10
+ const TYPE_COLORS = {
11
+ function: 'cyan',
12
+ class: 'magenta',
13
+ method: 'blue',
14
+ module: 'gray',
15
+ };
16
+ /**
17
+ * Extension to language mapping for syntax highlighting.
18
+ */
19
+ const EXT_TO_LANG = {
20
+ ts: 'typescript',
21
+ tsx: 'typescript',
22
+ js: 'javascript',
23
+ jsx: 'javascript',
24
+ py: 'python',
25
+ rs: 'rust',
26
+ go: 'go',
27
+ java: 'java',
28
+ };
29
+ /**
30
+ * Get language from filepath for syntax highlighting.
31
+ */
32
+ function getLanguage(filepath) {
33
+ const ext = filepath.split('.').pop()?.toLowerCase() ?? '';
34
+ return EXT_TO_LANG[ext] ?? 'plaintext';
35
+ }
36
+ /**
37
+ * Get score color based on value.
38
+ */
39
+ function getScoreColor(score) {
40
+ if (score > 0.8)
41
+ return 'green';
42
+ if (score > 0.5)
43
+ return 'yellow';
44
+ return 'red';
45
+ }
46
+ /**
47
+ * Truncate and format code snippet for display.
48
+ */
49
+ function formatSnippet(text, filepath, maxWidth, maxLines = 4) {
50
+ const language = getLanguage(filepath);
51
+ const lines = text.split('\n').slice(0, maxLines);
52
+ // Truncate each line to max width
53
+ const truncatedLines = lines.map(line => {
54
+ if (line.length > maxWidth - 4) {
55
+ return line.slice(0, maxWidth - 7) + '...';
56
+ }
57
+ return line;
58
+ });
59
+ const truncated = truncatedLines.join('\n');
60
+ // Try to syntax highlight
61
+ try {
62
+ return highlight(truncated, { language, ignoreIllegals: true });
63
+ }
64
+ catch {
65
+ return truncated;
66
+ }
67
+ }
68
+ /**
69
+ * Single search result component.
70
+ */
71
+ function SearchResult({ result, maxWidth, }) {
72
+ const typeColor = TYPE_COLORS[result.type] ?? 'white';
73
+ const scoreColor = getScoreColor(result.score);
74
+ // Format snippet with syntax highlighting
75
+ const snippet = formatSnippet(result.text, result.filepath, maxWidth);
76
+ return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
77
+ React.createElement(Box, null,
78
+ React.createElement(Text, { color: typeColor },
79
+ "[",
80
+ result.type,
81
+ "]"),
82
+ result.name && React.createElement(Text, null,
83
+ " ",
84
+ result.name)),
85
+ React.createElement(Box, null,
86
+ React.createElement(Text, null, " "),
87
+ React.createElement(Text, { color: "green" }, result.filepath),
88
+ React.createElement(Text, { dimColor: true },
89
+ ":",
90
+ result.startLine,
91
+ "-",
92
+ result.endLine)),
93
+ React.createElement(Box, null,
94
+ React.createElement(Text, null, " Score: "),
95
+ React.createElement(Text, { color: scoreColor }, result.score.toFixed(4))),
96
+ React.createElement(Box, { marginLeft: 1, marginTop: 0 },
97
+ React.createElement(Text, null, snippet))));
98
+ }
99
+ /**
100
+ * Search results display component.
101
+ */
102
+ export default function SearchResultsDisplay({ data }) {
103
+ const { stdout } = useStdout();
104
+ const terminalWidth = stdout?.columns ?? 80;
105
+ const maxSnippetWidth = Math.min(terminalWidth - 4, 176);
106
+ if (data.results.length === 0) {
107
+ return (React.createElement(Box, null,
108
+ React.createElement(Text, { dimColor: true },
109
+ "No results found for \"",
110
+ data.query,
111
+ "\" (",
112
+ data.elapsedMs,
113
+ "ms)")));
114
+ }
115
+ return (React.createElement(Box, { flexDirection: "column" },
116
+ React.createElement(Box, { marginBottom: 1 },
117
+ React.createElement(Text, { bold: true },
118
+ "Found ",
119
+ data.results.length,
120
+ " results for "),
121
+ React.createElement(Text, { color: "cyan" },
122
+ "\"",
123
+ data.query,
124
+ "\""),
125
+ React.createElement(Text, { dimColor: true },
126
+ " (",
127
+ data.elapsedMs,
128
+ "ms):")),
129
+ data.results.map((result, index) => (React.createElement(SearchResult, { key: `${result.filepath}:${result.startLine}-${index}`, result: result, maxWidth: maxSnippetWidth })))));
130
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { IndexDisplayStats } from '../../common/types.js';
3
+ type Props = {
4
+ version: string;
5
+ cwd: string;
6
+ isInitialized?: boolean;
7
+ indexStats: IndexDisplayStats | null | undefined;
8
+ };
9
+ export default function WelcomeBanner({ version, cwd, isInitialized, indexStats, }: Props): React.JSX.Element;
10
+ export {};
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import Gradient from 'ink-gradient';
4
+ import BigText from 'ink-big-text';
5
+ export default function WelcomeBanner({ version, cwd, isInitialized, indexStats, }) {
6
+ // indexStats is only passed once fully loaded (undefined means still loading)
7
+ const isIndexed = indexStats != null && indexStats.totalChunks > 0;
8
+ return (React.createElement(Box, { flexDirection: "column", paddingX: 1 },
9
+ React.createElement(Gradient, { colors: ['#9D4EDD', '#00D9FF'] },
10
+ React.createElement(BigText, { text: "VibeRAG" })),
11
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
12
+ React.createElement(Box, null,
13
+ React.createElement(Text, { dimColor: true },
14
+ "v",
15
+ version),
16
+ isInitialized === true && isIndexed && (React.createElement(React.Fragment, null,
17
+ React.createElement(Text, null, " "),
18
+ React.createElement(Text, { color: "green" }, "\u2713 Ready")))),
19
+ React.createElement(Text, { dimColor: true }, cwd)),
20
+ React.createElement(Box, { marginTop: 1 },
21
+ React.createElement(Text, { dimColor: true }, "Type /help for available commands")),
22
+ isInitialized === false && (React.createElement(Box, { marginTop: 1 },
23
+ React.createElement(Text, { color: "yellow" }, "Run /init to set up"))),
24
+ isInitialized === true && !isIndexed && (React.createElement(Box, { marginTop: 1 },
25
+ React.createElement(Text, { color: "yellow" }, "Run /index to build the code index")))));
26
+ }
@@ -0,0 +1 @@
1
+ export { default as WelcomeBanner } from './WelcomeBanner.js';
@@ -0,0 +1 @@
1
+ export { default as WelcomeBanner } from './WelcomeBanner.js';
@@ -0,0 +1,80 @@
1
+ /**
2
+ * MCP Editor Configuration Data
3
+ *
4
+ * Configuration for all supported AI coding tools and their MCP setup.
5
+ */
6
+ /**
7
+ * Supported editor/agent identifiers.
8
+ */
9
+ export type EditorId = 'claude-code' | 'vscode' | 'cursor' | 'windsurf' | 'roo-code' | 'zed' | 'gemini-cli' | 'codex' | 'jetbrains' | 'opencode';
10
+ /**
11
+ * Configuration for an editor/agent's MCP setup.
12
+ */
13
+ export interface EditorConfig {
14
+ /** Unique identifier */
15
+ id: EditorId;
16
+ /** Display name */
17
+ name: string;
18
+ /** Config file path (null = no file config, ~ expanded at runtime) */
19
+ configPath: string | null;
20
+ /** Config file format */
21
+ configFormat: 'json' | 'toml' | 'ui';
22
+ /** Configuration scope */
23
+ scope: 'project' | 'global' | 'ui';
24
+ /** Whether we can auto-create the config */
25
+ canAutoCreate: boolean;
26
+ /** CLI command if available (null = none) */
27
+ cliCommand: string | null;
28
+ /** Official documentation URL */
29
+ docsUrl: string;
30
+ /** JSON key for servers object */
31
+ jsonKey: string;
32
+ /** Short description for wizard */
33
+ description: string;
34
+ /** Restart/reload instructions */
35
+ restartInstructions: string;
36
+ /** Verification steps */
37
+ verificationSteps: string[];
38
+ }
39
+ /**
40
+ * All supported editors with their MCP configurations.
41
+ * Sorted alphabetically by name.
42
+ */
43
+ export declare const EDITORS: EditorConfig[];
44
+ /**
45
+ * Get editor by ID.
46
+ */
47
+ export declare function getEditor(id: EditorId): EditorConfig | undefined;
48
+ /**
49
+ * Get editors that support auto-creation of project-level config.
50
+ */
51
+ export declare function getAutoCreateEditors(): EditorConfig[];
52
+ /**
53
+ * Get editors that require global config merging.
54
+ */
55
+ export declare function getGlobalConfigEditors(): EditorConfig[];
56
+ /**
57
+ * Get editors that have CLI commands.
58
+ */
59
+ export declare function getCliCommandEditors(): EditorConfig[];
60
+ /**
61
+ * Expand ~ to home directory in path.
62
+ */
63
+ export declare function expandPath(configPath: string): string;
64
+ /**
65
+ * Get the absolute config path for an editor.
66
+ * For project-scope editors, projectRoot is required.
67
+ */
68
+ export declare function getConfigPath(editor: EditorConfig, projectRoot?: string): string | null;
69
+ /**
70
+ * Get Zed settings path based on platform.
71
+ */
72
+ export declare function getZedSettingsPath(): string;
73
+ /**
74
+ * Get Windsurf config path based on platform.
75
+ */
76
+ export declare function getWindsurfConfigPath(): string;
77
+ /**
78
+ * Get OpenCode config path based on platform.
79
+ */
80
+ export declare function getOpenCodeConfigPath(): string;