codeep 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +576 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.js +421 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.js +1406 -0
- package/dist/components/AgentProgress.d.ts +33 -0
- package/dist/components/AgentProgress.js +97 -0
- package/dist/components/Export.d.ts +8 -0
- package/dist/components/Export.js +27 -0
- package/dist/components/Help.d.ts +2 -0
- package/dist/components/Help.js +3 -0
- package/dist/components/Input.d.ts +9 -0
- package/dist/components/Input.js +89 -0
- package/dist/components/Loading.d.ts +9 -0
- package/dist/components/Loading.js +31 -0
- package/dist/components/Login.d.ts +7 -0
- package/dist/components/Login.js +77 -0
- package/dist/components/Logo.d.ts +8 -0
- package/dist/components/Logo.js +89 -0
- package/dist/components/LogoutPicker.d.ts +8 -0
- package/dist/components/LogoutPicker.js +61 -0
- package/dist/components/Message.d.ts +10 -0
- package/dist/components/Message.js +234 -0
- package/dist/components/MessageList.d.ts +10 -0
- package/dist/components/MessageList.js +8 -0
- package/dist/components/ProjectPermission.d.ts +7 -0
- package/dist/components/ProjectPermission.js +52 -0
- package/dist/components/Search.d.ts +10 -0
- package/dist/components/Search.js +30 -0
- package/dist/components/SessionPicker.d.ts +9 -0
- package/dist/components/SessionPicker.js +88 -0
- package/dist/components/Sessions.d.ts +12 -0
- package/dist/components/Sessions.js +102 -0
- package/dist/components/Settings.d.ts +7 -0
- package/dist/components/Settings.js +162 -0
- package/dist/components/Status.d.ts +2 -0
- package/dist/components/Status.js +12 -0
- package/dist/config/config.test.d.ts +1 -0
- package/dist/config/config.test.js +157 -0
- package/dist/config/index.d.ts +121 -0
- package/dist/config/index.js +555 -0
- package/dist/config/providers.d.ts +43 -0
- package/dist/config/providers.js +82 -0
- package/dist/config/providers.test.d.ts +1 -0
- package/dist/config/providers.test.js +132 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/utils/agent.d.ts +37 -0
- package/dist/utils/agent.js +627 -0
- package/dist/utils/codeReview.d.ts +36 -0
- package/dist/utils/codeReview.js +390 -0
- package/dist/utils/context.d.ts +49 -0
- package/dist/utils/context.js +216 -0
- package/dist/utils/diffPreview.d.ts +57 -0
- package/dist/utils/diffPreview.js +335 -0
- package/dist/utils/export.d.ts +19 -0
- package/dist/utils/export.js +94 -0
- package/dist/utils/git.d.ts +85 -0
- package/dist/utils/git.js +399 -0
- package/dist/utils/git.test.d.ts +1 -0
- package/dist/utils/git.test.js +193 -0
- package/dist/utils/history.d.ts +93 -0
- package/dist/utils/history.js +348 -0
- package/dist/utils/interactive.d.ts +34 -0
- package/dist/utils/interactive.js +206 -0
- package/dist/utils/keychain.d.ts +17 -0
- package/dist/utils/keychain.js +160 -0
- package/dist/utils/learning.d.ts +89 -0
- package/dist/utils/learning.js +330 -0
- package/dist/utils/logger.d.ts +33 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/project.d.ts +86 -0
- package/dist/utils/project.js +415 -0
- package/dist/utils/project.test.d.ts +1 -0
- package/dist/utils/project.test.js +212 -0
- package/dist/utils/ratelimit.d.ts +26 -0
- package/dist/utils/ratelimit.js +132 -0
- package/dist/utils/ratelimit.test.d.ts +1 -0
- package/dist/utils/ratelimit.test.js +131 -0
- package/dist/utils/retry.d.ts +28 -0
- package/dist/utils/retry.js +109 -0
- package/dist/utils/retry.test.d.ts +1 -0
- package/dist/utils/retry.test.js +163 -0
- package/dist/utils/search.d.ts +11 -0
- package/dist/utils/search.js +29 -0
- package/dist/utils/shell.d.ts +45 -0
- package/dist/utils/shell.js +242 -0
- package/dist/utils/skills.d.ts +144 -0
- package/dist/utils/skills.js +1137 -0
- package/dist/utils/smartContext.d.ts +29 -0
- package/dist/utils/smartContext.js +441 -0
- package/dist/utils/tools.d.ts +224 -0
- package/dist/utils/tools.js +731 -0
- package/dist/utils/update.d.ts +22 -0
- package/dist/utils/update.js +128 -0
- package/dist/utils/validation.d.ts +28 -0
- package/dist/utils/validation.js +141 -0
- package/dist/utils/validation.test.d.ts +1 -0
- package/dist/utils/validation.test.js +164 -0
- package/dist/utils/verify.d.ts +78 -0
- package/dist/utils/verify.js +464 -0
- package/package.json +68 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent progress display component
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { ActionLog } from '../utils/tools';
|
|
6
|
+
interface AgentProgressProps {
|
|
7
|
+
isRunning: boolean;
|
|
8
|
+
iteration: number;
|
|
9
|
+
maxIterations: number;
|
|
10
|
+
actions: ActionLog[];
|
|
11
|
+
currentThinking?: string;
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const AgentProgress: React.FC<AgentProgressProps>;
|
|
15
|
+
/**
|
|
16
|
+
* Agent summary component - shown when agent completes
|
|
17
|
+
*/
|
|
18
|
+
interface AgentSummaryProps {
|
|
19
|
+
success: boolean;
|
|
20
|
+
iterations: number;
|
|
21
|
+
actions: ActionLog[];
|
|
22
|
+
error?: string;
|
|
23
|
+
aborted?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare const AgentSummary: React.FC<AgentSummaryProps>;
|
|
26
|
+
/**
|
|
27
|
+
* Changes list component - for /changes command
|
|
28
|
+
*/
|
|
29
|
+
interface ChangesListProps {
|
|
30
|
+
actions: ActionLog[];
|
|
31
|
+
}
|
|
32
|
+
export declare const ChangesList: React.FC<ChangesListProps>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Agent progress display component
|
|
4
|
+
*/
|
|
5
|
+
import { useState, useEffect } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
// Spinner frames for animation (no emojis)
|
|
8
|
+
const SPINNER_FRAMES = ['/', '-', '\\', '|'];
|
|
9
|
+
export const AgentProgress = ({ isRunning, iteration, maxIterations, actions, currentThinking, dryRun, }) => {
|
|
10
|
+
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
11
|
+
// Animate spinner when running
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!isRunning)
|
|
14
|
+
return;
|
|
15
|
+
const timer = setInterval(() => {
|
|
16
|
+
setSpinnerFrame(f => (f + 1) % SPINNER_FRAMES.length);
|
|
17
|
+
}, 150);
|
|
18
|
+
return () => clearInterval(timer);
|
|
19
|
+
}, [isRunning]);
|
|
20
|
+
// Don't show anything if not running and no actions
|
|
21
|
+
if (!isRunning && actions.length === 0) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// Show last 8 actions
|
|
25
|
+
const recentActions = actions.slice(-8);
|
|
26
|
+
// Count file changes
|
|
27
|
+
const fileChanges = {
|
|
28
|
+
created: actions.filter(a => a.type === 'write' && a.result === 'success').length,
|
|
29
|
+
modified: actions.filter(a => a.type === 'edit' && a.result === 'success').length,
|
|
30
|
+
deleted: actions.filter(a => a.type === 'delete' && a.result === 'success').length,
|
|
31
|
+
};
|
|
32
|
+
const totalFileChanges = fileChanges.created + fileChanges.modified + fileChanges.deleted;
|
|
33
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: dryRun ? 'yellow' : '#f02a30', padding: 1, marginY: 1, children: [_jsx(Box, { children: isRunning ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', children: ["[", SPINNER_FRAMES[spinnerFrame], "]"] }), _jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', bold: true, children: [' ', dryRun ? 'DRY RUN' : 'AGENT', ' '] }), _jsx(Text, { color: "gray", children: "|" }), _jsxs(Text, { color: "cyan", children: [" step ", iteration] }), _jsx(Text, { color: "gray", children: " | " }), _jsxs(Text, { color: "white", children: [actions.length, " actions"] })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: "green", bold: true, children: "[DONE] " }), _jsx(Text, { children: "Agent completed" }), _jsx(Text, { color: "gray", children: " | " }), _jsxs(Text, { color: "white", children: [actions.length, " actions"] })] })) }), _jsx(Text, { color: "gray", children: '─'.repeat(50) }), recentActions.length > 0 && (_jsx(Box, { flexDirection: "column", children: recentActions.map((action, i) => (_jsx(ActionItem, { action: action }, i))) })), isRunning && totalFileChanges > 0 && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Changes: " }), fileChanges.created > 0 && _jsxs(Text, { color: "green", children: ["+", fileChanges.created, " "] }), fileChanges.modified > 0 && _jsxs(Text, { color: "yellow", children: ["~", fileChanges.modified, " "] }), fileChanges.deleted > 0 && _jsxs(Text, { color: "red", children: ["-", fileChanges.deleted] })] })), isRunning && currentThinking && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", wrap: "truncate-end", children: ["> ", currentThinking.slice(0, 80), currentThinking.length > 80 ? '...' : ''] }) })), isRunning && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Press " }), _jsx(Text, { color: "#f02a30", children: "Esc" }), _jsx(Text, { color: "gray", children: " to stop" })] })), !isRunning && totalFileChanges > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "File Changes:" }), fileChanges.created > 0 && (_jsxs(Text, { color: "green", children: [" + ", fileChanges.created, " file(s) created"] })), fileChanges.modified > 0 && (_jsxs(Text, { color: "yellow", children: [" ~ ", fileChanges.modified, " file(s) modified"] })), fileChanges.deleted > 0 && (_jsxs(Text, { color: "red", children: [" - ", fileChanges.deleted, " file(s) deleted"] }))] }))] }));
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Single action item display
|
|
37
|
+
*/
|
|
38
|
+
const ActionItem = ({ action }) => {
|
|
39
|
+
const getStatusIndicator = () => {
|
|
40
|
+
switch (action.result) {
|
|
41
|
+
case 'success':
|
|
42
|
+
return _jsx(Text, { color: "green", children: "[ok]" });
|
|
43
|
+
case 'error':
|
|
44
|
+
return _jsx(Text, { color: "red", children: "[err]" });
|
|
45
|
+
default:
|
|
46
|
+
return _jsx(Text, { color: "yellow", children: "[..]" });
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const getTypeInfo = () => {
|
|
50
|
+
switch (action.type) {
|
|
51
|
+
case 'read':
|
|
52
|
+
return { color: 'blue', label: 'READ' };
|
|
53
|
+
case 'write':
|
|
54
|
+
return { color: 'green', label: 'CREATE' };
|
|
55
|
+
case 'edit':
|
|
56
|
+
return { color: 'yellow', label: 'EDIT' };
|
|
57
|
+
case 'delete':
|
|
58
|
+
return { color: 'red', label: 'DELETE' };
|
|
59
|
+
case 'command':
|
|
60
|
+
return { color: 'magenta', label: 'EXEC' };
|
|
61
|
+
case 'search':
|
|
62
|
+
return { color: 'cyan', label: 'SEARCH' };
|
|
63
|
+
case 'list':
|
|
64
|
+
return { color: 'white', label: 'LIST' };
|
|
65
|
+
case 'mkdir':
|
|
66
|
+
return { color: 'blue', label: 'MKDIR' };
|
|
67
|
+
case 'fetch':
|
|
68
|
+
return { color: 'cyan', label: 'FETCH' };
|
|
69
|
+
default:
|
|
70
|
+
return { color: 'white', label: String(action.type).toUpperCase() };
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const typeInfo = getTypeInfo();
|
|
74
|
+
return (_jsxs(Text, { children: [getStatusIndicator(), ' ', _jsx(Text, { color: typeInfo.color, children: typeInfo.label.padEnd(6) }), ' ', _jsxs(Text, { children: [action.target.slice(0, 40), action.target.length > 40 ? '...' : ''] })] }));
|
|
75
|
+
};
|
|
76
|
+
export const AgentSummary = ({ success, iterations, actions, error, aborted, }) => {
|
|
77
|
+
const filesWritten = actions.filter(a => a.type === 'write' && a.result === 'success');
|
|
78
|
+
const filesEdited = actions.filter(a => a.type === 'edit' && a.result === 'success');
|
|
79
|
+
const filesDeleted = actions.filter(a => a.type === 'delete' && a.result === 'success');
|
|
80
|
+
const dirsCreated = actions.filter(a => a.type === 'mkdir' && a.result === 'success');
|
|
81
|
+
const commandsRun = actions.filter(a => a.type === 'command' && a.result === 'success');
|
|
82
|
+
const errors = actions.filter(a => a.result === 'error');
|
|
83
|
+
const hasFileChanges = filesWritten.length > 0 || filesEdited.length > 0 ||
|
|
84
|
+
filesDeleted.length > 0 || dirsCreated.length > 0;
|
|
85
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: success ? 'green' : aborted ? 'yellow' : 'red', padding: 1, marginY: 1, children: [_jsxs(Box, { children: [success ? (_jsx(Text, { color: "green", bold: true, children: "[OK] Agent completed" })) : aborted ? (_jsx(Text, { color: "yellow", bold: true, children: "[--] Agent stopped" })) : (_jsx(Text, { color: "red", bold: true, children: "[!!] Agent failed" })), _jsxs(Text, { color: "gray", children: [" | ", iterations, " iterations | ", actions.length, " actions"] })] }), error && (_jsxs(Text, { color: "red", children: ["Error: ", error] })), hasFileChanges && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: '─'.repeat(40) }), _jsx(Text, { bold: true, children: "Changes:" }), filesWritten.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "green", children: ["+ Created (", filesWritten.length, "):"] }), filesWritten.map((f, i) => (_jsxs(Text, { color: "green", children: [" ", f.target] }, i)))] })), filesEdited.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "yellow", children: ["~ Modified (", filesEdited.length, "):"] }), filesEdited.map((f, i) => (_jsxs(Text, { color: "yellow", children: [" ", f.target] }, i)))] })), filesDeleted.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: ["- Deleted (", filesDeleted.length, "):"] }), filesDeleted.map((f, i) => (_jsxs(Text, { color: "red", children: [" ", f.target] }, i)))] })), dirsCreated.length > 0 && (_jsxs(Text, { color: "blue", children: ["+ ", dirsCreated.length, " director(ies) created"] }))] })), commandsRun.length > 0 && (_jsxs(Text, { color: "magenta", children: [commandsRun.length, " command(s) executed"] })), errors.length > 0 && (_jsxs(Text, { color: "red", children: [errors.length, " error(s) occurred"] }))] }));
|
|
86
|
+
};
|
|
87
|
+
export const ChangesList = ({ actions }) => {
|
|
88
|
+
const writes = actions.filter(a => a.type === 'write' && a.result === 'success');
|
|
89
|
+
const edits = actions.filter(a => a.type === 'edit' && a.result === 'success');
|
|
90
|
+
const deletes = actions.filter(a => a.type === 'delete' && a.result === 'success');
|
|
91
|
+
const mkdirs = actions.filter(a => a.type === 'mkdir' && a.result === 'success');
|
|
92
|
+
const totalChanges = writes.length + edits.length + deletes.length + mkdirs.length;
|
|
93
|
+
if (totalChanges === 0) {
|
|
94
|
+
return (_jsx(Box, { children: _jsx(Text, { color: "gray", children: "No file changes in current session" }) }));
|
|
95
|
+
}
|
|
96
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["Session Changes (", totalChanges, " total)"] }), _jsx(Text, { color: "gray", children: '─'.repeat(40) }), writes.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "green", bold: true, children: ["Created (", writes.length, "):"] }), writes.map((w, i) => (_jsxs(Text, { children: [" + ", w.target] }, i)))] })), edits.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Modified (", edits.length, "):"] }), edits.map((e, i) => (_jsxs(Text, { children: [" ~ ", e.target] }, i)))] })), deletes.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "red", bold: true, children: ["Deleted (", deletes.length, "):"] }), deletes.map((d, i) => (_jsxs(Text, { children: [" - ", d.target] }, i)))] })), mkdirs.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "blue", bold: true, children: ["Directories (", mkdirs.length, "):"] }), mkdirs.map((m, i) => (_jsxs(Text, { children: [" + ", m.target, "/"] }, i)))] }))] }));
|
|
97
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
export const Export = ({ onExport, onCancel }) => {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const formats = [
|
|
7
|
+
{ id: 'md', name: 'Markdown', description: 'Formatted with headers and separators' },
|
|
8
|
+
{ id: 'json', name: 'JSON', description: 'Structured data format' },
|
|
9
|
+
{ id: 'txt', name: 'Plain Text', description: 'Simple text format' },
|
|
10
|
+
];
|
|
11
|
+
useInput((input, key) => {
|
|
12
|
+
if (key.escape) {
|
|
13
|
+
onCancel();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (key.upArrow) {
|
|
17
|
+
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : formats.length - 1));
|
|
18
|
+
}
|
|
19
|
+
if (key.downArrow) {
|
|
20
|
+
setSelectedIndex((prev) => (prev < formats.length - 1 ? prev + 1 : 0));
|
|
21
|
+
}
|
|
22
|
+
if (key.return) {
|
|
23
|
+
onExport(formats[selectedIndex].id);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", padding: 1, children: [_jsx(Text, { color: "green", bold: true, children: "Export Chat" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Select export format:" }), _jsx(Text, { children: " " }), formats.map((format, index) => (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { children: [selectedIndex === index ? '› ' : ' ', _jsx(Text, { color: selectedIndex === index ? 'green' : 'white', bold: selectedIndex === index, children: format.name }), _jsxs(Text, { children: [" - ", format.description] })] }) }, format.id))), _jsx(Text, { children: " " }), _jsx(Text, { children: "\u2191/\u2193 Navigate \u2022 Enter Export \u2022 Esc Cancel" })] }));
|
|
27
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
export const Help = () => (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#f02a30", padding: 1, children: [_jsx(Text, { color: "#f02a30", bold: true, children: "Commands" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/help" }), " - Show this help"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/status" }), " - Show current status"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/version" }), " - Show version info"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/update" }), " - Check for updates"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/model" }), " - Switch model"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/protocol" }), " - Switch API protocol"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/provider" }), " - Switch API provider"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/lang" }), " - Set response language"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/settings" }), " - Adjust temp, tokens, timeout, rate limits"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/sessions" }), " - Save/load chat sessions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/sessions delete" }), " ", '<name>', " - Delete a session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/rename" }), " ", '<name>', " - Rename current session"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/search" }), " ", '<term>', " - Search through messages (e.g. /search error)"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/export" }), " - Export chat to MD/JSON/TXT format"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/diff" }), " [--staged] - Review git changes with AI"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/commit" }), " - Generate commit message from staged changes"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/apply" }), " - Apply file changes from AI response"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/copy" }), " [n] - Copy code block [n] to clipboard"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/agent" }), " ", '<task>', " - Start autonomous agent for task"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/agent-dry" }), " ", '<task>', " - Preview agent actions (no changes)"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/agent-stop" }), " - Stop running agent"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/clear" }), " - Clear chat history"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/login" }), " - Login with different key"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/logout" }), " - Logout and clear key"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "/exit" }), " - Quit application"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "#f02a30", bold: true, children: "Shortcuts" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2191/\u2193" }), " - Navigate input history or command suggestions"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "Tab" }), " - Autocomplete selected command"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "Ctrl+L" }), " - Clear chat (same as /clear)"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "Escape" }), " - Cancel request"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "#f02a30", bold: true, children: "Code Blocks" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Code blocks are numbered [0], [1], etc." }), _jsxs(Text, { children: ["Use ", _jsx(Text, { color: "#f02a30", children: "/copy" }), " to copy last block, ", _jsx(Text, { color: "#f02a30", children: "/copy 0" }), " for first"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "#f02a30", bold: true, children: "Project Context" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "When started in a project directory, Codeep can:" }), _jsx(Text, { children: " \u2022 Auto-detect file paths in your messages" }), _jsx(Text, { children: " \u2022 Attach file contents automatically" }), _jsx(Text, { children: " \u2022 Understand your project structure" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Examples:" }), _jsxs(Text, { children: [" ", _jsx(Text, { children: "\"check src/app.tsx\"" }), " - reads and analyzes file"] }), _jsxs(Text, { children: [" ", _jsx(Text, { children: "\"what does package.json contain\"" }), " - shows file"] }), _jsxs(Text, { children: [" ", _jsx(Text, { children: "\"improve error handling\"" }), " - AI knows project"] }), _jsx(Text, { children: " " }), _jsx(Text, { color: "#f02a30", bold: true, children: "Agent Mode" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Use /agent for autonomous task execution:" }), _jsx(Text, { children: " \u2022 Creates, edits, deletes files automatically" }), _jsx(Text, { children: " \u2022 Runs shell commands (npm, git, etc.)" }), _jsx(Text, { children: " \u2022 Loops until task is complete" }), _jsx(Text, { children: " \u2022 Shows progress and all actions taken" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "Examples:" }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "#f02a30", children: "/agent" }), " \"add error handling to api.ts\""] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "#f02a30", children: "/agent" }), " \"run tests and fix failures\""] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "#f02a30", children: "/agent" }), " \"create a new React component for user profile\""] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "#f02a30", children: "/agent-dry" }), " \"refactor utils folder\" - preview only"] })] }));
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useMemo, useEffect } from 'react';
|
|
3
|
+
import { Text, Box, useInput } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
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: '/clear', desc: 'Clear chat' },
|
|
26
|
+
{ cmd: '/login', desc: 'Change API key' },
|
|
27
|
+
{ cmd: '/logout', desc: 'Logout' },
|
|
28
|
+
{ cmd: '/exit', desc: 'Quit' },
|
|
29
|
+
];
|
|
30
|
+
export const ChatInput = ({ onSubmit, disabled, history = [], clearTrigger = 0 }) => {
|
|
31
|
+
const [value, setValue] = useState('');
|
|
32
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
33
|
+
const [isSelectingCommand, setIsSelectingCommand] = useState(false);
|
|
34
|
+
// Clear input when clearTrigger changes
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (clearTrigger > 0) {
|
|
37
|
+
setValue('');
|
|
38
|
+
setSelectedIndex(0);
|
|
39
|
+
setIsSelectingCommand(false);
|
|
40
|
+
}
|
|
41
|
+
}, [clearTrigger]);
|
|
42
|
+
// Filter commands based on input
|
|
43
|
+
const suggestions = useMemo(() => {
|
|
44
|
+
if (!value.startsWith('/') || value.includes(' '))
|
|
45
|
+
return [];
|
|
46
|
+
return COMMANDS.filter(c => c.cmd.startsWith(value.toLowerCase()));
|
|
47
|
+
}, [value]);
|
|
48
|
+
// Reset selection when suggestions change
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (suggestions.length > 0) {
|
|
51
|
+
setSelectedIndex(0);
|
|
52
|
+
setIsSelectingCommand(true);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
setIsSelectingCommand(false);
|
|
56
|
+
}
|
|
57
|
+
}, [suggestions.length]);
|
|
58
|
+
// Handle keyboard navigation for command suggestions
|
|
59
|
+
useInput((input, key) => {
|
|
60
|
+
if (disabled || suggestions.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
// Navigate suggestions with up/down arrows
|
|
63
|
+
if (key.upArrow) {
|
|
64
|
+
setSelectedIndex(i => Math.max(0, i - 1));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (key.downArrow) {
|
|
68
|
+
setSelectedIndex(i => Math.min(suggestions.length - 1, i + 1));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Tab to autocomplete selected command
|
|
72
|
+
if (key.tab) {
|
|
73
|
+
setValue(suggestions[selectedIndex].cmd);
|
|
74
|
+
setIsSelectingCommand(false);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}, { isActive: isSelectingCommand });
|
|
78
|
+
const handleChange = (newValue) => {
|
|
79
|
+
setValue(newValue);
|
|
80
|
+
};
|
|
81
|
+
const handleSubmit = (text) => {
|
|
82
|
+
if (text.trim() && !disabled) {
|
|
83
|
+
onSubmit(text.trim());
|
|
84
|
+
setValue('');
|
|
85
|
+
setIsSelectingCommand(false);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return (_jsxs(Box, { flexDirection: "column", children: [suggestions.length > 0 && (_jsxs(Box, { flexDirection: "column", marginBottom: 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))), _jsxs(Text, { color: "gray", children: ["\u2191\u2193 Navigate \u2022 Tab Complete \u2022 ", suggestions.length, " ", suggestions.length === 1 ? 'command' : 'commands'] })] })), _jsxs(Box, { children: [_jsx(Text, { color: "#f02a30", bold: true, children: '> ' }), disabled ? (_jsx(Text, { children: "..." })) : (_jsx(TextInput, { value: value, onChange: handleChange, onSubmit: handleSubmit, placeholder: "Type a message or /command..." }))] })] }));
|
|
89
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Text, Box } from 'ink';
|
|
4
|
+
// Spinner frames
|
|
5
|
+
const SPINNER = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
|
|
6
|
+
export const Loading = ({ isStreaming = false }) => {
|
|
7
|
+
const [tick, setTick] = useState(0);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
// Force re-render every 100ms to animate even when parent doesn't update
|
|
10
|
+
const timer = setInterval(() => {
|
|
11
|
+
setTick(t => t + 1);
|
|
12
|
+
}, 100);
|
|
13
|
+
return () => clearInterval(timer);
|
|
14
|
+
}, []);
|
|
15
|
+
const spinnerFrame = tick % SPINNER.length;
|
|
16
|
+
const dotsCount = (Math.floor(tick / 3) % 4); // 0, 1, 2, 3 dots cycling
|
|
17
|
+
const dots = '.'.repeat(dotsCount);
|
|
18
|
+
const message = isStreaming ? 'Writing' : 'Thinking';
|
|
19
|
+
return (_jsx(Box, { paddingLeft: 2, paddingY: 0, children: _jsxs(Text, { color: "#f02a30", bold: true, children: [SPINNER[spinnerFrame], " ", message, dots] }) }));
|
|
20
|
+
};
|
|
21
|
+
// Simple inline spinner for smaller spaces
|
|
22
|
+
export const InlineSpinner = ({ text = 'Loading' }) => {
|
|
23
|
+
const [tick, setTick] = useState(0);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const timer = setInterval(() => {
|
|
26
|
+
setTick(t => t + 1);
|
|
27
|
+
}, 80);
|
|
28
|
+
return () => clearInterval(timer);
|
|
29
|
+
}, []);
|
|
30
|
+
return (_jsxs(Text, { children: [_jsxs(Text, { color: "#f02a30", children: [SPINNER[tick % SPINNER.length], " "] }), _jsx(Text, { children: text })] }));
|
|
31
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
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';
|
|
7
|
+
import { validateApiKey } from '../api/index';
|
|
8
|
+
import { Logo } from './Logo';
|
|
9
|
+
import { getProviderList } from '../config/providers';
|
|
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
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
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 {};
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
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 { getConfiguredProviders, clearApiKey, getCurrentProvider } from '../config/index';
|
|
5
|
+
export const LogoutPicker = ({ onLogout, onLogoutAll, onCancel }) => {
|
|
6
|
+
const providers = getConfiguredProviders();
|
|
7
|
+
const currentProvider = getCurrentProvider();
|
|
8
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
9
|
+
// Options: individual providers + "All" + "Cancel"
|
|
10
|
+
const options = [
|
|
11
|
+
...providers.map(p => ({
|
|
12
|
+
type: 'provider',
|
|
13
|
+
id: p.id,
|
|
14
|
+
label: p.name,
|
|
15
|
+
isCurrent: p.id === currentProvider.id
|
|
16
|
+
})),
|
|
17
|
+
{ type: 'all', id: 'all', label: 'Logout from all providers', isCurrent: false },
|
|
18
|
+
{ type: 'cancel', id: 'cancel', label: 'Cancel', isCurrent: false },
|
|
19
|
+
];
|
|
20
|
+
useInput((input, key) => {
|
|
21
|
+
if (key.escape) {
|
|
22
|
+
onCancel();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (key.upArrow) {
|
|
26
|
+
setSelectedIndex(i => Math.max(0, i - 1));
|
|
27
|
+
}
|
|
28
|
+
if (key.downArrow) {
|
|
29
|
+
setSelectedIndex(i => Math.min(options.length - 1, i + 1));
|
|
30
|
+
}
|
|
31
|
+
if (key.return) {
|
|
32
|
+
const selected = options[selectedIndex];
|
|
33
|
+
if (selected.type === 'provider') {
|
|
34
|
+
clearApiKey(selected.id);
|
|
35
|
+
onLogout(selected.id);
|
|
36
|
+
}
|
|
37
|
+
else if (selected.type === 'all') {
|
|
38
|
+
for (const p of providers) {
|
|
39
|
+
clearApiKey(p.id);
|
|
40
|
+
}
|
|
41
|
+
onLogoutAll();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
onCancel();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (providers.length === 0) {
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { color: "yellow", children: "No providers configured." }), _jsx(Text, { color: "gray", children: "Press Escape to go back." })] }));
|
|
50
|
+
}
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Select provider to logout:" }) }), _jsx(Box, { flexDirection: "column", marginBottom: 1, children: options.map((option, index) => {
|
|
52
|
+
const isSelected = index === selectedIndex;
|
|
53
|
+
const prefix = isSelected ? '→ ' : ' ';
|
|
54
|
+
let color = isSelected ? 'green' : 'white';
|
|
55
|
+
if (option.type === 'all')
|
|
56
|
+
color = isSelected ? 'red' : 'yellow';
|
|
57
|
+
if (option.type === 'cancel')
|
|
58
|
+
color = isSelected ? 'blue' : 'gray';
|
|
59
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: color, bold: isSelected, children: [prefix, option.label] }), option.isCurrent && (_jsx(Text, { color: "cyan", children: " (current)" }))] }, option.id));
|
|
60
|
+
}) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2191\u2193 Navigate Enter Select Esc Cancel" }) })] }));
|
|
61
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function getCodeBlocks(): string[];
|
|
3
|
+
export declare function clearCodeBlocks(): void;
|
|
4
|
+
export declare function getCodeBlock(index: number): string | null;
|
|
5
|
+
interface MessageProps {
|
|
6
|
+
role: 'user' | 'assistant' | 'system';
|
|
7
|
+
content: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const MessageView: React.FC<MessageProps>;
|
|
10
|
+
export {};
|