agentk8 2.2.6 → 2.3.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/App.js +322 -62
- package/dist/components/ChatMessage.js +93 -1
- package/dist/components/Confirmation.d.ts +13 -0
- package/dist/components/Confirmation.js +39 -0
- package/dist/components/QuestionWizard.d.ts +21 -0
- package/dist/components/QuestionWizard.js +152 -0
- package/dist/components/StatusBar.d.ts +6 -0
- package/dist/components/StatusBar.js +31 -7
- package/dist/components/WelcomeBox.js +17 -11
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/lib/claude.js +59 -22
- package/dist/lib/council.d.ts +61 -0
- package/dist/lib/council.js +189 -0
- package/package.json +2 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ConfirmationOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ConfirmationProps {
|
|
8
|
+
message: string;
|
|
9
|
+
options: ConfirmationOption[];
|
|
10
|
+
onSelect: (value: string) => void;
|
|
11
|
+
onCancel: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare const Confirmation: React.FC<ConfirmationProps>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
const theme = {
|
|
5
|
+
selected: '#4fd1c5', // teal-400
|
|
6
|
+
unselected: '#a0aec0', // gray-400
|
|
7
|
+
message: '#e2e8f0', // gray-200
|
|
8
|
+
key: '#718096', // gray-500
|
|
9
|
+
border: '#2d3748', // gray-800
|
|
10
|
+
};
|
|
11
|
+
export const Confirmation = ({ message, options, onSelect, onCancel, }) => {
|
|
12
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
13
|
+
useInput((input, key) => {
|
|
14
|
+
if (key.upArrow) {
|
|
15
|
+
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : options.length - 1));
|
|
16
|
+
}
|
|
17
|
+
else if (key.downArrow) {
|
|
18
|
+
setSelectedIndex((prev) => (prev < options.length - 1 ? prev + 1 : 0));
|
|
19
|
+
}
|
|
20
|
+
else if (key.return) {
|
|
21
|
+
onSelect(options[selectedIndex].value);
|
|
22
|
+
}
|
|
23
|
+
else if (key.escape) {
|
|
24
|
+
onCancel();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Handle number keys (1-9)
|
|
28
|
+
const num = parseInt(input, 10);
|
|
29
|
+
if (!isNaN(num) && num > 0 && num <= options.length) {
|
|
30
|
+
onSelect(options[num - 1].value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.border, padding: 1, children: [_jsx(Text, { color: theme.message, bold: true, children: message }), _jsx(Box, { height: 1 }), options.map((option, index) => {
|
|
35
|
+
const isSelected = index === selectedIndex;
|
|
36
|
+
const prefix = isSelected ? '❯' : ' ';
|
|
37
|
+
return (_jsxs(Box, { marginLeft: 1, children: [_jsxs(Text, { color: isSelected ? theme.selected : theme.unselected, children: [prefix, " ", index + 1, ". ", option.label] }), option.key && (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: theme.key, children: ["(", option.key, ")"] }) }))] }, option.value));
|
|
38
|
+
}), _jsx(Box, { height: 1 }), _jsx(Text, { color: theme.key, dimColor: true, children: "Use \u2191/\u2193 to navigate, Enter to select, Esc to cancel" })] }));
|
|
39
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface QuestionOption {
|
|
3
|
+
label: string;
|
|
4
|
+
recommended?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface Question {
|
|
7
|
+
header: string;
|
|
8
|
+
question: string;
|
|
9
|
+
options: QuestionOption[];
|
|
10
|
+
answer?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface QuestionWizardProps {
|
|
13
|
+
questions: Question[];
|
|
14
|
+
onComplete: (answers: {
|
|
15
|
+
header: string;
|
|
16
|
+
answer: string;
|
|
17
|
+
}[]) => void;
|
|
18
|
+
onCancel: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const QuestionWizard: React.NamedExoticComponent<QuestionWizardProps>;
|
|
21
|
+
export default QuestionWizard;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useCallback, memo } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
const theme = {
|
|
5
|
+
border: '#2d3748',
|
|
6
|
+
accent: '#4fd1c5',
|
|
7
|
+
highlight: '#81e6d9',
|
|
8
|
+
text: '#e2e8f0',
|
|
9
|
+
dim: '#4a5568',
|
|
10
|
+
selected: '#4fd1c5',
|
|
11
|
+
unselected: '#718096',
|
|
12
|
+
answered: '#48bb78',
|
|
13
|
+
header: '#63b3ed',
|
|
14
|
+
no: '#e53e3e',
|
|
15
|
+
};
|
|
16
|
+
const QuestionWizardInner = ({ questions: initialQuestions, onComplete, onCancel, }) => {
|
|
17
|
+
// Single state object for atomic updates
|
|
18
|
+
const [state, setState] = useState({
|
|
19
|
+
questions: initialQuestions,
|
|
20
|
+
currentIndex: 0,
|
|
21
|
+
selectedOption: 0,
|
|
22
|
+
customInputMode: false,
|
|
23
|
+
customInputValue: '',
|
|
24
|
+
cursorPosition: 0,
|
|
25
|
+
});
|
|
26
|
+
const { questions, currentIndex, selectedOption, customInputMode, customInputValue, cursorPosition } = state;
|
|
27
|
+
const currentQuestion = questions[currentIndex];
|
|
28
|
+
const allOptions = [...currentQuestion.options, { label: 'No', recommended: false }];
|
|
29
|
+
const isOnNoOption = selectedOption === allOptions.length - 1;
|
|
30
|
+
const termWidth = process.stdout.columns || 80;
|
|
31
|
+
// Update state atomically
|
|
32
|
+
const updateState = useCallback((updates) => {
|
|
33
|
+
setState(prev => ({ ...prev, ...updates }));
|
|
34
|
+
}, []);
|
|
35
|
+
// Set answer and optionally advance
|
|
36
|
+
const selectOption = useCallback((answer, shouldAdvance) => {
|
|
37
|
+
setState(prev => {
|
|
38
|
+
const updatedQuestions = [...prev.questions];
|
|
39
|
+
updatedQuestions[prev.currentIndex] = {
|
|
40
|
+
...updatedQuestions[prev.currentIndex],
|
|
41
|
+
answer
|
|
42
|
+
};
|
|
43
|
+
// Check if this is the last question and all are answered
|
|
44
|
+
const isLast = prev.currentIndex === prev.questions.length - 1;
|
|
45
|
+
const allAnswered = updatedQuestions.every(q => q.answer !== undefined);
|
|
46
|
+
if (isLast && allAnswered) {
|
|
47
|
+
// Will complete after state update
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
onComplete(updatedQuestions.map(q => ({
|
|
50
|
+
header: q.header,
|
|
51
|
+
answer: q.answer || '',
|
|
52
|
+
})));
|
|
53
|
+
}, 0);
|
|
54
|
+
return prev; // Keep current state, will unmount soon
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
...prev,
|
|
58
|
+
questions: updatedQuestions,
|
|
59
|
+
currentIndex: shouldAdvance && !isLast ? prev.currentIndex + 1 : prev.currentIndex,
|
|
60
|
+
selectedOption: shouldAdvance && !isLast ? 0 : prev.selectedOption,
|
|
61
|
+
customInputMode: false,
|
|
62
|
+
customInputValue: '',
|
|
63
|
+
cursorPosition: 0,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}, [onComplete]);
|
|
67
|
+
useInput((input, key) => {
|
|
68
|
+
if (customInputMode) {
|
|
69
|
+
if (key.escape) {
|
|
70
|
+
updateState({ customInputMode: false, customInputValue: '', cursorPosition: 0 });
|
|
71
|
+
}
|
|
72
|
+
else if (key.return && customInputValue.trim()) {
|
|
73
|
+
selectOption(customInputValue.trim(), true);
|
|
74
|
+
}
|
|
75
|
+
else if (key.backspace || key.delete) {
|
|
76
|
+
if (cursorPosition > 0) {
|
|
77
|
+
updateState({
|
|
78
|
+
customInputValue: customInputValue.slice(0, cursorPosition - 1) + customInputValue.slice(cursorPosition),
|
|
79
|
+
cursorPosition: cursorPosition - 1,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (key.leftArrow) {
|
|
84
|
+
updateState({ cursorPosition: Math.max(0, cursorPosition - 1) });
|
|
85
|
+
}
|
|
86
|
+
else if (key.rightArrow) {
|
|
87
|
+
updateState({ cursorPosition: Math.min(customInputValue.length, cursorPosition + 1) });
|
|
88
|
+
}
|
|
89
|
+
else if (!key.ctrl && !key.meta && input) {
|
|
90
|
+
updateState({
|
|
91
|
+
customInputValue: customInputValue.slice(0, cursorPosition) + input + customInputValue.slice(cursorPosition),
|
|
92
|
+
cursorPosition: cursorPosition + input.length,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Selection mode
|
|
98
|
+
if (key.upArrow) {
|
|
99
|
+
updateState({ selectedOption: selectedOption > 0 ? selectedOption - 1 : allOptions.length - 1 });
|
|
100
|
+
}
|
|
101
|
+
else if (key.downArrow) {
|
|
102
|
+
updateState({ selectedOption: selectedOption < allOptions.length - 1 ? selectedOption + 1 : 0 });
|
|
103
|
+
}
|
|
104
|
+
else if (key.leftArrow && currentIndex > 0) {
|
|
105
|
+
updateState({ currentIndex: currentIndex - 1, selectedOption: 0 });
|
|
106
|
+
}
|
|
107
|
+
else if (key.rightArrow && currentIndex < questions.length - 1 && currentQuestion.answer) {
|
|
108
|
+
updateState({ currentIndex: currentIndex + 1, selectedOption: 0 });
|
|
109
|
+
}
|
|
110
|
+
else if (key.tab) {
|
|
111
|
+
// Tab always opens custom input mode
|
|
112
|
+
updateState({ customInputMode: true, customInputValue: '', cursorPosition: 0 });
|
|
113
|
+
}
|
|
114
|
+
else if (key.return && isOnNoOption) {
|
|
115
|
+
// Enter on "No" also opens custom input
|
|
116
|
+
updateState({ customInputMode: true, customInputValue: '', cursorPosition: 0 });
|
|
117
|
+
}
|
|
118
|
+
else if (key.return && !isOnNoOption) {
|
|
119
|
+
selectOption(allOptions[selectedOption].label, true);
|
|
120
|
+
}
|
|
121
|
+
else if (key.escape) {
|
|
122
|
+
onCancel();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const num = parseInt(input, 10);
|
|
126
|
+
if (!isNaN(num) && num > 0 && num <= allOptions.length) {
|
|
127
|
+
updateState({ selectedOption: num - 1 });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.border, paddingX: 2, paddingY: 1, children: [_jsx(Box, { children: questions.map((q, i) => {
|
|
132
|
+
const isCurrent = i === currentIndex;
|
|
133
|
+
const isAnswered = q.answer !== undefined;
|
|
134
|
+
const color = isCurrent ? theme.accent : isAnswered ? theme.answered : theme.unselected;
|
|
135
|
+
return (_jsxs(React.Fragment, { children: [_jsxs(Text, { color: color, bold: isCurrent, children: ["[", isAnswered ? `${q.header} ✓` : q.header, "]"] }), i < questions.length - 1 && _jsx(Text, { color: theme.dim, children: " " })] }, i));
|
|
136
|
+
}) }), _jsx(Box, { marginY: 1, children: questions.map((q, i) => {
|
|
137
|
+
const isAnswered = q.answer !== undefined;
|
|
138
|
+
const isCurrent = i === currentIndex;
|
|
139
|
+
return (_jsxs(React.Fragment, { children: [_jsx(Text, { color: isAnswered ? theme.answered : isCurrent ? theme.accent : theme.dim, children: isAnswered ? '✓' : isCurrent ? '●' : '○' }), i < questions.length - 1 && _jsx(Text, { color: theme.dim, children: "\u2500\u2500\u2500\u2500" })] }, i));
|
|
140
|
+
}) }), _jsxs(Box, { children: [_jsx(Text, { color: theme.accent, children: "\u25C6 " }), _jsx(Text, { color: theme.header, bold: true, children: currentQuestion.header })] }), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsx(Text, { color: theme.text, children: currentQuestion.question }) }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: allOptions.map((opt, idx) => {
|
|
141
|
+
const isSelected = idx === selectedOption;
|
|
142
|
+
const isNo = idx === allOptions.length - 1;
|
|
143
|
+
if (isNo) {
|
|
144
|
+
// "No" option with inline custom input
|
|
145
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: isSelected ? (customInputMode ? theme.selected : theme.no) : theme.unselected, children: [isSelected ? '❯' : ' ', " ", idx + 1, ". No"] }), customInputMode ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.dim, children: ", " }), _jsx(Text, { color: theme.text, children: customInputValue.slice(0, cursorPosition) }), _jsx(Text, { inverse: true, children: customInputValue[cursorPosition] || ' ' }), _jsx(Text, { color: theme.text, children: customInputValue.slice(cursorPosition + 1) })] })) : (_jsx(Text, { color: theme.dim, children: " (Tab to type custom)" }))] }, idx));
|
|
146
|
+
}
|
|
147
|
+
return (_jsxs(Text, { color: isSelected ? theme.selected : theme.unselected, children: [isSelected ? '❯' : ' ', " ", idx + 1, ". ", opt.recommended ? `${opt.label} (Recommended)` : opt.label] }, idx));
|
|
148
|
+
}) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.dim, children: customInputMode ? 'Type your answer · Enter submit · Esc cancel' : '↑/↓ select · Enter confirm · Tab custom · ←/→ questions' }) })] }));
|
|
149
|
+
};
|
|
150
|
+
// Memoize to prevent unnecessary re-renders
|
|
151
|
+
export const QuestionWizard = memo(QuestionWizardInner);
|
|
152
|
+
export default QuestionWizard;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AgentName } from './AgentPanel.js';
|
|
3
|
+
type CouncilMode = 'solo' | 'council' | 'off';
|
|
3
4
|
interface StatusBarProps {
|
|
4
5
|
mode: 'dev' | 'ml';
|
|
6
|
+
executionMode: 'plan' | 'auto';
|
|
5
7
|
tokens: number;
|
|
6
8
|
startTime: Date;
|
|
7
9
|
isProcessing?: boolean;
|
|
8
10
|
activeAgent?: AgentName;
|
|
9
11
|
completedAgents?: AgentName[];
|
|
10
12
|
autoAccept?: boolean;
|
|
13
|
+
councilMode?: CouncilMode;
|
|
14
|
+
councilStage?: string | null;
|
|
15
|
+
availableModels?: Record<string, boolean>;
|
|
16
|
+
showExitHint?: boolean;
|
|
11
17
|
}
|
|
12
18
|
export declare const StatusBar: React.FC<StatusBarProps>;
|
|
13
19
|
export default StatusBar;
|
|
@@ -23,7 +23,13 @@ const agentIcons = {
|
|
|
23
23
|
'Data Engineer': '&',
|
|
24
24
|
Evaluator: '^',
|
|
25
25
|
};
|
|
26
|
-
|
|
26
|
+
// Model icons for council mode
|
|
27
|
+
const modelIcons = {
|
|
28
|
+
gpt: 'G',
|
|
29
|
+
gemini: 'M',
|
|
30
|
+
claude: 'C',
|
|
31
|
+
};
|
|
32
|
+
export const StatusBar = ({ mode, executionMode, tokens, startTime, isProcessing = false, activeAgent, completedAgents = [], autoAccept = false, councilMode = 'off', councilStage = null, availableModels = {}, showExitHint = false, }) => {
|
|
27
33
|
const [elapsed, setElapsed] = useState('');
|
|
28
34
|
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
29
35
|
const [pulseFrame, setPulseFrame] = useState(0);
|
|
@@ -77,11 +83,29 @@ export const StatusBar = ({ mode, tokens, startTime, isProcessing = false, activ
|
|
|
77
83
|
return theme.done;
|
|
78
84
|
return theme.dim;
|
|
79
85
|
};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
// Get stage label for council mode
|
|
87
|
+
const getStageLabel = () => {
|
|
88
|
+
if (!councilStage)
|
|
89
|
+
return null;
|
|
90
|
+
const stages = {
|
|
91
|
+
'scout': 'Scout',
|
|
92
|
+
'stage1': '1/3',
|
|
93
|
+
'stage2': '2/3',
|
|
94
|
+
'stage3': '3/3',
|
|
95
|
+
};
|
|
96
|
+
return stages[councilStage] || councilStage;
|
|
97
|
+
};
|
|
98
|
+
return (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [_jsxs(Box, { children: [_jsx(Text, { color: theme.dim, children: " " }), _jsx(Text, { color: theme.accent, children: modeLabel }), _jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: executionMode === 'auto' ? theme.active : theme.accent, children: executionMode.toUpperCase() }), _jsx(Text, { color: theme.border, children: " \u2502 " }), councilMode !== 'off' ? (_jsxs(_Fragment, { children: [Object.entries(modelIcons).map(([model, icon], i) => {
|
|
99
|
+
const isAvailable = availableModels[model];
|
|
100
|
+
const color = isAvailable ? theme.done : theme.dim;
|
|
101
|
+
return (_jsxs(React.Fragment, { children: [_jsx(Text, { color: color, children: "[" }), _jsx(Text, { color: color, children: icon }), _jsx(Text, { color: color, children: "]" }), i < Object.keys(modelIcons).length - 1 && _jsx(Text, { color: theme.dim, children: " " })] }, model));
|
|
102
|
+
}), councilStage && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsxs(Text, { color: theme.active, children: ["Stage ", getStageLabel()] })] }))] })) : (
|
|
103
|
+
/* Agent boxes (standard mode) */
|
|
104
|
+
modeAgents.map((agent, i) => {
|
|
105
|
+
const isActive = activeAgent === agent;
|
|
106
|
+
const leftBracket = isActive ? pulseBrackets[pulseFrame] : '[';
|
|
107
|
+
const rightBracket = isActive ? pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '<' ? '>' : pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '{' ? '}' : pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '(' ? ')' : ']' : ']';
|
|
108
|
+
return (_jsxs(React.Fragment, { children: [_jsx(Text, { color: getAgentColor(agent), children: leftBracket }), _jsx(Text, { color: getAgentColor(agent), children: agentIcons[agent] }), _jsx(Text, { color: getAgentColor(agent), children: rightBracket }), i < modeAgents.length - 1 && _jsx(Text, { color: theme.dim, children: " " })] }, agent));
|
|
109
|
+
})), _jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.dim, children: "? help" }), councilMode !== 'off' && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.highlight, children: councilMode === 'council' ? 'COUNCIL' : 'SOLO' })] })), autoAccept && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: theme.active, children: "FAST" })] })), 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 })] }))] }), _jsxs(Box, { children: [showExitHint && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.dim, children: "Press Esc again to exit" }), _jsx(Text, { color: theme.border, children: " \u2502 " })] })), _jsxs(Text, { color: theme.accent, children: ["\u2191 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: " tokens " })] })] }));
|
|
86
110
|
};
|
|
87
111
|
export default StatusBar;
|
|
@@ -2,21 +2,21 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
const theme = {
|
|
5
|
-
border: '#
|
|
6
|
-
accent: '#
|
|
7
|
-
highlight: '#
|
|
5
|
+
border: '#2d3748', // gray-800
|
|
6
|
+
accent: '#a0aec0', // gray-400
|
|
7
|
+
highlight: '#e2e8f0', // gray-200
|
|
8
8
|
dim: '#718096',
|
|
9
|
-
text: '#
|
|
10
|
-
title: '#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
text: '#cbd5e0',
|
|
10
|
+
title: '#718096', // gray-500
|
|
11
|
+
c1: '#a0aec0', // gray-400
|
|
12
|
+
c2: '#4a5568', // gray-700
|
|
13
|
+
c3: '#63b3ed', // blue-400 (eye)
|
|
14
14
|
};
|
|
15
15
|
export const WelcomeBox = ({ version, mode }) => {
|
|
16
16
|
const termWidth = Math.min(process.stdout.columns || 120, 120);
|
|
17
17
|
const boxWidth = termWidth - 4;
|
|
18
|
-
const leftWidth = Math.floor(boxWidth * 0.
|
|
19
|
-
const rightWidth = boxWidth - leftWidth -
|
|
18
|
+
const leftWidth = Math.floor(boxWidth * 0.55);
|
|
19
|
+
const rightWidth = boxWidth - leftWidth - 1;
|
|
20
20
|
const modeLabel = mode === 'dev' ? 'Software Development' : 'ML Research';
|
|
21
21
|
// Agent icons matching StatusBar
|
|
22
22
|
const agentIcons = {
|
|
@@ -35,6 +35,12 @@ export const WelcomeBox = ({ version, mode }) => {
|
|
|
35
35
|
const titleText = ` AGENT-K v${version} `;
|
|
36
36
|
const titlePadLeft = Math.floor((boxWidth - titleText.length) / 2);
|
|
37
37
|
const titlePadRight = boxWidth - titleText.length - titlePadLeft;
|
|
38
|
-
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
|
|
38
|
+
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) }), _jsx(Text, { color: theme.title, bold: true, children: titleText }), _jsx(Text, { color: theme.border, children: '─'.repeat(titlePadRight) }), _jsx(Text, { color: theme.border, children: "\u256E" })] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: theme.border, children: "\u2502" }), _jsx(Box, { width: leftWidth, justifyContent: "center", alignItems: "center", flexDirection: "column", children: _jsx(Text, { color: theme.c1, children: `
|
|
39
|
+
___________________ ____....-----....____
|
|
40
|
+
(________________LL_) ==============================
|
|
41
|
+
______\\ \\_______.--'. \`---..._____...---'
|
|
42
|
+
\`-------..__ \` ,/
|
|
43
|
+
\`-._ - - - |
|
|
44
|
+
\`-------'` }) }), _jsx(Text, { color: theme.border, children: "\u2502" }), _jsxs(Box, { width: rightWidth, flexDirection: "column", justifyContent: "center", paddingLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: theme.text, children: "Welcome to " }), _jsx(Text, { color: theme.accent, bold: true, children: "AGENT-K" })] }), _jsx(Text, { color: theme.dim, children: "Pack Intelligence System" }), _jsxs(Box, { marginTop: 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: [_jsxs(Text, { color: theme.accent, children: ["[", agentIcons[agent], "] "] }), _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 Esc Esc 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" })] })] }));
|
|
39
45
|
};
|
|
40
46
|
export default WelcomeBox;
|
|
@@ -9,3 +9,5 @@ export { RetroBox } from './Box.js';
|
|
|
9
9
|
export { AgentStatus } from './AgentStatus.js';
|
|
10
10
|
export { AgentPanel } from './AgentPanel.js';
|
|
11
11
|
export type { AgentName, AgentState } from './AgentPanel.js';
|
|
12
|
+
export { QuestionWizard } from './QuestionWizard.js';
|
|
13
|
+
export type { Question, QuestionOption, QuestionWizardProps } from './QuestionWizard.js';
|
package/dist/components/index.js
CHANGED
package/dist/lib/claude.js
CHANGED
|
@@ -127,32 +127,69 @@ You are the Orchestrator—the central intelligence coordinator in AGENT-K, a mu
|
|
|
127
127
|
4. **Think Transparently**: Show your reasoning process
|
|
128
128
|
5. **Synthesize Results**: Provide cohesive, actionable outputs
|
|
129
129
|
|
|
130
|
-
## RESPONSE
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<response>
|
|
149
|
-
[Your comprehensive response here]
|
|
150
|
-
</response>
|
|
130
|
+
## RESPONSE FORMAT
|
|
131
|
+
|
|
132
|
+
Structure your response with clear markdown headers (no XML tags in output):
|
|
133
|
+
|
|
134
|
+
### Task Analysis
|
|
135
|
+
| Aspect | Assessment |
|
|
136
|
+
|--------|------------|
|
|
137
|
+
| **Complexity** | Simple / Moderate / Complex |
|
|
138
|
+
| **Agents** | List specialists needed |
|
|
139
|
+
|
|
140
|
+
### Plan
|
|
141
|
+
Numbered steps for execution.
|
|
142
|
+
|
|
143
|
+
### Notes
|
|
144
|
+
Any clarifications or considerations.
|
|
145
|
+
|
|
146
|
+
IMPORTANT: Do NOT output raw XML tags like <thinking>, <task_analysis>, or <response> in your response. Use clean markdown formatting only.
|
|
151
147
|
|
|
152
148
|
## COMPLEXITY SCALING
|
|
153
149
|
- **Simple** (1 agent, direct response): Factual questions, single-file changes, explanations
|
|
154
150
|
- **Moderate** (2-3 agents, coordinated): Feature implementation, debugging, code review
|
|
155
|
-
- **Complex** (3+ agents, parallel): Architecture design, full features, multi-file refactors
|
|
151
|
+
- **Complex** (3+ agents, parallel): Architecture design, full features, multi-file refactors
|
|
152
|
+
|
|
153
|
+
## ASKING QUESTIONS
|
|
154
|
+
|
|
155
|
+
When you need clarification or user input before proceeding, use this XML format for EACH question:
|
|
156
|
+
|
|
157
|
+
<question header="ShortLabel">
|
|
158
|
+
Your question text here?
|
|
159
|
+
<options>
|
|
160
|
+
<option recommended="true">First option (mark recommended if applicable)</option>
|
|
161
|
+
<option>Second option</option>
|
|
162
|
+
<option>Third option</option>
|
|
163
|
+
<option>Fourth option</option>
|
|
164
|
+
</options>
|
|
165
|
+
</question>
|
|
166
|
+
|
|
167
|
+
Guidelines for questions:
|
|
168
|
+
- header: Short label (1-2 words) like "Language", "Framework", "Approach"
|
|
169
|
+
- question: Clear, specific question ending with ?
|
|
170
|
+
- options: 2-4 concrete choices (user can also provide custom answer)
|
|
171
|
+
- recommended: Add recommended="true" to the best default option
|
|
172
|
+
|
|
173
|
+
Example with multiple questions:
|
|
174
|
+
<question header="Language">
|
|
175
|
+
What programming language should I use?
|
|
176
|
+
<options>
|
|
177
|
+
<option recommended="true">TypeScript</option>
|
|
178
|
+
<option>Python</option>
|
|
179
|
+
<option>Go</option>
|
|
180
|
+
</options>
|
|
181
|
+
</question>
|
|
182
|
+
|
|
183
|
+
<question header="Features">
|
|
184
|
+
Which features do you need?
|
|
185
|
+
<options>
|
|
186
|
+
<option recommended="true">Standard validation with error messages</option>
|
|
187
|
+
<option>NIST guidelines compliance</option>
|
|
188
|
+
<option>Password strength meter</option>
|
|
189
|
+
</options>
|
|
190
|
+
</question>
|
|
191
|
+
|
|
192
|
+
IMPORTANT: Only ask questions when genuinely needed. For straightforward requests, proceed directly with analysis and recommendations.`;
|
|
156
193
|
if (mode === 'ml') {
|
|
157
194
|
return `${orchestratorCore}
|
|
158
195
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Council Integration for AGENT-K
|
|
3
|
+
*
|
|
4
|
+
* Connects TypeScript UI to Python council backend.
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - Council: Multi-LLM via LiteLLM (GPT, Gemini, Claude)
|
|
7
|
+
* - Solo: Multi-Claude CLI instances with personas
|
|
8
|
+
*/
|
|
9
|
+
export interface StageUpdate {
|
|
10
|
+
stage: string;
|
|
11
|
+
message?: string;
|
|
12
|
+
responses?: Record<string, string>;
|
|
13
|
+
reviews?: Record<string, string>;
|
|
14
|
+
final?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CouncilResult {
|
|
17
|
+
query: string;
|
|
18
|
+
mode: 'council' | 'solo';
|
|
19
|
+
stages: Array<{
|
|
20
|
+
stage: number;
|
|
21
|
+
stage_name: string;
|
|
22
|
+
responses: Record<string, string>;
|
|
23
|
+
timestamp: string;
|
|
24
|
+
}>;
|
|
25
|
+
final_response: string;
|
|
26
|
+
chairman: string;
|
|
27
|
+
total_tokens: {
|
|
28
|
+
input: number;
|
|
29
|
+
output: number;
|
|
30
|
+
};
|
|
31
|
+
timestamp: string;
|
|
32
|
+
}
|
|
33
|
+
export interface CouncilOptions {
|
|
34
|
+
mode?: 'council' | 'solo';
|
|
35
|
+
skipScout?: boolean;
|
|
36
|
+
projectRoot?: string;
|
|
37
|
+
timeout?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run the council process.
|
|
41
|
+
*
|
|
42
|
+
* @param query User's query
|
|
43
|
+
* @param options Council options
|
|
44
|
+
* @param onStage Callback for stage updates
|
|
45
|
+
* @returns Promise resolving to final result
|
|
46
|
+
*/
|
|
47
|
+
export declare function runCouncil(query: string, options?: CouncilOptions, onStage?: (update: StageUpdate) => void): Promise<CouncilResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the council backend is available.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkCouncilAvailable(): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Get available models status from the council backend.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getAvailableModels(): Promise<Record<string, boolean>>;
|
|
56
|
+
declare const _default: {
|
|
57
|
+
runCouncil: typeof runCouncil;
|
|
58
|
+
checkCouncilAvailable: typeof checkCouncilAvailable;
|
|
59
|
+
getAvailableModels: typeof getAvailableModels;
|
|
60
|
+
};
|
|
61
|
+
export default _default;
|