gencode-ai 0.1.0 → 0.1.2
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/.gencode/settings.local.json +7 -0
- package/README.md +20 -102
- package/dist/agent/agent.d.ts +43 -2
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +90 -17
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/types.d.ts +9 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/cli/components/AllModelsSelector.d.ts +11 -0
- package/dist/cli/components/AllModelsSelector.d.ts.map +1 -0
- package/dist/cli/components/AllModelsSelector.js +153 -0
- package/dist/cli/components/AllModelsSelector.js.map +1 -0
- package/dist/cli/components/App.d.ts +8 -1
- package/dist/cli/components/App.d.ts.map +1 -1
- package/dist/cli/components/App.js +276 -40
- package/dist/cli/components/App.js.map +1 -1
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
- package/dist/cli/components/CommandSuggestions.js +3 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -1
- package/dist/cli/components/Header.d.ts +1 -1
- package/dist/cli/components/Header.d.ts.map +1 -1
- package/dist/cli/components/Header.js +4 -6
- package/dist/cli/components/Header.js.map +1 -1
- package/dist/cli/components/Logo.d.ts +1 -0
- package/dist/cli/components/Logo.d.ts.map +1 -1
- package/dist/cli/components/Logo.js +16 -3
- package/dist/cli/components/Logo.js.map +1 -1
- package/dist/cli/components/Messages.d.ts +17 -3
- package/dist/cli/components/Messages.d.ts.map +1 -1
- package/dist/cli/components/Messages.js +70 -18
- package/dist/cli/components/Messages.js.map +1 -1
- package/dist/cli/components/ModelSelector.d.ts +7 -7
- package/dist/cli/components/ModelSelector.d.ts.map +1 -1
- package/dist/cli/components/ModelSelector.js +116 -33
- package/dist/cli/components/ModelSelector.js.map +1 -1
- package/dist/cli/components/PermissionPrompt.d.ts +60 -0
- package/dist/cli/components/PermissionPrompt.d.ts.map +1 -0
- package/dist/cli/components/PermissionPrompt.js +192 -0
- package/dist/cli/components/PermissionPrompt.js.map +1 -0
- package/dist/cli/components/ProviderManager.d.ts +8 -0
- package/dist/cli/components/ProviderManager.d.ts.map +1 -0
- package/dist/cli/components/ProviderManager.js +280 -0
- package/dist/cli/components/ProviderManager.js.map +1 -0
- package/dist/cli/components/Spinner.d.ts +7 -2
- package/dist/cli/components/Spinner.d.ts.map +1 -1
- package/dist/cli/components/Spinner.js +116 -25
- package/dist/cli/components/Spinner.js.map +1 -1
- package/dist/cli/components/TodoList.d.ts +7 -0
- package/dist/cli/components/TodoList.d.ts.map +1 -0
- package/dist/cli/components/TodoList.js +34 -0
- package/dist/cli/components/TodoList.js.map +1 -0
- package/dist/cli/components/index.d.ts +1 -0
- package/dist/cli/components/index.d.ts.map +1 -1
- package/dist/cli/components/index.js +1 -0
- package/dist/cli/components/index.js.map +1 -1
- package/dist/cli/components/markdown.d.ts +9 -0
- package/dist/cli/components/markdown.d.ts.map +1 -0
- package/dist/cli/components/markdown.js +129 -0
- package/dist/cli/components/markdown.js.map +1 -0
- package/dist/cli/components/theme.d.ts +5 -0
- package/dist/cli/components/theme.d.ts.map +1 -1
- package/dist/cli/components/theme.js +7 -0
- package/dist/cli/components/theme.js.map +1 -1
- package/dist/cli/index.js +66 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +14 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +19 -3
- package/dist/config/index.js.map +1 -1
- package/dist/config/levels.d.ts +49 -0
- package/dist/config/levels.d.ts.map +1 -0
- package/dist/config/levels.js +222 -0
- package/dist/config/levels.js.map +1 -0
- package/dist/config/loader.d.ts +46 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +153 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +115 -15
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +260 -34
- package/dist/config/manager.js.map +1 -1
- package/dist/config/manager.test.d.ts +5 -0
- package/dist/config/manager.test.d.ts.map +1 -0
- package/dist/config/manager.test.js +192 -0
- package/dist/config/manager.test.js.map +1 -0
- package/dist/config/merger.d.ts +56 -0
- package/dist/config/merger.d.ts.map +1 -0
- package/dist/config/merger.js +177 -0
- package/dist/config/merger.js.map +1 -0
- package/dist/config/providers-config.d.ts +28 -0
- package/dist/config/providers-config.d.ts.map +1 -0
- package/dist/config/providers-config.js +79 -0
- package/dist/config/providers-config.js.map +1 -0
- package/dist/config/test-utils.d.ts +24 -0
- package/dist/config/test-utils.d.ts.map +1 -0
- package/dist/config/test-utils.js +55 -0
- package/dist/config/test-utils.js.map +1 -0
- package/dist/config/types.d.ts +108 -9
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +53 -2
- package/dist/config/types.js.map +1 -1
- package/dist/memory/import-resolver.d.ts +46 -0
- package/dist/memory/import-resolver.d.ts.map +1 -0
- package/dist/memory/import-resolver.js +117 -0
- package/dist/memory/import-resolver.js.map +1 -0
- package/dist/memory/index.d.ts +7 -6
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +7 -5
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/init-prompt.d.ts +22 -0
- package/dist/memory/init-prompt.d.ts.map +1 -0
- package/dist/memory/init-prompt.js +103 -0
- package/dist/memory/init-prompt.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +119 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +587 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/rules-parser.d.ts +38 -0
- package/dist/memory/rules-parser.d.ts.map +1 -0
- package/dist/memory/rules-parser.js +69 -0
- package/dist/memory/rules-parser.js.map +1 -0
- package/dist/memory/test-utils.d.ts +20 -0
- package/dist/memory/test-utils.d.ts.map +1 -0
- package/dist/memory/test-utils.js +44 -0
- package/dist/memory/test-utils.js.map +1 -0
- package/dist/memory/types.d.ts +70 -63
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +42 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/permissions/audit.d.ts +82 -0
- package/dist/permissions/audit.d.ts.map +1 -0
- package/dist/permissions/audit.js +229 -0
- package/dist/permissions/audit.js.map +1 -0
- package/dist/permissions/index.d.ts +11 -1
- package/dist/permissions/index.d.ts.map +1 -1
- package/dist/permissions/index.js +15 -0
- package/dist/permissions/index.js.map +1 -1
- package/dist/permissions/manager.d.ts +149 -13
- package/dist/permissions/manager.d.ts.map +1 -1
- package/dist/permissions/manager.js +480 -35
- package/dist/permissions/manager.js.map +1 -1
- package/dist/permissions/manager.test.d.ts +5 -0
- package/dist/permissions/manager.test.d.ts.map +1 -0
- package/dist/permissions/manager.test.js +213 -0
- package/dist/permissions/manager.test.js.map +1 -0
- package/dist/permissions/persistence.d.ts +74 -0
- package/dist/permissions/persistence.d.ts.map +1 -0
- package/dist/permissions/persistence.js +248 -0
- package/dist/permissions/persistence.js.map +1 -0
- package/dist/permissions/persistence.test.d.ts +5 -0
- package/dist/permissions/persistence.test.d.ts.map +1 -0
- package/dist/permissions/persistence.test.js +171 -0
- package/dist/permissions/persistence.test.js.map +1 -0
- package/dist/permissions/prompt-matcher.d.ts +64 -0
- package/dist/permissions/prompt-matcher.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.js +415 -0
- package/dist/permissions/prompt-matcher.js.map +1 -0
- package/dist/permissions/prompt-matcher.test.d.ts +5 -0
- package/dist/permissions/prompt-matcher.test.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.test.js +107 -0
- package/dist/permissions/prompt-matcher.test.js.map +1 -0
- package/dist/permissions/types.d.ts +157 -0
- package/dist/permissions/types.d.ts.map +1 -1
- package/dist/permissions/types.js +43 -8
- package/dist/permissions/types.js.map +1 -1
- package/dist/prompts/index.d.ts +92 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +241 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +14 -3
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/index.d.ts +5 -3
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +13 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/registry.d.ts +66 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +158 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/search/brave.d.ts +14 -0
- package/dist/providers/search/brave.d.ts.map +1 -0
- package/dist/providers/search/brave.js +87 -0
- package/dist/providers/search/brave.js.map +1 -0
- package/dist/providers/search/exa.d.ts +12 -0
- package/dist/providers/search/exa.d.ts.map +1 -0
- package/dist/providers/search/exa.js +158 -0
- package/dist/providers/search/exa.js.map +1 -0
- package/dist/providers/search/index.d.ts +31 -0
- package/dist/providers/search/index.d.ts.map +1 -0
- package/dist/providers/search/index.js +75 -0
- package/dist/providers/search/index.js.map +1 -0
- package/dist/providers/search/serper.d.ts +14 -0
- package/dist/providers/search/serper.d.ts.map +1 -0
- package/dist/providers/search/serper.js +87 -0
- package/dist/providers/search/serper.js.map +1 -0
- package/dist/providers/search/types.d.ts +21 -0
- package/dist/providers/search/types.d.ts.map +1 -0
- package/dist/providers/search/types.js +5 -0
- package/dist/providers/search/types.js.map +1 -0
- package/dist/providers/store.d.ts +104 -0
- package/dist/providers/store.d.ts.map +1 -0
- package/dist/providers/store.js +171 -0
- package/dist/providers/store.js.map +1 -0
- package/dist/providers/types.d.ts +7 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/vertex-ai.d.ts +33 -0
- package/dist/providers/vertex-ai.d.ts.map +1 -0
- package/dist/providers/vertex-ai.js +407 -0
- package/dist/providers/vertex-ai.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -1
- package/dist/tools/builtin/bash.js +2 -1
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/edit.d.ts.map +1 -1
- package/dist/tools/builtin/edit.js +2 -1
- package/dist/tools/builtin/edit.js.map +1 -1
- package/dist/tools/builtin/glob.d.ts.map +1 -1
- package/dist/tools/builtin/glob.js +2 -1
- package/dist/tools/builtin/glob.js.map +1 -1
- package/dist/tools/builtin/grep.d.ts.map +1 -1
- package/dist/tools/builtin/grep.js +2 -1
- package/dist/tools/builtin/grep.js.map +1 -1
- package/dist/tools/builtin/read.d.ts.map +1 -1
- package/dist/tools/builtin/read.js +2 -1
- package/dist/tools/builtin/read.js.map +1 -1
- package/dist/tools/builtin/todowrite.d.ts +15 -0
- package/dist/tools/builtin/todowrite.d.ts.map +1 -0
- package/dist/tools/builtin/todowrite.js +88 -0
- package/dist/tools/builtin/todowrite.js.map +1 -0
- package/dist/tools/builtin/webfetch.d.ts +20 -0
- package/dist/tools/builtin/webfetch.d.ts.map +1 -0
- package/dist/tools/builtin/webfetch.js +228 -0
- package/dist/tools/builtin/webfetch.js.map +1 -0
- package/dist/tools/builtin/websearch.d.ts +17 -0
- package/dist/tools/builtin/websearch.d.ts.map +1 -0
- package/dist/tools/builtin/websearch.js +87 -0
- package/dist/tools/builtin/websearch.js.map +1 -0
- package/dist/tools/builtin/write.d.ts.map +1 -1
- package/dist/tools/builtin/write.js +2 -1
- package/dist/tools/builtin/write.js.map +1 -1
- package/dist/tools/index.d.ts +18 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +28 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/types.d.ts +41 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +16 -0
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/utils/ssrf.d.ts +18 -0
- package/dist/tools/utils/ssrf.d.ts.map +1 -0
- package/dist/tools/utils/ssrf.js +70 -0
- package/dist/tools/utils/ssrf.js.map +1 -0
- package/docs/README.md +5 -4
- package/docs/config-system-comparison.md +707 -0
- package/docs/memory-system.md +238 -0
- package/docs/permissions.md +368 -0
- package/docs/proposals/0001-web-fetch-tool.md +32 -2
- package/docs/proposals/0002-web-search-tool.md +59 -2
- package/docs/proposals/0005-todo-system.md +350 -85
- package/docs/proposals/0006-memory-system.md +11 -10
- package/docs/proposals/0012-ask-user-question.md +941 -206
- package/docs/proposals/0023-permission-enhancements.md +61 -2
- package/docs/proposals/0041-configuration-system.md +587 -0
- package/docs/proposals/0042-prompt-optimization.md +866 -0
- package/docs/proposals/README.md +8 -6
- package/docs/providers.md +220 -0
- package/jest.config.js +26 -0
- package/package.json +14 -3
- package/src/agent/agent.ts +120 -18
- package/src/agent/types.ts +9 -1
- package/src/cli/components/App.tsx +369 -47
- package/src/cli/components/CommandSuggestions.tsx +3 -0
- package/src/cli/components/Header.tsx +11 -17
- package/src/cli/components/Logo.tsx +76 -9
- package/src/cli/components/Messages.tsx +146 -38
- package/src/cli/components/ModelSelector.tsx +169 -52
- package/src/cli/components/PermissionPrompt.tsx +388 -0
- package/src/cli/components/ProviderManager.tsx +534 -0
- package/src/cli/components/Spinner.tsx +138 -25
- package/src/cli/components/TodoList.tsx +54 -0
- package/src/cli/components/index.ts +6 -0
- package/src/cli/components/markdown.ts +157 -0
- package/src/cli/components/theme.ts +7 -0
- package/src/cli/index.tsx +76 -13
- package/src/config/index.ts +79 -4
- package/src/config/levels.test.ts +163 -0
- package/src/config/levels.ts +285 -0
- package/src/config/loader.test.ts +120 -0
- package/src/config/loader.ts +178 -0
- package/src/config/manager.test.ts +215 -0
- package/src/config/manager.ts +328 -40
- package/src/config/merger.test.ts +360 -0
- package/src/config/merger.ts +221 -0
- package/src/config/providers-config.ts +85 -0
- package/src/config/test-utils.ts +79 -0
- package/src/config/types.ts +186 -9
- package/src/memory/import-resolver.test.ts +117 -0
- package/src/memory/import-resolver.ts +149 -0
- package/src/memory/index.ts +11 -0
- package/src/memory/init-prompt.ts +113 -0
- package/src/memory/memory-manager.test.ts +198 -0
- package/src/memory/memory-manager.ts +716 -0
- package/src/memory/rules-parser.test.ts +182 -0
- package/src/memory/rules-parser.ts +82 -0
- package/src/memory/test-utils.ts +60 -0
- package/src/memory/types.ts +119 -0
- package/src/permissions/audit.ts +284 -0
- package/src/permissions/index.ts +20 -1
- package/src/permissions/manager.test.ts +260 -0
- package/src/permissions/manager.ts +592 -40
- package/src/permissions/persistence.test.ts +220 -0
- package/src/permissions/persistence.ts +301 -0
- package/src/permissions/prompt-matcher.test.ts +213 -0
- package/src/permissions/prompt-matcher.ts +472 -0
- package/src/permissions/types.ts +236 -8
- package/src/prompts/index.test.ts +279 -0
- package/src/prompts/index.ts +306 -0
- package/src/prompts/system/anthropic.txt +29 -0
- package/src/prompts/system/base.txt +124 -0
- package/src/prompts/system/gemini.txt +35 -0
- package/src/prompts/system/generic.txt +128 -0
- package/src/prompts/system/openai.txt +29 -0
- package/src/prompts/tools/bash.txt +60 -0
- package/src/prompts/tools/edit.txt +29 -0
- package/src/prompts/tools/glob.txt +35 -0
- package/src/prompts/tools/grep.txt +43 -0
- package/src/prompts/tools/read.txt +22 -0
- package/src/prompts/tools/todowrite.txt +71 -0
- package/src/prompts/tools/webfetch.txt +34 -0
- package/src/prompts/tools/websearch.txt +41 -0
- package/src/prompts/tools/write.txt +23 -0
- package/src/providers/gemini.ts +20 -4
- package/src/providers/index.ts +18 -3
- package/src/providers/registry.ts +198 -0
- package/src/providers/search/brave.ts +132 -0
- package/src/providers/search/exa.ts +217 -0
- package/src/providers/search/index.ts +79 -0
- package/src/providers/search/serper.ts +133 -0
- package/src/providers/search/types.ts +24 -0
- package/src/providers/store.ts +216 -0
- package/src/providers/types.ts +9 -1
- package/src/providers/vertex-ai.ts +594 -0
- package/src/tools/builtin/bash.ts +2 -1
- package/src/tools/builtin/edit.ts +2 -1
- package/src/tools/builtin/glob.ts +2 -1
- package/src/tools/builtin/grep.ts +2 -1
- package/src/tools/builtin/read.ts +2 -1
- package/src/tools/builtin/todowrite.ts +102 -0
- package/src/tools/builtin/webfetch.ts +261 -0
- package/src/tools/builtin/websearch.ts +103 -0
- package/src/tools/builtin/write.ts +2 -1
- package/src/tools/index.ts +28 -2
- package/src/tools/types.ts +32 -0
- package/src/tools/utils/ssrf.ts +79 -0
- package/tsconfig.json +1 -1
- package/CLAUDE.md +0 -70
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Manager - Manage provider connections
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
5
|
+
import { Box, Text, useInput } from 'ink';
|
|
6
|
+
import TextInput from 'ink-text-input';
|
|
7
|
+
import { colors, icons } from './theme.js';
|
|
8
|
+
import { LoadingSpinner } from './Spinner.js';
|
|
9
|
+
import {
|
|
10
|
+
getProvidersSorted,
|
|
11
|
+
getAvailableConnections,
|
|
12
|
+
isConnectionReady,
|
|
13
|
+
getSearchProvidersSorted,
|
|
14
|
+
type ProviderDefinition,
|
|
15
|
+
type ConnectionOption,
|
|
16
|
+
type SearchProviderDefinition,
|
|
17
|
+
} from '../../providers/registry.js';
|
|
18
|
+
import { getProviderStore, type ModelInfo } from '../../providers/store.js';
|
|
19
|
+
import { createProvider, type ProviderName } from '../../providers/index.js';
|
|
20
|
+
import { isSearchProviderAvailable, type SearchProviderName } from '../../providers/search/index.js';
|
|
21
|
+
|
|
22
|
+
interface ProviderManagerProps {
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
onProviderChange?: (providerId: ProviderName, model: string) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type View = 'list' | 'select-connection' | 'confirm-remove' | 'search-list';
|
|
28
|
+
type Tab = 'llm' | 'search';
|
|
29
|
+
|
|
30
|
+
interface ProviderItem {
|
|
31
|
+
provider: ProviderDefinition;
|
|
32
|
+
connected: boolean;
|
|
33
|
+
modelCount: number;
|
|
34
|
+
connectionMethod?: string;
|
|
35
|
+
readyConnections: ConnectionOption[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface SearchProviderItem {
|
|
39
|
+
provider: SearchProviderDefinition;
|
|
40
|
+
isSelected: boolean;
|
|
41
|
+
isAvailable: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function ProviderManager({ onClose }: ProviderManagerProps) {
|
|
45
|
+
const store = getProviderStore();
|
|
46
|
+
|
|
47
|
+
const [view, setView] = useState<View>('list');
|
|
48
|
+
const [tab, setTab] = useState<Tab>('llm');
|
|
49
|
+
const [filter, setFilter] = useState('');
|
|
50
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
51
|
+
const [connectionIndex, setConnectionIndex] = useState(0);
|
|
52
|
+
const [loading, setLoading] = useState(false);
|
|
53
|
+
const [message, setMessage] = useState<string | null>(null);
|
|
54
|
+
const [selectedProvider, setSelectedProvider] = useState<ProviderDefinition | null>(null);
|
|
55
|
+
const [searchSelectedIndex, setSearchSelectedIndex] = useState(0);
|
|
56
|
+
|
|
57
|
+
// Build provider list
|
|
58
|
+
const buildProviderList = useCallback((): ProviderItem[] => {
|
|
59
|
+
const allProviders = getProvidersSorted();
|
|
60
|
+
return allProviders.map((provider) => {
|
|
61
|
+
const connected = store.isConnected(provider.id);
|
|
62
|
+
const connection = store.getConnection(provider.id);
|
|
63
|
+
const readyConnections = getAvailableConnections(provider);
|
|
64
|
+
return {
|
|
65
|
+
provider,
|
|
66
|
+
connected,
|
|
67
|
+
modelCount: store.getModelCount(provider.id),
|
|
68
|
+
connectionMethod: connection?.method,
|
|
69
|
+
readyConnections,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}, [store]);
|
|
73
|
+
|
|
74
|
+
const [providerList, setProviderList] = useState<ProviderItem[]>(buildProviderList);
|
|
75
|
+
|
|
76
|
+
// Refresh list
|
|
77
|
+
const refreshList = useCallback(() => {
|
|
78
|
+
setProviderList(buildProviderList());
|
|
79
|
+
}, [buildProviderList]);
|
|
80
|
+
|
|
81
|
+
// Build search provider list
|
|
82
|
+
const buildSearchProviderList = useCallback((): SearchProviderItem[] => {
|
|
83
|
+
const currentSearch = store.getSearchProvider();
|
|
84
|
+
return getSearchProvidersSorted().map((provider) => ({
|
|
85
|
+
provider,
|
|
86
|
+
isSelected: provider.id === currentSearch || (!currentSearch && provider.id === 'exa'),
|
|
87
|
+
isAvailable: isSearchProviderAvailable(provider.id),
|
|
88
|
+
}));
|
|
89
|
+
}, [store]);
|
|
90
|
+
|
|
91
|
+
const searchProviders = buildSearchProviderList();
|
|
92
|
+
|
|
93
|
+
// Select search provider
|
|
94
|
+
const selectSearchProvider = (id: SearchProviderName) => {
|
|
95
|
+
if (id === 'exa') {
|
|
96
|
+
store.clearSearchProvider(); // Use default
|
|
97
|
+
} else {
|
|
98
|
+
store.setSearchProvider(id);
|
|
99
|
+
}
|
|
100
|
+
setMessage(`Search provider set to ${id}`);
|
|
101
|
+
setTimeout(() => setMessage(null), 2000);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Filter providers
|
|
105
|
+
const filterLower = filter.toLowerCase();
|
|
106
|
+
const filteredProviders = providerList.filter(
|
|
107
|
+
(item) =>
|
|
108
|
+
item.provider.name.toLowerCase().includes(filterLower) ||
|
|
109
|
+
item.provider.id.toLowerCase().includes(filterLower)
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Split into connected and available
|
|
113
|
+
const connected = filteredProviders.filter((p) => p.connected);
|
|
114
|
+
const available = filteredProviders.filter((p) => !p.connected);
|
|
115
|
+
|
|
116
|
+
// Combined list for navigation
|
|
117
|
+
const allItems = [...connected, ...available];
|
|
118
|
+
|
|
119
|
+
// Reset selection when filter changes
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
setSelectedIndex(0);
|
|
122
|
+
}, [filter]);
|
|
123
|
+
|
|
124
|
+
// Fetch and cache models for a provider (use providerImpl if specified)
|
|
125
|
+
const fetchModels = async (
|
|
126
|
+
providerId: ProviderName,
|
|
127
|
+
connOption?: ConnectionOption
|
|
128
|
+
): Promise<ModelInfo[]> => {
|
|
129
|
+
try {
|
|
130
|
+
// Use providerImpl if specified, otherwise use the provider id
|
|
131
|
+
const implId = connOption?.providerImpl || providerId;
|
|
132
|
+
const provider = createProvider({ provider: implId });
|
|
133
|
+
const models = await provider.listModels();
|
|
134
|
+
store.cacheModels(providerId, models);
|
|
135
|
+
return models;
|
|
136
|
+
} catch {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Connect with a specific connection option
|
|
142
|
+
const connectWithOption = async (item: ProviderItem, connOption: ConnectionOption) => {
|
|
143
|
+
setLoading(true);
|
|
144
|
+
setMessage(`Connecting via ${connOption.name}...`);
|
|
145
|
+
store.connect(item.provider.id, connOption.method);
|
|
146
|
+
const models = await fetchModels(item.provider.id, connOption);
|
|
147
|
+
setLoading(false);
|
|
148
|
+
setMessage(`Connected! Cached ${models.length} models`);
|
|
149
|
+
refreshList();
|
|
150
|
+
setView('list');
|
|
151
|
+
setSelectedProvider(null);
|
|
152
|
+
setTimeout(() => setMessage(null), 2000);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Handle connect/refresh
|
|
156
|
+
const handleConnect = async (item: ProviderItem) => {
|
|
157
|
+
if (item.connected) {
|
|
158
|
+
// Refresh: re-fetch models
|
|
159
|
+
setLoading(true);
|
|
160
|
+
setMessage(`Refreshing ${item.provider.name}...`);
|
|
161
|
+
// Get the connection method to find the right provider impl
|
|
162
|
+
const connMethod = item.connectionMethod;
|
|
163
|
+
const connOption = item.provider.connections.find((c) => c.method === connMethod);
|
|
164
|
+
const models = await fetchModels(item.provider.id, connOption);
|
|
165
|
+
setLoading(false);
|
|
166
|
+
setMessage(`Cached ${models.length} models`);
|
|
167
|
+
refreshList();
|
|
168
|
+
setTimeout(() => setMessage(null), 2000);
|
|
169
|
+
} else {
|
|
170
|
+
// Check ready connections
|
|
171
|
+
const readyConns = item.readyConnections;
|
|
172
|
+
|
|
173
|
+
if (readyConns.length === 1) {
|
|
174
|
+
// One ready connection - auto-connect
|
|
175
|
+
await connectWithOption(item, readyConns[0]);
|
|
176
|
+
} else {
|
|
177
|
+
// Zero or multiple ready connections - show selection view
|
|
178
|
+
setSelectedProvider(item.provider);
|
|
179
|
+
setConnectionIndex(0);
|
|
180
|
+
setView('select-connection');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Handle remove
|
|
186
|
+
const handleRemove = (item: ProviderItem) => {
|
|
187
|
+
if (!item.connected) return;
|
|
188
|
+
setSelectedProvider(item.provider);
|
|
189
|
+
setView('confirm-remove');
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Confirm remove
|
|
193
|
+
const confirmRemove = () => {
|
|
194
|
+
if (selectedProvider) {
|
|
195
|
+
store.disconnect(selectedProvider.id);
|
|
196
|
+
refreshList();
|
|
197
|
+
setView('list');
|
|
198
|
+
setSelectedProvider(null);
|
|
199
|
+
setMessage('Provider removed');
|
|
200
|
+
setTimeout(() => setMessage(null), 2000);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Go back to list
|
|
205
|
+
const goBack = () => {
|
|
206
|
+
setView('list');
|
|
207
|
+
setSelectedProvider(null);
|
|
208
|
+
setConnectionIndex(0);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// Keyboard navigation for list view (LLM providers)
|
|
212
|
+
useInput(
|
|
213
|
+
(input, key) => {
|
|
214
|
+
if (key.tab || input === 's') {
|
|
215
|
+
// Switch to search tab
|
|
216
|
+
setTab('search');
|
|
217
|
+
setSearchSelectedIndex(0);
|
|
218
|
+
} else if (key.upArrow) {
|
|
219
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
220
|
+
} else if (key.downArrow) {
|
|
221
|
+
setSelectedIndex((i) => Math.min(allItems.length - 1, i + 1));
|
|
222
|
+
} else if (key.return && allItems.length > 0) {
|
|
223
|
+
handleConnect(allItems[selectedIndex]);
|
|
224
|
+
} else if (input === 'r' && allItems.length > 0 && allItems[selectedIndex].connected) {
|
|
225
|
+
handleRemove(allItems[selectedIndex]);
|
|
226
|
+
} else if (key.escape) {
|
|
227
|
+
onClose();
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{ isActive: view === 'list' && tab === 'llm' && !loading }
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Keyboard navigation for search providers tab
|
|
234
|
+
useInput(
|
|
235
|
+
(input, key) => {
|
|
236
|
+
if (key.tab || input === 'l') {
|
|
237
|
+
// Switch to LLM tab
|
|
238
|
+
setTab('llm');
|
|
239
|
+
setSelectedIndex(0);
|
|
240
|
+
} else if (key.upArrow) {
|
|
241
|
+
setSearchSelectedIndex((i) => Math.max(0, i - 1));
|
|
242
|
+
} else if (key.downArrow) {
|
|
243
|
+
setSearchSelectedIndex((i) => Math.min(searchProviders.length - 1, i + 1));
|
|
244
|
+
} else if (key.return && searchProviders.length > 0) {
|
|
245
|
+
const selected = searchProviders[searchSelectedIndex];
|
|
246
|
+
if (selected.isAvailable) {
|
|
247
|
+
selectSearchProvider(selected.provider.id);
|
|
248
|
+
}
|
|
249
|
+
} else if (key.escape) {
|
|
250
|
+
onClose();
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{ isActive: view === 'list' && tab === 'search' && !loading }
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Keyboard for select-connection view
|
|
257
|
+
useInput(
|
|
258
|
+
(_input, key) => {
|
|
259
|
+
if (!selectedProvider) return;
|
|
260
|
+
const allConns = selectedProvider.connections;
|
|
261
|
+
|
|
262
|
+
if (key.upArrow) {
|
|
263
|
+
setConnectionIndex((i) => Math.max(0, i - 1));
|
|
264
|
+
} else if (key.downArrow) {
|
|
265
|
+
setConnectionIndex((i) => Math.min(allConns.length - 1, i + 1));
|
|
266
|
+
} else if (key.return && allConns.length > 0) {
|
|
267
|
+
const selectedConn = allConns[connectionIndex];
|
|
268
|
+
if (isConnectionReady(selectedConn)) {
|
|
269
|
+
const item = allItems.find((i) => i.provider.id === selectedProvider.id);
|
|
270
|
+
if (item) {
|
|
271
|
+
connectWithOption(item, selectedConn);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// If not ready, do nothing (user needs to set env vars first)
|
|
275
|
+
} else if (key.escape) {
|
|
276
|
+
goBack();
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
{ isActive: view === 'select-connection' }
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Keyboard for confirm-remove view
|
|
283
|
+
useInput(
|
|
284
|
+
(input, key) => {
|
|
285
|
+
if (input === 'y' || input === 'Y') {
|
|
286
|
+
confirmRemove();
|
|
287
|
+
} else if (input === 'n' || input === 'N' || key.escape) {
|
|
288
|
+
goBack();
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
{ isActive: view === 'confirm-remove' }
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
// Loading state
|
|
296
|
+
if (loading) {
|
|
297
|
+
return (
|
|
298
|
+
<Box flexDirection="column">
|
|
299
|
+
<Box>
|
|
300
|
+
<LoadingSpinner />
|
|
301
|
+
<Text color={colors.textMuted}> {message || 'Loading...'}</Text>
|
|
302
|
+
</Box>
|
|
303
|
+
</Box>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Confirm remove view
|
|
308
|
+
if (view === 'confirm-remove' && selectedProvider) {
|
|
309
|
+
return (
|
|
310
|
+
<Box flexDirection="column">
|
|
311
|
+
<Text color={colors.warning}>Remove {selectedProvider.name}?</Text>
|
|
312
|
+
<Text color={colors.textMuted}>
|
|
313
|
+
This will clear cached models for this provider.
|
|
314
|
+
</Text>
|
|
315
|
+
<Box marginTop={1}>
|
|
316
|
+
<Text color={colors.textMuted}>[Y] Confirm [N] Cancel</Text>
|
|
317
|
+
</Box>
|
|
318
|
+
</Box>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Select connection method view
|
|
323
|
+
if (view === 'select-connection' && selectedProvider) {
|
|
324
|
+
const allConns = selectedProvider.connections;
|
|
325
|
+
const selectedConn = allConns[connectionIndex];
|
|
326
|
+
const isSelectedReady = selectedConn ? isConnectionReady(selectedConn) : false;
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<Box flexDirection="column">
|
|
330
|
+
<Text color={colors.primary}>Connect to {selectedProvider.name}</Text>
|
|
331
|
+
<Text color={colors.textMuted}>Select connection method:</Text>
|
|
332
|
+
|
|
333
|
+
<Box flexDirection="column" marginTop={1}>
|
|
334
|
+
{allConns.map((conn, idx) => {
|
|
335
|
+
const isSelected = idx === connectionIndex;
|
|
336
|
+
const ready = isConnectionReady(conn);
|
|
337
|
+
return (
|
|
338
|
+
<Box key={conn.method} paddingLeft={2} flexDirection="column">
|
|
339
|
+
<Box>
|
|
340
|
+
<Text color={isSelected ? colors.primary : colors.textMuted}>
|
|
341
|
+
{isSelected ? icons.arrow : ' '}
|
|
342
|
+
</Text>
|
|
343
|
+
<Text color={isSelected ? colors.text : colors.textSecondary} bold={isSelected}>
|
|
344
|
+
{conn.name}
|
|
345
|
+
</Text>
|
|
346
|
+
{ready ? (
|
|
347
|
+
<Text color={colors.success}> (ready)</Text>
|
|
348
|
+
) : (
|
|
349
|
+
<Text color={colors.textMuted}> (not configured)</Text>
|
|
350
|
+
)}
|
|
351
|
+
{conn.description && (
|
|
352
|
+
<Text color={colors.textMuted}> - {conn.description}</Text>
|
|
353
|
+
)}
|
|
354
|
+
</Box>
|
|
355
|
+
{isSelected && !ready && (
|
|
356
|
+
<Text color={colors.textMuted} dimColor>
|
|
357
|
+
{' '}Set: {conn.envVars.join(' or ')}
|
|
358
|
+
</Text>
|
|
359
|
+
)}
|
|
360
|
+
</Box>
|
|
361
|
+
);
|
|
362
|
+
})}
|
|
363
|
+
</Box>
|
|
364
|
+
|
|
365
|
+
<Box marginTop={1}>
|
|
366
|
+
<Text color={colors.textMuted}>
|
|
367
|
+
↑↓ navigate · {isSelectedReady ? 'Enter connect · ' : ''}Esc back
|
|
368
|
+
</Text>
|
|
369
|
+
</Box>
|
|
370
|
+
</Box>
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Main list view
|
|
375
|
+
return (
|
|
376
|
+
<Box flexDirection="column">
|
|
377
|
+
<Text color={colors.primary} bold>
|
|
378
|
+
Provider Management
|
|
379
|
+
</Text>
|
|
380
|
+
|
|
381
|
+
{/* Tabs */}
|
|
382
|
+
<Box marginTop={1}>
|
|
383
|
+
<Text
|
|
384
|
+
color={tab === 'llm' ? colors.primary : colors.textMuted}
|
|
385
|
+
bold={tab === 'llm'}
|
|
386
|
+
>
|
|
387
|
+
[L] LLM Providers
|
|
388
|
+
</Text>
|
|
389
|
+
<Text color={colors.textMuted}> | </Text>
|
|
390
|
+
<Text
|
|
391
|
+
color={tab === 'search' ? colors.primary : colors.textMuted}
|
|
392
|
+
bold={tab === 'search'}
|
|
393
|
+
>
|
|
394
|
+
[S] Search Providers
|
|
395
|
+
</Text>
|
|
396
|
+
</Box>
|
|
397
|
+
|
|
398
|
+
{message && (
|
|
399
|
+
<Box marginTop={1}>
|
|
400
|
+
<Text color={colors.success}>{icons.success} {message}</Text>
|
|
401
|
+
</Box>
|
|
402
|
+
)}
|
|
403
|
+
|
|
404
|
+
{/* LLM Providers Tab */}
|
|
405
|
+
{tab === 'llm' && (
|
|
406
|
+
<>
|
|
407
|
+
<Box marginTop={1}>
|
|
408
|
+
<Text color={colors.textMuted}>{icons.prompt} </Text>
|
|
409
|
+
<TextInput value={filter} onChange={setFilter} placeholder="Filter providers..." />
|
|
410
|
+
</Box>
|
|
411
|
+
|
|
412
|
+
<Box flexDirection="column" marginTop={1}>
|
|
413
|
+
{/* Connected section */}
|
|
414
|
+
{connected.length > 0 && (
|
|
415
|
+
<>
|
|
416
|
+
<Text color={colors.textMuted}>Connected:</Text>
|
|
417
|
+
{connected.map((item, idx) => {
|
|
418
|
+
const isSelected = idx === selectedIndex;
|
|
419
|
+
// Find connection name
|
|
420
|
+
const connOption = item.provider.connections.find(
|
|
421
|
+
(c) => c.method === item.connectionMethod
|
|
422
|
+
);
|
|
423
|
+
const connName = connOption?.name || item.connectionMethod;
|
|
424
|
+
return (
|
|
425
|
+
<Box key={item.provider.id} paddingLeft={2}>
|
|
426
|
+
<Text color={isSelected ? colors.primary : colors.textMuted}>
|
|
427
|
+
{isSelected ? icons.arrow : ' '}{' '}
|
|
428
|
+
</Text>
|
|
429
|
+
<Text color={isSelected ? colors.text : colors.textSecondary} bold={isSelected}>
|
|
430
|
+
{item.provider.name}
|
|
431
|
+
</Text>
|
|
432
|
+
<Text color={colors.textMuted}>
|
|
433
|
+
{' '}({connName}) · {item.modelCount} models
|
|
434
|
+
</Text>
|
|
435
|
+
<Text color={colors.success}> {icons.success}</Text>
|
|
436
|
+
</Box>
|
|
437
|
+
);
|
|
438
|
+
})}
|
|
439
|
+
</>
|
|
440
|
+
)}
|
|
441
|
+
|
|
442
|
+
{/* Available section */}
|
|
443
|
+
{available.length > 0 && (
|
|
444
|
+
<>
|
|
445
|
+
<Text color={colors.textMuted} dimColor={connected.length > 0}>
|
|
446
|
+
{connected.length > 0 ? '\n' : ''}Available:
|
|
447
|
+
</Text>
|
|
448
|
+
{available.map((item, idx) => {
|
|
449
|
+
const actualIndex = connected.length + idx;
|
|
450
|
+
const isSelected = actualIndex === selectedIndex;
|
|
451
|
+
const hasReady = item.readyConnections.length > 0;
|
|
452
|
+
|
|
453
|
+
// Show which connection methods are ready
|
|
454
|
+
const readyNames = item.readyConnections.map((c) => c.name);
|
|
455
|
+
|
|
456
|
+
return (
|
|
457
|
+
<Box key={item.provider.id} paddingLeft={2}>
|
|
458
|
+
<Text color={isSelected ? colors.primary : colors.textMuted}>
|
|
459
|
+
{isSelected ? icons.arrow : ' '}{' '}
|
|
460
|
+
</Text>
|
|
461
|
+
<Text color={isSelected ? colors.text : colors.textSecondary} bold={isSelected}>
|
|
462
|
+
{item.provider.name}
|
|
463
|
+
</Text>
|
|
464
|
+
{hasReady && (
|
|
465
|
+
<Text color={colors.success}> ({readyNames.join(', ')})</Text>
|
|
466
|
+
)}
|
|
467
|
+
</Box>
|
|
468
|
+
);
|
|
469
|
+
})}
|
|
470
|
+
</>
|
|
471
|
+
)}
|
|
472
|
+
|
|
473
|
+
{allItems.length === 0 && (
|
|
474
|
+
<Text color={colors.textMuted}>No providers match "{filter}"</Text>
|
|
475
|
+
)}
|
|
476
|
+
</Box>
|
|
477
|
+
|
|
478
|
+
<Box marginTop={1}>
|
|
479
|
+
<Text color={colors.textMuted}>
|
|
480
|
+
↑↓ navigate · Enter connect · r remove · Tab/s search · Esc exit
|
|
481
|
+
</Text>
|
|
482
|
+
</Box>
|
|
483
|
+
</>
|
|
484
|
+
)}
|
|
485
|
+
|
|
486
|
+
{/* Search Providers Tab */}
|
|
487
|
+
{tab === 'search' && (
|
|
488
|
+
<>
|
|
489
|
+
<Box flexDirection="column" marginTop={1}>
|
|
490
|
+
<Text color={colors.textMuted}>Select search provider:</Text>
|
|
491
|
+
{searchProviders.map((item, idx) => {
|
|
492
|
+
const isSelected = idx === searchSelectedIndex;
|
|
493
|
+
const envVars = item.provider.connections[0]?.envVars || [];
|
|
494
|
+
|
|
495
|
+
return (
|
|
496
|
+
<Box key={item.provider.id} paddingLeft={2} flexDirection="column">
|
|
497
|
+
<Box>
|
|
498
|
+
<Text color={isSelected ? colors.primary : colors.textMuted}>
|
|
499
|
+
{isSelected ? icons.arrow : ' '}{' '}
|
|
500
|
+
</Text>
|
|
501
|
+
<Text color={isSelected ? colors.text : colors.textSecondary} bold={isSelected}>
|
|
502
|
+
{item.provider.name}
|
|
503
|
+
</Text>
|
|
504
|
+
{!item.provider.requiresKey && (
|
|
505
|
+
<Text color={colors.success}> (no key required)</Text>
|
|
506
|
+
)}
|
|
507
|
+
{item.provider.requiresKey && item.isAvailable && (
|
|
508
|
+
<Text color={colors.success}> (configured)</Text>
|
|
509
|
+
)}
|
|
510
|
+
{item.provider.requiresKey && !item.isAvailable && (
|
|
511
|
+
<Text color={colors.textMuted}> (not configured)</Text>
|
|
512
|
+
)}
|
|
513
|
+
{item.isSelected && <Text color={colors.success}> {icons.success}</Text>}
|
|
514
|
+
</Box>
|
|
515
|
+
{isSelected && item.provider.requiresKey && !item.isAvailable && (
|
|
516
|
+
<Text color={colors.textMuted} dimColor>
|
|
517
|
+
{' '}Set: {envVars.join(' or ')}
|
|
518
|
+
</Text>
|
|
519
|
+
)}
|
|
520
|
+
</Box>
|
|
521
|
+
);
|
|
522
|
+
})}
|
|
523
|
+
</Box>
|
|
524
|
+
|
|
525
|
+
<Box marginTop={1}>
|
|
526
|
+
<Text color={colors.textMuted}>
|
|
527
|
+
↑↓ navigate · Enter select · Tab/l LLM providers · Esc exit
|
|
528
|
+
</Text>
|
|
529
|
+
</Box>
|
|
530
|
+
</>
|
|
531
|
+
)}
|
|
532
|
+
</Box>
|
|
533
|
+
);
|
|
534
|
+
}
|