codeep 1.2.11 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/bin/codeep.js +13 -1
  2. package/dist/config/providers.d.ts +6 -0
  3. package/dist/config/providers.js +41 -2
  4. package/dist/config/providers.test.js +31 -2
  5. package/dist/utils/agent.js +2 -2
  6. package/dist/utils/tools.d.ts +64 -4
  7. package/dist/utils/tools.js +209 -4
  8. package/dist/utils/tools.test.js +12 -7
  9. package/package.json +2 -1
  10. package/dist/app.d.ts +0 -2
  11. package/dist/app.js +0 -1501
  12. package/dist/components/AgentActions.d.ts +0 -18
  13. package/dist/components/AgentActions.js +0 -122
  14. package/dist/components/AgentProgress.d.ts +0 -59
  15. package/dist/components/AgentProgress.js +0 -368
  16. package/dist/components/Export.d.ts +0 -8
  17. package/dist/components/Export.js +0 -27
  18. package/dist/components/Help.d.ts +0 -6
  19. package/dist/components/Help.js +0 -7
  20. package/dist/components/Input.d.ts +0 -9
  21. package/dist/components/Input.js +0 -334
  22. package/dist/components/Loading.d.ts +0 -17
  23. package/dist/components/Loading.js +0 -52
  24. package/dist/components/Login.d.ts +0 -7
  25. package/dist/components/Login.js +0 -77
  26. package/dist/components/Logo.d.ts +0 -8
  27. package/dist/components/Logo.js +0 -89
  28. package/dist/components/LogoutPicker.d.ts +0 -8
  29. package/dist/components/LogoutPicker.js +0 -61
  30. package/dist/components/Message.d.ts +0 -10
  31. package/dist/components/Message.js +0 -242
  32. package/dist/components/MessageList.d.ts +0 -10
  33. package/dist/components/MessageList.js +0 -42
  34. package/dist/components/ProjectPermission.d.ts +0 -7
  35. package/dist/components/ProjectPermission.js +0 -65
  36. package/dist/components/Search.d.ts +0 -10
  37. package/dist/components/Search.js +0 -30
  38. package/dist/components/SessionPicker.d.ts +0 -9
  39. package/dist/components/SessionPicker.js +0 -88
  40. package/dist/components/Sessions.d.ts +0 -12
  41. package/dist/components/Sessions.js +0 -119
  42. package/dist/components/Settings.d.ts +0 -9
  43. package/dist/components/Settings.js +0 -198
  44. package/dist/components/Spinner.d.ts +0 -34
  45. package/dist/components/Spinner.js +0 -38
  46. package/dist/components/Status.d.ts +0 -2
  47. package/dist/components/Status.js +0 -13
  48. package/dist/components/StreamingMessage.d.ts +0 -14
  49. package/dist/components/StreamingMessage.js +0 -19
  50. package/dist/index.d.ts +0 -2
  51. package/dist/index.js +0 -42
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- interface InputProps {
3
- onSubmit: (value: string) => void;
4
- disabled?: boolean;
5
- history?: string[];
6
- clearTrigger?: number;
7
- }
8
- export declare const ChatInput: React.FC<InputProps>;
9
- export {};
@@ -1,334 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useMemo, useEffect, useRef } from 'react';
3
- import { Text, Box, useInput } from 'ink';
4
- import clipboardy from 'clipboardy';
5
- const COMMANDS = [
6
- { cmd: '/help', desc: 'Show help' },
7
- { cmd: '/status', desc: 'Show status' },
8
- { cmd: '/version', desc: 'Show version' },
9
- { cmd: '/update', desc: 'Check updates' },
10
- { cmd: '/model', desc: 'Switch model' },
11
- { cmd: '/protocol', desc: 'Switch protocol' },
12
- { cmd: '/provider', desc: 'Switch provider' },
13
- { cmd: '/lang', desc: 'Set language' },
14
- { cmd: '/settings', desc: 'Adjust settings' },
15
- { cmd: '/sessions', desc: 'Manage sessions' },
16
- { cmd: '/sessions delete', desc: 'Delete session' },
17
- { cmd: '/rename', desc: 'Rename session' },
18
- { cmd: '/search', desc: 'Search history' },
19
- { cmd: '/export', desc: 'Export chat' },
20
- { cmd: '/diff', desc: 'Review git changes' },
21
- { cmd: '/diff --staged', desc: 'Review staged changes' },
22
- { cmd: '/commit', desc: 'Generate commit message' },
23
- { cmd: '/apply', desc: 'Apply file changes' },
24
- { cmd: '/copy', desc: 'Copy code block' },
25
- { cmd: '/paste', desc: 'Paste from clipboard' },
26
- { cmd: '/grant', desc: 'Grant write permission for agent' },
27
- { cmd: '/agent', desc: 'Run agent for a task' },
28
- { cmd: '/agent-dry', desc: 'Preview agent actions' },
29
- { cmd: '/agent-stop', desc: 'Stop running agent' },
30
- { cmd: '/scan', desc: 'Scan project for AI context' },
31
- { cmd: '/scan status', desc: 'Show scan status' },
32
- { cmd: '/scan clear', desc: 'Clear cached scan' },
33
- { cmd: '/clear', desc: 'Clear chat' },
34
- { cmd: '/login', desc: 'Change API key' },
35
- { cmd: '/logout', desc: 'Logout' },
36
- { cmd: '/exit', desc: 'Quit' },
37
- ];
38
- export const ChatInput = ({ onSubmit, disabled, history = [], clearTrigger = 0 }) => {
39
- const [value, setValue] = useState('');
40
- const [cursorPos, setCursorPos] = useState(0);
41
- const [selectedIndex, setSelectedIndex] = useState(0);
42
- const [pasteInfo, setPasteInfo] = useState(null);
43
- const [historyIndex, setHistoryIndex] = useState(-1);
44
- // Paste detection using timing - chars arriving fast = paste
45
- const inputBuffer = useRef('');
46
- const lastInputTime = useRef(0);
47
- const pasteTimeout = useRef(null);
48
- const charTimings = useRef([]);
49
- // Clear input when clearTrigger changes
50
- useEffect(() => {
51
- if (clearTrigger > 0) {
52
- setValue('');
53
- setCursorPos(0);
54
- setSelectedIndex(0);
55
- setPasteInfo(null);
56
- setHistoryIndex(-1);
57
- }
58
- }, [clearTrigger]);
59
- // Filter commands based on input
60
- const suggestions = useMemo(() => {
61
- // No suggestions for empty input or just '/'
62
- if (!value || value.length === 0 || value === '/')
63
- return [];
64
- if (!value.startsWith('/') || value.includes(' '))
65
- return [];
66
- return COMMANDS.filter(c => c.cmd.startsWith(value.toLowerCase()));
67
- }, [value]);
68
- // Reset selection when suggestions change
69
- useEffect(() => {
70
- if (suggestions.length > 0) {
71
- setSelectedIndex(0);
72
- }
73
- }, [suggestions.length]);
74
- // Process buffered input - called after paste timeout
75
- const processBuffer = () => {
76
- const buffer = inputBuffer.current;
77
- inputBuffer.current = '';
78
- if (!buffer)
79
- return;
80
- // If buffer has multiple chars (> 20), treat as paste and show indicator
81
- if (buffer.length > 20) {
82
- handlePastedText(buffer, true);
83
- }
84
- else {
85
- // Short buffer - just add to value normally
86
- setValue(prev => prev + buffer);
87
- setCursorPos(prev => prev + buffer.length);
88
- }
89
- };
90
- const handlePastedText = (text, fromCtrlV = false) => {
91
- const trimmed = text.trim();
92
- if (!trimmed)
93
- return;
94
- const lines = trimmed.split(/\r?\n/);
95
- const lineCount = lines.length;
96
- const charCount = trimmed.length;
97
- // For multi-line or long pastes - show info box with preview
98
- if (lineCount > 1 || charCount > 80 || (fromCtrlV && charCount > 30)) {
99
- // Create preview - first line truncated
100
- const firstLine = lines[0].substring(0, 50);
101
- const preview = firstLine + (lines[0].length > 50 || lineCount > 1 ? '...' : '');
102
- setPasteInfo({
103
- lines: lineCount,
104
- chars: charCount,
105
- preview,
106
- fullText: trimmed,
107
- });
108
- // Show truncated text in input (not ugly indicator)
109
- const displayText = trimmed.replace(/\r?\n/g, ' ').substring(0, 60);
110
- const inputText = displayText + (trimmed.length > 60 ? '...' : '');
111
- setValue(inputText);
112
- setCursorPos(inputText.length);
113
- }
114
- else {
115
- // Short paste - insert directly
116
- setValue(prev => prev + trimmed);
117
- setCursorPos(prev => prev + trimmed.length);
118
- setPasteInfo(null);
119
- }
120
- };
121
- // Main input handler
122
- useInput((input, key) => {
123
- if (disabled)
124
- return;
125
- // Handle Enter - submit
126
- if (key.return) {
127
- const trimmedValue = value.trim();
128
- // Handle /paste command - read from clipboard
129
- if (trimmedValue === '/paste') {
130
- try {
131
- const clipboardText = clipboardy.readSync();
132
- if (clipboardText && clipboardText.trim()) {
133
- handlePastedText(clipboardText.trim(), true);
134
- }
135
- }
136
- catch {
137
- // Clipboard read failed
138
- }
139
- return;
140
- }
141
- if (trimmedValue) {
142
- // If we have paste info, submit the full pasted text
143
- const submitValue = pasteInfo ? pasteInfo.fullText : trimmedValue;
144
- onSubmit(submitValue);
145
- setValue('');
146
- setCursorPos(0);
147
- setPasteInfo(null);
148
- setHistoryIndex(-1);
149
- }
150
- return;
151
- }
152
- // Handle Escape - clear paste info or input
153
- if (key.escape) {
154
- if (pasteInfo) {
155
- // Clear pasted content
156
- setValue('');
157
- setCursorPos(0);
158
- setPasteInfo(null);
159
- }
160
- else if (value) {
161
- setValue('');
162
- setCursorPos(0);
163
- }
164
- return;
165
- }
166
- // Handle Backspace
167
- if (key.backspace || key.delete) {
168
- if (cursorPos > 0) {
169
- // If paste info exists, clear everything on backspace
170
- if (pasteInfo) {
171
- setValue('');
172
- setCursorPos(0);
173
- setPasteInfo(null);
174
- return;
175
- }
176
- setValue(prev => prev.slice(0, cursorPos - 1) + prev.slice(cursorPos));
177
- setCursorPos(prev => prev - 1);
178
- }
179
- return;
180
- }
181
- // Handle Tab - autocomplete command
182
- if (key.tab && suggestions.length > 0) {
183
- setValue(suggestions[selectedIndex].cmd + ' ');
184
- setCursorPos(suggestions[selectedIndex].cmd.length + 1);
185
- return;
186
- }
187
- // Handle Up Arrow - navigate suggestions or history
188
- if (key.upArrow) {
189
- if (suggestions.length > 0) {
190
- setSelectedIndex(i => Math.max(0, i - 1));
191
- }
192
- else if (history.length > 0) {
193
- const newIndex = historyIndex < history.length - 1 ? historyIndex + 1 : historyIndex;
194
- setHistoryIndex(newIndex);
195
- if (newIndex >= 0 && history[history.length - 1 - newIndex]) {
196
- const historyValue = history[history.length - 1 - newIndex];
197
- setValue(historyValue);
198
- setCursorPos(historyValue.length);
199
- }
200
- }
201
- return;
202
- }
203
- // Handle Down Arrow - navigate suggestions or history
204
- if (key.downArrow) {
205
- if (suggestions.length > 0) {
206
- setSelectedIndex(i => Math.min(suggestions.length - 1, i + 1));
207
- }
208
- else if (historyIndex > 0) {
209
- const newIndex = historyIndex - 1;
210
- setHistoryIndex(newIndex);
211
- const historyValue = history[history.length - 1 - newIndex];
212
- setValue(historyValue);
213
- setCursorPos(historyValue.length);
214
- }
215
- else if (historyIndex === 0) {
216
- setHistoryIndex(-1);
217
- setValue('');
218
- setCursorPos(0);
219
- }
220
- return;
221
- }
222
- // Handle Left Arrow
223
- if (key.leftArrow) {
224
- setCursorPos(prev => Math.max(0, prev - 1));
225
- return;
226
- }
227
- // Handle Right Arrow
228
- if (key.rightArrow) {
229
- setCursorPos(prev => Math.min(value.length, prev + 1));
230
- return;
231
- }
232
- // Handle Ctrl+A - go to beginning
233
- if (key.ctrl && input === 'a') {
234
- setCursorPos(0);
235
- return;
236
- }
237
- // Handle Ctrl+E - go to end
238
- if (key.ctrl && input === 'e') {
239
- setCursorPos(value.length);
240
- return;
241
- }
242
- // Handle Ctrl+U - clear line
243
- if (key.ctrl && input === 'u') {
244
- setValue('');
245
- setCursorPos(0);
246
- setPasteInfo(null);
247
- return;
248
- }
249
- // Handle Ctrl+W - delete word
250
- if (key.ctrl && input === 'w') {
251
- const beforeCursor = value.slice(0, cursorPos);
252
- const afterCursor = value.slice(cursorPos);
253
- const lastSpace = beforeCursor.trimEnd().lastIndexOf(' ');
254
- const newBefore = lastSpace >= 0 ? beforeCursor.slice(0, lastSpace + 1) : '';
255
- setValue(newBefore + afterCursor);
256
- setCursorPos(newBefore.length);
257
- return;
258
- }
259
- // Handle Ctrl+V - paste from clipboard
260
- // Terminal sends ASCII 22 (\x16) for Ctrl+V
261
- if (input === '\x16' || (key.ctrl && input === 'v')) {
262
- try {
263
- const clipboardText = clipboardy.readSync();
264
- if (clipboardText) {
265
- handlePastedText(clipboardText, true);
266
- }
267
- }
268
- catch {
269
- // Clipboard read failed, ignore
270
- }
271
- return;
272
- }
273
- // Regular character input
274
- if (input && !key.ctrl && !key.meta) {
275
- // If we have paste info and user types new char, clear paste
276
- if (pasteInfo) {
277
- setPasteInfo(null);
278
- setValue('');
279
- setCursorPos(0);
280
- }
281
- const now = Date.now();
282
- const timeSinceLastInput = now - lastInputTime.current;
283
- lastInputTime.current = now;
284
- // Track timing for paste detection
285
- // Paste typically sends many chars with < 10ms between them
286
- const isPasteLikeTiming = timeSinceLastInput < 15;
287
- if (isPasteLikeTiming || inputBuffer.current.length > 0) {
288
- // Add to buffer
289
- inputBuffer.current += input;
290
- charTimings.current.push(timeSinceLastInput);
291
- // Clear existing timeout
292
- if (pasteTimeout.current) {
293
- clearTimeout(pasteTimeout.current);
294
- }
295
- // Set timeout to process buffer - wait a bit longer to collect all paste chars
296
- pasteTimeout.current = setTimeout(() => {
297
- const buffer = inputBuffer.current;
298
- const timings = charTimings.current;
299
- inputBuffer.current = '';
300
- charTimings.current = [];
301
- if (!buffer)
302
- return;
303
- // Calculate average timing - if most chars came fast, it's a paste
304
- const fastChars = timings.filter(t => t < 15).length;
305
- const isPaste = buffer.length > 5 && (fastChars / timings.length) > 0.5;
306
- if (isPaste && (buffer.length > 30 || buffer.includes('\n'))) {
307
- // Treat as paste
308
- handlePastedText(buffer, true);
309
- }
310
- else {
311
- // Just fast typing, add normally
312
- setValue(prev => prev + buffer);
313
- setCursorPos(prev => prev + buffer.length);
314
- }
315
- }, 50); // Wait 50ms to collect all paste chars
316
- return; // Don't add to value yet
317
- }
318
- // Normal single character input (slow typing)
319
- setValue(prev => prev.slice(0, cursorPos) + input + prev.slice(cursorPos));
320
- setCursorPos(prev => prev + input.length);
321
- }
322
- }, { isActive: !disabled });
323
- // Render input with cursor
324
- const renderInput = () => {
325
- if (!value) {
326
- return _jsx(Text, { color: "cyan", children: "Type a message or /command..." });
327
- }
328
- const before = value.slice(0, cursorPos);
329
- const cursor = value[cursorPos] || ' ';
330
- const after = value.slice(cursorPos + 1);
331
- return (_jsxs(Text, { children: [before, _jsx(Text, { backgroundColor: "white", color: "black", children: cursor }), after] }));
332
- };
333
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "#f02a30", bold: true, children: '> ' }), disabled ? (_jsx(Text, { color: "yellow", children: "Agent working... (Esc to stop)" })) : (renderInput())] }), value === '/' && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "cyan", dimColor: true, children: "Type command name (e.g., help, status, settings) or press Tab to see all" }) })), suggestions.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [suggestions.map((s, i) => (_jsxs(Text, { children: [i === selectedIndex ? _jsx(Text, { color: "#f02a30", children: "\u25B8 " }) : ' ', _jsx(Text, { color: i === selectedIndex ? '#f02a30' : undefined, bold: i === selectedIndex, children: s.cmd }), _jsxs(Text, { color: i === selectedIndex ? undefined : 'gray', children: [" - ", s.desc] })] }, s.cmd))), _jsx(Text, { color: "cyan", dimColor: true, children: "\u2191\u2193 navigate \u2022 Tab complete \u2022 Esc cancel" })] })), pasteInfo && (_jsx(Box, { borderStyle: "round", borderColor: "green", paddingX: 1, marginTop: 1, flexDirection: "column", children: _jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "\uD83D\uDCCB " }), _jsx(Text, { color: "white", bold: true, children: pasteInfo.chars }), _jsx(Text, { color: "cyan", children: " chars" }), pasteInfo.lines > 1 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "cyan", children: " \u2022 " }), _jsx(Text, { color: "white", bold: true, children: pasteInfo.lines }), _jsx(Text, { color: "cyan", children: " lines" })] })), _jsx(Text, { color: "cyan", dimColor: true, children: " (Enter send \u2022 Esc cancel)" })] }) }))] }));
334
- };
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- interface LoadingProps {
3
- isStreaming?: boolean;
4
- }
5
- /**
6
- * Loading indicator with isolated animation
7
- * Parent component won't re-render when spinner animates
8
- */
9
- export declare const Loading: React.FC<LoadingProps>;
10
- /**
11
- * Simple inline spinner for smaller spaces
12
- * Also uses isolated animation
13
- */
14
- export declare const InlineSpinner: React.FC<{
15
- text?: string;
16
- }>;
17
- export {};
@@ -1,52 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, memo } from 'react';
3
- import { Text, Box } from 'ink';
4
- // Spinner frames - Braille pattern for smooth animation
5
- const SPINNER = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
6
- /**
7
- * Isolated spinner animation component
8
- * Only this component re-renders during animation, not the parent
9
- */
10
- const AnimatedSpinner = memo(() => {
11
- const [frame, setFrame] = useState(0);
12
- useEffect(() => {
13
- const timer = setInterval(() => {
14
- setFrame(f => (f + 1) % SPINNER.length);
15
- }, 100);
16
- return () => clearInterval(timer);
17
- }, []);
18
- return _jsx(Text, { color: "#f02a30", children: SPINNER[frame] });
19
- });
20
- AnimatedSpinner.displayName = 'AnimatedSpinner';
21
- /**
22
- * Animated dots component
23
- * Isolated animation state
24
- */
25
- const AnimatedDots = memo(() => {
26
- const [count, setCount] = useState(0);
27
- useEffect(() => {
28
- const timer = setInterval(() => {
29
- setCount(c => (c + 1) % 4);
30
- }, 300);
31
- return () => clearInterval(timer);
32
- }, []);
33
- return _jsx(Text, { color: "#f02a30", children: '.'.repeat(count) });
34
- });
35
- AnimatedDots.displayName = 'AnimatedDots';
36
- /**
37
- * Loading indicator with isolated animation
38
- * Parent component won't re-render when spinner animates
39
- */
40
- export const Loading = memo(({ isStreaming = false }) => {
41
- const message = isStreaming ? 'Writing' : 'Thinking';
42
- return (_jsxs(Box, { paddingLeft: 2, paddingY: 0, children: [_jsx(AnimatedSpinner, {}), _jsxs(Text, { color: "#f02a30", bold: true, children: [" ", message] }), _jsx(AnimatedDots, {})] }));
43
- });
44
- Loading.displayName = 'Loading';
45
- /**
46
- * Simple inline spinner for smaller spaces
47
- * Also uses isolated animation
48
- */
49
- export const InlineSpinner = memo(({ text = 'Loading' }) => {
50
- return (_jsxs(Text, { children: [_jsx(AnimatedSpinner, {}), _jsxs(Text, { children: [" ", text] })] }));
51
- });
52
- InlineSpinner.displayName = 'InlineSpinner';
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- interface LoginProps {
3
- onLogin: () => void;
4
- onCancel?: () => void;
5
- }
6
- export declare const Login: React.FC<LoginProps>;
7
- export {};
@@ -1,77 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
3
- import { Text, Box, useInput } from 'ink';
4
- import TextInput from 'ink-text-input';
5
- import open from 'open';
6
- import { setApiKey, setProvider } from '../config/index.js';
7
- import { validateApiKey } from '../api/index.js';
8
- import { Logo } from './Logo.js';
9
- import { getProviderList } from '../config/providers.js';
10
- const PROVIDER_URLS = {
11
- 'z.ai': 'https://z.ai/subscribe?ic=NXYNXZOV14',
12
- 'minimax': 'https://platform.minimax.io/subscribe/coding-plan?code=2lWvoWUhrp&source=link',
13
- };
14
- export const Login = ({ onLogin, onCancel }) => {
15
- const [step, setStep] = useState('provider');
16
- const [selectedProvider, setSelectedProvider] = useState(0);
17
- const [apiKey, setApiKeyState] = useState('');
18
- const [error, setError] = useState('');
19
- const [validating, setValidating] = useState(false);
20
- const providers = getProviderList();
21
- const currentProvider = providers[selectedProvider];
22
- // Handle keyboard input
23
- useInput((input, key) => {
24
- if (step === 'provider') {
25
- if (key.upArrow) {
26
- setSelectedProvider(i => Math.max(0, i - 1));
27
- }
28
- if (key.downArrow) {
29
- setSelectedProvider(i => Math.min(providers.length - 1, i + 1));
30
- }
31
- if (key.return) {
32
- setProvider(currentProvider.id);
33
- setStep('apikey');
34
- }
35
- // Escape to cancel login
36
- if (key.escape && onCancel) {
37
- onCancel();
38
- }
39
- }
40
- else if (step === 'apikey') {
41
- // G key to open browser for API key
42
- if ((input === 'g' || input === 'G') && apiKey === '') {
43
- const url = PROVIDER_URLS[currentProvider.id];
44
- if (url)
45
- open(url);
46
- }
47
- // Escape to go back to provider selection
48
- if (key.escape) {
49
- setStep('provider');
50
- setError('');
51
- }
52
- }
53
- });
54
- const handleSubmit = async (key) => {
55
- if (!key.trim()) {
56
- setError('Please enter your API key');
57
- return;
58
- }
59
- setValidating(true);
60
- setError('');
61
- const result = await validateApiKey(key, currentProvider.id);
62
- if (result.valid) {
63
- setApiKey(key, currentProvider.id);
64
- onLogin();
65
- }
66
- else {
67
- setError(result.error || 'Invalid API key');
68
- setValidating(false);
69
- }
70
- };
71
- // Provider selection screen
72
- if (step === 'provider') {
73
- return (_jsxs(Box, { flexDirection: "column", alignItems: "center", padding: 2, children: [_jsx(Logo, {}), _jsx(Text, { children: " " }), _jsx(Text, { color: "#f02a30", bold: true, children: "Select AI Provider" }), _jsx(Text, { children: " " }), providers.map((provider, i) => (_jsxs(Text, { children: [i === selectedProvider ? _jsx(Text, { color: "#f02a30", children: "\u25B8 " }) : ' ', _jsx(Text, { color: i === selectedProvider ? '#f02a30' : undefined, bold: i === selectedProvider, children: provider.name }), _jsxs(Text, { children: [" - ", provider.description] })] }, provider.id))), _jsx(Text, { children: " " }), _jsx(Text, { children: "\u2191/\u2193 Navigate, Enter = Select, Esc = Cancel" })] }));
74
- }
75
- // API key input screen
76
- return (_jsxs(Box, { flexDirection: "column", alignItems: "center", padding: 2, children: [_jsx(Logo, {}), _jsx(Text, { children: " " }), _jsxs(Text, { color: "#f02a30", children: ["Enter your ", _jsx(Text, { bold: true, children: currentProvider.name }), " API key"] }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Press ", _jsx(Text, { color: "#f02a30", children: "G" }), " to get an API key, or paste your key below:"] }), _jsx(Text, { children: " " }), _jsxs(Box, { children: [_jsx(Text, { color: "#f02a30", children: "Key: " }), validating ? (_jsx(Text, { children: "Validating..." })) : (_jsx(TextInput, { value: apiKey, onChange: setApiKeyState, onSubmit: handleSubmit, mask: "*", placeholder: "Enter API key..." }))] }), error && (_jsx(Text, { color: "#f02a30", children: error })), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Enter = login, ", _jsx(Text, { color: "#f02a30", children: "G" }), " = get key, Esc = back, Ctrl+C = exit"] })] }));
77
- };
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- export declare const LOGO = "\n \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\n\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\n\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D\n\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\n \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D ";
3
- export declare const Logo: React.FC;
4
- interface IntroProps {
5
- onComplete: () => void;
6
- }
7
- export declare const IntroAnimation: React.FC<IntroProps>;
8
- export {};
@@ -1,89 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from 'react';
3
- import { Text, Box } from 'ink';
4
- export const LOGO = `
5
- ██████╗ ██████╗ ██████╗ ███████╗███████╗██████╗
6
- ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗
7
- ██║ ██║ ██║██║ ██║█████╗ █████╗ ██████╔╝
8
- ██║ ██║ ██║██║ ██║██╔══╝ ██╔══╝ ██╔═══╝
9
- ╚██████╗╚██████╔╝██████╔╝███████╗███████╗██║
10
- ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ `;
11
- // Static logo for after intro
12
- export const Logo = () => (_jsxs(Box, { flexDirection: "column", alignItems: "center", children: [_jsx(Text, { color: "#f02a30", bold: true, children: LOGO }), _jsx(Text, { color: "#f02a30", children: "Deep into Code." })] }));
13
- const GLITCH_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%&*<>?/;:[]=';
14
- export const IntroAnimation = ({ onComplete }) => {
15
- const [phase, setPhase] = useState('init');
16
- const [progress, setProgress] = useState(0);
17
- useEffect(() => {
18
- const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
19
- const sequence = async () => {
20
- // Phase 1: Initial Noise
21
- setPhase('init');
22
- // Run noise loop (similar to index.html's 10 steps of 50ms)
23
- for (let i = 0; i < 10; i++) {
24
- setProgress(Math.random()); // Trigger re-render
25
- await delay(50);
26
- }
27
- // Phase 2: Unified Decryption
28
- setPhase('decrypt');
29
- const duration = 1500;
30
- const startTime = Date.now();
31
- const animate = () => {
32
- const elapsed = Date.now() - startTime;
33
- const p = Math.min(elapsed / duration, 1);
34
- setProgress(p);
35
- if (p < 1) {
36
- setTimeout(animate, 16); // ~60 FPS
37
- }
38
- else {
39
- // Phase 3: Done
40
- setPhase('done');
41
- // Short delay before firing complete
42
- setTimeout(() => onComplete(), 200);
43
- }
44
- };
45
- animate();
46
- };
47
- sequence();
48
- }, [onComplete]);
49
- const getDecryptedText = () => {
50
- const rawLines = LOGO.split('\n');
51
- // Handle leading newline similar to index.html logic if needed
52
- // index.html logic: const linesToRender = rawLines[0] === '' ? rawLines.slice(1) : rawLines;
53
- const lines = rawLines[0] === '' ? rawLines.slice(1) : rawLines;
54
- return lines.map((line) => {
55
- let resultLine = '';
56
- for (let charIndex = 0; charIndex < line.length; charIndex++) {
57
- const char = line[charIndex];
58
- let isDecrypted = false;
59
- if (phase === 'init') {
60
- isDecrypted = false;
61
- }
62
- else if (phase === 'decrypt' || phase === 'done') {
63
- const threshold = line.length > 0 ? charIndex / line.length : 0;
64
- if (progress >= threshold - 0.1) {
65
- isDecrypted = Math.random() > 0.2;
66
- }
67
- }
68
- if (phase === 'done')
69
- isDecrypted = true;
70
- if (char === ' ' && phase !== 'init') {
71
- resultLine += ' ';
72
- }
73
- else if (isDecrypted) {
74
- resultLine += char;
75
- }
76
- else {
77
- if (char === ' ' && Math.random() > 0.1) {
78
- resultLine += ' ';
79
- }
80
- else {
81
- resultLine += GLITCH_CHARS.charAt(Math.floor(Math.random() * GLITCH_CHARS.length));
82
- }
83
- }
84
- }
85
- return resultLine;
86
- }).join('\n');
87
- };
88
- return (_jsxs(Box, { flexDirection: "column", alignItems: "center", children: [_jsx(Text, { color: "#f02a30", bold: true, children: getDecryptedText() }), phase === 'done' && (_jsx(Text, { color: "#f02a30", children: "Deep into Code." }))] }));
89
- };
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- interface LogoutPickerProps {
3
- onLogout: (providerId: string) => void;
4
- onLogoutAll: () => void;
5
- onCancel: () => void;
6
- }
7
- export declare const LogoutPicker: React.FC<LogoutPickerProps>;
8
- export {};