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
|
@@ -1,16 +1,83 @@
|
|
|
1
1
|
import { Box, Text } from 'ink';
|
|
2
|
+
import { colors } from './theme.js';
|
|
2
3
|
|
|
4
|
+
// Small G logo for inline use
|
|
3
5
|
export function Logo() {
|
|
4
|
-
// Full G with 3D shadow - subdued slate color
|
|
5
|
-
const slateColor = "#64748B"; // Slate 500 - stable, professional
|
|
6
6
|
return (
|
|
7
|
-
<Box
|
|
8
|
-
<Text color={
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
<Box marginRight={1}>
|
|
8
|
+
<Text bold color={colors.brand}>◆</Text>
|
|
9
|
+
</Box>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Large ASCII art logo with elegant gradient
|
|
14
|
+
export function BigLogo() {
|
|
15
|
+
// Indigo gradient - brand colors
|
|
16
|
+
const c1 = '#818CF8'; // Indigo 400
|
|
17
|
+
const c2 = '#818CF8'; // Indigo 400
|
|
18
|
+
const c3 = '#A5B4FC'; // Indigo 300
|
|
19
|
+
const c4 = '#A5B4FC'; // Indigo 300
|
|
20
|
+
const c5 = '#C7D2FE'; // Indigo 200
|
|
21
|
+
const c6 = '#C7D2FE'; // Indigo 200
|
|
22
|
+
const c7 = '#C7D2FE'; // Indigo 200
|
|
23
|
+
|
|
24
|
+
// G E N C O D E
|
|
25
|
+
return (
|
|
26
|
+
<Box flexDirection="column">
|
|
27
|
+
<Text>
|
|
28
|
+
<Text color={c1}> ██████╗ </Text>
|
|
29
|
+
<Text color={c2}>███████╗</Text>
|
|
30
|
+
<Text color={c3}>███╗ ██╗</Text>
|
|
31
|
+
<Text color={c4}> ██████╗</Text>
|
|
32
|
+
<Text color={c5}> ██████╗ </Text>
|
|
33
|
+
<Text color={c6}>██████╗ </Text>
|
|
34
|
+
<Text color={c7}>███████╗</Text>
|
|
35
|
+
</Text>
|
|
36
|
+
<Text>
|
|
37
|
+
<Text color={c1}>██╔════╝ </Text>
|
|
38
|
+
<Text color={c2}>██╔════╝</Text>
|
|
39
|
+
<Text color={c3}>████╗ ██║</Text>
|
|
40
|
+
<Text color={c4}>██╔════╝</Text>
|
|
41
|
+
<Text color={c5}>██╔═══██╗</Text>
|
|
42
|
+
<Text color={c6}>██╔══██╗</Text>
|
|
43
|
+
<Text color={c7}>██╔════╝</Text>
|
|
44
|
+
</Text>
|
|
45
|
+
<Text>
|
|
46
|
+
<Text color={c1}>██║ ███╗</Text>
|
|
47
|
+
<Text color={c2}>█████╗ </Text>
|
|
48
|
+
<Text color={c3}>██╔██╗ ██║</Text>
|
|
49
|
+
<Text color={c4}>██║ </Text>
|
|
50
|
+
<Text color={c5}>██║ ██║</Text>
|
|
51
|
+
<Text color={c6}>██║ ██║</Text>
|
|
52
|
+
<Text color={c7}>█████╗ </Text>
|
|
53
|
+
</Text>
|
|
54
|
+
<Text>
|
|
55
|
+
<Text color={c1}>██║ ██║</Text>
|
|
56
|
+
<Text color={c2}>██╔══╝ </Text>
|
|
57
|
+
<Text color={c3}>██║╚██╗██║</Text>
|
|
58
|
+
<Text color={c4}>██║ </Text>
|
|
59
|
+
<Text color={c5}>██║ ██║</Text>
|
|
60
|
+
<Text color={c6}>██║ ██║</Text>
|
|
61
|
+
<Text color={c7}>██╔══╝ </Text>
|
|
62
|
+
</Text>
|
|
63
|
+
<Text>
|
|
64
|
+
<Text color={c1}>╚██████╔╝</Text>
|
|
65
|
+
<Text color={c2}>███████╗</Text>
|
|
66
|
+
<Text color={c3}>██║ ╚████║</Text>
|
|
67
|
+
<Text color={c4}>╚██████╗</Text>
|
|
68
|
+
<Text color={c5}>╚██████╔╝</Text>
|
|
69
|
+
<Text color={c6}>██████╔╝</Text>
|
|
70
|
+
<Text color={c7}>███████╗</Text>
|
|
71
|
+
</Text>
|
|
72
|
+
<Text>
|
|
73
|
+
<Text color={c1}> ╚═════╝ </Text>
|
|
74
|
+
<Text color={c2}>╚══════╝</Text>
|
|
75
|
+
<Text color={c3}>╚═╝ ╚═══╝</Text>
|
|
76
|
+
<Text color={c4}> ╚═════╝</Text>
|
|
77
|
+
<Text color={c5}> ╚═════╝ </Text>
|
|
78
|
+
<Text color={c6}>╚═════╝ </Text>
|
|
79
|
+
<Text color={c7}>╚══════╝</Text>
|
|
80
|
+
</Text>
|
|
14
81
|
</Box>
|
|
15
82
|
);
|
|
16
83
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
1
2
|
import { Box, Text } from 'ink';
|
|
3
|
+
import InkSpinner from 'ink-spinner';
|
|
2
4
|
import { colors, icons } from './theme.js';
|
|
5
|
+
import { renderMarkdown } from './markdown.js';
|
|
6
|
+
|
|
7
|
+
// Truncate string with ellipsis
|
|
8
|
+
const truncate = (str: string, maxLen: number) =>
|
|
9
|
+
str.length > maxLen ? str.slice(0, maxLen - 3) + '...' : str;
|
|
3
10
|
|
|
4
11
|
// Word wrap text to terminal width
|
|
5
12
|
function wrapText(text: string, width: number): string[] {
|
|
@@ -31,12 +38,15 @@ interface UserMessageProps {
|
|
|
31
38
|
|
|
32
39
|
export function UserMessage({ text }: UserMessageProps) {
|
|
33
40
|
const lines = text.trimEnd().split('\n');
|
|
41
|
+
// Subtle gray - ~8% darker than pure white
|
|
42
|
+
const inputBg = '#EFEFEF';
|
|
43
|
+
|
|
34
44
|
return (
|
|
35
45
|
<Box flexDirection="column" marginTop={1} marginBottom={0}>
|
|
36
46
|
{lines.map((line, i) => (
|
|
37
|
-
<Box key={i}>
|
|
47
|
+
<Box key={i} backgroundColor={inputBg}>
|
|
38
48
|
<Text color={colors.brand}>{icons.userPrompt} </Text>
|
|
39
|
-
<Text
|
|
49
|
+
<Text>{line}</Text>
|
|
40
50
|
</Box>
|
|
41
51
|
))}
|
|
42
52
|
</Box>
|
|
@@ -51,29 +61,40 @@ interface AssistantMessageProps {
|
|
|
51
61
|
export function AssistantMessage({ text, streaming }: AssistantMessageProps) {
|
|
52
62
|
if (!text) return null;
|
|
53
63
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
// Streaming: use simple text display (markdown incomplete during stream)
|
|
65
|
+
if (streaming) {
|
|
66
|
+
const termWidth = process.stdout.columns || 80;
|
|
67
|
+
const contentWidth = termWidth - 4;
|
|
68
|
+
const lines = wrapText(text.trimEnd(), contentWidth);
|
|
57
69
|
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
return (
|
|
71
|
+
<Box flexDirection="column" marginTop={1} marginBottom={0}>
|
|
72
|
+
{lines.map((line, i) => (
|
|
73
|
+
<Box key={i}>
|
|
74
|
+
{i === 0 && <Text color={colors.success}>{icons.assistant} </Text>}
|
|
75
|
+
{i > 0 && <Text> </Text>}
|
|
76
|
+
<Text>
|
|
77
|
+
{line}
|
|
78
|
+
{i === lines.length - 1 && (
|
|
79
|
+
<Text color={colors.brandLight}>{icons.cursor}</Text>
|
|
80
|
+
)}
|
|
81
|
+
</Text>
|
|
82
|
+
</Box>
|
|
83
|
+
))}
|
|
84
|
+
</Box>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Completed: render with markdown
|
|
89
|
+
const rendered = renderMarkdown(text);
|
|
60
90
|
|
|
61
91
|
return (
|
|
62
92
|
<Box flexDirection="column" marginTop={1} marginBottom={0}>
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{line}
|
|
69
|
-
{streaming && i === lines.length - 1 ? (
|
|
70
|
-
<Text color={colors.brandLight}>{icons.cursor}</Text>
|
|
71
|
-
) : (
|
|
72
|
-
''
|
|
73
|
-
)}
|
|
74
|
-
</Text>
|
|
75
|
-
</Box>
|
|
76
|
-
))}
|
|
93
|
+
<Box>
|
|
94
|
+
<Text color={colors.success}>{icons.assistant}</Text>
|
|
95
|
+
<Text> </Text>
|
|
96
|
+
<Text wrap="wrap">{rendered}</Text>
|
|
97
|
+
</Box>
|
|
77
98
|
</Box>
|
|
78
99
|
);
|
|
79
100
|
}
|
|
@@ -83,38 +104,126 @@ interface ToolCallProps {
|
|
|
83
104
|
input: Record<string, unknown>;
|
|
84
105
|
}
|
|
85
106
|
|
|
107
|
+
// Format tool input for display
|
|
108
|
+
function formatToolInput(name: string, input: Record<string, unknown>): string {
|
|
109
|
+
switch (name) {
|
|
110
|
+
case 'Read':
|
|
111
|
+
return input.file_path as string || '';
|
|
112
|
+
case 'Write':
|
|
113
|
+
case 'Edit':
|
|
114
|
+
return input.file_path as string || '';
|
|
115
|
+
case 'Glob':
|
|
116
|
+
return input.pattern as string || '';
|
|
117
|
+
case 'Grep':
|
|
118
|
+
return `"${input.pattern}"` + (input.path ? ` in ${input.path}` : '');
|
|
119
|
+
case 'Bash':
|
|
120
|
+
return truncate(input.command as string || '', 50);
|
|
121
|
+
case 'WebFetch':
|
|
122
|
+
return input.url as string || '';
|
|
123
|
+
case 'WebSearch':
|
|
124
|
+
return `"${input.query}"` || '';
|
|
125
|
+
case 'TodoWrite': {
|
|
126
|
+
const todos = input.todos as Array<{ content: string; status: string }> || [];
|
|
127
|
+
return `${todos.length} task${todos.length !== 1 ? 's' : ''}`;
|
|
128
|
+
}
|
|
129
|
+
default:
|
|
130
|
+
return truncate(JSON.stringify(input), 40);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
86
134
|
export function ToolCall({ name, input }: ToolCallProps) {
|
|
87
|
-
|
|
88
|
-
|
|
135
|
+
// Hide TodoWrite (shown in TodoList component)
|
|
136
|
+
if (name === 'TodoWrite') return null;
|
|
137
|
+
|
|
138
|
+
const displayInput = formatToolInput(name, input);
|
|
89
139
|
|
|
90
140
|
return (
|
|
91
|
-
<Box
|
|
92
|
-
<Text
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
<Box marginTop={1}>
|
|
142
|
+
<Text color={colors.tool}>{icons.tool}</Text>
|
|
143
|
+
<Text> </Text>
|
|
144
|
+
<Text bold>{name}</Text>
|
|
145
|
+
{displayInput && (
|
|
146
|
+
<>
|
|
147
|
+
<Text color={colors.textMuted}> </Text>
|
|
148
|
+
<Text color={colors.textSecondary}>{truncate(displayInput, 60)}</Text>
|
|
149
|
+
</>
|
|
150
|
+
)}
|
|
151
|
+
</Box>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Pending tool call with spinning indicator
|
|
156
|
+
interface PendingToolCallProps {
|
|
157
|
+
name: string;
|
|
158
|
+
input: Record<string, unknown>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function PendingToolCall({ name, input }: PendingToolCallProps) {
|
|
162
|
+
// Hide TodoWrite (shown in TodoList component)
|
|
163
|
+
if (name === 'TodoWrite') return null;
|
|
164
|
+
|
|
165
|
+
const displayInput = formatToolInput(name, input);
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<Box marginTop={1}>
|
|
169
|
+
<Text color={colors.tool}>
|
|
170
|
+
<InkSpinner type="dots" />
|
|
95
171
|
</Text>
|
|
172
|
+
<Text> </Text>
|
|
173
|
+
<Text bold>{name}</Text>
|
|
174
|
+
{displayInput && (
|
|
175
|
+
<>
|
|
176
|
+
<Text> </Text>
|
|
177
|
+
<Text color={colors.textSecondary}>{truncate(displayInput, 60)}</Text>
|
|
178
|
+
</>
|
|
179
|
+
)}
|
|
96
180
|
</Box>
|
|
97
181
|
);
|
|
98
182
|
}
|
|
99
183
|
|
|
184
|
+
interface ToolResultMetadata {
|
|
185
|
+
title?: string;
|
|
186
|
+
subtitle?: string;
|
|
187
|
+
size?: number;
|
|
188
|
+
statusCode?: number;
|
|
189
|
+
contentType?: string;
|
|
190
|
+
duration?: number;
|
|
191
|
+
}
|
|
192
|
+
|
|
100
193
|
interface ToolResultProps {
|
|
101
194
|
name: string;
|
|
102
195
|
success: boolean;
|
|
103
196
|
output: string;
|
|
197
|
+
metadata?: ToolResultMetadata;
|
|
104
198
|
}
|
|
105
199
|
|
|
106
|
-
export function ToolResult({ name, success, output }: ToolResultProps) {
|
|
107
|
-
const firstLine = output.split('\n')[0]?.trim() || '';
|
|
108
|
-
const displayOutput = firstLine.length > 50 ? firstLine.slice(0, 47) + '...' : firstLine;
|
|
200
|
+
export function ToolResult({ name, success, output, metadata }: ToolResultProps) {
|
|
109
201
|
const statusColor = success ? colors.success : colors.error;
|
|
110
|
-
|
|
202
|
+
|
|
203
|
+
// If metadata has subtitle (e.g., "Received 540.3KB (200 OK)"), show it
|
|
204
|
+
if (metadata?.subtitle) {
|
|
205
|
+
return (
|
|
206
|
+
<Box marginLeft={2}>
|
|
207
|
+
<Text color={colors.textMuted}>{icons.treeEnd}</Text>
|
|
208
|
+
<Text> </Text>
|
|
209
|
+
<Text color={statusColor}>{metadata.subtitle}</Text>
|
|
210
|
+
</Box>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// TodoWrite: Don't show result (TodoList component shows the full list)
|
|
215
|
+
if (name === 'TodoWrite') {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Default: Show first line of output with status icon
|
|
220
|
+
const displayOutput = truncate(output.split('\n')[0]?.trim() || '', 60);
|
|
111
221
|
|
|
112
222
|
return (
|
|
113
223
|
<Box marginLeft={2}>
|
|
114
|
-
<Text
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
</Text>
|
|
224
|
+
<Text color={colors.textMuted}>{icons.treeEnd}</Text>
|
|
225
|
+
<Text> </Text>
|
|
226
|
+
<Text color={statusColor}>{displayOutput || (success ? 'Done' : 'Failed')}</Text>
|
|
118
227
|
</Box>
|
|
119
228
|
);
|
|
120
229
|
}
|
|
@@ -150,11 +259,10 @@ interface WelcomeMessageProps {
|
|
|
150
259
|
model: string;
|
|
151
260
|
}
|
|
152
261
|
|
|
153
|
-
export function WelcomeMessage({ model }: WelcomeMessageProps) {
|
|
262
|
+
export function WelcomeMessage({ model: _model }: WelcomeMessageProps) {
|
|
154
263
|
return (
|
|
155
264
|
<Box marginTop={1} marginBottom={0}>
|
|
156
|
-
<Text color={colors.textMuted}
|
|
157
|
-
<Text color={colors.brand}>{model}</Text>
|
|
265
|
+
<Text color={colors.textMuted}>? for help · Ctrl+C to exit</Text>
|
|
158
266
|
</Box>
|
|
159
267
|
);
|
|
160
268
|
}
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model Selector Component - Interactive model selection
|
|
2
|
+
* Model Selector Component - Interactive model selection from cached providers
|
|
3
3
|
*/
|
|
4
|
-
import { useState, useEffect } from 'react';
|
|
4
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
5
5
|
import { Box, Text, useInput } from 'ink';
|
|
6
6
|
import TextInput from 'ink-text-input';
|
|
7
7
|
import { colors, icons } from './theme.js';
|
|
8
8
|
import { LoadingSpinner } from './Spinner.js';
|
|
9
|
+
import { getProviderStore, type ModelInfo } from '../../providers/store.js';
|
|
10
|
+
import { getProvider } from '../../providers/registry.js';
|
|
11
|
+
import type { ProviderName } from '../../providers/index.js';
|
|
9
12
|
|
|
10
|
-
interface
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
interface ModelItem {
|
|
14
|
+
providerId: ProviderName;
|
|
15
|
+
providerName: string;
|
|
16
|
+
model: ModelInfo;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
interface ModelSelectorProps {
|
|
16
20
|
currentModel: string;
|
|
17
|
-
onSelect: (modelId: string) => void;
|
|
21
|
+
onSelect: (modelId: string, providerId: ProviderName) => void;
|
|
18
22
|
onCancel: () => void;
|
|
19
|
-
listModels: () => Promise<
|
|
23
|
+
listModels: () => Promise<{ id: string; name: string }[]>; // Fallback for current provider
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
export function ModelSelector({
|
|
@@ -25,32 +29,86 @@ export function ModelSelector({
|
|
|
25
29
|
onCancel,
|
|
26
30
|
listModels,
|
|
27
31
|
}: ModelSelectorProps) {
|
|
28
|
-
const
|
|
32
|
+
const store = getProviderStore();
|
|
29
33
|
const [loading, setLoading] = useState(true);
|
|
30
|
-
const [error, setError] = useState<string | null>(null);
|
|
31
34
|
const [filter, setFilter] = useState('');
|
|
32
35
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
36
|
+
const [allModels, setAllModels] = useState<ModelItem[]>([]);
|
|
33
37
|
|
|
38
|
+
// Load models from cache
|
|
34
39
|
useEffect(() => {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
const loadModels = async () => {
|
|
41
|
+
const connectedProviders = store.getConnectedProviders();
|
|
42
|
+
const items: ModelItem[] = [];
|
|
43
|
+
|
|
44
|
+
for (const providerId of connectedProviders) {
|
|
45
|
+
const cachedModels = store.getModels(providerId);
|
|
46
|
+
const providerDef = getProvider(providerId);
|
|
47
|
+
const providerName = providerDef?.name || providerId;
|
|
48
|
+
|
|
49
|
+
for (const model of cachedModels) {
|
|
50
|
+
items.push({
|
|
51
|
+
providerId,
|
|
52
|
+
providerName,
|
|
53
|
+
model,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
43
56
|
}
|
|
57
|
+
|
|
58
|
+
// If no cached models, fallback to listModels for current provider
|
|
59
|
+
if (items.length === 0) {
|
|
60
|
+
try {
|
|
61
|
+
const models = await listModels();
|
|
62
|
+
for (const model of models) {
|
|
63
|
+
items.push({
|
|
64
|
+
providerId: 'anthropic' as ProviderName, // Default, will be overridden
|
|
65
|
+
providerName: 'Current Provider',
|
|
66
|
+
model,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
// Ignore errors
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setAllModels(items);
|
|
75
|
+
setLoading(false);
|
|
44
76
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
77
|
+
|
|
78
|
+
loadModels();
|
|
79
|
+
}, [store, listModels]);
|
|
80
|
+
|
|
81
|
+
// Filter models
|
|
82
|
+
const filterLower = filter.toLowerCase();
|
|
83
|
+
const filtered = useMemo(() => {
|
|
84
|
+
return allModels.filter(
|
|
85
|
+
(item) =>
|
|
86
|
+
item.model.id.toLowerCase().includes(filterLower) ||
|
|
87
|
+
item.model.name.toLowerCase().includes(filterLower) ||
|
|
88
|
+
item.providerName.toLowerCase().includes(filterLower)
|
|
89
|
+
);
|
|
90
|
+
}, [allModels, filterLower]);
|
|
91
|
+
|
|
92
|
+
// Group by provider for display
|
|
93
|
+
const groupedModels = useMemo(() => {
|
|
94
|
+
const groups: Record<string, ModelItem[]> = {};
|
|
95
|
+
for (const item of filtered) {
|
|
96
|
+
if (!groups[item.providerId]) {
|
|
97
|
+
groups[item.providerId] = [];
|
|
98
|
+
}
|
|
99
|
+
groups[item.providerId].push(item);
|
|
100
|
+
}
|
|
101
|
+
return groups;
|
|
102
|
+
}, [filtered]);
|
|
103
|
+
|
|
104
|
+
// Flat list for navigation
|
|
105
|
+
const flatList = useMemo(() => {
|
|
106
|
+
const items: ModelItem[] = [];
|
|
107
|
+
for (const providerId of Object.keys(groupedModels)) {
|
|
108
|
+
items.push(...groupedModels[providerId]);
|
|
109
|
+
}
|
|
110
|
+
return items;
|
|
111
|
+
}, [groupedModels]);
|
|
54
112
|
|
|
55
113
|
// Reset selection when filter changes
|
|
56
114
|
useEffect(() => {
|
|
@@ -62,10 +120,11 @@ export function ModelSelector({
|
|
|
62
120
|
if (key.upArrow) {
|
|
63
121
|
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
64
122
|
} else if (key.downArrow) {
|
|
65
|
-
setSelectedIndex((i) => Math.min(
|
|
123
|
+
setSelectedIndex((i) => Math.min(flatList.length - 1, i + 1));
|
|
66
124
|
} else if (key.return) {
|
|
67
|
-
if (
|
|
68
|
-
|
|
125
|
+
if (flatList.length > 0) {
|
|
126
|
+
const selected = flatList[selectedIndex];
|
|
127
|
+
onSelect(selected.model.id, selected.providerId);
|
|
69
128
|
}
|
|
70
129
|
} else if (key.escape) {
|
|
71
130
|
onCancel();
|
|
@@ -81,43 +140,99 @@ export function ModelSelector({
|
|
|
81
140
|
);
|
|
82
141
|
}
|
|
83
142
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
143
|
+
// Count providers and models
|
|
144
|
+
const providerCount = Object.keys(groupedModels).length;
|
|
145
|
+
const modelCount = flatList.length;
|
|
88
146
|
|
|
89
|
-
|
|
147
|
+
// Calculate visible window
|
|
148
|
+
const maxVisible = 10;
|
|
90
149
|
const startIndex = Math.max(
|
|
91
150
|
0,
|
|
92
|
-
Math.min(selectedIndex - Math.floor(maxVisible / 2),
|
|
151
|
+
Math.min(selectedIndex - Math.floor(maxVisible / 2), flatList.length - maxVisible)
|
|
93
152
|
);
|
|
94
|
-
const
|
|
153
|
+
const endIndex = Math.min(startIndex + maxVisible, flatList.length);
|
|
154
|
+
|
|
155
|
+
// Build visible items with provider headers
|
|
156
|
+
let currentIdx = 0;
|
|
157
|
+
const renderItems: Array<{ type: 'header' | 'model'; content: string; item?: ModelItem }> = [];
|
|
158
|
+
|
|
159
|
+
for (const providerId of Object.keys(groupedModels)) {
|
|
160
|
+
const models = groupedModels[providerId];
|
|
161
|
+
const firstIdx = currentIdx;
|
|
162
|
+
const lastIdx = currentIdx + models.length - 1;
|
|
163
|
+
|
|
164
|
+
// Check if any model from this provider is in visible range
|
|
165
|
+
if (lastIdx >= startIndex && firstIdx < endIndex) {
|
|
166
|
+
// Add header if first visible item is from this provider
|
|
167
|
+
const providerDef = getProvider(providerId as ProviderName);
|
|
168
|
+
const connection = store.getConnection(providerId as ProviderName);
|
|
169
|
+
const headerText = `${providerDef?.name || providerId}${connection ? ` (${connection.method})` : ''}:`;
|
|
170
|
+
|
|
171
|
+
// Only add header if we're showing models from this provider
|
|
172
|
+
const visibleModelsFromProvider = models.filter((_, i) => {
|
|
173
|
+
const globalIdx = currentIdx + i;
|
|
174
|
+
return globalIdx >= startIndex && globalIdx < endIndex;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (visibleModelsFromProvider.length > 0 && (firstIdx >= startIndex || renderItems.length === 0)) {
|
|
178
|
+
renderItems.push({ type: 'header', content: headerText });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (let i = 0; i < models.length; i++) {
|
|
182
|
+
const globalIdx = currentIdx + i;
|
|
183
|
+
if (globalIdx >= startIndex && globalIdx < endIndex) {
|
|
184
|
+
renderItems.push({ type: 'model', content: '', item: models[i] });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
currentIdx += models.length;
|
|
190
|
+
}
|
|
95
191
|
|
|
96
192
|
return (
|
|
97
193
|
<Box flexDirection="column">
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/>
|
|
194
|
+
<Text color={colors.primary} bold>
|
|
195
|
+
Select Model
|
|
196
|
+
</Text>
|
|
197
|
+
|
|
198
|
+
<Box marginTop={1}>
|
|
199
|
+
<Text color={colors.textMuted}>{icons.prompt} </Text>
|
|
200
|
+
<TextInput value={filter} onChange={setFilter} placeholder="Filter models..." />
|
|
105
201
|
</Box>
|
|
202
|
+
|
|
106
203
|
<Box flexDirection="column" marginTop={1}>
|
|
107
|
-
{
|
|
108
|
-
<
|
|
204
|
+
{flatList.length === 0 ? (
|
|
205
|
+
<Box flexDirection="column">
|
|
206
|
+
<Text color={colors.textMuted}>No cached models.</Text>
|
|
207
|
+
<Text color={colors.textMuted}>Use /provider to connect and cache models.</Text>
|
|
208
|
+
</Box>
|
|
109
209
|
) : (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
210
|
+
renderItems.map((renderItem, i) => {
|
|
211
|
+
if (renderItem.type === 'header') {
|
|
212
|
+
return (
|
|
213
|
+
<Text key={`header-${i}`} color={colors.textSecondary}>
|
|
214
|
+
{renderItem.content}
|
|
215
|
+
</Text>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const item = renderItem.item!;
|
|
220
|
+
const globalIndex = flatList.findIndex(
|
|
221
|
+
(f) => f.providerId === item.providerId && f.model.id === item.model.id
|
|
222
|
+
);
|
|
223
|
+
const isSelected = globalIndex === selectedIndex;
|
|
224
|
+
const isCurrent = item.model.id === currentModel;
|
|
225
|
+
|
|
114
226
|
return (
|
|
115
|
-
<Box key={
|
|
227
|
+
<Box key={`${item.providerId}-${item.model.id}`} paddingLeft={2}>
|
|
116
228
|
<Text color={isSelected ? colors.primary : colors.textMuted}>
|
|
117
229
|
{isSelected ? icons.arrow : ' '}
|
|
118
230
|
</Text>
|
|
231
|
+
<Text color={isCurrent ? colors.primary : colors.textMuted}>
|
|
232
|
+
{isCurrent ? icons.radio : icons.radioEmpty}
|
|
233
|
+
</Text>
|
|
119
234
|
<Text color={isSelected ? colors.text : colors.textSecondary} bold={isSelected}>
|
|
120
|
-
{
|
|
235
|
+
{' '}{item.model.name || item.model.id}
|
|
121
236
|
</Text>
|
|
122
237
|
{isCurrent && <Text color={colors.success}> (current)</Text>}
|
|
123
238
|
</Box>
|
|
@@ -125,9 +240,11 @@ export function ModelSelector({
|
|
|
125
240
|
})
|
|
126
241
|
)}
|
|
127
242
|
</Box>
|
|
243
|
+
|
|
128
244
|
<Box marginTop={1}>
|
|
129
245
|
<Text color={colors.textMuted}>
|
|
130
|
-
{
|
|
246
|
+
{providerCount} provider{providerCount !== 1 ? 's' : ''} · {modelCount} model
|
|
247
|
+
{modelCount !== 1 ? 's' : ''} · ↑↓ navigate · Enter select · Esc cancel
|
|
131
248
|
</Text>
|
|
132
249
|
</Box>
|
|
133
250
|
</Box>
|