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.
- package/LICENSE +661 -0
- package/README.md +219 -0
- package/dist/cli/__tests__/mcp-setup.test.d.ts +6 -0
- package/dist/cli/__tests__/mcp-setup.test.js +597 -0
- package/dist/cli/app.d.ts +2 -0
- package/dist/cli/app.js +238 -0
- package/dist/cli/commands/handlers.d.ts +57 -0
- package/dist/cli/commands/handlers.js +231 -0
- package/dist/cli/commands/index.d.ts +2 -0
- package/dist/cli/commands/index.js +2 -0
- package/dist/cli/commands/mcp-setup.d.ts +107 -0
- package/dist/cli/commands/mcp-setup.js +509 -0
- package/dist/cli/commands/useRagCommands.d.ts +23 -0
- package/dist/cli/commands/useRagCommands.js +180 -0
- package/dist/cli/components/CleanWizard.d.ts +17 -0
- package/dist/cli/components/CleanWizard.js +169 -0
- package/dist/cli/components/InitWizard.d.ts +20 -0
- package/dist/cli/components/InitWizard.js +370 -0
- package/dist/cli/components/McpSetupWizard.d.ts +37 -0
- package/dist/cli/components/McpSetupWizard.js +387 -0
- package/dist/cli/components/SearchResultsDisplay.d.ts +13 -0
- package/dist/cli/components/SearchResultsDisplay.js +130 -0
- package/dist/cli/components/WelcomeBanner.d.ts +10 -0
- package/dist/cli/components/WelcomeBanner.js +26 -0
- package/dist/cli/components/index.d.ts +1 -0
- package/dist/cli/components/index.js +1 -0
- package/dist/cli/data/mcp-editors.d.ts +80 -0
- package/dist/cli/data/mcp-editors.js +270 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli-bundle.cjs +5269 -0
- package/dist/common/commands/terminalSetup.d.ts +2 -0
- package/dist/common/commands/terminalSetup.js +144 -0
- package/dist/common/components/CommandSuggestions.d.ts +9 -0
- package/dist/common/components/CommandSuggestions.js +20 -0
- package/dist/common/components/StaticWithResize.d.ts +23 -0
- package/dist/common/components/StaticWithResize.js +62 -0
- package/dist/common/components/StatusBar.d.ts +8 -0
- package/dist/common/components/StatusBar.js +64 -0
- package/dist/common/components/TextInput.d.ts +12 -0
- package/dist/common/components/TextInput.js +239 -0
- package/dist/common/components/index.d.ts +3 -0
- package/dist/common/components/index.js +3 -0
- package/dist/common/hooks/index.d.ts +4 -0
- package/dist/common/hooks/index.js +4 -0
- package/dist/common/hooks/useCommandHistory.d.ts +7 -0
- package/dist/common/hooks/useCommandHistory.js +51 -0
- package/dist/common/hooks/useCtrlC.d.ts +9 -0
- package/dist/common/hooks/useCtrlC.js +40 -0
- package/dist/common/hooks/useKittyKeyboard.d.ts +10 -0
- package/dist/common/hooks/useKittyKeyboard.js +26 -0
- package/dist/common/hooks/useStaticOutputBuffer.d.ts +31 -0
- package/dist/common/hooks/useStaticOutputBuffer.js +58 -0
- package/dist/common/hooks/useTerminalResize.d.ts +28 -0
- package/dist/common/hooks/useTerminalResize.js +51 -0
- package/dist/common/hooks/useTextBuffer.d.ts +13 -0
- package/dist/common/hooks/useTextBuffer.js +165 -0
- package/dist/common/index.d.ts +13 -0
- package/dist/common/index.js +17 -0
- package/dist/common/types.d.ts +162 -0
- package/dist/common/types.js +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +66 -0
- package/dist/mcp/server.d.ts +25 -0
- package/dist/mcp/server.js +837 -0
- package/dist/mcp/watcher.d.ts +86 -0
- package/dist/mcp/watcher.js +334 -0
- package/dist/rag/__tests__/grammar-smoke.test.d.ts +9 -0
- package/dist/rag/__tests__/grammar-smoke.test.js +161 -0
- package/dist/rag/__tests__/helpers.d.ts +30 -0
- package/dist/rag/__tests__/helpers.js +67 -0
- package/dist/rag/__tests__/merkle.test.d.ts +5 -0
- package/dist/rag/__tests__/merkle.test.js +161 -0
- package/dist/rag/__tests__/metadata-extraction.test.d.ts +10 -0
- package/dist/rag/__tests__/metadata-extraction.test.js +202 -0
- package/dist/rag/__tests__/multi-language.test.d.ts +13 -0
- package/dist/rag/__tests__/multi-language.test.js +535 -0
- package/dist/rag/__tests__/rag.test.d.ts +10 -0
- package/dist/rag/__tests__/rag.test.js +311 -0
- package/dist/rag/__tests__/search-exhaustive.test.d.ts +9 -0
- package/dist/rag/__tests__/search-exhaustive.test.js +87 -0
- package/dist/rag/__tests__/search-filters.test.d.ts +10 -0
- package/dist/rag/__tests__/search-filters.test.js +250 -0
- package/dist/rag/__tests__/search-modes.test.d.ts +8 -0
- package/dist/rag/__tests__/search-modes.test.js +133 -0
- package/dist/rag/config/index.d.ts +61 -0
- package/dist/rag/config/index.js +111 -0
- package/dist/rag/constants.d.ts +41 -0
- package/dist/rag/constants.js +57 -0
- package/dist/rag/embeddings/fastembed.d.ts +62 -0
- package/dist/rag/embeddings/fastembed.js +124 -0
- package/dist/rag/embeddings/gemini.d.ts +26 -0
- package/dist/rag/embeddings/gemini.js +116 -0
- package/dist/rag/embeddings/index.d.ts +10 -0
- package/dist/rag/embeddings/index.js +9 -0
- package/dist/rag/embeddings/local-4b.d.ts +28 -0
- package/dist/rag/embeddings/local-4b.js +51 -0
- package/dist/rag/embeddings/local.d.ts +29 -0
- package/dist/rag/embeddings/local.js +119 -0
- package/dist/rag/embeddings/mistral.d.ts +22 -0
- package/dist/rag/embeddings/mistral.js +85 -0
- package/dist/rag/embeddings/openai.d.ts +22 -0
- package/dist/rag/embeddings/openai.js +85 -0
- package/dist/rag/embeddings/types.d.ts +37 -0
- package/dist/rag/embeddings/types.js +1 -0
- package/dist/rag/gitignore/index.d.ts +57 -0
- package/dist/rag/gitignore/index.js +178 -0
- package/dist/rag/index.d.ts +15 -0
- package/dist/rag/index.js +25 -0
- package/dist/rag/indexer/chunker.d.ts +129 -0
- package/dist/rag/indexer/chunker.js +1352 -0
- package/dist/rag/indexer/index.d.ts +6 -0
- package/dist/rag/indexer/index.js +6 -0
- package/dist/rag/indexer/indexer.d.ts +73 -0
- package/dist/rag/indexer/indexer.js +356 -0
- package/dist/rag/indexer/types.d.ts +68 -0
- package/dist/rag/indexer/types.js +47 -0
- package/dist/rag/logger/index.d.ts +20 -0
- package/dist/rag/logger/index.js +75 -0
- package/dist/rag/manifest/index.d.ts +50 -0
- package/dist/rag/manifest/index.js +97 -0
- package/dist/rag/merkle/diff.d.ts +26 -0
- package/dist/rag/merkle/diff.js +95 -0
- package/dist/rag/merkle/hash.d.ts +34 -0
- package/dist/rag/merkle/hash.js +165 -0
- package/dist/rag/merkle/index.d.ts +68 -0
- package/dist/rag/merkle/index.js +298 -0
- package/dist/rag/merkle/node.d.ts +51 -0
- package/dist/rag/merkle/node.js +69 -0
- package/dist/rag/search/filters.d.ts +21 -0
- package/dist/rag/search/filters.js +100 -0
- package/dist/rag/search/fts.d.ts +32 -0
- package/dist/rag/search/fts.js +61 -0
- package/dist/rag/search/hybrid.d.ts +17 -0
- package/dist/rag/search/hybrid.js +58 -0
- package/dist/rag/search/index.d.ts +89 -0
- package/dist/rag/search/index.js +367 -0
- package/dist/rag/search/types.d.ts +130 -0
- package/dist/rag/search/types.js +4 -0
- package/dist/rag/search/vector.d.ts +25 -0
- package/dist/rag/search/vector.js +44 -0
- package/dist/rag/storage/index.d.ts +92 -0
- package/dist/rag/storage/index.js +287 -0
- package/dist/rag/storage/lancedb-native.d.ts +7 -0
- package/dist/rag/storage/lancedb-native.js +10 -0
- package/dist/rag/storage/schema.d.ts +23 -0
- package/dist/rag/storage/schema.js +50 -0
- package/dist/rag/storage/types.d.ts +100 -0
- package/dist/rag/storage/types.js +68 -0
- package/package.json +67 -0
- 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;
|