activo 0.4.4 → 0.5.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/README.md +203 -1
- package/data/2026-03-04_20-54.json +181 -0
- package/data/2026-03-04_20-56.json +181 -0
- package/data/apex-rulesets/egov.yaml +469 -0
- package/data/apex-rulesets/modernize.yaml +687 -0
- package/data/apex-rulesets/quality.yaml +1677 -0
- package/data/apex-rulesets/rule-schema.yaml +587 -0
- package/data/apex-rulesets/secure.yaml +1688 -0
- package/data/apex-rulesets/spring.yaml +455 -0
- package/data/apex-rulesets/sql-format.yaml +99 -0
- package/data/apex-rulesets/sql-oracle.yaml +281 -0
- package/data/apex-rulesets/sql.yaml +1660 -0
- package/dist/cli/headless.d.ts.map +1 -1
- package/dist/cli/headless.js +32 -10
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/index.js +31 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agent.d.ts +3 -3
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +203 -384
- package/dist/core/agent.js.map +1 -1
- package/dist/core/commands.d.ts +2 -1
- package/dist/core/commands.d.ts.map +1 -1
- package/dist/core/commands.js +61 -9
- package/dist/core/commands.js.map +1 -1
- package/dist/core/config.d.ts +14 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +41 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/conversation.d.ts +2 -2
- package/dist/core/conversation.d.ts.map +1 -1
- package/dist/core/conversation.js.map +1 -1
- package/dist/core/intentRouter.d.ts +43 -0
- package/dist/core/intentRouter.d.ts.map +1 -0
- package/dist/core/intentRouter.js +804 -0
- package/dist/core/intentRouter.js.map +1 -0
- package/dist/core/llm/anthropic.d.ts +24 -0
- package/dist/core/llm/anthropic.d.ts.map +1 -0
- package/dist/core/llm/anthropic.js +226 -0
- package/dist/core/llm/anthropic.js.map +1 -0
- package/dist/core/llm/ollama.d.ts +5 -14
- package/dist/core/llm/ollama.d.ts.map +1 -1
- package/dist/core/llm/ollama.js +3 -0
- package/dist/core/llm/ollama.js.map +1 -1
- package/dist/core/llm/types.d.ts +22 -0
- package/dist/core/llm/types.d.ts.map +1 -0
- package/dist/core/llm/types.js +2 -0
- package/dist/core/llm/types.js.map +1 -0
- package/dist/core/mcp/client.d.ts +6 -0
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +16 -0
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/init.d.ts +12 -0
- package/dist/core/mcp/init.d.ts.map +1 -0
- package/dist/core/mcp/init.js +55 -0
- package/dist/core/mcp/init.js.map +1 -0
- package/dist/core/mcp/logger.d.ts +14 -0
- package/dist/core/mcp/logger.d.ts.map +1 -0
- package/dist/core/mcp/logger.js +50 -0
- package/dist/core/mcp/logger.js.map +1 -0
- package/dist/core/tools/analyzePatterns.d.ts +3 -0
- package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
- package/dist/core/tools/analyzePatterns.js +293 -0
- package/dist/core/tools/analyzePatterns.js.map +1 -0
- package/dist/core/tools/apexPaths.d.ts +14 -0
- package/dist/core/tools/apexPaths.d.ts.map +1 -0
- package/dist/core/tools/apexPaths.js +54 -0
- package/dist/core/tools/apexPaths.js.map +1 -0
- package/dist/core/tools/apexUtils.d.ts +36 -0
- package/dist/core/tools/apexUtils.d.ts.map +1 -0
- package/dist/core/tools/apexUtils.js +83 -0
- package/dist/core/tools/apexUtils.js.map +1 -0
- package/dist/core/tools/explainIssue.d.ts +3 -0
- package/dist/core/tools/explainIssue.d.ts.map +1 -0
- package/dist/core/tools/explainIssue.js +181 -0
- package/dist/core/tools/explainIssue.js.map +1 -0
- package/dist/core/tools/fixGen.d.ts +3 -0
- package/dist/core/tools/fixGen.d.ts.map +1 -0
- package/dist/core/tools/fixGen.js +338 -0
- package/dist/core/tools/fixGen.js.map +1 -0
- package/dist/core/tools/generateImprovements.d.ts +21 -0
- package/dist/core/tools/generateImprovements.d.ts.map +1 -0
- package/dist/core/tools/generateImprovements.js +602 -0
- package/dist/core/tools/generateImprovements.js.map +1 -0
- package/dist/core/tools/generateReport.d.ts +3 -0
- package/dist/core/tools/generateReport.d.ts.map +1 -0
- package/dist/core/tools/generateReport.js +315 -0
- package/dist/core/tools/generateReport.js.map +1 -0
- package/dist/core/tools/index.d.ts +7 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +62 -23
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/recommendProfile.d.ts +3 -0
- package/dist/core/tools/recommendProfile.d.ts.map +1 -0
- package/dist/core/tools/recommendProfile.js +334 -0
- package/dist/core/tools/recommendProfile.js.map +1 -0
- package/dist/core/tools/ruleGen.d.ts +3 -0
- package/dist/core/tools/ruleGen.d.ts.map +1 -0
- package/dist/core/tools/ruleGen.js +1103 -0
- package/dist/core/tools/ruleGen.js.map +1 -0
- package/dist/core/tools/standards.d.ts.map +1 -1
- package/dist/core/tools/standards.js +7 -3
- package/dist/core/tools/standards.js.map +1 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +86 -35
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/InputBox.d.ts +1 -3
- package/dist/ui/components/InputBox.d.ts.map +1 -1
- package/dist/ui/components/InputBox.js +146 -5
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/MessageList.d.ts +3 -1
- package/dist/ui/components/MessageList.d.ts.map +1 -1
- package/dist/ui/components/MessageList.js +13 -7
- package/dist/ui/components/MessageList.js.map +1 -1
- package/dist/ui/components/StatusBar.d.ts +1 -1
- package/dist/ui/components/StatusBar.d.ts.map +1 -1
- package/dist/ui/components/StatusBar.js +3 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/ToolStatus.d.ts +3 -1
- package/dist/ui/components/ToolStatus.d.ts.map +1 -1
- package/dist/ui/components/ToolStatus.js +19 -4
- package/dist/ui/components/ToolStatus.js.map +1 -1
- package/package.json +7 -1
- package/demo.gif +0 -0
- package/demo.tape +0 -53
- package/screenshot.png +0 -0
- package/src/cli/banner.ts +0 -38
- package/src/cli/headless.ts +0 -63
- package/src/cli/index.ts +0 -57
- package/src/core/agent.ts +0 -711
- package/src/core/commands.ts +0 -118
- package/src/core/config.ts +0 -98
- package/src/core/conversation.ts +0 -235
- package/src/core/llm/ollama.ts +0 -351
- package/src/core/mcp/client.ts +0 -143
- package/src/core/tools/analyzeAll.ts +0 -482
- package/src/core/tools/ast.ts +0 -826
- package/src/core/tools/builtIn.ts +0 -221
- package/src/core/tools/cache.ts +0 -570
- package/src/core/tools/cssAnalysis.ts +0 -324
- package/src/core/tools/dependencyAnalysis.ts +0 -363
- package/src/core/tools/embeddings.ts +0 -746
- package/src/core/tools/frontendAst.ts +0 -802
- package/src/core/tools/htmlAnalysis.ts +0 -466
- package/src/core/tools/index.ts +0 -160
- package/src/core/tools/javaAst.ts +0 -1030
- package/src/core/tools/javaQuality.integration.test.ts +0 -537
- package/src/core/tools/memory.ts +0 -655
- package/src/core/tools/mybatisAnalysis.ts +0 -322
- package/src/core/tools/openapiAnalysis.ts +0 -431
- package/src/core/tools/pythonAnalysis.ts +0 -477
- package/src/core/tools/sqlAnalysis.ts +0 -298
- package/src/core/tools/standards.test.ts +0 -186
- package/src/core/tools/standards.ts +0 -889
- package/src/core/tools/types.ts +0 -38
- package/src/ui/App.tsx +0 -334
- package/src/ui/components/InputBox.tsx +0 -37
- package/src/ui/components/MessageList.tsx +0 -80
- package/src/ui/components/StatusBar.tsx +0 -36
- package/src/ui/components/ToolStatus.tsx +0 -38
- package/tsconfig.json +0 -21
package/src/core/tools/types.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export interface Tool {
|
|
2
|
-
name: string;
|
|
3
|
-
description: string;
|
|
4
|
-
parameters: {
|
|
5
|
-
type: "object";
|
|
6
|
-
required?: string[];
|
|
7
|
-
properties: Record<string, ToolParameter>;
|
|
8
|
-
};
|
|
9
|
-
handler: (args: Record<string, unknown>) => Promise<ToolResult>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ToolParameter {
|
|
13
|
-
type: string;
|
|
14
|
-
description: string;
|
|
15
|
-
enum?: string[];
|
|
16
|
-
default?: unknown;
|
|
17
|
-
items?: { type: string };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ToolCall {
|
|
21
|
-
id: string;
|
|
22
|
-
name: string;
|
|
23
|
-
arguments: Record<string, unknown>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ToolResult {
|
|
27
|
-
success: boolean;
|
|
28
|
-
content: string;
|
|
29
|
-
error?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface ToolEvent {
|
|
33
|
-
type: "tool_use";
|
|
34
|
-
tool: string;
|
|
35
|
-
status: "start" | "complete" | "error";
|
|
36
|
-
args?: Record<string, unknown>;
|
|
37
|
-
result?: ToolResult;
|
|
38
|
-
}
|
package/src/ui/App.tsx
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
2
|
-
import { Box, Text, useApp, useInput } from "ink";
|
|
3
|
-
import { Config } from "../core/config.js";
|
|
4
|
-
import { OllamaClient, ChatMessage } from "../core/llm/ollama.js";
|
|
5
|
-
import { streamProcessMessage, AgentEvent } from "../core/agent.js";
|
|
6
|
-
import { handleSlashCommand } from "../core/commands.js";
|
|
7
|
-
import { InputBox } from "./components/InputBox.js";
|
|
8
|
-
import { MessageList } from "./components/MessageList.js";
|
|
9
|
-
import { StatusBar } from "./components/StatusBar.js";
|
|
10
|
-
import { ToolStatus } from "./components/ToolStatus.js";
|
|
11
|
-
import {
|
|
12
|
-
createSession,
|
|
13
|
-
loadLatestSession,
|
|
14
|
-
saveSession,
|
|
15
|
-
getSessionContext,
|
|
16
|
-
cleanOldSessions,
|
|
17
|
-
} from "../core/conversation.js";
|
|
18
|
-
|
|
19
|
-
interface AppProps {
|
|
20
|
-
initialPrompt?: string;
|
|
21
|
-
config: Config;
|
|
22
|
-
resume?: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface Message {
|
|
26
|
-
role: "user" | "assistant";
|
|
27
|
-
content: string;
|
|
28
|
-
toolCalls?: Array<{
|
|
29
|
-
tool: string;
|
|
30
|
-
status: "running" | "complete" | "error";
|
|
31
|
-
result?: string;
|
|
32
|
-
}>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function App({ initialPrompt, config, resume }: AppProps): React.ReactElement {
|
|
36
|
-
const { exit } = useApp();
|
|
37
|
-
const [messages, setMessages] = useState<Message[]>([]);
|
|
38
|
-
const [input, setInput] = useState("");
|
|
39
|
-
const [isProcessing, setIsProcessing] = useState(false);
|
|
40
|
-
const [currentTool, setCurrentTool] = useState<string | null>(null);
|
|
41
|
-
const [toolStatus, setToolStatus] = useState<"running" | "complete" | "error" | null>(null);
|
|
42
|
-
const [error, setError] = useState<string | null>(null);
|
|
43
|
-
const [client] = useState(() => new OllamaClient(config.ollama));
|
|
44
|
-
const [currentModel, setCurrentModel] = useState(config.ollama.model);
|
|
45
|
-
const [exitPending, setExitPending] = useState(false);
|
|
46
|
-
const [cancelled, setCancelled] = useState(false);
|
|
47
|
-
const abortControllerRef = useRef<AbortController | null>(null);
|
|
48
|
-
|
|
49
|
-
// Session management
|
|
50
|
-
const [session, setSession] = useState(() => createSession());
|
|
51
|
-
const [contextSummary, setContextSummary] = useState<string>("");
|
|
52
|
-
|
|
53
|
-
// Handle Ctrl+C and ESC
|
|
54
|
-
useInput((inputChar, key) => {
|
|
55
|
-
// ESC key to cancel current operation
|
|
56
|
-
if (key.escape && isProcessing) {
|
|
57
|
-
if (abortControllerRef.current) {
|
|
58
|
-
abortControllerRef.current.abort();
|
|
59
|
-
setCancelled(true);
|
|
60
|
-
setIsProcessing(false);
|
|
61
|
-
setCurrentTool(null);
|
|
62
|
-
setToolStatus(null);
|
|
63
|
-
setError("Operation cancelled by user (ESC)");
|
|
64
|
-
}
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Ctrl+C to exit
|
|
69
|
-
if (key.ctrl && inputChar === "c") {
|
|
70
|
-
if (isProcessing && abortControllerRef.current) {
|
|
71
|
-
abortControllerRef.current.abort();
|
|
72
|
-
setCancelled(true);
|
|
73
|
-
setIsProcessing(false);
|
|
74
|
-
setCurrentTool(null);
|
|
75
|
-
setToolStatus(null);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (exitPending) {
|
|
79
|
-
exit();
|
|
80
|
-
} else {
|
|
81
|
-
setExitPending(true);
|
|
82
|
-
setTimeout(() => setExitPending(false), 1000);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Check Ollama connection on mount
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
const checkConnection = async () => {
|
|
90
|
-
const connected = await client.isConnected();
|
|
91
|
-
if (!connected) {
|
|
92
|
-
setError(`Cannot connect to Ollama at ${config.ollama.baseUrl}`);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
checkConnection();
|
|
96
|
-
}, [client, config.ollama.baseUrl]);
|
|
97
|
-
|
|
98
|
-
// Load previous session context on mount (if resume)
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
const loadContext = async () => {
|
|
101
|
-
if (resume) {
|
|
102
|
-
try {
|
|
103
|
-
const { summary, recentMessages } = await getSessionContext(client, 5);
|
|
104
|
-
if (summary) {
|
|
105
|
-
setContextSummary(summary);
|
|
106
|
-
}
|
|
107
|
-
// Optionally load recent messages to display
|
|
108
|
-
if (recentMessages.length > 0) {
|
|
109
|
-
const displayMessages: Message[] = recentMessages
|
|
110
|
-
.filter(m => m.role === "user" || m.role === "assistant")
|
|
111
|
-
.map(m => ({
|
|
112
|
-
role: m.role as "user" | "assistant",
|
|
113
|
-
content: m.content,
|
|
114
|
-
}));
|
|
115
|
-
setMessages(displayMessages);
|
|
116
|
-
}
|
|
117
|
-
} catch {
|
|
118
|
-
// Ignore context loading errors
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
// Clean old sessions
|
|
122
|
-
cleanOldSessions(10);
|
|
123
|
-
};
|
|
124
|
-
loadContext();
|
|
125
|
-
}, [resume, client]);
|
|
126
|
-
|
|
127
|
-
// Process initial prompt
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
if (initialPrompt) {
|
|
130
|
-
handleSubmit(initialPrompt);
|
|
131
|
-
}
|
|
132
|
-
}, [initialPrompt]);
|
|
133
|
-
|
|
134
|
-
const handleSubmit = useCallback(async (text: string) => {
|
|
135
|
-
if (!text.trim() || isProcessing) return;
|
|
136
|
-
|
|
137
|
-
setInput("");
|
|
138
|
-
setError(null);
|
|
139
|
-
|
|
140
|
-
// Handle slash commands first
|
|
141
|
-
if (text.startsWith("/")) {
|
|
142
|
-
const result = handleSlashCommand(text, config);
|
|
143
|
-
if (result) {
|
|
144
|
-
// Add command as user message
|
|
145
|
-
setMessages((prev) => [...prev, { role: "user", content: text }]);
|
|
146
|
-
|
|
147
|
-
if (result.exit) {
|
|
148
|
-
const exitMsg: Message = { role: "assistant", content: result.output || "Goodbye!" };
|
|
149
|
-
setMessages((prev) => [...prev, exitMsg]);
|
|
150
|
-
setTimeout(() => exit(), 500);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (result.clear) {
|
|
155
|
-
setMessages([]);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (result.changeModel) {
|
|
160
|
-
setCurrentModel(result.changeModel);
|
|
161
|
-
client.setModel(result.changeModel);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (result.output) {
|
|
165
|
-
const outputMsg: Message = { role: "assistant", content: result.output };
|
|
166
|
-
setMessages((prev) => [...prev, outputMsg]);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
setIsProcessing(true);
|
|
174
|
-
setCancelled(false);
|
|
175
|
-
|
|
176
|
-
// Create AbortController for this request
|
|
177
|
-
const abortController = new AbortController();
|
|
178
|
-
abortControllerRef.current = abortController;
|
|
179
|
-
|
|
180
|
-
// Add user message
|
|
181
|
-
const userMessage: Message = { role: "user", content: text };
|
|
182
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
183
|
-
|
|
184
|
-
// Convert messages to chat format
|
|
185
|
-
const history: ChatMessage[] = messages.map((m) => ({
|
|
186
|
-
role: m.role,
|
|
187
|
-
content: m.content,
|
|
188
|
-
}));
|
|
189
|
-
|
|
190
|
-
// Create assistant message placeholder
|
|
191
|
-
const assistantMessage: Message = { role: "assistant", content: "", toolCalls: [] };
|
|
192
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
let fullContent = "";
|
|
196
|
-
|
|
197
|
-
for await (const event of streamProcessMessage(text, history, client, config, abortController.signal, contextSummary)) {
|
|
198
|
-
// Check if cancelled
|
|
199
|
-
if (abortController.signal.aborted) {
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
switch (event.type) {
|
|
203
|
-
case "content":
|
|
204
|
-
fullContent += event.content || "";
|
|
205
|
-
setMessages((prev) => {
|
|
206
|
-
const updated = [...prev];
|
|
207
|
-
const last = updated[updated.length - 1];
|
|
208
|
-
if (last.role === "assistant") {
|
|
209
|
-
last.content = fullContent;
|
|
210
|
-
}
|
|
211
|
-
return updated;
|
|
212
|
-
});
|
|
213
|
-
break;
|
|
214
|
-
|
|
215
|
-
case "tool_use":
|
|
216
|
-
setCurrentTool(event.tool || null);
|
|
217
|
-
setToolStatus("running");
|
|
218
|
-
setMessages((prev) => {
|
|
219
|
-
const updated = [...prev];
|
|
220
|
-
const last = updated[updated.length - 1];
|
|
221
|
-
if (last.role === "assistant") {
|
|
222
|
-
last.toolCalls = [
|
|
223
|
-
...(last.toolCalls || []),
|
|
224
|
-
{ tool: event.tool!, status: "running" },
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
return updated;
|
|
228
|
-
});
|
|
229
|
-
break;
|
|
230
|
-
|
|
231
|
-
case "tool_result":
|
|
232
|
-
setToolStatus(event.status as "complete" | "error");
|
|
233
|
-
setMessages((prev) => {
|
|
234
|
-
const updated = [...prev];
|
|
235
|
-
const last = updated[updated.length - 1];
|
|
236
|
-
if (last.role === "assistant" && last.toolCalls) {
|
|
237
|
-
const toolCall = last.toolCalls.find((tc) => tc.tool === event.tool);
|
|
238
|
-
if (toolCall) {
|
|
239
|
-
toolCall.status = event.status as "complete" | "error";
|
|
240
|
-
toolCall.result = event.result?.content || event.result?.error;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return updated;
|
|
244
|
-
});
|
|
245
|
-
setTimeout(() => {
|
|
246
|
-
setCurrentTool(null);
|
|
247
|
-
setToolStatus(null);
|
|
248
|
-
}, 500);
|
|
249
|
-
break;
|
|
250
|
-
|
|
251
|
-
case "error":
|
|
252
|
-
setError(event.error || "Unknown error");
|
|
253
|
-
break;
|
|
254
|
-
|
|
255
|
-
case "done":
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
} catch (err) {
|
|
260
|
-
if (!abortController.signal.aborted) {
|
|
261
|
-
setError(String(err));
|
|
262
|
-
}
|
|
263
|
-
} finally {
|
|
264
|
-
setIsProcessing(false);
|
|
265
|
-
setCurrentTool(null);
|
|
266
|
-
setToolStatus(null);
|
|
267
|
-
abortControllerRef.current = null;
|
|
268
|
-
|
|
269
|
-
// Save conversation to session
|
|
270
|
-
setSession((prevSession) => {
|
|
271
|
-
const updatedSession = { ...prevSession };
|
|
272
|
-
// Add user message
|
|
273
|
-
updatedSession.messages.push({ role: "user", content: text });
|
|
274
|
-
// Add assistant message (get from current messages state)
|
|
275
|
-
setMessages((currentMessages) => {
|
|
276
|
-
const lastMessage = currentMessages[currentMessages.length - 1];
|
|
277
|
-
if (lastMessage?.role === "assistant") {
|
|
278
|
-
updatedSession.messages.push({
|
|
279
|
-
role: "assistant",
|
|
280
|
-
content: lastMessage.content,
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
return currentMessages;
|
|
284
|
-
});
|
|
285
|
-
saveSession(updatedSession);
|
|
286
|
-
return updatedSession;
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}, [messages, client, config, isProcessing, contextSummary]);
|
|
290
|
-
|
|
291
|
-
return (
|
|
292
|
-
<Box flexDirection="column" height="100%">
|
|
293
|
-
{/* Messages */}
|
|
294
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
295
|
-
<MessageList messages={messages} />
|
|
296
|
-
</Box>
|
|
297
|
-
|
|
298
|
-
{/* Tool Status */}
|
|
299
|
-
{currentTool && (
|
|
300
|
-
<ToolStatus tool={currentTool} status={toolStatus || "running"} />
|
|
301
|
-
)}
|
|
302
|
-
|
|
303
|
-
{/* Error */}
|
|
304
|
-
{error && (
|
|
305
|
-
<Box marginY={1}>
|
|
306
|
-
<Text color="red">⚠ {error}</Text>
|
|
307
|
-
</Box>
|
|
308
|
-
)}
|
|
309
|
-
|
|
310
|
-
{/* Exit Warning */}
|
|
311
|
-
{exitPending && (
|
|
312
|
-
<Box marginY={1}>
|
|
313
|
-
<Text color="yellow">Press Ctrl+C again to exit</Text>
|
|
314
|
-
</Box>
|
|
315
|
-
)}
|
|
316
|
-
|
|
317
|
-
{/* Input */}
|
|
318
|
-
<InputBox
|
|
319
|
-
value={input}
|
|
320
|
-
onChange={setInput}
|
|
321
|
-
onSubmit={handleSubmit}
|
|
322
|
-
isProcessing={isProcessing}
|
|
323
|
-
placeholder="Type your message..."
|
|
324
|
-
/>
|
|
325
|
-
|
|
326
|
-
{/* Status Bar */}
|
|
327
|
-
<StatusBar
|
|
328
|
-
model={currentModel}
|
|
329
|
-
isProcessing={isProcessing}
|
|
330
|
-
messageCount={messages.length}
|
|
331
|
-
/>
|
|
332
|
-
</Box>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
import TextInput from "ink-text-input";
|
|
4
|
-
|
|
5
|
-
interface InputBoxProps {
|
|
6
|
-
value: string;
|
|
7
|
-
onChange: (value: string) => void;
|
|
8
|
-
onSubmit: (value: string) => void;
|
|
9
|
-
isProcessing: boolean;
|
|
10
|
-
placeholder?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function InputBox({
|
|
14
|
-
value,
|
|
15
|
-
onChange,
|
|
16
|
-
onSubmit,
|
|
17
|
-
isProcessing,
|
|
18
|
-
placeholder,
|
|
19
|
-
}: InputBoxProps): React.ReactElement {
|
|
20
|
-
return (
|
|
21
|
-
<Box borderStyle="round" borderColor={isProcessing ? "gray" : "cyan"} paddingX={1}>
|
|
22
|
-
<Text color="green" bold>
|
|
23
|
-
{isProcessing ? "⏳" : "❯"}{" "}
|
|
24
|
-
</Text>
|
|
25
|
-
{isProcessing ? (
|
|
26
|
-
<Text color="gray">Processing...</Text>
|
|
27
|
-
) : (
|
|
28
|
-
<TextInput
|
|
29
|
-
value={value}
|
|
30
|
-
onChange={onChange}
|
|
31
|
-
onSubmit={onSubmit}
|
|
32
|
-
placeholder={placeholder}
|
|
33
|
-
/>
|
|
34
|
-
)}
|
|
35
|
-
</Box>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
|
|
4
|
-
interface ToolCall {
|
|
5
|
-
tool: string;
|
|
6
|
-
status: "running" | "complete" | "error";
|
|
7
|
-
result?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface Message {
|
|
11
|
-
role: "user" | "assistant";
|
|
12
|
-
content: string;
|
|
13
|
-
toolCalls?: ToolCall[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface MessageListProps {
|
|
17
|
-
messages: Message[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function MessageList({ messages }: MessageListProps): React.ReactElement {
|
|
21
|
-
if (messages.length === 0) {
|
|
22
|
-
return (
|
|
23
|
-
<Box marginY={1}>
|
|
24
|
-
<Text color="gray">Start a conversation by typing below...</Text>
|
|
25
|
-
</Box>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<Box flexDirection="column">
|
|
31
|
-
{messages.map((message, index) => (
|
|
32
|
-
<MessageItem key={index} message={message} />
|
|
33
|
-
))}
|
|
34
|
-
</Box>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function MessageItem({ message }: { message: Message }): React.ReactElement {
|
|
39
|
-
const isUser = message.role === "user";
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Box flexDirection="column" marginY={1}>
|
|
43
|
-
{/* Role indicator */}
|
|
44
|
-
<Box>
|
|
45
|
-
<Text color={isUser ? "green" : "cyan"} bold>
|
|
46
|
-
{isUser ? "You" : "ACTIVO"}
|
|
47
|
-
</Text>
|
|
48
|
-
</Box>
|
|
49
|
-
|
|
50
|
-
{/* Tool calls */}
|
|
51
|
-
{message.toolCalls && message.toolCalls.length > 0 && (
|
|
52
|
-
<Box flexDirection="column" marginLeft={2} marginY={1}>
|
|
53
|
-
{message.toolCalls.map((tc, idx) => (
|
|
54
|
-
<Box key={idx}>
|
|
55
|
-
<Text color="gray">
|
|
56
|
-
{tc.status === "running" ? "🔄" : tc.status === "complete" ? "✓" : "✗"}{" "}
|
|
57
|
-
</Text>
|
|
58
|
-
<Text color={tc.status === "error" ? "red" : "yellow"}>{tc.tool}</Text>
|
|
59
|
-
{tc.status === "complete" && tc.result && (
|
|
60
|
-
<Text color="gray"> - {truncate(tc.result, 50)}</Text>
|
|
61
|
-
)}
|
|
62
|
-
</Box>
|
|
63
|
-
))}
|
|
64
|
-
</Box>
|
|
65
|
-
)}
|
|
66
|
-
|
|
67
|
-
{/* Content */}
|
|
68
|
-
{message.content && (
|
|
69
|
-
<Box marginLeft={2}>
|
|
70
|
-
<Text wrap="wrap">{message.content}</Text>
|
|
71
|
-
</Box>
|
|
72
|
-
)}
|
|
73
|
-
</Box>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function truncate(text: string, maxLength: number): string {
|
|
78
|
-
if (text.length <= maxLength) return text;
|
|
79
|
-
return text.slice(0, maxLength) + "...";
|
|
80
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
|
|
4
|
-
interface StatusBarProps {
|
|
5
|
-
model: string;
|
|
6
|
-
isProcessing: boolean;
|
|
7
|
-
messageCount: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function StatusBar({
|
|
11
|
-
model,
|
|
12
|
-
isProcessing,
|
|
13
|
-
messageCount,
|
|
14
|
-
}: StatusBarProps): React.ReactElement {
|
|
15
|
-
return (
|
|
16
|
-
<Box justifyContent="space-between" paddingX={1} marginTop={1}>
|
|
17
|
-
<Box>
|
|
18
|
-
<Text color="gray">Model: </Text>
|
|
19
|
-
<Text color="cyan">{model}</Text>
|
|
20
|
-
</Box>
|
|
21
|
-
|
|
22
|
-
<Box>
|
|
23
|
-
<Text color="gray">Messages: </Text>
|
|
24
|
-
<Text color="white">{messageCount}</Text>
|
|
25
|
-
</Box>
|
|
26
|
-
|
|
27
|
-
<Box>
|
|
28
|
-
{isProcessing ? (
|
|
29
|
-
<Text color="yellow">● Processing</Text>
|
|
30
|
-
) : (
|
|
31
|
-
<Text color="green">● Ready</Text>
|
|
32
|
-
)}
|
|
33
|
-
</Box>
|
|
34
|
-
</Box>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
3
|
-
import Spinner from "ink-spinner";
|
|
4
|
-
|
|
5
|
-
interface ToolStatusProps {
|
|
6
|
-
tool: string;
|
|
7
|
-
status: "running" | "complete" | "error";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function ToolStatus({ tool, status }: ToolStatusProps): React.ReactElement {
|
|
11
|
-
return (
|
|
12
|
-
<Box marginY={1} paddingX={1}>
|
|
13
|
-
{status === "running" ? (
|
|
14
|
-
<>
|
|
15
|
-
<Text color="cyan">
|
|
16
|
-
<Spinner type="dots" />
|
|
17
|
-
</Text>
|
|
18
|
-
<Text color="cyan"> Using tool: </Text>
|
|
19
|
-
<Text color="yellow" bold>
|
|
20
|
-
{tool}
|
|
21
|
-
</Text>
|
|
22
|
-
</>
|
|
23
|
-
) : status === "complete" ? (
|
|
24
|
-
<>
|
|
25
|
-
<Text color="green">✓ </Text>
|
|
26
|
-
<Text color="gray">Tool completed: </Text>
|
|
27
|
-
<Text color="white">{tool}</Text>
|
|
28
|
-
</>
|
|
29
|
-
) : (
|
|
30
|
-
<>
|
|
31
|
-
<Text color="red">✗ </Text>
|
|
32
|
-
<Text color="gray">Tool failed: </Text>
|
|
33
|
-
<Text color="red">{tool}</Text>
|
|
34
|
-
</>
|
|
35
|
-
)}
|
|
36
|
-
</Box>
|
|
37
|
-
);
|
|
38
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": ["ES2022"],
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"declarationMap": true,
|
|
15
|
-
"sourceMap": true,
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"jsx": "react-jsx"
|
|
18
|
-
},
|
|
19
|
-
"include": ["src/**/*"],
|
|
20
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
21
|
-
}
|