viberag 0.3.2 → 0.4.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/README.md +2 -2
- package/dist/cli/app.d.ts +3 -0
- package/dist/cli/app.js +100 -102
- package/dist/cli/commands/handlers.d.ts +8 -6
- package/dist/cli/commands/handlers.js +90 -32
- package/dist/cli/commands/useCommands.d.ts +20 -0
- package/dist/cli/commands/useCommands.js +189 -0
- package/dist/cli/commands/useRagCommands.d.ts +2 -5
- package/dist/cli/commands/useRagCommands.js +11 -18
- package/dist/cli/components/InitWizard.js +66 -27
- package/dist/cli/components/McpSetupWizard.js +23 -4
- package/dist/cli/components/SlotRow.d.ts +22 -0
- package/dist/cli/components/SlotRow.js +55 -0
- package/dist/cli/components/StatusBar.d.ts +14 -0
- package/dist/cli/components/StatusBar.js +156 -0
- package/dist/cli/contexts/DaemonStatusContext.d.ts +38 -0
- package/dist/cli/contexts/DaemonStatusContext.js +106 -0
- package/dist/cli/hooks/useStatusPolling.d.ts +34 -0
- package/dist/cli/hooks/useStatusPolling.js +121 -0
- package/dist/cli/store/app/selectors.d.ts +87 -0
- package/dist/cli/store/app/selectors.js +28 -0
- package/dist/cli/store/app/slice.d.ts +1013 -0
- package/dist/cli/store/app/slice.js +112 -0
- package/dist/cli/store/hooks.d.ts +22 -0
- package/dist/cli/store/hooks.js +17 -0
- package/dist/cli/store/store.d.ts +17 -0
- package/dist/cli/store/store.js +18 -0
- package/dist/cli/store/wizard/selectors.d.ts +115 -0
- package/dist/cli/store/wizard/selectors.js +36 -0
- package/dist/cli/store/wizard/slice.d.ts +523 -0
- package/dist/cli/store/wizard/slice.js +119 -0
- package/dist/cli/utils/error-handler.d.ts +55 -0
- package/dist/cli/utils/error-handler.js +92 -0
- package/dist/client/auto-start.d.ts +42 -0
- package/dist/client/auto-start.js +250 -0
- package/dist/client/connection.d.ts +48 -0
- package/dist/client/connection.js +200 -0
- package/dist/client/index.d.ts +93 -0
- package/dist/client/index.js +209 -0
- package/dist/client/types.d.ts +105 -0
- package/dist/client/types.js +7 -0
- package/dist/common/components/SlotRow.d.ts +22 -0
- package/dist/common/components/SlotRow.js +53 -0
- package/dist/common/components/StatusBar.js +82 -31
- package/dist/common/types.d.ts +12 -13
- package/dist/daemon/handlers.d.ts +15 -0
- package/dist/daemon/handlers.js +157 -0
- package/dist/daemon/index.d.ts +21 -0
- package/dist/daemon/index.js +123 -0
- package/dist/daemon/lib/chunker/bounded-channel.d.ts +51 -0
- package/dist/daemon/lib/chunker/bounded-channel.js +138 -0
- package/dist/daemon/lib/chunker/index.d.ts +135 -0
- package/dist/daemon/lib/chunker/index.js +1370 -0
- package/dist/daemon/lib/chunker/types.d.ts +77 -0
- package/dist/daemon/lib/chunker/types.js +50 -0
- package/dist/daemon/lib/config.d.ts +73 -0
- package/dist/daemon/lib/config.js +149 -0
- package/dist/daemon/lib/constants.d.ts +75 -0
- package/dist/daemon/lib/constants.js +114 -0
- package/dist/daemon/lib/gitignore.d.ts +57 -0
- package/dist/daemon/lib/gitignore.js +246 -0
- package/dist/daemon/lib/logger.d.ts +51 -0
- package/dist/daemon/lib/logger.js +167 -0
- package/dist/daemon/lib/manifest.d.ts +58 -0
- package/dist/daemon/lib/manifest.js +116 -0
- package/dist/daemon/lib/merkle/diff.d.ts +32 -0
- package/dist/daemon/lib/merkle/diff.js +107 -0
- package/dist/daemon/lib/merkle/hash.d.ts +40 -0
- package/dist/daemon/lib/merkle/hash.js +180 -0
- package/dist/daemon/lib/merkle/index.d.ts +71 -0
- package/dist/daemon/lib/merkle/index.js +309 -0
- package/dist/daemon/lib/merkle/node.d.ts +55 -0
- package/dist/daemon/lib/merkle/node.js +82 -0
- package/dist/daemon/lifecycle.d.ts +50 -0
- package/dist/daemon/lifecycle.js +142 -0
- package/dist/daemon/owner.d.ts +175 -0
- package/dist/daemon/owner.js +609 -0
- package/dist/daemon/protocol.d.ts +100 -0
- package/dist/daemon/protocol.js +163 -0
- package/dist/daemon/providers/api-utils.d.ts +130 -0
- package/dist/daemon/providers/api-utils.js +248 -0
- package/dist/daemon/providers/gemini.d.ts +39 -0
- package/dist/daemon/providers/gemini.js +205 -0
- package/dist/daemon/providers/index.d.ts +14 -0
- package/dist/daemon/providers/index.js +14 -0
- package/dist/daemon/providers/local-4b.d.ts +28 -0
- package/dist/daemon/providers/local-4b.js +51 -0
- package/dist/daemon/providers/local.d.ts +36 -0
- package/dist/daemon/providers/local.js +166 -0
- package/dist/daemon/providers/mistral.d.ts +35 -0
- package/dist/daemon/providers/mistral.js +160 -0
- package/dist/daemon/providers/mock.d.ts +35 -0
- package/dist/daemon/providers/mock.js +69 -0
- package/dist/daemon/providers/openai.d.ts +41 -0
- package/dist/daemon/providers/openai.js +190 -0
- package/dist/daemon/providers/types.d.ts +68 -0
- package/dist/daemon/providers/types.js +6 -0
- package/dist/daemon/providers/validate.d.ts +30 -0
- package/dist/daemon/providers/validate.js +162 -0
- package/dist/daemon/server.d.ts +79 -0
- package/dist/daemon/server.js +293 -0
- package/dist/daemon/services/index.d.ts +11 -0
- package/dist/daemon/services/index.js +16 -0
- package/dist/daemon/services/indexing.d.ts +117 -0
- package/dist/daemon/services/indexing.js +573 -0
- package/dist/daemon/services/search/filters.d.ts +21 -0
- package/dist/daemon/services/search/filters.js +106 -0
- package/dist/daemon/services/search/fts.d.ts +32 -0
- package/dist/daemon/services/search/fts.js +61 -0
- package/dist/daemon/services/search/hybrid.d.ts +17 -0
- package/dist/daemon/services/search/hybrid.js +58 -0
- package/dist/daemon/services/search/index.d.ts +108 -0
- package/dist/daemon/services/search/index.js +417 -0
- package/dist/daemon/services/search/types.d.ts +126 -0
- package/dist/daemon/services/search/types.js +4 -0
- package/dist/daemon/services/search/vector.d.ts +25 -0
- package/dist/daemon/services/search/vector.js +44 -0
- package/dist/daemon/services/storage/index.d.ts +110 -0
- package/dist/daemon/services/storage/index.js +378 -0
- package/dist/daemon/services/storage/schema.d.ts +24 -0
- package/dist/daemon/services/storage/schema.js +51 -0
- package/dist/daemon/services/storage/types.d.ts +105 -0
- package/dist/daemon/services/storage/types.js +71 -0
- package/dist/daemon/services/types.d.ts +192 -0
- package/dist/daemon/services/types.js +53 -0
- package/dist/daemon/services/watcher.d.ts +98 -0
- package/dist/daemon/services/watcher.js +386 -0
- package/dist/daemon/state.d.ts +119 -0
- package/dist/daemon/state.js +161 -0
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +44 -60
- package/dist/mcp/server.d.ts +10 -14
- package/dist/mcp/server.js +75 -74
- package/dist/mcp/services/lazy-loader.d.ts +23 -0
- package/dist/mcp/services/lazy-loader.js +34 -0
- package/dist/mcp/warmup.d.ts +3 -3
- package/dist/mcp/warmup.js +39 -40
- package/dist/mcp/watcher.d.ts +5 -7
- package/dist/mcp/watcher.js +73 -64
- package/dist/rag/config/index.d.ts +2 -0
- package/dist/rag/constants.d.ts +30 -0
- package/dist/rag/constants.js +38 -0
- package/dist/rag/embeddings/api-utils.d.ts +121 -0
- package/dist/rag/embeddings/api-utils.js +259 -0
- package/dist/rag/embeddings/gemini.d.ts +4 -12
- package/dist/rag/embeddings/gemini.js +22 -72
- package/dist/rag/embeddings/index.d.ts +5 -3
- package/dist/rag/embeddings/index.js +5 -2
- package/dist/rag/embeddings/local-4b.d.ts +2 -2
- package/dist/rag/embeddings/local-4b.js +1 -1
- package/dist/rag/embeddings/local.d.ts +10 -3
- package/dist/rag/embeddings/local.js +58 -12
- package/dist/rag/embeddings/mistral.d.ts +4 -12
- package/dist/rag/embeddings/mistral.js +22 -72
- package/dist/rag/embeddings/mock.d.ts +35 -0
- package/dist/rag/embeddings/mock.js +69 -0
- package/dist/rag/embeddings/openai.d.ts +11 -13
- package/dist/rag/embeddings/openai.js +47 -75
- package/dist/rag/embeddings/types.d.ts +27 -1
- package/dist/rag/embeddings/validate.d.ts +9 -1
- package/dist/rag/embeddings/validate.js +17 -4
- package/dist/rag/index.d.ts +2 -2
- package/dist/rag/index.js +1 -1
- package/dist/rag/indexer/bounded-channel.d.ts +51 -0
- package/dist/rag/indexer/bounded-channel.js +138 -0
- package/dist/rag/indexer/indexer.d.ts +4 -14
- package/dist/rag/indexer/indexer.js +246 -169
- package/dist/rag/indexer/types.d.ts +1 -0
- package/dist/rag/logger/index.d.ts +22 -0
- package/dist/rag/logger/index.js +78 -1
- package/dist/rag/manifest/index.js +1 -2
- package/dist/rag/search/index.js +1 -1
- package/dist/rag/storage/schema.d.ts +2 -4
- package/dist/rag/storage/schema.js +3 -5
- package/dist/store/app/selectors.d.ts +87 -0
- package/dist/store/app/selectors.js +28 -0
- package/dist/store/app/slice.d.ts +1013 -0
- package/dist/store/app/slice.js +112 -0
- package/dist/store/hooks.d.ts +22 -0
- package/dist/store/hooks.js +17 -0
- package/dist/store/index.d.ts +12 -0
- package/dist/store/index.js +18 -0
- package/dist/store/indexing/listeners.d.ts +25 -0
- package/dist/store/indexing/listeners.js +46 -0
- package/dist/store/indexing/selectors.d.ts +195 -0
- package/dist/store/indexing/selectors.js +69 -0
- package/dist/store/indexing/slice.d.ts +309 -0
- package/dist/store/indexing/slice.js +113 -0
- package/dist/store/slot-progress/listeners.d.ts +23 -0
- package/dist/store/slot-progress/listeners.js +33 -0
- package/dist/store/slot-progress/selectors.d.ts +67 -0
- package/dist/store/slot-progress/selectors.js +36 -0
- package/dist/store/slot-progress/slice.d.ts +246 -0
- package/dist/store/slot-progress/slice.js +70 -0
- package/dist/store/store.d.ts +17 -0
- package/dist/store/store.js +18 -0
- package/dist/store/warmup/selectors.d.ts +109 -0
- package/dist/store/warmup/selectors.js +44 -0
- package/dist/store/warmup/slice.d.ts +137 -0
- package/dist/store/warmup/slice.js +72 -0
- package/dist/store/watcher/selectors.d.ts +115 -0
- package/dist/store/watcher/selectors.js +52 -0
- package/dist/store/watcher/slice.d.ts +269 -0
- package/dist/store/watcher/slice.js +100 -0
- package/dist/store/wizard/selectors.d.ts +115 -0
- package/dist/store/wizard/selectors.js +36 -0
- package/dist/store/wizard/slice.d.ts +523 -0
- package/dist/store/wizard/slice.js +119 -0
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -575,13 +575,13 @@ Choose your embedding provider during `/init`:
|
|
|
575
575
|
- Initial indexing may take time; future updates are incremental
|
|
576
576
|
- Works great for code and natural language (docs, docstrings, code comments, etc.)
|
|
577
577
|
|
|
578
|
-
### Cloud Providers - Fastest, Best Quality
|
|
578
|
+
### Cloud Providers - Fastest, Best Quality, Largest Vocabulary
|
|
579
579
|
|
|
580
580
|
| Provider | Model | Dims | Cost | Get API Key |
|
|
581
581
|
| -------- | ---------------------- | ---- | --------- | ------------------------------------------------------- |
|
|
582
582
|
| Gemini | gemini-embedding-001 | 1536 | Free tier | [Google AI Studio](https://aistudio.google.com) |
|
|
583
583
|
| Mistral | codestral-embed | 1536 | $0.10/1M | [Mistral Console](https://console.mistral.ai/api-keys/) |
|
|
584
|
-
| OpenAI | text-embedding-3-
|
|
584
|
+
| OpenAI | text-embedding-3-large | 1536 | $0.13/1M | [OpenAI Platform](https://platform.openai.com/api-keys) |
|
|
585
585
|
|
|
586
586
|
- **Gemini** - Free tier available, great for getting started
|
|
587
587
|
- **Mistral** - Code-optimized embeddings for technical content
|
package/dist/cli/app.d.ts
CHANGED
package/dist/cli/app.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useCallback } from 'react';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { Box, Text, useStdout } from 'ink';
|
|
4
|
+
import { Provider } from 'react-redux';
|
|
5
|
+
import { store } from './store/store.js';
|
|
6
|
+
import { useAppDispatch, useAppSelector } from './store/hooks.js';
|
|
7
|
+
import { WizardActions } from './store/wizard/slice.js';
|
|
8
|
+
import { selectActiveWizard, selectInitStep, selectMcpStep, selectInitConfig, selectMcpConfig, selectIsReinit, selectShowMcpPrompt, selectExistingApiKey, selectExistingProvider, } from './store/wizard/selectors.js';
|
|
9
|
+
import { AppActions } from './store/app/slice.js';
|
|
10
|
+
import { selectIsInitialized, selectIndexStats, selectAppStatus, selectOutputItems, selectStartupLoaded, } from './store/app/selectors.js';
|
|
4
11
|
// Common infrastructure
|
|
5
12
|
import TextInput from '../common/components/TextInput.js';
|
|
6
|
-
import StatusBar from '
|
|
13
|
+
import StatusBar from './components/StatusBar.js';
|
|
7
14
|
import StaticWithResize from '../common/components/StaticWithResize.js';
|
|
8
15
|
import { useCtrlC } from '../common/hooks/useCtrlC.js';
|
|
9
16
|
import { useCommandHistory } from '../common/hooks/useCommandHistory.js';
|
|
@@ -14,9 +21,11 @@ import SearchResultsDisplay from './components/SearchResultsDisplay.js';
|
|
|
14
21
|
import InitWizard from './components/InitWizard.js';
|
|
15
22
|
import McpSetupWizard from './components/McpSetupWizard.js';
|
|
16
23
|
import CleanWizard from './components/CleanWizard.js';
|
|
17
|
-
import {
|
|
24
|
+
import { useCommands } from './commands/useCommands.js';
|
|
25
|
+
import { DaemonStatusProvider } from './contexts/DaemonStatusContext.js';
|
|
18
26
|
import { checkInitialized, loadIndexStats, runInit, runIndex, formatIndexStats, } from './commands/handlers.js';
|
|
19
|
-
import { getViberagDir
|
|
27
|
+
import { getViberagDir } from '../daemon/lib/constants.js';
|
|
28
|
+
import { loadConfig } from '../daemon/lib/config.js';
|
|
20
29
|
const require = createRequire(import.meta.url);
|
|
21
30
|
// Path is relative from dist/ after compilation
|
|
22
31
|
const { version } = require('../../package.json');
|
|
@@ -37,18 +46,28 @@ const COMMANDS = [
|
|
|
37
46
|
{ command: '/clean', description: 'Remove Viberag from project' },
|
|
38
47
|
{ command: '/quit', description: 'Exit the application' },
|
|
39
48
|
];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
49
|
+
/**
|
|
50
|
+
* Inner app content that uses Redux hooks.
|
|
51
|
+
* Must be rendered inside Provider.
|
|
52
|
+
*/
|
|
53
|
+
function AppContent() {
|
|
54
|
+
const dispatch = useAppDispatch();
|
|
55
|
+
// Redux wizard state
|
|
56
|
+
const activeWizard = useAppSelector(selectActiveWizard);
|
|
57
|
+
const initStep = useAppSelector(selectInitStep);
|
|
58
|
+
const mcpStep = useAppSelector(selectMcpStep);
|
|
59
|
+
const initConfig = useAppSelector(selectInitConfig);
|
|
60
|
+
const mcpConfig = useAppSelector(selectMcpConfig);
|
|
61
|
+
const isReinit = useAppSelector(selectIsReinit);
|
|
62
|
+
const showMcpPrompt = useAppSelector(selectShowMcpPrompt);
|
|
63
|
+
const existingApiKey = useAppSelector(selectExistingApiKey);
|
|
64
|
+
const existingProvider = useAppSelector(selectExistingProvider);
|
|
65
|
+
// Redux app state (migrated from useState)
|
|
66
|
+
const isInitialized = useAppSelector(selectIsInitialized);
|
|
67
|
+
const indexStats = useAppSelector(selectIndexStats);
|
|
68
|
+
const appStatus = useAppSelector(selectAppStatus);
|
|
69
|
+
const outputItems = useAppSelector(selectOutputItems);
|
|
70
|
+
const startupLoaded = useAppSelector(selectStartupLoaded);
|
|
52
71
|
const { stdout } = useStdout();
|
|
53
72
|
// Enable Kitty keyboard protocol for Shift+Enter support in iTerm2/Kitty/WezTerm
|
|
54
73
|
useKittyKeyboard();
|
|
@@ -57,144 +76,115 @@ export default function App() {
|
|
|
57
76
|
// Check initialization status and load stats on mount
|
|
58
77
|
useEffect(() => {
|
|
59
78
|
checkInitialized(projectRoot).then(async (initialized) => {
|
|
60
|
-
|
|
79
|
+
dispatch(AppActions.setInitialized(initialized));
|
|
61
80
|
// Load existing config for API key preservation during reinit
|
|
62
81
|
if (initialized) {
|
|
63
82
|
const config = await loadConfig(projectRoot);
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
dispatch(WizardActions.setExistingConfig({
|
|
84
|
+
apiKey: config.apiKey,
|
|
85
|
+
provider: config.embeddingProvider,
|
|
86
|
+
}));
|
|
66
87
|
}
|
|
67
88
|
});
|
|
68
|
-
loadIndexStats(projectRoot).then(setIndexStats);
|
|
69
|
-
}, [projectRoot]);
|
|
89
|
+
loadIndexStats(projectRoot).then(stats => dispatch(AppActions.setIndexStats(stats)));
|
|
90
|
+
}, [projectRoot, dispatch]);
|
|
70
91
|
// Command history
|
|
71
92
|
const { addToHistory, navigateUp, navigateDown, resetIndex } = useCommandHistory();
|
|
72
|
-
const addOutput = (type, content) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
type,
|
|
79
|
-
content,
|
|
80
|
-
},
|
|
81
|
-
]);
|
|
82
|
-
};
|
|
83
|
-
const addSearchResults = (data) => {
|
|
84
|
-
const id = String(nextId++);
|
|
85
|
-
setOutputItems(prev => [
|
|
86
|
-
...prev,
|
|
87
|
-
{
|
|
88
|
-
id,
|
|
89
|
-
type: 'search-results',
|
|
90
|
-
data,
|
|
91
|
-
},
|
|
92
|
-
]);
|
|
93
|
-
};
|
|
93
|
+
const addOutput = useCallback((type, content) => {
|
|
94
|
+
dispatch(AppActions.addOutput({ type, content }));
|
|
95
|
+
}, [dispatch]);
|
|
96
|
+
const addSearchResults = useCallback((data) => {
|
|
97
|
+
dispatch(AppActions.addSearchResults(data));
|
|
98
|
+
}, [dispatch]);
|
|
94
99
|
// Start the init wizard
|
|
95
100
|
const startInitWizard = useCallback((isReinit) => {
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
dispatch(WizardActions.startInit({
|
|
102
|
+
isReinit,
|
|
103
|
+
existingApiKey: existingApiKey ?? undefined,
|
|
104
|
+
existingProvider: existingProvider ?? undefined,
|
|
105
|
+
}));
|
|
106
|
+
}, [dispatch, existingApiKey, existingProvider]);
|
|
98
107
|
// Start the MCP setup wizard
|
|
99
108
|
const startMcpSetupWizard = useCallback((showPrompt = false) => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
type: 'mcp-setup',
|
|
103
|
-
step: showPrompt ? 'prompt' : 'select',
|
|
104
|
-
config: {},
|
|
105
|
-
showPrompt,
|
|
106
|
-
});
|
|
107
|
-
}, []);
|
|
109
|
+
dispatch(WizardActions.startMcpSetup({ showPrompt }));
|
|
110
|
+
}, [dispatch]);
|
|
108
111
|
// Start the clean wizard
|
|
109
112
|
const startCleanWizard = useCallback(() => {
|
|
110
|
-
|
|
111
|
-
}, []);
|
|
113
|
+
dispatch(WizardActions.startClean());
|
|
114
|
+
}, [dispatch]);
|
|
112
115
|
// Handle clean wizard completion
|
|
113
116
|
const handleCleanWizardComplete = useCallback(() => {
|
|
114
|
-
|
|
117
|
+
dispatch(WizardActions.close());
|
|
115
118
|
// Reset app state to uninitialized after cleaning
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}, []);
|
|
119
|
+
dispatch(AppActions.resetInitialized());
|
|
120
|
+
}, [dispatch]);
|
|
119
121
|
// Handle init wizard step changes
|
|
120
122
|
const handleInitWizardStep = useCallback((step, data) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
: prev);
|
|
124
|
-
}, []);
|
|
123
|
+
dispatch(WizardActions.setInitStep({ step, config: data }));
|
|
124
|
+
}, [dispatch]);
|
|
125
125
|
// Handle MCP wizard step changes
|
|
126
126
|
const handleMcpWizardStep = useCallback((step, data) => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
: prev);
|
|
130
|
-
}, []);
|
|
127
|
+
dispatch(WizardActions.setMcpStep({ step, config: data }));
|
|
128
|
+
}, [dispatch]);
|
|
131
129
|
// Handle init wizard completion
|
|
132
130
|
const handleInitWizardComplete = useCallback(async (config) => {
|
|
133
131
|
// Close wizard first, then run init after a tick to ensure proper re-render
|
|
134
|
-
|
|
132
|
+
dispatch(WizardActions.close());
|
|
135
133
|
// Wait for next tick so wizard unmounts before we add output
|
|
136
134
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
137
135
|
addOutput('system', 'Initializing Viberag...');
|
|
138
|
-
|
|
136
|
+
dispatch(AppActions.setWarning('Initializing...'));
|
|
139
137
|
try {
|
|
140
138
|
const result = await runInit(projectRoot, isInitialized ?? false, config);
|
|
141
139
|
addOutput('system', result);
|
|
142
|
-
|
|
140
|
+
dispatch(AppActions.setInitialized(true));
|
|
143
141
|
// Automatically start indexing after init
|
|
144
142
|
addOutput('system', 'Indexing codebase...');
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
current,
|
|
154
|
-
total,
|
|
155
|
-
stage,
|
|
156
|
-
throttleMessage,
|
|
157
|
-
chunksProcessed,
|
|
158
|
-
}));
|
|
159
|
-
addOutput('system', formatIndexStats(stats));
|
|
143
|
+
// Progress is synced via DaemonStatusContext polling
|
|
144
|
+
const stats = await runIndex(projectRoot, true);
|
|
145
|
+
if (stats) {
|
|
146
|
+
addOutput('system', formatIndexStats(stats));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
addOutput('system', 'Index complete.');
|
|
150
|
+
}
|
|
160
151
|
// Reload stats after indexing
|
|
161
152
|
const newStats = await loadIndexStats(projectRoot);
|
|
162
|
-
setIndexStats(newStats);
|
|
163
|
-
setAppStatus({ state: 'ready' });
|
|
153
|
+
dispatch(AppActions.setIndexStats(newStats));
|
|
164
154
|
// Prompt for MCP setup after init completes
|
|
165
155
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
166
156
|
startMcpSetupWizard(true); // showPrompt = true for post-init flow
|
|
167
157
|
}
|
|
168
158
|
catch (err) {
|
|
169
159
|
addOutput('system', `Init failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
170
|
-
setAppStatus({ state: 'ready' });
|
|
171
160
|
}
|
|
172
|
-
|
|
161
|
+
finally {
|
|
162
|
+
dispatch(AppActions.setReady());
|
|
163
|
+
}
|
|
164
|
+
}, [projectRoot, isInitialized, startMcpSetupWizard, dispatch, addOutput]);
|
|
173
165
|
// Handle MCP wizard completion
|
|
174
166
|
const handleMcpWizardComplete = useCallback((_config) => {
|
|
175
|
-
|
|
167
|
+
dispatch(WizardActions.close());
|
|
176
168
|
// Results are already shown in the wizard summary
|
|
177
|
-
}, []);
|
|
169
|
+
}, [dispatch]);
|
|
178
170
|
// Handle wizard cancellation
|
|
179
171
|
const handleWizardCancel = useCallback(() => {
|
|
180
|
-
const wasInit =
|
|
181
|
-
|
|
172
|
+
const wasInit = activeWizard === 'init';
|
|
173
|
+
dispatch(WizardActions.close());
|
|
182
174
|
if (wasInit) {
|
|
183
175
|
addOutput('system', 'Initialization cancelled.');
|
|
184
176
|
}
|
|
185
177
|
// MCP wizard cancel just closes silently
|
|
186
|
-
}, [
|
|
178
|
+
}, [dispatch, activeWizard]);
|
|
187
179
|
// Handle Ctrl+C with status message callback
|
|
188
180
|
const { handleCtrlC } = useCtrlC({
|
|
189
|
-
onFirstPress: () =>
|
|
190
|
-
onStatusClear: () =>
|
|
181
|
+
onFirstPress: () => dispatch(AppActions.setWarning('Press Ctrl+C again to quit')),
|
|
182
|
+
onStatusClear: () => dispatch(AppActions.setReady()),
|
|
191
183
|
});
|
|
192
184
|
// Command handling (all logic consolidated in useRagCommands)
|
|
193
|
-
const { isCommand, executeCommand } =
|
|
185
|
+
const { isCommand, executeCommand } = useCommands({
|
|
194
186
|
addOutput,
|
|
195
187
|
addSearchResults,
|
|
196
|
-
setAppStatus,
|
|
197
|
-
setIndexStats,
|
|
198
188
|
projectRoot,
|
|
199
189
|
stdout,
|
|
200
190
|
startInitWizard,
|
|
@@ -218,8 +208,7 @@ export default function App() {
|
|
|
218
208
|
}
|
|
219
209
|
};
|
|
220
210
|
// Prepend welcome banner as first static item (only after BOTH init status AND stats are loaded)
|
|
221
|
-
//
|
|
222
|
-
const startupLoaded = isInitialized !== undefined && indexStats !== undefined;
|
|
211
|
+
// startupLoaded is computed via Redux selector
|
|
223
212
|
const staticItems = [
|
|
224
213
|
...(startupLoaded
|
|
225
214
|
? [{ id: 'welcome', type: 'welcome', content: '' }]
|
|
@@ -241,5 +230,14 @@ export default function App() {
|
|
|
241
230
|
item.content)) : (React.createElement(Text, null, item.content))));
|
|
242
231
|
}),
|
|
243
232
|
React.createElement(StatusBar, { status: appStatus, stats: indexStats }),
|
|
244
|
-
|
|
233
|
+
activeWizard === 'init' ? (React.createElement(InitWizard, { step: initStep, config: initConfig, isReinit: isReinit, existingApiKey: existingApiKey ?? undefined, existingProvider: existingProvider ?? undefined, onStepChange: handleInitWizardStep, onComplete: handleInitWizardComplete, onCancel: handleWizardCancel })) : activeWizard === 'mcp-setup' ? (React.createElement(McpSetupWizard, { step: mcpStep, config: mcpConfig, projectRoot: projectRoot, showPrompt: showMcpPrompt, onStepChange: handleMcpWizardStep, onComplete: handleMcpWizardComplete, onCancel: handleWizardCancel, addOutput: addOutput })) : activeWizard === 'clean' ? (React.createElement(CleanWizard, { projectRoot: projectRoot, viberagDir: getViberagDir(projectRoot), onComplete: handleCleanWizardComplete, onCancel: handleWizardCancel, addOutput: addOutput })) : (React.createElement(TextInput, { onSubmit: handleSubmit, onCtrlC: handleCtrlC, commands: COMMANDS, navigateHistoryUp: navigateUp, navigateHistoryDown: navigateDown, resetHistoryIndex: resetIndex }))));
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Main App component with Redux Provider and DaemonStatusProvider.
|
|
237
|
+
*/
|
|
238
|
+
export default function App() {
|
|
239
|
+
const projectRoot = process.cwd();
|
|
240
|
+
return (React.createElement(Provider, { store: store },
|
|
241
|
+
React.createElement(DaemonStatusProvider, { projectRoot: projectRoot },
|
|
242
|
+
React.createElement(AppContent, null))));
|
|
245
243
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RAG commands for the CLI.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import type { IndexStats, SearchResults } from '../../client/types.js';
|
|
5
5
|
import type { InitWizardConfig } from '../../common/types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Index display stats type (re-exported for convenience).
|
|
@@ -21,21 +21,23 @@ export declare function loadIndexStats(projectRoot: string): Promise<IndexDispla
|
|
|
21
21
|
/**
|
|
22
22
|
* Initialize a project for Viberag.
|
|
23
23
|
* Creates .viberag/ directory with config.json.
|
|
24
|
-
* With isReinit=true,
|
|
24
|
+
* With isReinit=true, shuts down daemon and deletes everything first.
|
|
25
25
|
*/
|
|
26
26
|
export declare function runInit(projectRoot: string, isReinit?: boolean, wizardConfig?: InitWizardConfig): Promise<string>;
|
|
27
27
|
/**
|
|
28
28
|
* Run the indexer and return stats.
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* Delegates to daemon which handles dimension sync internally.
|
|
30
|
+
*
|
|
31
|
+
* Note: Indexing starts asynchronously; completion is detected via status polling.
|
|
31
32
|
*/
|
|
32
|
-
export declare function runIndex(projectRoot: string, force?: boolean
|
|
33
|
+
export declare function runIndex(projectRoot: string, force?: boolean): Promise<IndexStats | null>;
|
|
33
34
|
/**
|
|
34
35
|
* Format index stats for display.
|
|
35
36
|
*/
|
|
36
37
|
export declare function formatIndexStats(stats: IndexStats): string;
|
|
37
38
|
/**
|
|
38
39
|
* Run a search query and return results.
|
|
40
|
+
* Delegates to daemon for search.
|
|
39
41
|
*/
|
|
40
42
|
export declare function runSearch(projectRoot: string, query: string, limit?: number): Promise<SearchResults>;
|
|
41
43
|
/**
|
|
@@ -48,7 +50,7 @@ export declare function formatSearchResults(results: SearchResults): string;
|
|
|
48
50
|
export declare function getStatus(projectRoot: string): Promise<string>;
|
|
49
51
|
/**
|
|
50
52
|
* Clean/uninstall Viberag from a project.
|
|
51
|
-
*
|
|
53
|
+
* Shuts down daemon first, then removes the entire .viberag/ directory.
|
|
52
54
|
*/
|
|
53
55
|
export declare function runClean(projectRoot: string): Promise<string>;
|
|
54
56
|
/**
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import fs from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import {
|
|
7
|
+
import { loadManifest, manifestExists } from '../../daemon/lib/manifest.js';
|
|
8
|
+
import { configExists, saveConfig, DEFAULT_CONFIG, PROVIDER_CONFIGS, } from '../../daemon/lib/config.js';
|
|
9
|
+
import { getViberagDir } from '../../daemon/lib/constants.js';
|
|
10
|
+
import { DaemonClient } from '../../client/index.js';
|
|
8
11
|
/**
|
|
9
12
|
* Check if project is initialized.
|
|
10
13
|
*/
|
|
@@ -27,13 +30,28 @@ export async function loadIndexStats(projectRoot) {
|
|
|
27
30
|
/**
|
|
28
31
|
* Initialize a project for Viberag.
|
|
29
32
|
* Creates .viberag/ directory with config.json.
|
|
30
|
-
* With isReinit=true,
|
|
33
|
+
* With isReinit=true, shuts down daemon and deletes everything first.
|
|
31
34
|
*/
|
|
32
35
|
export async function runInit(projectRoot, isReinit = false, wizardConfig) {
|
|
33
36
|
const viberagDir = getViberagDir(projectRoot);
|
|
34
37
|
const isExisting = await configExists(projectRoot);
|
|
35
|
-
// If reinit, delete entire .viberag directory first
|
|
38
|
+
// If reinit, shutdown daemon and delete entire .viberag directory first
|
|
36
39
|
if (isReinit && isExisting) {
|
|
40
|
+
const client = new DaemonClient(projectRoot);
|
|
41
|
+
try {
|
|
42
|
+
if (await client.isRunning()) {
|
|
43
|
+
await client.connect();
|
|
44
|
+
await client.shutdown('reinit');
|
|
45
|
+
// Wait for daemon to exit
|
|
46
|
+
await new Promise(r => setTimeout(r, 500));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Ignore errors - daemon may not be running
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await client.disconnect();
|
|
54
|
+
}
|
|
37
55
|
await fs.rm(viberagDir, { recursive: true, force: true });
|
|
38
56
|
}
|
|
39
57
|
// Create .viberag directory
|
|
@@ -41,12 +59,21 @@ export async function runInit(projectRoot, isReinit = false, wizardConfig) {
|
|
|
41
59
|
// Build config from wizard choices
|
|
42
60
|
const provider = wizardConfig?.provider ?? 'gemini';
|
|
43
61
|
const { model, dimensions } = PROVIDER_CONFIGS[provider];
|
|
62
|
+
// Map OpenAI region to base URL
|
|
63
|
+
const openaiBaseUrl = wizardConfig?.openaiRegion
|
|
64
|
+
? {
|
|
65
|
+
default: undefined,
|
|
66
|
+
us: 'https://us.api.openai.com/v1',
|
|
67
|
+
eu: 'https://eu.api.openai.com/v1',
|
|
68
|
+
}[wizardConfig.openaiRegion]
|
|
69
|
+
: undefined;
|
|
44
70
|
const config = {
|
|
45
71
|
...DEFAULT_CONFIG,
|
|
46
72
|
embeddingProvider: provider,
|
|
47
73
|
embeddingModel: model,
|
|
48
74
|
embeddingDimensions: dimensions,
|
|
49
75
|
...(wizardConfig?.apiKey && { apiKey: wizardConfig.apiKey }),
|
|
76
|
+
...(openaiBaseUrl && { openaiBaseUrl }),
|
|
50
77
|
};
|
|
51
78
|
// Save config
|
|
52
79
|
await saveConfig(projectRoot, config);
|
|
@@ -68,35 +95,48 @@ export async function runInit(projectRoot, isReinit = false, wizardConfig) {
|
|
|
68
95
|
}
|
|
69
96
|
/**
|
|
70
97
|
* Run the indexer and return stats.
|
|
71
|
-
*
|
|
72
|
-
*
|
|
98
|
+
* Delegates to daemon which handles dimension sync internally.
|
|
99
|
+
*
|
|
100
|
+
* Note: Indexing starts asynchronously; completion is detected via status polling.
|
|
73
101
|
*/
|
|
74
|
-
export async function runIndex(projectRoot, force = false
|
|
75
|
-
|
|
76
|
-
// This handles cases where PROVIDER_CONFIGS dimensions changed (e.g., Gemini 768→1536)
|
|
77
|
-
if (force) {
|
|
78
|
-
const { loadConfig } = await import('../../rag/config/index.js');
|
|
79
|
-
const config = await loadConfig(projectRoot);
|
|
80
|
-
const currentDimensions = PROVIDER_CONFIGS[config.embeddingProvider]?.dimensions;
|
|
81
|
-
if (currentDimensions && config.embeddingDimensions !== currentDimensions) {
|
|
82
|
-
const updatedConfig = {
|
|
83
|
-
...config,
|
|
84
|
-
embeddingDimensions: currentDimensions,
|
|
85
|
-
embeddingModel: PROVIDER_CONFIGS[config.embeddingProvider].model,
|
|
86
|
-
};
|
|
87
|
-
await saveConfig(projectRoot, updatedConfig);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const indexer = new Indexer(projectRoot);
|
|
102
|
+
export async function runIndex(projectRoot, force = false) {
|
|
103
|
+
const client = new DaemonClient(projectRoot);
|
|
91
104
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
return
|
|
105
|
+
await client.connect();
|
|
106
|
+
const initialStatus = await client.status();
|
|
107
|
+
const previousCompletion = initialStatus.indexing.lastCompleted;
|
|
108
|
+
await client.indexAsync({ force });
|
|
109
|
+
return await waitForIndexCompletion(client, previousCompletion);
|
|
97
110
|
}
|
|
98
111
|
finally {
|
|
99
|
-
|
|
112
|
+
await client.disconnect();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Poll daemon status until a new index completion is observed.
|
|
117
|
+
*/
|
|
118
|
+
async function waitForIndexCompletion(client, previousLastCompleted) {
|
|
119
|
+
const pollIntervalMs = 500;
|
|
120
|
+
const statsGraceMs = 5000;
|
|
121
|
+
let completionDetectedAt = null;
|
|
122
|
+
for (;;) {
|
|
123
|
+
const status = await client.status();
|
|
124
|
+
if (status.indexing.status === 'error') {
|
|
125
|
+
throw new Error(status.indexing.error ?? 'Index failed');
|
|
126
|
+
}
|
|
127
|
+
const lastCompleted = status.indexing.lastCompleted;
|
|
128
|
+
if (lastCompleted && lastCompleted !== previousLastCompleted) {
|
|
129
|
+
if (status.indexing.lastStats) {
|
|
130
|
+
return status.indexing.lastStats;
|
|
131
|
+
}
|
|
132
|
+
if (completionDetectedAt === null) {
|
|
133
|
+
completionDetectedAt = Date.now();
|
|
134
|
+
}
|
|
135
|
+
else if (Date.now() - completionDetectedAt > statsGraceMs) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
|
|
100
140
|
}
|
|
101
141
|
}
|
|
102
142
|
/**
|
|
@@ -118,14 +158,16 @@ export function formatIndexStats(stats) {
|
|
|
118
158
|
}
|
|
119
159
|
/**
|
|
120
160
|
* Run a search query and return results.
|
|
161
|
+
* Delegates to daemon for search.
|
|
121
162
|
*/
|
|
122
163
|
export async function runSearch(projectRoot, query, limit = 10) {
|
|
123
|
-
const
|
|
164
|
+
const client = new DaemonClient(projectRoot);
|
|
124
165
|
try {
|
|
125
|
-
|
|
166
|
+
await client.connect();
|
|
167
|
+
return await client.search(query, { limit });
|
|
126
168
|
}
|
|
127
169
|
finally {
|
|
128
|
-
|
|
170
|
+
await client.disconnect();
|
|
129
171
|
}
|
|
130
172
|
}
|
|
131
173
|
/**
|
|
@@ -198,7 +240,7 @@ export async function getStatus(projectRoot) {
|
|
|
198
240
|
}
|
|
199
241
|
/**
|
|
200
242
|
* Clean/uninstall Viberag from a project.
|
|
201
|
-
*
|
|
243
|
+
* Shuts down daemon first, then removes the entire .viberag/ directory.
|
|
202
244
|
*/
|
|
203
245
|
export async function runClean(projectRoot) {
|
|
204
246
|
const viberagDir = getViberagDir(projectRoot);
|
|
@@ -206,6 +248,22 @@ export async function runClean(projectRoot) {
|
|
|
206
248
|
if (!exists) {
|
|
207
249
|
return 'Viberag is not initialized in this project. Nothing to clean.';
|
|
208
250
|
}
|
|
251
|
+
// Shutdown daemon if running
|
|
252
|
+
const client = new DaemonClient(projectRoot);
|
|
253
|
+
try {
|
|
254
|
+
if (await client.isRunning()) {
|
|
255
|
+
await client.connect();
|
|
256
|
+
await client.shutdown('clean');
|
|
257
|
+
// Wait for daemon to exit
|
|
258
|
+
await new Promise(r => setTimeout(r, 500));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// Ignore errors - daemon may not be running
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
await client.disconnect();
|
|
266
|
+
}
|
|
209
267
|
await fs.rm(viberagDir, { recursive: true, force: true });
|
|
210
268
|
return `Removed ${viberagDir}\nViberag has been uninstalled from this project.\nRun /init to reinitialize.`;
|
|
211
269
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command handling hook.
|
|
3
|
+
* Consolidates all command routing and handler implementations.
|
|
4
|
+
*/
|
|
5
|
+
import type { SearchResultsData } from '../../common/types.js';
|
|
6
|
+
type CommandContext = {
|
|
7
|
+
addOutput: (type: 'user' | 'system', content: string) => void;
|
|
8
|
+
addSearchResults: (data: SearchResultsData) => void;
|
|
9
|
+
projectRoot: string;
|
|
10
|
+
stdout: NodeJS.WriteStream;
|
|
11
|
+
startInitWizard: (isReinit: boolean) => void;
|
|
12
|
+
startMcpSetupWizard: (showPrompt?: boolean) => void;
|
|
13
|
+
startCleanWizard: () => void;
|
|
14
|
+
isInitialized: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare function useCommands({ addOutput, addSearchResults, projectRoot, stdout, startInitWizard, startMcpSetupWizard, startCleanWizard, isInitialized, }: CommandContext): {
|
|
17
|
+
isCommand: (text: string) => boolean;
|
|
18
|
+
executeCommand: (text: string) => void;
|
|
19
|
+
};
|
|
20
|
+
export {};
|