codebase-rag-tui 0.1.0 → 0.3.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/dist/api/chat.d.ts +5 -1
- package/dist/api/chat.js +9 -2
- package/dist/app.js +86 -21
- package/dist/components/Input.d.ts +2 -1
- package/dist/components/Input.js +6 -2
- package/dist/components/Message.d.ts +2 -1
- package/dist/components/Message.js +7 -5
- package/dist/components/TreeAnimation.d.ts +6 -0
- package/dist/components/TreeAnimation.js +100 -0
- package/dist/contexts/SocketContext.js +1 -5
- package/package.json +3 -1
package/dist/api/chat.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export declare function sendMessage(question: string, socketId: string, sessionId?: string): Promise<{
|
|
1
|
+
export declare function sendMessage(question: string, socketId: string, mode: string, sessionId?: string): Promise<{
|
|
2
2
|
session_id: string;
|
|
3
3
|
response: string;
|
|
4
|
+
edit: boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function rejectChange(socketId: string, sessionId: string): Promise<{
|
|
7
|
+
response: string;
|
|
4
8
|
}>;
|
package/dist/api/chat.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
export async function sendMessage(question, socketId, sessionId) {
|
|
1
|
+
export async function sendMessage(question, socketId, mode, sessionId) {
|
|
2
2
|
const res = await fetch(`${process.env['BACKEND_URI']}/remote/repo/query`, {
|
|
3
3
|
method: "POST",
|
|
4
4
|
headers: {
|
|
5
|
-
"Content-Type": "application/json",
|
|
5
|
+
"Content-Type": "application/json",
|
|
6
6
|
},
|
|
7
7
|
body: JSON.stringify({
|
|
8
8
|
question: question,
|
|
9
9
|
socket_id: socketId,
|
|
10
|
+
mode: mode,
|
|
10
11
|
session_id: sessionId,
|
|
11
12
|
})
|
|
12
13
|
});
|
|
13
14
|
return res.json();
|
|
14
15
|
}
|
|
16
|
+
export async function rejectChange(socketId, sessionId) {
|
|
17
|
+
const res = await fetch(`${process.env['BACKEND_URI']}/remote/repo/reject/sessions/${sessionId}?socket_id=${encodeURIComponent(socketId)}`, {
|
|
18
|
+
method: "DELETE",
|
|
19
|
+
});
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
package/dist/app.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { Box, Text, useApp } from 'ink';
|
|
3
3
|
import Header from './components/Header.js';
|
|
4
4
|
import Message from './components/Message.js';
|
|
5
5
|
import Input from './components/Input.js';
|
|
6
|
-
import
|
|
6
|
+
import TreeAnimation from './components/TreeAnimation.js';
|
|
7
|
+
import { sendMessage, rejectChange } from './api/chat.js';
|
|
7
8
|
import { useSocket } from './contexts/SocketContext.js';
|
|
8
9
|
import { getWorkspaceInfo } from './utils/workspace.js';
|
|
9
10
|
import { useWorkspace } from './contexts/WorkspaceContext.js';
|
|
11
|
+
import SelectInput from 'ink-select-input';
|
|
10
12
|
export default function App() {
|
|
11
13
|
const { exit } = useApp();
|
|
12
14
|
const { socket, isConnected, isConnecting, connectionError } = useSocket();
|
|
@@ -15,9 +17,51 @@ export default function App() {
|
|
|
15
17
|
const [isLoading, setIsLoading] = useState(false);
|
|
16
18
|
const [error, setError] = useState(null);
|
|
17
19
|
const [sessionId, setSessionId] = useState(null);
|
|
20
|
+
const [mode, setMode] = useState(null);
|
|
21
|
+
const [pendingReview, setPendingReview] = useState(false);
|
|
22
|
+
const modes = [
|
|
23
|
+
{
|
|
24
|
+
label: 'Chat',
|
|
25
|
+
value: 'chat'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Agent',
|
|
29
|
+
value: 'agent'
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
const [showAnimation, setShowAnimation] = useState(true);
|
|
33
|
+
const handleAnimationComplete = useCallback(() => {
|
|
34
|
+
setShowAnimation(false);
|
|
35
|
+
}, []);
|
|
36
|
+
const reviewChoices = [
|
|
37
|
+
{ label: '✅ Accept changes', value: 'accept' },
|
|
38
|
+
{ label: '❌ Reject changes', value: 'reject' },
|
|
39
|
+
];
|
|
40
|
+
const handleReviewSelect = async (item) => {
|
|
41
|
+
if (item.value === 'accept') {
|
|
42
|
+
setMessages((prev) => [...prev, { role: 'model', text: 'Changes accepted.', edit: false }]);
|
|
43
|
+
setPendingReview(false);
|
|
44
|
+
}
|
|
45
|
+
else if (item.value === 'reject') {
|
|
46
|
+
if (!socket || !isConnected || !socket.id || !sessionId) {
|
|
47
|
+
setMessages((prev) => [...prev, { role: 'model', text: 'Cannot reject: not connected or no active session.', edit: false }]);
|
|
48
|
+
setPendingReview(false);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const res = await rejectChange(socket.id, sessionId);
|
|
53
|
+
setMessages((prev) => [...prev, { role: 'model', text: res.response, edit: false }]);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const message = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
57
|
+
setMessages((prev) => [...prev, { role: 'model', text: `Error rejecting changes: ${message}`, edit: false }]);
|
|
58
|
+
}
|
|
59
|
+
setPendingReview(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
18
62
|
const welcomeMessage = 'Start you session by entering the path to your repository';
|
|
19
63
|
useEffect(() => {
|
|
20
|
-
setMessages([{ role: 'model', text: welcomeMessage }]);
|
|
64
|
+
setMessages([{ role: 'model', text: welcomeMessage, edit: false }]);
|
|
21
65
|
}, []); // Only run once on mount
|
|
22
66
|
const handleSubmit = async (text) => {
|
|
23
67
|
if (text === '/help') {
|
|
@@ -25,8 +69,10 @@ export default function App() {
|
|
|
25
69
|
• /help - Show this help message
|
|
26
70
|
• /clear - Clear conversation
|
|
27
71
|
• /quit - Leave current session and reset workspace
|
|
28
|
-
• /exit - Exit the application
|
|
29
|
-
|
|
72
|
+
• /exit - Exit the application
|
|
73
|
+
• /agent - Switch to agent mode
|
|
74
|
+
• /chat - Switch to chat mode`;
|
|
75
|
+
setMessages((prev) => [...prev, { role: 'model', text: helpText, edit: false }]);
|
|
30
76
|
}
|
|
31
77
|
if (text === '/exit') {
|
|
32
78
|
exit();
|
|
@@ -40,45 +86,59 @@ export default function App() {
|
|
|
40
86
|
if (text === '/quit') {
|
|
41
87
|
setSessionId(null);
|
|
42
88
|
setWorkspace(process.cwd());
|
|
43
|
-
setMessages([{ role: 'model', text: welcomeMessage }]);
|
|
89
|
+
setMessages([{ role: 'model', text: welcomeMessage, edit: false }]);
|
|
44
90
|
return;
|
|
45
91
|
}
|
|
46
|
-
|
|
92
|
+
// if (text === '/agent') {
|
|
93
|
+
// setMode('agent');
|
|
94
|
+
// setMessages((prev) => [...prev, {role: 'model', text: 'Switched to agent mode'}]);
|
|
95
|
+
// return;
|
|
96
|
+
// }
|
|
97
|
+
// if (text === '/chat') {
|
|
98
|
+
// setMode('chat');
|
|
99
|
+
// setMessages((prev) => [...prev, {role: 'model', text: 'Switched to chat mode'}]);
|
|
100
|
+
// return;
|
|
101
|
+
// }
|
|
102
|
+
setMessages((prev) => [...prev, { role: 'user', text, edit: false }]);
|
|
47
103
|
if (workspace == process.cwd()) {
|
|
48
104
|
try {
|
|
49
105
|
const info = await getWorkspaceInfo(text);
|
|
50
106
|
if (info.exists && info.isDirectory) {
|
|
51
107
|
setWorkspace(info.absolutePath);
|
|
52
|
-
setMessages((prev) => [...prev, { role: 'model', text: `Workspace is set to: ${info.absolutePath}
|
|
108
|
+
setMessages((prev) => [...prev, { role: 'model', text: `Workspace is set to: ${info.absolutePath}`, edit: false }]);
|
|
53
109
|
}
|
|
54
110
|
else if (info.exists) {
|
|
55
|
-
setMessages((prev) => [...prev, { role: 'model', text: 'Path exists but is not a directory. Please enter a valid directory path.' }]);
|
|
111
|
+
setMessages((prev) => [...prev, { role: 'model', text: 'Path exists but is not a directory. Please enter a valid directory path.', edit: false }]);
|
|
56
112
|
}
|
|
57
113
|
else {
|
|
58
|
-
setMessages((prev) => [...prev, { role: 'model', text: 'Directory does not exist. Please enter a valid project directory path.' }]);
|
|
114
|
+
setMessages((prev) => [...prev, { role: 'model', text: 'Directory does not exist. Please enter a valid project directory path.', edit: false }]);
|
|
59
115
|
}
|
|
60
116
|
}
|
|
61
117
|
catch (err) {
|
|
62
118
|
const message = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
63
|
-
setMessages((prev) => [...prev, { role: 'model', text: `Error validating path: ${message}
|
|
119
|
+
setMessages((prev) => [...prev, { role: 'model', text: `Error validating path: ${message}`, edit: false }]);
|
|
64
120
|
}
|
|
65
121
|
return;
|
|
66
122
|
}
|
|
67
123
|
setIsLoading(true);
|
|
68
124
|
setError(null);
|
|
69
125
|
if (!socket || !isConnected || !socket.id) {
|
|
70
|
-
setMessages((prev) => [...prev, { role: 'model', text: 'Failed to connect to server' }]);
|
|
126
|
+
setMessages((prev) => [...prev, { role: 'model', text: 'Failed to connect to server', edit: false }]);
|
|
71
127
|
return;
|
|
72
128
|
}
|
|
73
129
|
try {
|
|
74
130
|
if (sessionId) {
|
|
75
|
-
const res = await sendMessage(text, socket.id, sessionId);
|
|
76
|
-
setMessages((prev) => [...prev, { role: 'model', text: res.response }]);
|
|
131
|
+
const res = await sendMessage(text, socket.id, mode, sessionId);
|
|
132
|
+
setMessages((prev) => [...prev, { role: 'model', text: res.response, edit: res.edit }]);
|
|
133
|
+
if (res.edit)
|
|
134
|
+
setPendingReview(true);
|
|
77
135
|
}
|
|
78
136
|
else {
|
|
79
|
-
const res = await sendMessage(text, socket.id);
|
|
137
|
+
const res = await sendMessage(text, socket.id, mode);
|
|
80
138
|
setSessionId(res.session_id);
|
|
81
|
-
setMessages((prev) => [...prev, { role: 'model', text: res.response }]);
|
|
139
|
+
setMessages((prev) => [...prev, { role: 'model', text: res.response, edit: res.edit }]);
|
|
140
|
+
if (res.edit)
|
|
141
|
+
setPendingReview(true);
|
|
82
142
|
}
|
|
83
143
|
}
|
|
84
144
|
catch (err) {
|
|
@@ -89,17 +149,22 @@ export default function App() {
|
|
|
89
149
|
setIsLoading(false);
|
|
90
150
|
}
|
|
91
151
|
};
|
|
152
|
+
if (showAnimation) {
|
|
153
|
+
return React.createElement(TreeAnimation, { onComplete: handleAnimationComplete });
|
|
154
|
+
}
|
|
92
155
|
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
93
156
|
React.createElement(Header, null),
|
|
94
|
-
React.createElement(
|
|
95
|
-
|
|
96
|
-
React.createElement(Message, { key: i, role: msg.role, text: msg.text })))),
|
|
157
|
+
(!mode) && (React.createElement(SelectInput, { items: modes, onSelect: m => setMode(m.value) })),
|
|
158
|
+
(mode) && (React.createElement(Box, { flexDirection: "column", marginTop: 1 }, messages.map((msg, i) => (React.createElement(Message, { key: i, role: msg.role, text: msg.text, edit: msg.edit }))))),
|
|
97
159
|
(error || connectionError) && (React.createElement(Box, { marginTop: 1 },
|
|
98
160
|
React.createElement(Text, { color: "red" }, error || connectionError))),
|
|
99
161
|
isConnecting && (React.createElement(Box, { marginTop: 1 },
|
|
100
162
|
React.createElement(Text, { color: "yellow" }, "Connecting to server..."))),
|
|
101
163
|
!isConnected && !isConnecting && !connectionError && (React.createElement(Box, { marginTop: 1 },
|
|
102
164
|
React.createElement(Text, { color: "gray" }, "Disconnected from server"))),
|
|
103
|
-
React.createElement(Box, { marginTop: 1 },
|
|
104
|
-
React.createElement(
|
|
165
|
+
mode && pendingReview && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
166
|
+
React.createElement(Text, { color: "yellow", bold: true }, "Review changes \u2014 accept or reject?"),
|
|
167
|
+
React.createElement(SelectInput, { items: reviewChoices, onSelect: handleReviewSelect }))),
|
|
168
|
+
mode && !pendingReview && (React.createElement(Box, { marginTop: 1 },
|
|
169
|
+
React.createElement(Input, { onSubmit: handleSubmit, isLoading: isLoading, mode: mode })))));
|
|
105
170
|
}
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
type Props = {
|
|
3
3
|
onSubmit: (value: string) => void;
|
|
4
4
|
isLoading: boolean;
|
|
5
|
+
mode: string;
|
|
5
6
|
};
|
|
6
|
-
export default function Input({ onSubmit, isLoading }: Props): React.JSX.Element;
|
|
7
|
+
export default function Input({ onSubmit, isLoading, mode }: Props): React.JSX.Element;
|
|
7
8
|
export {};
|
package/dist/components/Input.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import TextInput from 'ink-text-input';
|
|
4
|
-
export default function Input({ onSubmit, isLoading }) {
|
|
4
|
+
export default function Input({ onSubmit, isLoading, mode }) {
|
|
5
5
|
const [value, setValue] = useState('');
|
|
6
6
|
const handleSubmit = (text) => {
|
|
7
7
|
if (text.trim().length === 0) {
|
|
@@ -15,6 +15,10 @@ export default function Input({ onSubmit, isLoading }) {
|
|
|
15
15
|
React.createElement(Text, { dimColor: true }, "Thinking...")));
|
|
16
16
|
}
|
|
17
17
|
return (React.createElement(Box, null,
|
|
18
|
-
React.createElement(Text, {
|
|
18
|
+
React.createElement(Text, { color: "cyan" },
|
|
19
|
+
"[",
|
|
20
|
+
mode,
|
|
21
|
+
"]"),
|
|
22
|
+
React.createElement(Text, { bold: true, color: "green" }, ' > '),
|
|
19
23
|
React.createElement(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: "Type a message...", focus: !isLoading })));
|
|
20
24
|
}
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
type Props = {
|
|
3
3
|
role: 'user' | 'model';
|
|
4
4
|
text: string;
|
|
5
|
+
edit?: boolean;
|
|
5
6
|
};
|
|
6
|
-
export default function Message({ role, text }: Props): React.JSX.Element;
|
|
7
|
+
export default function Message({ role, text, edit }: Props): React.JSX.Element;
|
|
7
8
|
export {};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
|
|
3
|
+
import Markdown from 'ink-markdown-es';
|
|
4
|
+
export default function Message({ role, text, edit }) {
|
|
4
5
|
if (role === 'user') {
|
|
5
6
|
return (React.createElement(Box, null,
|
|
6
7
|
React.createElement(Text, { color: "green" },
|
|
7
8
|
'> ',
|
|
8
9
|
text)));
|
|
9
10
|
}
|
|
10
|
-
return (React.createElement(Box,
|
|
11
|
-
React.createElement(Text, { color: "blue" },
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
12
|
+
React.createElement(Text, { color: "blue", bold: true }, "Codebase Rag Agent:"),
|
|
13
|
+
React.createElement(Markdown, null, text),
|
|
14
|
+
edit && (React.createElement(Box, { marginLeft: 2, marginTop: 0 },
|
|
15
|
+
React.createElement(Text, { color: "yellow" }, "\u26A1 Code changes were applied")))));
|
|
14
16
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
const treeFrames = [
|
|
4
|
+
// Frame 1: Ground only
|
|
5
|
+
String.raw `
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
| =|
|
|
16
|
+
| |
|
|
17
|
+
--------------------/ , . \--------._
|
|
18
|
+
`,
|
|
19
|
+
// Frame 2: Trunk grows
|
|
20
|
+
String.raw `
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
| |//
|
|
29
|
+
|_ /
|
|
30
|
+
|- |
|
|
31
|
+
| =|
|
|
32
|
+
| |
|
|
33
|
+
--------------------/ , . \--------._
|
|
34
|
+
`,
|
|
35
|
+
// Frame 3: Lower branches
|
|
36
|
+
String.raw `
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
'7-,--. || / / ,
|
|
42
|
+
/' . / / |/_.'
|
|
43
|
+
| |//
|
|
44
|
+
|_ /
|
|
45
|
+
|- |
|
|
46
|
+
| =|
|
|
47
|
+
| |
|
|
48
|
+
--------------------/ , . \--------._
|
|
49
|
+
`,
|
|
50
|
+
// Frame 4: More branches
|
|
51
|
+
String.raw `
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
\\ y | //
|
|
55
|
+
_ _.___\\, / -. ||
|
|
56
|
+
'7-,--.'._|| / / ,
|
|
57
|
+
/' '-. './ / |/_.'
|
|
58
|
+
| |//
|
|
59
|
+
|_ /
|
|
60
|
+
|- |
|
|
61
|
+
| =|
|
|
62
|
+
| |
|
|
63
|
+
--------------------/ , . \--------._
|
|
64
|
+
`,
|
|
65
|
+
// Frame 5: Full tree
|
|
66
|
+
String.raw `
|
|
67
|
+
v . ._, |_ .,
|
|
68
|
+
'-._\/ . \ / |/_
|
|
69
|
+
\\ _\, y | \//
|
|
70
|
+
_\_.___\\, \\/ -.\||
|
|
71
|
+
'7-,--.'. || / / ,
|
|
72
|
+
/' '-. './ / |/_.'
|
|
73
|
+
| |//
|
|
74
|
+
|_ /
|
|
75
|
+
|- |
|
|
76
|
+
| =|
|
|
77
|
+
| |
|
|
78
|
+
--------------------/ , . \--------._
|
|
79
|
+
`,
|
|
80
|
+
];
|
|
81
|
+
export default function TreeAnimation({ onComplete }) {
|
|
82
|
+
const [frameIndex, setFrameIndex] = useState(0);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (frameIndex < treeFrames.length - 1) {
|
|
85
|
+
const timer = setTimeout(() => {
|
|
86
|
+
setFrameIndex((prev) => prev + 1);
|
|
87
|
+
}, 200);
|
|
88
|
+
return () => clearTimeout(timer);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const timer = setTimeout(() => {
|
|
92
|
+
onComplete();
|
|
93
|
+
}, 800);
|
|
94
|
+
return () => clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
}, [frameIndex, onComplete]);
|
|
97
|
+
return (React.createElement(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 2 },
|
|
98
|
+
React.createElement(Text, { color: "green" }, treeFrames[frameIndex]),
|
|
99
|
+
React.createElement(Text, { color: "cyan", bold: true }, "Codebase RAG Agent")));
|
|
100
|
+
}
|
|
@@ -55,27 +55,23 @@ export const SocketProvider = ({ children, serverUrl = process.env['BACKEND_URI'
|
|
|
55
55
|
});
|
|
56
56
|
// File system event handlers
|
|
57
57
|
newSocket.on('dir:list', async (payload, ack) => {
|
|
58
|
-
console.log('dir:list event heard');
|
|
59
58
|
const result = await listDirectory(payload.dir_path, workspaceRef.current);
|
|
60
59
|
ack(result);
|
|
61
60
|
});
|
|
62
61
|
newSocket.on('bytes:read', async (payload, ack) => {
|
|
63
|
-
console.log('bytes:read event heard');
|
|
64
62
|
const result = await readFileBytes(payload.file_path, workspaceRef.current);
|
|
65
63
|
ack(result);
|
|
66
64
|
});
|
|
67
65
|
newSocket.on('file:read', async (payload, ack) => {
|
|
68
|
-
console.log('file:read event heard');
|
|
69
66
|
const result = await readFileText(payload.file_path, workspaceRef.current);
|
|
70
67
|
ack(result);
|
|
71
68
|
});
|
|
72
69
|
newSocket.on('file:write', async (payload, ack) => {
|
|
73
|
-
console.log('file:write event heard');
|
|
74
70
|
const result = await writeFile(payload.file_path, payload.content, workspaceRef.current);
|
|
75
71
|
ack(result);
|
|
76
72
|
});
|
|
77
73
|
newSocket.on("command:run", async (payload, ack) => {
|
|
78
|
-
const res = await runCommand(payload.cmd_parts,
|
|
74
|
+
const res = await runCommand(payload.cmd_parts, workspaceRef.current, payload.timeout);
|
|
79
75
|
ack(res);
|
|
80
76
|
});
|
|
81
77
|
setSocket(newSocket);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codebase-rag-tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Terminal-based AI agent for codebase RAG (Retrieval-Augmented Generation)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "johnsonafool",
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"@google/generative-ai": "^0.24.1",
|
|
43
43
|
"dotenv": "^17.2.4",
|
|
44
44
|
"ink": "^4.1.0",
|
|
45
|
+
"ink-markdown-es": "^1.1.0",
|
|
46
|
+
"ink-select-input": "^6.2.0",
|
|
45
47
|
"ink-text-input": "^6.0.0",
|
|
46
48
|
"meow": "^11.0.0",
|
|
47
49
|
"react": "^18.2.0",
|