agentk8 2.1.4 → 2.2.1
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/cli.js +1 -1
- package/dist/components/AgentPanel.d.ts +10 -0
- package/dist/components/AgentPanel.js +56 -0
- package/dist/components/AgentStatus.d.ts +13 -0
- package/dist/components/AgentStatus.js +39 -0
- package/dist/components/App.js +148 -7
- package/dist/components/ChatMessage.d.ts +1 -1
- package/dist/components/ChatMessage.js +3 -1
- package/dist/components/Input.js +12 -19
- package/dist/components/StatusBar.d.ts +3 -0
- package/dist/components/StatusBar.js +33 -10
- package/dist/components/WelcomeBox.d.ts +7 -0
- package/dist/components/WelcomeBox.js +27 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +3 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type AgentName = 'Orchestrator' | 'Engineer' | 'Tester' | 'Security' | 'Scout' | 'Researcher' | 'ML Engineer' | 'Data Engineer' | 'Evaluator';
|
|
3
|
+
export type AgentState = 'idle' | 'active' | 'done';
|
|
4
|
+
interface AgentPanelProps {
|
|
5
|
+
mode: 'dev' | 'ml';
|
|
6
|
+
activeAgent?: AgentName;
|
|
7
|
+
completedAgents: AgentName[];
|
|
8
|
+
}
|
|
9
|
+
export declare const AgentPanel: React.FC<AgentPanelProps>;
|
|
10
|
+
export default AgentPanel;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
const theme = {
|
|
5
|
+
border: '#2d3748',
|
|
6
|
+
accent: '#4fd1c5',
|
|
7
|
+
highlight: '#81e6d9',
|
|
8
|
+
dim: '#4a5568',
|
|
9
|
+
success: '#48bb78',
|
|
10
|
+
active: '#f6e05e',
|
|
11
|
+
};
|
|
12
|
+
// Animated border characters
|
|
13
|
+
const borderFrames = ['◢', '◣', '◤', '◥'];
|
|
14
|
+
const pulseChars = ['░', '▒', '▓', '█', '▓', '▒'];
|
|
15
|
+
const AgentBox = ({ name, icon, state, width }) => {
|
|
16
|
+
const [frame, setFrame] = useState(0);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (state !== 'active')
|
|
19
|
+
return;
|
|
20
|
+
const interval = setInterval(() => {
|
|
21
|
+
setFrame(f => (f + 1) % borderFrames.length);
|
|
22
|
+
}, 150);
|
|
23
|
+
return () => clearInterval(interval);
|
|
24
|
+
}, [state]);
|
|
25
|
+
const borderColor = state === 'active' ? theme.active : state === 'done' ? theme.success : theme.border;
|
|
26
|
+
const textColor = state === 'active' ? theme.highlight : state === 'done' ? theme.success : theme.dim;
|
|
27
|
+
const corner = state === 'active' ? borderFrames[frame] : state === 'done' ? '✓' : '○';
|
|
28
|
+
const innerWidth = width - 4;
|
|
29
|
+
const paddedName = name.length > innerWidth ? name.slice(0, innerWidth) : name.padEnd(innerWidth);
|
|
30
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: borderColor, children: corner }), _jsx(Text, { color: borderColor, children: '─'.repeat(width - 2) }), _jsx(Text, { color: borderColor, children: corner })] }), _jsxs(Box, { children: [_jsx(Text, { color: borderColor, children: "\u2502" }), _jsxs(Text, { color: textColor, children: [" ", icon, " "] }), _jsx(Text, { color: textColor, children: paddedName }), _jsx(Text, { color: borderColor, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: borderColor, children: state === 'active' ? borderFrames[(frame + 2) % 4] : '└' }), _jsx(Text, { color: borderColor, children: '─'.repeat(width - 2) }), _jsx(Text, { color: borderColor, children: state === 'active' ? borderFrames[(frame + 2) % 4] : '┘' })] })] }));
|
|
31
|
+
};
|
|
32
|
+
export const AgentPanel = ({ mode, activeAgent, completedAgents }) => {
|
|
33
|
+
const devAgents = [
|
|
34
|
+
{ name: 'Orchestrator', icon: '◆' },
|
|
35
|
+
{ name: 'Engineer', icon: '⚙' },
|
|
36
|
+
{ name: 'Tester', icon: '✓' },
|
|
37
|
+
{ name: 'Security', icon: '⛨' },
|
|
38
|
+
];
|
|
39
|
+
const mlAgents = [
|
|
40
|
+
{ name: 'Orchestrator', icon: '◆' },
|
|
41
|
+
{ name: 'Researcher', icon: '◈' },
|
|
42
|
+
{ name: 'ML Engineer', icon: '⬡' },
|
|
43
|
+
{ name: 'Evaluator', icon: '◉' },
|
|
44
|
+
];
|
|
45
|
+
const agents = mode === 'dev' ? devAgents : mlAgents;
|
|
46
|
+
const boxWidth = 16;
|
|
47
|
+
const getState = (name) => {
|
|
48
|
+
if (activeAgent === name)
|
|
49
|
+
return 'active';
|
|
50
|
+
if (completedAgents.includes(name))
|
|
51
|
+
return 'done';
|
|
52
|
+
return 'idle';
|
|
53
|
+
};
|
|
54
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { justifyContent: "center", children: [_jsx(Text, { color: theme.dim, children: "\u2500\u2500\u2500 " }), _jsx(Text, { color: theme.accent, children: "Agents" }), _jsx(Text, { color: theme.dim, children: " \u2500\u2500\u2500" })] }), _jsx(Box, { justifyContent: "center", marginTop: 1, children: agents.map((agent, i) => (_jsx(Box, { marginRight: i < agents.length - 1 ? 1 : 0, children: _jsx(AgentBox, { name: agent.name, icon: agent.icon, state: getState(agent.name), width: boxWidth }) }, agent.name))) })] }));
|
|
55
|
+
};
|
|
56
|
+
export default AgentPanel;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type AgentName = 'Orchestrator' | 'Engineer' | 'Tester' | 'Security' | 'Scout' | 'Researcher' | 'ML Engineer' | 'Data Engineer' | 'Evaluator';
|
|
3
|
+
export type AgentState = 'idle' | 'thinking' | 'working' | 'done';
|
|
4
|
+
interface Agent {
|
|
5
|
+
name: AgentName;
|
|
6
|
+
state: AgentState;
|
|
7
|
+
}
|
|
8
|
+
interface AgentStatusProps {
|
|
9
|
+
agents: Agent[];
|
|
10
|
+
mode: 'dev' | 'ml';
|
|
11
|
+
}
|
|
12
|
+
export declare const AgentStatus: React.FC<AgentStatusProps>;
|
|
13
|
+
export default AgentStatus;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
const theme = {
|
|
4
|
+
accent: '#4fd1c5',
|
|
5
|
+
highlight: '#81e6d9',
|
|
6
|
+
dim: '#4a5568',
|
|
7
|
+
border: '#2d3748',
|
|
8
|
+
success: '#48bb78',
|
|
9
|
+
warning: '#ecc94b',
|
|
10
|
+
};
|
|
11
|
+
const agentIcons = {
|
|
12
|
+
Orchestrator: '◆',
|
|
13
|
+
Engineer: '⚙',
|
|
14
|
+
Tester: '✓',
|
|
15
|
+
Security: '⛨',
|
|
16
|
+
Scout: '◎',
|
|
17
|
+
Researcher: '◈',
|
|
18
|
+
'ML Engineer': '⬡',
|
|
19
|
+
'Data Engineer': '⬢',
|
|
20
|
+
Evaluator: '◉',
|
|
21
|
+
};
|
|
22
|
+
const stateColors = {
|
|
23
|
+
idle: theme.dim,
|
|
24
|
+
thinking: theme.warning,
|
|
25
|
+
working: theme.accent,
|
|
26
|
+
done: theme.success,
|
|
27
|
+
};
|
|
28
|
+
const stateIndicators = {
|
|
29
|
+
idle: '○',
|
|
30
|
+
thinking: '◐',
|
|
31
|
+
working: '●',
|
|
32
|
+
done: '✓',
|
|
33
|
+
};
|
|
34
|
+
export const AgentStatus = ({ agents, mode }) => {
|
|
35
|
+
if (agents.length === 0)
|
|
36
|
+
return null;
|
|
37
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, marginLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: theme.dim, children: "\u250C\u2500 " }), _jsx(Text, { color: theme.accent, children: "Active Agents" }), _jsx(Text, { color: theme.dim, children: " \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" })] }), agents.map((agent, i) => (_jsxs(Box, { marginLeft: 1, children: [_jsx(Text, { color: theme.dim, children: "\u2502 " }), _jsxs(Text, { color: stateColors[agent.state], children: [stateIndicators[agent.state], " "] }), _jsxs(Text, { color: theme.highlight, children: [agentIcons[agent.name], " "] }), _jsx(Text, { color: agent.state === 'idle' ? theme.dim : theme.highlight, children: agent.name }), agent.state !== 'idle' && agent.state !== 'done' && (_jsxs(Text, { color: theme.dim, children: [" ", agent.state, "..."] }))] }, agent.name))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.dim, children: "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) })] }));
|
|
38
|
+
};
|
|
39
|
+
export default AgentStatus;
|
package/dist/components/App.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useApp, useInput, Static } from 'ink';
|
|
4
|
-
import {
|
|
4
|
+
import { WelcomeBox } from './WelcomeBox.js';
|
|
5
5
|
import { ChatMessage } from './ChatMessage.js';
|
|
6
6
|
import { Input } from './Input.js';
|
|
7
7
|
import { StatusBar } from './StatusBar.js';
|
|
@@ -15,6 +15,24 @@ export const App = ({ mode, version }) => {
|
|
|
15
15
|
const [totalTokens, setTotalTokens] = useState(0);
|
|
16
16
|
const [startTime] = useState(new Date());
|
|
17
17
|
const [error, setError] = useState(null);
|
|
18
|
+
const [executionMode, setExecutionMode] = useState('plan');
|
|
19
|
+
const [activeAgent, setActiveAgent] = useState(undefined);
|
|
20
|
+
const [completedAgents, setCompletedAgents] = useState([]);
|
|
21
|
+
const [pendingPlan, setPendingPlan] = useState(null);
|
|
22
|
+
const [awaitingApproval, setAwaitingApproval] = useState(false);
|
|
23
|
+
// Detect agents mentioned in response
|
|
24
|
+
const detectMentionedAgents = (content) => {
|
|
25
|
+
const agents = [];
|
|
26
|
+
const devAgents = ['Engineer', 'Tester', 'Security', 'Scout'];
|
|
27
|
+
const mlAgents = ['Researcher', 'ML Engineer', 'Data Engineer', 'Evaluator'];
|
|
28
|
+
const relevantAgents = mode === 'dev' ? devAgents : mlAgents;
|
|
29
|
+
for (const agent of relevantAgents) {
|
|
30
|
+
if (content.toLowerCase().includes(agent.toLowerCase())) {
|
|
31
|
+
agents.push(agent);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return agents;
|
|
35
|
+
};
|
|
18
36
|
// Handle input submission
|
|
19
37
|
const handleSubmit = async (input) => {
|
|
20
38
|
// Check for commands
|
|
@@ -22,6 +40,23 @@ export const App = ({ mode, version }) => {
|
|
|
22
40
|
handleCommand(input);
|
|
23
41
|
return;
|
|
24
42
|
}
|
|
43
|
+
// Handle approval response
|
|
44
|
+
if (awaitingApproval) {
|
|
45
|
+
if (input.toLowerCase() === 'y' || input.toLowerCase() === 'yes') {
|
|
46
|
+
setAwaitingApproval(false);
|
|
47
|
+
if (pendingPlan) {
|
|
48
|
+
await executeTask(pendingPlan);
|
|
49
|
+
setPendingPlan(null);
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
else if (input.toLowerCase() === 'n' || input.toLowerCase() === 'no') {
|
|
54
|
+
setAwaitingApproval(false);
|
|
55
|
+
setPendingPlan(null);
|
|
56
|
+
addSystemMessage('Plan cancelled. What would you like to do instead?');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
25
60
|
// Add user message
|
|
26
61
|
const userMessage = {
|
|
27
62
|
id: Date.now().toString(),
|
|
@@ -30,13 +65,71 @@ export const App = ({ mode, version }) => {
|
|
|
30
65
|
timestamp: new Date(),
|
|
31
66
|
};
|
|
32
67
|
setMessages(prev => [...prev, userMessage]);
|
|
68
|
+
if (executionMode === 'plan') {
|
|
69
|
+
await generatePlan(input);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
await executeTask(input);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
// Generate a plan for approval
|
|
76
|
+
const generatePlan = async (input) => {
|
|
33
77
|
setIsProcessing(true);
|
|
34
78
|
setProcessingStartTime(new Date());
|
|
79
|
+
setActiveAgent('Orchestrator');
|
|
80
|
+
setError(null);
|
|
81
|
+
try {
|
|
82
|
+
const planPrompt = `Analyze this request and create a detailed execution plan. Do NOT execute yet - just analyze and plan.
|
|
83
|
+
|
|
84
|
+
Request: ${input}
|
|
85
|
+
|
|
86
|
+
Respond with:
|
|
87
|
+
1. Task Analysis (complexity, scope)
|
|
88
|
+
2. Agents Required (list which specialists are needed)
|
|
89
|
+
3. Step-by-Step Plan (numbered steps)
|
|
90
|
+
4. Questions (if any clarification needed)
|
|
91
|
+
|
|
92
|
+
Format your response clearly with headers.`;
|
|
93
|
+
const result = await runClaude(planPrompt, mode);
|
|
94
|
+
const mentioned = detectMentionedAgents(result.response);
|
|
95
|
+
setCompletedAgents(['Orchestrator', ...mentioned]);
|
|
96
|
+
setActiveAgent(undefined);
|
|
97
|
+
const planMessage = {
|
|
98
|
+
id: (Date.now() + 1).toString(),
|
|
99
|
+
role: 'agent',
|
|
100
|
+
agentName: 'Orchestrator',
|
|
101
|
+
content: result.response,
|
|
102
|
+
tokens: result.tokens,
|
|
103
|
+
timestamp: new Date(),
|
|
104
|
+
};
|
|
105
|
+
setMessages(prev => [...prev, planMessage]);
|
|
106
|
+
if (result.tokens) {
|
|
107
|
+
setTotalTokens(prev => prev + result.tokens.input + result.tokens.output);
|
|
108
|
+
}
|
|
109
|
+
setPendingPlan(input);
|
|
110
|
+
setAwaitingApproval(true);
|
|
111
|
+
addSystemMessage('Execute this plan? (y/n)');
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
setIsProcessing(false);
|
|
118
|
+
setProcessingStartTime(null);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
// Execute task directly
|
|
122
|
+
const executeTask = async (input) => {
|
|
123
|
+
setIsProcessing(true);
|
|
124
|
+
setProcessingStartTime(new Date());
|
|
125
|
+
setActiveAgent('Orchestrator');
|
|
126
|
+
setCompletedAgents([]);
|
|
35
127
|
setError(null);
|
|
36
128
|
try {
|
|
37
|
-
// Call Claude
|
|
38
129
|
const result = await runClaude(input, mode);
|
|
39
|
-
|
|
130
|
+
const mentioned = detectMentionedAgents(result.response);
|
|
131
|
+
setCompletedAgents(['Orchestrator', ...mentioned]);
|
|
132
|
+
setActiveAgent(undefined);
|
|
40
133
|
const agentMessage = {
|
|
41
134
|
id: (Date.now() + 1).toString(),
|
|
42
135
|
role: 'agent',
|
|
@@ -46,7 +139,6 @@ export const App = ({ mode, version }) => {
|
|
|
46
139
|
timestamp: new Date(),
|
|
47
140
|
};
|
|
48
141
|
setMessages(prev => [...prev, agentMessage]);
|
|
49
|
-
// Update token count
|
|
50
142
|
if (result.tokens) {
|
|
51
143
|
setTotalTokens(prev => prev + result.tokens.input + result.tokens.output);
|
|
52
144
|
}
|
|
@@ -59,6 +151,17 @@ export const App = ({ mode, version }) => {
|
|
|
59
151
|
setProcessingStartTime(null);
|
|
60
152
|
}
|
|
61
153
|
};
|
|
154
|
+
// Add system message helper
|
|
155
|
+
const addSystemMessage = (content) => {
|
|
156
|
+
const msg = {
|
|
157
|
+
id: Date.now().toString(),
|
|
158
|
+
role: 'system',
|
|
159
|
+
agentName: 'System',
|
|
160
|
+
content,
|
|
161
|
+
timestamp: new Date(),
|
|
162
|
+
};
|
|
163
|
+
setMessages(prev => [...prev, msg]);
|
|
164
|
+
};
|
|
62
165
|
// Handle slash commands
|
|
63
166
|
const handleCommand = (cmd) => {
|
|
64
167
|
const [command] = cmd.slice(1).split(' ');
|
|
@@ -69,6 +172,29 @@ export const App = ({ mode, version }) => {
|
|
|
69
172
|
break;
|
|
70
173
|
case 'clear':
|
|
71
174
|
setMessages([]);
|
|
175
|
+
setActiveAgent(undefined);
|
|
176
|
+
setCompletedAgents([]);
|
|
177
|
+
break;
|
|
178
|
+
case 'plan':
|
|
179
|
+
setExecutionMode('plan');
|
|
180
|
+
addSystemMessage('Plan mode enabled. I will show plans for approval before executing.');
|
|
181
|
+
break;
|
|
182
|
+
case 'auto':
|
|
183
|
+
setExecutionMode('auto');
|
|
184
|
+
addSystemMessage('Auto mode enabled. I will execute tasks directly without approval.');
|
|
185
|
+
break;
|
|
186
|
+
case 'mode':
|
|
187
|
+
addSystemMessage(`Current execution mode: ${executionMode}\nUse /plan or /auto to switch.`);
|
|
188
|
+
break;
|
|
189
|
+
case 'agents':
|
|
190
|
+
if (!activeAgent && completedAgents.length === 0) {
|
|
191
|
+
addSystemMessage('No agents currently active.');
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const status = activeAgent ? `Active: ${activeAgent}\n` : '';
|
|
195
|
+
const completed = completedAgents.length > 0 ? `Completed: ${completedAgents.join(', ')}` : '';
|
|
196
|
+
addSystemMessage(`Agent Status:\n${status}${completed}`);
|
|
197
|
+
}
|
|
72
198
|
break;
|
|
73
199
|
case 'help':
|
|
74
200
|
const helpMessage = {
|
|
@@ -79,13 +205,17 @@ export const App = ({ mode, version }) => {
|
|
|
79
205
|
/help - Show this help
|
|
80
206
|
/clear - Clear chat history
|
|
81
207
|
/status - Show session status
|
|
208
|
+
/plan - Enable plan mode (ask before executing)
|
|
209
|
+
/auto - Enable auto mode (execute directly)
|
|
210
|
+
/mode - Show current execution mode
|
|
211
|
+
/agents - Show active agents
|
|
82
212
|
/exit - Exit AGENT-K
|
|
83
213
|
|
|
84
214
|
Keyboard shortcuts:
|
|
85
215
|
↑/↓ - Browse command history
|
|
216
|
+
Tab - Autocomplete commands
|
|
86
217
|
Ctrl+C - Exit
|
|
87
|
-
Ctrl+U - Clear input line
|
|
88
|
-
Ctrl+A/E - Jump to start/end`,
|
|
218
|
+
Ctrl+U - Clear input line`,
|
|
89
219
|
timestamp: new Date(),
|
|
90
220
|
};
|
|
91
221
|
setMessages(prev => [...prev, helpMessage]);
|
|
@@ -97,8 +227,10 @@ Ctrl+A/E - Jump to start/end`,
|
|
|
97
227
|
agentName: 'System',
|
|
98
228
|
content: `Session Status:
|
|
99
229
|
◇ Mode: ${mode === 'dev' ? 'Development' : 'ML Research'}
|
|
230
|
+
◇ Execution: ${executionMode === 'plan' ? 'Plan (approval required)' : 'Auto (direct execution)'}
|
|
100
231
|
◇ Messages: ${messages.length}
|
|
101
232
|
◇ Total Tokens: ${totalTokens}
|
|
233
|
+
◇ Active Agent: ${activeAgent || 'None'}
|
|
102
234
|
◇ Session Time: ${formatElapsed(startTime)}`,
|
|
103
235
|
timestamp: new Date(),
|
|
104
236
|
};
|
|
@@ -114,7 +246,16 @@ Ctrl+A/E - Jump to start/end`,
|
|
|
114
246
|
exit();
|
|
115
247
|
}
|
|
116
248
|
});
|
|
117
|
-
|
|
249
|
+
// Prepare items for Static (include welcome box as first item)
|
|
250
|
+
const staticItems = messages.length === 0
|
|
251
|
+
? [{ id: 'welcome', isWelcome: true, role: 'system', content: '', timestamp: new Date() }]
|
|
252
|
+
: messages;
|
|
253
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: staticItems, children: (item) => {
|
|
254
|
+
if ('isWelcome' in item && item.isWelcome) {
|
|
255
|
+
return _jsx(WelcomeBox, { version: version, mode: mode }, "welcome");
|
|
256
|
+
}
|
|
257
|
+
return (_jsx(ChatMessage, { role: item.role, agentName: item.agentName, content: item.content, tokens: item.tokens }, item.id));
|
|
258
|
+
} }), isProcessing && processingStartTime && (_jsx(ThinkingIndicator, { startTime: processingStartTime })), error && (_jsx(Box, { marginY: 1, marginLeft: 1, children: _jsxs(Text, { color: "#e53e3e", children: ["\u2717 Error: ", error] }) })), _jsx(Input, { onSubmit: handleSubmit, disabled: isProcessing, placeholder: awaitingApproval ? "Execute plan? (y/n)" : 'Try "build a password validator"' }), _jsx(StatusBar, { mode: mode, tokens: totalTokens, startTime: startTime, isProcessing: isProcessing, activeAgent: activeAgent, completedAgents: completedAgents })] }));
|
|
118
259
|
};
|
|
119
260
|
function formatElapsed(start) {
|
|
120
261
|
const secs = Math.floor((Date.now() - start.getTime()) / 1000);
|
|
@@ -9,10 +9,12 @@ const theme = {
|
|
|
9
9
|
dim: '#4a5568',
|
|
10
10
|
user: '#9f7aea', // Purple for user
|
|
11
11
|
agent: '#4fd1c5', // Teal for agent
|
|
12
|
+
system: '#f6e05e', // Yellow for system
|
|
12
13
|
};
|
|
13
14
|
export const ChatMessage = ({ role, agentName = 'Agent', content, tokens, }) => {
|
|
14
15
|
const isUser = role === 'user';
|
|
15
|
-
const
|
|
16
|
+
const isSystem = role === 'system';
|
|
17
|
+
const symbolColor = isUser ? theme.user : isSystem ? theme.system : theme.agent;
|
|
16
18
|
const title = isUser ? 'You' : agentName;
|
|
17
19
|
const termWidth = process.stdout.columns || 80;
|
|
18
20
|
const contentWidth = termWidth - 6;
|
package/dist/components/Input.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
4
|
// Sophisticated theme
|
|
5
5
|
const theme = {
|
|
6
6
|
accent: '#4fd1c5',
|
|
7
7
|
dim: '#4a5568',
|
|
8
|
+
border: '#4a5568',
|
|
8
9
|
suggestion: '#718096',
|
|
10
|
+
text: '#e2e8f0',
|
|
9
11
|
};
|
|
10
12
|
// Available commands for autocomplete
|
|
11
|
-
const COMMANDS = ['/help', '/status', '/clear', '/exit', '/mode'];
|
|
13
|
+
const COMMANDS = ['/help', '/status', '/clear', '/exit', '/plan', '/auto', '/mode', '/agents'];
|
|
12
14
|
// Store history globally so it persists across re-renders
|
|
13
15
|
const commandHistory = [];
|
|
14
16
|
const MAX_HISTORY = 100;
|
|
15
|
-
export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '
|
|
17
|
+
export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '❯', disabled = false, }) => {
|
|
16
18
|
const [value, setValue] = useState('');
|
|
17
19
|
const [cursorPosition, setCursorPosition] = useState(0);
|
|
18
20
|
const [historyIndex, setHistoryIndex] = useState(-1);
|
|
19
|
-
const [tempValue, setTempValue] = useState('');
|
|
20
|
-
const [tabIndex, setTabIndex] = useState(0);
|
|
21
|
+
const [tempValue, setTempValue] = useState('');
|
|
22
|
+
const [tabIndex, setTabIndex] = useState(0);
|
|
23
|
+
const termWidth = process.stdout.columns || 80;
|
|
21
24
|
// Get autocomplete suggestion
|
|
22
25
|
const getSuggestion = () => {
|
|
23
26
|
if (!value.startsWith('/') || value.length < 1)
|
|
@@ -33,7 +36,6 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
33
36
|
return;
|
|
34
37
|
if (key.return) {
|
|
35
38
|
if (value.trim()) {
|
|
36
|
-
// Add to history (avoid duplicates at the end)
|
|
37
39
|
if (commandHistory.length === 0 || commandHistory[commandHistory.length - 1] !== value) {
|
|
38
40
|
commandHistory.push(value);
|
|
39
41
|
if (commandHistory.length > MAX_HISTORY) {
|
|
@@ -48,10 +50,8 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
else if (key.upArrow) {
|
|
51
|
-
// Navigate history backwards
|
|
52
53
|
if (commandHistory.length > 0) {
|
|
53
54
|
if (historyIndex === -1) {
|
|
54
|
-
// Save current input before browsing history
|
|
55
55
|
setTempValue(value);
|
|
56
56
|
const newIndex = commandHistory.length - 1;
|
|
57
57
|
setHistoryIndex(newIndex);
|
|
@@ -67,7 +67,6 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
else if (key.downArrow) {
|
|
70
|
-
// Navigate history forwards
|
|
71
70
|
if (historyIndex !== -1) {
|
|
72
71
|
if (historyIndex < commandHistory.length - 1) {
|
|
73
72
|
const newIndex = historyIndex + 1;
|
|
@@ -76,7 +75,6 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
76
75
|
setCursorPosition(commandHistory[newIndex].length);
|
|
77
76
|
}
|
|
78
77
|
else {
|
|
79
|
-
// Return to the original input
|
|
80
78
|
setHistoryIndex(-1);
|
|
81
79
|
setValue(tempValue);
|
|
82
80
|
setCursorPosition(tempValue.length);
|
|
@@ -87,7 +85,7 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
87
85
|
if (cursorPosition > 0) {
|
|
88
86
|
setValue(prev => prev.slice(0, cursorPosition - 1) + prev.slice(cursorPosition));
|
|
89
87
|
setCursorPosition(pos => pos - 1);
|
|
90
|
-
setHistoryIndex(-1);
|
|
88
|
+
setHistoryIndex(-1);
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
else if (key.leftArrow) {
|
|
@@ -100,28 +98,23 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
100
98
|
process.exit(0);
|
|
101
99
|
}
|
|
102
100
|
else if (key.ctrl && input === 'u') {
|
|
103
|
-
// Clear line
|
|
104
101
|
setValue('');
|
|
105
102
|
setCursorPosition(0);
|
|
106
103
|
setHistoryIndex(-1);
|
|
107
104
|
}
|
|
108
105
|
else if (key.ctrl && input === 'a') {
|
|
109
|
-
// Go to beginning
|
|
110
106
|
setCursorPosition(0);
|
|
111
107
|
}
|
|
112
108
|
else if (key.ctrl && input === 'e') {
|
|
113
|
-
// Go to end
|
|
114
109
|
setCursorPosition(value.length);
|
|
115
110
|
}
|
|
116
111
|
else if (key.tab) {
|
|
117
|
-
// Tab completion
|
|
118
112
|
if (suggestion) {
|
|
119
113
|
const completed = value + suggestion;
|
|
120
114
|
setValue(completed);
|
|
121
115
|
setCursorPosition(completed.length);
|
|
122
116
|
}
|
|
123
117
|
else if (value.startsWith('/')) {
|
|
124
|
-
// Cycle through matching commands
|
|
125
118
|
const matches = COMMANDS.filter(cmd => cmd.startsWith(value.toLowerCase()));
|
|
126
119
|
if (matches.length > 0) {
|
|
127
120
|
const nextIndex = (tabIndex + 1) % matches.length;
|
|
@@ -134,14 +127,14 @@ export const Input = ({ onSubmit, placeholder = 'Type a message...', prefix = '>
|
|
|
134
127
|
else if (!key.ctrl && !key.meta && input) {
|
|
135
128
|
setValue(prev => prev.slice(0, cursorPosition) + input + prev.slice(cursorPosition));
|
|
136
129
|
setCursorPosition(pos => pos + input.length);
|
|
137
|
-
setHistoryIndex(-1);
|
|
138
|
-
setTabIndex(0);
|
|
130
|
+
setHistoryIndex(-1);
|
|
131
|
+
setTabIndex(0);
|
|
139
132
|
}
|
|
140
133
|
});
|
|
141
134
|
// Render input with cursor
|
|
142
135
|
const beforeCursor = value.slice(0, cursorPosition);
|
|
143
136
|
const atCursor = value[cursorPosition] || ' ';
|
|
144
137
|
const afterCursor = value.slice(cursorPosition + 1);
|
|
145
|
-
return (_jsxs(Box, {
|
|
138
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsx(Text, { color: theme.border, children: '─'.repeat(termWidth) }) }), _jsxs(Box, { paddingX: 1, children: [_jsxs(Text, { color: theme.accent, children: [prefix, " "] }), value.length === 0 && !disabled ? (_jsx(Text, { color: theme.dim, children: placeholder })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.text, children: beforeCursor }), _jsx(Text, { inverse: true, children: atCursor }), _jsx(Text, { color: theme.text, children: afterCursor }), suggestion && cursorPosition === value.length && (_jsx(Text, { color: theme.suggestion, children: suggestion }))] })), disabled && _jsx(Text, { color: theme.dim, children: " processing..." })] }), _jsx(Box, { children: _jsx(Text, { color: theme.border, children: '─'.repeat(termWidth) }) })] }));
|
|
146
139
|
};
|
|
147
140
|
export default Input;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { AgentName } from './AgentPanel.js';
|
|
2
3
|
interface StatusBarProps {
|
|
3
4
|
mode: 'dev' | 'ml';
|
|
4
5
|
tokens: number;
|
|
5
6
|
startTime: Date;
|
|
6
7
|
isProcessing?: boolean;
|
|
8
|
+
activeAgent?: AgentName;
|
|
9
|
+
completedAgents?: AgentName[];
|
|
7
10
|
}
|
|
8
11
|
export declare const StatusBar: React.FC<StatusBarProps>;
|
|
9
12
|
export default StatusBar;
|
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { icons } from '../themes/retro.js';
|
|
5
|
-
//
|
|
5
|
+
// Theme
|
|
6
6
|
const theme = {
|
|
7
|
-
border: '#
|
|
7
|
+
border: '#4a5568',
|
|
8
8
|
accent: '#4fd1c5',
|
|
9
9
|
highlight: '#81e6d9',
|
|
10
|
-
dim: '#
|
|
11
|
-
|
|
10
|
+
dim: '#718096',
|
|
11
|
+
active: '#f6e05e',
|
|
12
|
+
done: '#48bb78',
|
|
12
13
|
};
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
// Agent icons
|
|
15
|
+
const agentIcons = {
|
|
16
|
+
Orchestrator: '◆',
|
|
17
|
+
Engineer: '⚙',
|
|
18
|
+
Tester: '✓',
|
|
19
|
+
Security: '⛨',
|
|
20
|
+
Scout: '◎',
|
|
21
|
+
Researcher: '◈',
|
|
22
|
+
'ML Engineer': '⬡',
|
|
23
|
+
'Data Engineer': '⬢',
|
|
24
|
+
Evaluator: '◉',
|
|
25
|
+
};
|
|
26
|
+
export const StatusBar = ({ mode, tokens, startTime, isProcessing = false, activeAgent, completedAgents = [], }) => {
|
|
27
|
+
const [elapsed, setElapsed] = useState('');
|
|
15
28
|
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
16
29
|
useEffect(() => {
|
|
17
30
|
if (!isProcessing) {
|
|
@@ -42,7 +55,17 @@ export const StatusBar = ({ mode, tokens, startTime, isProcessing = false, }) =>
|
|
|
42
55
|
return t.toString();
|
|
43
56
|
};
|
|
44
57
|
const modeLabel = mode === 'dev' ? 'DEV' : 'ML';
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
// Get agents for this mode
|
|
59
|
+
const modeAgents = mode === 'dev'
|
|
60
|
+
? ['Orchestrator', 'Engineer', 'Tester', 'Security']
|
|
61
|
+
: ['Orchestrator', 'Researcher', 'ML Engineer', 'Evaluator'];
|
|
62
|
+
const getAgentColor = (agent) => {
|
|
63
|
+
if (activeAgent === agent)
|
|
64
|
+
return theme.active;
|
|
65
|
+
if (completedAgents.includes(agent))
|
|
66
|
+
return theme.done;
|
|
67
|
+
return theme.dim;
|
|
68
|
+
};
|
|
69
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: theme.dim, children: " " }), _jsx(Text, { color: theme.accent, children: modeLabel }), _jsx(Text, { color: theme.border, children: " \u2502 " }), modeAgents.map((agent, i) => (_jsxs(React.Fragment, { children: [_jsx(Text, { color: getAgentColor(agent), children: "[" }), _jsx(Text, { color: getAgentColor(agent), children: agentIcons[agent] }), _jsx(Text, { color: getAgentColor(agent), children: "]" }), i < modeAgents.length - 1 && _jsx(Text, { color: theme.dim, children: " " })] }, agent))), _jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.dim, children: "? help" }), isProcessing && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.highlight, children: icons.spinner[spinnerFrame] })] })), elapsed && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.dim, children: elapsed })] })), _jsx(Text, { color: theme.dim, children: ' '.repeat(3) }), _jsxs(Text, { color: theme.accent, children: ["\u2191 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: " tokens" })] }));
|
|
47
70
|
};
|
|
48
71
|
export default StatusBar;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
const theme = {
|
|
5
|
+
border: '#4a5568',
|
|
6
|
+
accent: '#4fd1c5',
|
|
7
|
+
highlight: '#81e6d9',
|
|
8
|
+
dim: '#718096',
|
|
9
|
+
text: '#e2e8f0',
|
|
10
|
+
title: '#f6e05e',
|
|
11
|
+
};
|
|
12
|
+
export const WelcomeBox = ({ version, mode }) => {
|
|
13
|
+
const termWidth = Math.min(process.stdout.columns || 120, 120);
|
|
14
|
+
const boxWidth = termWidth - 4;
|
|
15
|
+
const leftWidth = Math.floor(boxWidth * 0.45);
|
|
16
|
+
const rightWidth = boxWidth - leftWidth - 3;
|
|
17
|
+
const modeLabel = mode === 'dev' ? 'Software Development' : 'ML Research';
|
|
18
|
+
const agents = mode === 'dev'
|
|
19
|
+
? ['Orchestrator', 'Engineer', 'Tester', 'Security']
|
|
20
|
+
: ['Orchestrator', 'Researcher', 'ML Engineer', 'Evaluator'];
|
|
21
|
+
// Title bar
|
|
22
|
+
const titleText = ` AGENT-K v${version} `;
|
|
23
|
+
const titlePadLeft = Math.floor((boxWidth - titleText.length) / 2);
|
|
24
|
+
const titlePadRight = boxWidth - titleText.length - titlePadLeft;
|
|
25
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u256D" }), _jsx(Text, { color: theme.border, children: '─'.repeat(titlePadLeft - 1) }), _jsx(Text, { color: theme.title, bold: true, children: titleText }), _jsx(Text, { color: theme.border, children: '─'.repeat(titlePadRight - 1) }), _jsx(Text, { color: theme.border, children: "\u256E" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Text, { children: ' '.repeat(boxWidth) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: leftWidth, justifyContent: "center", children: _jsx(Text, { color: theme.accent, children: " /\\_/\\ " }) }), _jsx(Text, { color: theme.border, children: "\u2502" }), _jsxs(Box, { width: rightWidth, paddingLeft: 1, children: [_jsx(Text, { color: theme.text, children: "Welcome to " }), _jsx(Text, { color: theme.accent, bold: true, children: "AGENT-K" })] }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: leftWidth, justifyContent: "center", children: _jsx(Text, { color: theme.accent, children: " ( o.o ) " }) }), _jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: rightWidth, paddingLeft: 1, children: _jsx(Text, { color: theme.dim, children: "Multi-Agent Intelligence System" }) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: leftWidth, justifyContent: "center", children: _jsxs(Text, { color: theme.accent, children: [" ", '>', " ", '<', " "] }) }), _jsx(Text, { color: theme.border, children: "\u2502" }), _jsxs(Box, { width: rightWidth, paddingLeft: 1, children: [_jsx(Text, { color: theme.dim, children: "Mode: " }), _jsx(Text, { color: theme.highlight, children: modeLabel })] }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Text, { children: ' '.repeat(boxWidth) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: boxWidth, justifyContent: "center", children: agents.map((agent, i) => (_jsxs(React.Fragment, { children: [_jsx(Text, { color: theme.accent, children: "\u25C6 " }), _jsx(Text, { color: theme.text, children: agent }), i < agents.length - 1 && _jsx(Text, { color: theme.dim, children: " \u00B7 " })] }, agent))) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Text, { children: ' '.repeat(boxWidth) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: boxWidth, justifyContent: "center", children: _jsx(Text, { color: theme.dim, children: "/help for commands \u00B7 /plan or /auto to set mode \u00B7 Ctrl+C to exit" }) }), _jsx(Text, { color: theme.border, children: "\u2502" })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.border, children: "\u2570" }), _jsx(Text, { color: theme.border, children: '─'.repeat(boxWidth) }), _jsx(Text, { color: theme.border, children: "\u256F" })] })] }));
|
|
26
|
+
};
|
|
27
|
+
export default WelcomeBox;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export { App } from './App.js';
|
|
2
2
|
export { Banner } from './Banner.js';
|
|
3
|
+
export { WelcomeBox } from './WelcomeBox.js';
|
|
3
4
|
export { ChatMessage } from './ChatMessage.js';
|
|
4
5
|
export { Input } from './Input.js';
|
|
5
6
|
export { StatusBar } from './StatusBar.js';
|
|
6
7
|
export { ThinkingIndicator } from './ThinkingIndicator.js';
|
|
7
8
|
export { RetroBox } from './Box.js';
|
|
9
|
+
export { AgentStatus } from './AgentStatus.js';
|
|
10
|
+
export { AgentPanel } from './AgentPanel.js';
|
|
11
|
+
export type { AgentName, AgentState } from './AgentPanel.js';
|
package/dist/components/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export { App } from './App.js';
|
|
2
2
|
export { Banner } from './Banner.js';
|
|
3
|
+
export { WelcomeBox } from './WelcomeBox.js';
|
|
3
4
|
export { ChatMessage } from './ChatMessage.js';
|
|
4
5
|
export { Input } from './Input.js';
|
|
5
6
|
export { StatusBar } from './StatusBar.js';
|
|
6
7
|
export { ThinkingIndicator } from './ThinkingIndicator.js';
|
|
7
8
|
export { RetroBox } from './Box.js';
|
|
9
|
+
export { AgentStatus } from './AgentStatus.js';
|
|
10
|
+
export { AgentPanel } from './AgentPanel.js';
|