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 CHANGED
@@ -4,7 +4,7 @@ import { render } from 'ink';
4
4
  import meow from 'meow';
5
5
  import { App } from './components/App.js';
6
6
  import { checkClaudeInstalled } from './lib/claude.js';
7
- const VERSION = '2.1.4';
7
+ const VERSION = '2.2.1';
8
8
  const cli = meow(`
9
9
  Usage
10
10
  $ agentk8 [options]
@@ -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;
@@ -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 { Banner } from './Banner.js';
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
- // Add agent response
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
- return (_jsxs(Box, { flexDirection: "column", children: [messages.length === 0 && _jsx(Banner, { version: version }), _jsx(Static, { items: messages, children: (msg) => (_jsx(ChatMessage, { role: msg.role, agentName: msg.agentName, content: msg.content, tokens: msg.tokens }, msg.id)) }), 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: "Type a message or /help for commands..." }), _jsx(StatusBar, { mode: mode, tokens: totalTokens, startTime: startTime, isProcessing: isProcessing })] }));
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);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  interface ChatMessageProps {
3
- role: 'user' | 'agent';
3
+ role: 'user' | 'agent' | 'system';
4
4
  agentName?: string;
5
5
  content: string;
6
6
  tokens?: {
@@ -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 symbolColor = isUser ? theme.user : theme.agent;
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;
@@ -1,23 +1,26 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
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 = '>', disabled = false, }) => {
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(''); // Store current input when browsing history
20
- const [tabIndex, setTabIndex] = useState(0); // For cycling through completions
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); // Reset history navigation on edit
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); // Reset history navigation on edit
138
- setTabIndex(0); // Reset tab completion cycle
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, { marginTop: 1, children: [_jsxs(Text, { color: theme.accent, bold: true, children: [prefix, " "] }), value.length === 0 && !disabled ? (_jsx(Text, { color: theme.dim, children: placeholder })) : (_jsxs(_Fragment, { children: [_jsx(Text, { children: beforeCursor }), _jsx(Text, { inverse: true, children: atCursor }), _jsx(Text, { children: afterCursor }), suggestion && cursorPosition === value.length && (_jsx(Text, { color: theme.suggestion, children: suggestion }))] })), disabled && _jsx(Text, { color: theme.dim, children: " processing..." })] }));
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, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
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
- // Matching sophisticated theme
5
+ // Theme
6
6
  const theme = {
7
- border: '#2d3748',
7
+ border: '#4a5568',
8
8
  accent: '#4fd1c5',
9
9
  highlight: '#81e6d9',
10
- dim: '#4a5568',
11
- glow: '#319795',
10
+ dim: '#718096',
11
+ active: '#f6e05e',
12
+ done: '#48bb78',
12
13
  };
13
- export const StatusBar = ({ mode, tokens, startTime, isProcessing = false, }) => {
14
- const [elapsed, setElapsed] = useState('0s');
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
- const termWidth = process.stdout.columns || 80;
46
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: theme.border, children: ''.repeat(termWidth) }), _jsxs(Box, { justifyContent: "space-between", width: termWidth, children: [_jsxs(Box, { children: [_jsx(Text, { color: theme.dim, children: ' ◇ ' }), _jsx(Text, { color: theme.accent, children: modeLabel }), _jsx(Text, { color: theme.border, children: ' │ ' }), _jsx(Text, { color: theme.dim, children: "/help" }), isProcessing && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: ' │ ' }), _jsx(Text, { color: theme.highlight, children: icons.spinner[spinnerFrame] })] }))] }), _jsxs(Box, { children: [elapsed && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.dim, children: elapsed }), _jsx(Text, { color: theme.border, children: ' │ ' })] })), _jsxs(Text, { color: theme.accent, children: ["\u2191 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: ' tokens ' })] })] })] }));
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,7 @@
1
+ import React from 'react';
2
+ interface WelcomeBoxProps {
3
+ version: string;
4
+ mode: 'dev' | 'ml';
5
+ }
6
+ export declare const WelcomeBox: React.FC<WelcomeBoxProps>;
7
+ export default WelcomeBox;
@@ -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';
@@ -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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentk8",
3
- "version": "2.1.4",
3
+ "version": "2.2.1",
4
4
  "description": "Multi-Agent Claude Code Terminal Suite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",