agentk8 2.3.0 → 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/components/App.js +176 -39
- package/dist/components/ChatMessage.js +93 -1
- package/dist/components/QuestionWizard.d.ts +21 -0
- package/dist/components/QuestionWizard.js +152 -0
- package/dist/components/StatusBar.d.ts +1 -0
- package/dist/components/StatusBar.js +2 -2
- package/dist/components/WelcomeBox.js +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/lib/claude.js +59 -22
- package/package.json +1 -1
package/dist/components/App.js
CHANGED
|
@@ -9,9 +9,17 @@ import { ThinkingIndicator } from './ThinkingIndicator.js';
|
|
|
9
9
|
import { runClaude } from '../lib/claude.js';
|
|
10
10
|
import { runCouncil, checkCouncilAvailable, getAvailableModels } from '../lib/council.js';
|
|
11
11
|
import { Confirmation } from './Confirmation.js';
|
|
12
|
+
import { QuestionWizard } from './QuestionWizard.js';
|
|
12
13
|
export const App = ({ mode, version }) => {
|
|
13
14
|
const { exit } = useApp();
|
|
14
|
-
|
|
15
|
+
// Initialize with welcome message as permanent first item
|
|
16
|
+
const [messages, setMessages] = useState([{
|
|
17
|
+
id: 'welcome',
|
|
18
|
+
role: 'system',
|
|
19
|
+
content: '',
|
|
20
|
+
timestamp: new Date(),
|
|
21
|
+
isWelcome: true,
|
|
22
|
+
}]);
|
|
15
23
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
16
24
|
const [processingStartTime, setProcessingStartTime] = useState(null);
|
|
17
25
|
const [totalTokens, setTotalTokens] = useState(0);
|
|
@@ -26,6 +34,60 @@ export const App = ({ mode, version }) => {
|
|
|
26
34
|
const [councilAvailable, setCouncilAvailable] = useState(false);
|
|
27
35
|
const [availableModels, setAvailableModels] = useState({});
|
|
28
36
|
const [councilStage, setCouncilStage] = useState(null);
|
|
37
|
+
const [lastEscapeTime, setLastEscapeTime] = useState(0);
|
|
38
|
+
const [showExitHint, setShowExitHint] = useState(false);
|
|
39
|
+
const [questionWizardState, setQuestionWizardState] = useState(null);
|
|
40
|
+
// Clean orchestrator internal tags from response
|
|
41
|
+
const cleanOrchestratorTags = (response) => {
|
|
42
|
+
let cleaned = response;
|
|
43
|
+
// Remove <thinking>...</thinking> blocks
|
|
44
|
+
cleaned = cleaned.replace(/<thinking>[\s\S]*?<\/thinking>/g, '');
|
|
45
|
+
// Remove <task_analysis>...</task_analysis> blocks (keep content inside)
|
|
46
|
+
cleaned = cleaned.replace(/<\/?task_analysis>/g, '');
|
|
47
|
+
// Remove <response>...</response> tags (keep content inside)
|
|
48
|
+
cleaned = cleaned.replace(/<\/?response>/g, '');
|
|
49
|
+
// Clean up multiple consecutive newlines
|
|
50
|
+
cleaned = cleaned.replace(/\n{3,}/g, '\n\n');
|
|
51
|
+
// Clean up leading/trailing whitespace
|
|
52
|
+
cleaned = cleaned.trim();
|
|
53
|
+
return cleaned;
|
|
54
|
+
};
|
|
55
|
+
// Parse questions from orchestrator response
|
|
56
|
+
const parseQuestions = (response) => {
|
|
57
|
+
const questions = [];
|
|
58
|
+
let cleanedResponse = response;
|
|
59
|
+
// Match <question header="...">...</question> blocks
|
|
60
|
+
const questionRegex = /<question\s+header="([^"]+)">\s*([\s\S]*?)\s*<options>\s*([\s\S]*?)\s*<\/options>\s*<\/question>/g;
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = questionRegex.exec(response)) !== null) {
|
|
63
|
+
const header = match[1];
|
|
64
|
+
const questionText = match[2].trim();
|
|
65
|
+
const optionsBlock = match[3];
|
|
66
|
+
// Parse options
|
|
67
|
+
const optionRegex = /<option(?:\s+recommended="true")?>(.*?)<\/option>/g;
|
|
68
|
+
const options = [];
|
|
69
|
+
let optionMatch;
|
|
70
|
+
while ((optionMatch = optionRegex.exec(optionsBlock)) !== null) {
|
|
71
|
+
const isRecommended = optionMatch[0].includes('recommended="true"');
|
|
72
|
+
options.push({
|
|
73
|
+
label: optionMatch[1].trim(),
|
|
74
|
+
recommended: isRecommended,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (options.length > 0) {
|
|
78
|
+
questions.push({
|
|
79
|
+
header,
|
|
80
|
+
question: questionText,
|
|
81
|
+
options,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// Remove this question block from the response
|
|
85
|
+
cleanedResponse = cleanedResponse.replace(match[0], '').trim();
|
|
86
|
+
}
|
|
87
|
+
// Clean orchestrator internal tags from the remaining response
|
|
88
|
+
cleanedResponse = cleanOrchestratorTags(cleanedResponse);
|
|
89
|
+
return { questions, cleanedResponse };
|
|
90
|
+
};
|
|
29
91
|
// Check council availability on mount
|
|
30
92
|
useEffect(() => {
|
|
31
93
|
checkCouncilAvailable().then(setCouncilAvailable);
|
|
@@ -136,18 +198,21 @@ Respond with:
|
|
|
136
198
|
1. Task Analysis (complexity, scope)
|
|
137
199
|
2. Agents Required (list which specialists are needed)
|
|
138
200
|
3. Step-by-Step Plan (numbered steps)
|
|
139
|
-
4. Questions (if any clarification needed)
|
|
201
|
+
4. Questions (if any clarification needed - use the XML question format)
|
|
140
202
|
|
|
141
203
|
Format your response clearly with headers.`;
|
|
142
204
|
const result = await runClaude(planPrompt, mode, autoAccept);
|
|
143
|
-
|
|
205
|
+
// Check for questions in response
|
|
206
|
+
const { questions, cleanedResponse } = parseQuestions(result.response);
|
|
207
|
+
const mentioned = detectMentionedAgents(cleanedResponse || result.response);
|
|
144
208
|
setCompletedAgents(['Orchestrator', ...mentioned]);
|
|
145
209
|
setActiveAgent(undefined);
|
|
210
|
+
// Show the cleaned response (without question XML)
|
|
146
211
|
const planMessage = {
|
|
147
212
|
id: (Date.now() + 1).toString(),
|
|
148
213
|
role: 'agent',
|
|
149
214
|
agentName: 'Orchestrator',
|
|
150
|
-
content: result.response,
|
|
215
|
+
content: cleanedResponse || result.response,
|
|
151
216
|
tokens: result.tokens,
|
|
152
217
|
timestamp: new Date(),
|
|
153
218
|
};
|
|
@@ -155,31 +220,58 @@ Format your response clearly with headers.`;
|
|
|
155
220
|
if (result.tokens) {
|
|
156
221
|
setTotalTokens(prev => prev + result.tokens.input + result.tokens.output);
|
|
157
222
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
223
|
+
// Stop processing BEFORE showing wizard/confirmation to prevent overlap
|
|
224
|
+
setIsProcessing(false);
|
|
225
|
+
setProcessingStartTime(null);
|
|
226
|
+
// If questions were found, show the wizard
|
|
227
|
+
if (questions.length > 0) {
|
|
228
|
+
setQuestionWizardState({
|
|
229
|
+
questions,
|
|
230
|
+
originalInput: input,
|
|
231
|
+
onComplete: async (answers) => {
|
|
232
|
+
setQuestionWizardState(null);
|
|
233
|
+
// Format answers as follow-up message
|
|
234
|
+
const answerText = answers.map(a => `- ${a.header}: ${a.answer}`).join('\n');
|
|
235
|
+
const followUp = `My answers:\n${answerText}\n\nPlease proceed with these choices.`;
|
|
236
|
+
// Add user message with answers
|
|
237
|
+
const userAnswer = {
|
|
238
|
+
id: Date.now().toString(),
|
|
239
|
+
role: 'user',
|
|
240
|
+
content: followUp,
|
|
241
|
+
timestamp: new Date(),
|
|
242
|
+
};
|
|
243
|
+
setMessages(prev => [...prev, userAnswer]);
|
|
244
|
+
// Continue with the task including answers
|
|
245
|
+
await executeTask(`${input}\n\n${followUp}`);
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// No questions, show plan approval
|
|
251
|
+
setConfirmationState({
|
|
252
|
+
message: 'Do you want to execute this plan?',
|
|
253
|
+
options: [
|
|
254
|
+
{ label: 'Yes, execute plan', value: 'yes', key: 'Enter' },
|
|
255
|
+
{ label: 'No, cancel', value: 'no', key: 'Esc' },
|
|
256
|
+
],
|
|
257
|
+
onSelect: (value) => {
|
|
258
|
+
setConfirmationState(null);
|
|
259
|
+
if (value === 'yes') {
|
|
260
|
+
executeTask(input);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
addSystemMessage('Plan cancelled.');
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
onCancel: () => {
|
|
267
|
+
setConfirmationState(null);
|
|
170
268
|
addSystemMessage('Plan cancelled.');
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
setConfirmationState(null);
|
|
175
|
-
addSystemMessage('Plan cancelled.');
|
|
176
|
-
},
|
|
177
|
-
});
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
}
|
|
178
272
|
}
|
|
179
273
|
catch (err) {
|
|
180
274
|
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
181
|
-
}
|
|
182
|
-
finally {
|
|
183
275
|
setIsProcessing(false);
|
|
184
276
|
setProcessingStartTime(null);
|
|
185
277
|
}
|
|
@@ -193,14 +285,16 @@ Format your response clearly with headers.`;
|
|
|
193
285
|
setError(null);
|
|
194
286
|
try {
|
|
195
287
|
const result = await runClaude(input, mode, autoAccept);
|
|
196
|
-
|
|
288
|
+
// Check for questions in response
|
|
289
|
+
const { questions, cleanedResponse } = parseQuestions(result.response);
|
|
290
|
+
const mentioned = detectMentionedAgents(cleanedResponse || result.response);
|
|
197
291
|
setCompletedAgents(['Orchestrator', ...mentioned]);
|
|
198
292
|
setActiveAgent(undefined);
|
|
199
293
|
const agentMessage = {
|
|
200
294
|
id: (Date.now() + 1).toString(),
|
|
201
295
|
role: 'agent',
|
|
202
296
|
agentName: 'Orchestrator',
|
|
203
|
-
content: result.response,
|
|
297
|
+
content: cleanedResponse || result.response,
|
|
204
298
|
tokens: result.tokens,
|
|
205
299
|
timestamp: new Date(),
|
|
206
300
|
};
|
|
@@ -208,11 +302,35 @@ Format your response clearly with headers.`;
|
|
|
208
302
|
if (result.tokens) {
|
|
209
303
|
setTotalTokens(prev => prev + result.tokens.input + result.tokens.output);
|
|
210
304
|
}
|
|
305
|
+
// Stop processing BEFORE showing wizard to prevent overlap
|
|
306
|
+
setIsProcessing(false);
|
|
307
|
+
setProcessingStartTime(null);
|
|
308
|
+
// If questions were found, show the wizard
|
|
309
|
+
if (questions.length > 0) {
|
|
310
|
+
setQuestionWizardState({
|
|
311
|
+
questions,
|
|
312
|
+
originalInput: input,
|
|
313
|
+
onComplete: async (answers) => {
|
|
314
|
+
setQuestionWizardState(null);
|
|
315
|
+
// Format answers as follow-up message
|
|
316
|
+
const answerText = answers.map(a => `- ${a.header}: ${a.answer}`).join('\n');
|
|
317
|
+
const followUp = `My answers:\n${answerText}\n\nPlease proceed with these choices.`;
|
|
318
|
+
// Add user message with answers
|
|
319
|
+
const userAnswer = {
|
|
320
|
+
id: Date.now().toString(),
|
|
321
|
+
role: 'user',
|
|
322
|
+
content: followUp,
|
|
323
|
+
timestamp: new Date(),
|
|
324
|
+
};
|
|
325
|
+
setMessages(prev => [...prev, userAnswer]);
|
|
326
|
+
// Continue with the task including answers
|
|
327
|
+
await executeTask(`${input}\n\n${followUp}`);
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
}
|
|
211
331
|
}
|
|
212
332
|
catch (err) {
|
|
213
333
|
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
214
|
-
}
|
|
215
|
-
finally {
|
|
216
334
|
setIsProcessing(false);
|
|
217
335
|
setProcessingStartTime(null);
|
|
218
336
|
}
|
|
@@ -237,7 +355,14 @@ Format your response clearly with headers.`;
|
|
|
237
355
|
exit();
|
|
238
356
|
break;
|
|
239
357
|
case 'clear':
|
|
240
|
-
|
|
358
|
+
// Keep welcome message, clear everything else
|
|
359
|
+
setMessages([{
|
|
360
|
+
id: 'welcome',
|
|
361
|
+
role: 'system',
|
|
362
|
+
content: '',
|
|
363
|
+
timestamp: new Date(),
|
|
364
|
+
isWelcome: true,
|
|
365
|
+
}]);
|
|
241
366
|
setActiveAgent(undefined);
|
|
242
367
|
setCompletedAgents([]);
|
|
243
368
|
break;
|
|
@@ -339,7 +464,7 @@ Keyboard shortcuts:
|
|
|
339
464
|
↑/↓ - Browse command history
|
|
340
465
|
Tab - Autocomplete commands
|
|
341
466
|
Shift+Tab - Toggle auto-accept edits
|
|
342
|
-
|
|
467
|
+
Esc Esc - Exit
|
|
343
468
|
Ctrl+U - Clear input line`,
|
|
344
469
|
timestamp: new Date(),
|
|
345
470
|
};
|
|
@@ -369,8 +494,21 @@ Ctrl+U - Clear input line`,
|
|
|
369
494
|
};
|
|
370
495
|
// Handle keyboard shortcuts
|
|
371
496
|
useInput((input, key) => {
|
|
372
|
-
|
|
373
|
-
|
|
497
|
+
// Double-escape to exit (like Claude Code)
|
|
498
|
+
if (key.escape) {
|
|
499
|
+
const now = Date.now();
|
|
500
|
+
if (now - lastEscapeTime < 500) {
|
|
501
|
+
// Double escape - exit
|
|
502
|
+
exit();
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
// First escape - show hint and record time
|
|
506
|
+
setLastEscapeTime(now);
|
|
507
|
+
if (!questionWizardState && !confirmationState) {
|
|
508
|
+
setShowExitHint(true);
|
|
509
|
+
setTimeout(() => setShowExitHint(false), 1500);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
374
512
|
}
|
|
375
513
|
// Shift+Tab to toggle auto-accept
|
|
376
514
|
if (key.shift && key.tab) {
|
|
@@ -397,16 +535,15 @@ Ctrl+U - Clear input line`,
|
|
|
397
535
|
}
|
|
398
536
|
}
|
|
399
537
|
});
|
|
400
|
-
|
|
401
|
-
const staticItems = messages.length === 0
|
|
402
|
-
? [{ id: 'welcome', isWelcome: true, role: 'system', content: '', timestamp: new Date() }]
|
|
403
|
-
: messages;
|
|
404
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: staticItems, children: (item) => {
|
|
538
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: messages, children: (item) => {
|
|
405
539
|
if ('isWelcome' in item && item.isWelcome) {
|
|
406
540
|
return _jsx(WelcomeBox, { version: version, mode: mode }, "welcome");
|
|
407
541
|
}
|
|
408
542
|
return (_jsx(ChatMessage, { role: item.role, agentName: item.agentName, content: item.content, tokens: item.tokens }, item.id));
|
|
409
|
-
} }), isProcessing && processingStartTime && (_jsx(ThinkingIndicator, { startTime: processingStartTime })), error && (_jsx(Box, { marginY: 1, marginLeft: 1, children: _jsxs(Text, { color: "#e53e3e", children: ["\u2717 Error: ", error] }) })),
|
|
543
|
+
} }), isProcessing && processingStartTime && (_jsx(ThinkingIndicator, { startTime: processingStartTime })), error && (_jsx(Box, { marginY: 1, marginLeft: 1, children: _jsxs(Text, { color: "#e53e3e", children: ["\u2717 Error: ", error] }) })), questionWizardState ? (_jsx(QuestionWizard, { questions: questionWizardState.questions, onComplete: questionWizardState.onComplete, onCancel: () => {
|
|
544
|
+
setQuestionWizardState(null);
|
|
545
|
+
addSystemMessage('Questions cancelled.');
|
|
546
|
+
} }, `wizard-${questionWizardState.questions.map(q => q.header).join('-')}`)) : confirmationState ? (_jsx(Confirmation, { message: confirmationState.message, options: confirmationState.options, onSelect: confirmationState.onSelect, onCancel: confirmationState.onCancel })) : (_jsx(Input, { onSubmit: handleSubmit, disabled: isProcessing, placeholder: 'Try "build a password validator"' })), _jsx(StatusBar, { mode: mode, executionMode: executionMode, tokens: totalTokens, startTime: startTime, isProcessing: isProcessing, activeAgent: activeAgent, completedAgents: completedAgents, autoAccept: autoAccept, councilMode: councilMode, councilStage: councilStage, availableModels: availableModels, showExitHint: showExitHint })] }));
|
|
410
547
|
};
|
|
411
548
|
function formatElapsed(start) {
|
|
412
549
|
const secs = Math.floor((Date.now() - start.getTime()) / 1000);
|
|
@@ -10,21 +10,113 @@ const theme = {
|
|
|
10
10
|
user: '#9f7aea', // Purple for user
|
|
11
11
|
agent: '#4fd1c5', // Teal for agent
|
|
12
12
|
system: '#f6e05e', // Yellow for system
|
|
13
|
+
code: '#f6ad55', // Orange for inline code
|
|
14
|
+
header: '#63b3ed', // Blue for headers
|
|
13
15
|
};
|
|
16
|
+
// Parse inline markdown and return React elements
|
|
17
|
+
function parseInlineMarkdown(text, defaultColor) {
|
|
18
|
+
const elements = [];
|
|
19
|
+
let remaining = text;
|
|
20
|
+
let key = 0;
|
|
21
|
+
while (remaining.length > 0) {
|
|
22
|
+
// Check for bold **text**
|
|
23
|
+
const boldMatch = remaining.match(/^\*\*(.+?)\*\*/);
|
|
24
|
+
if (boldMatch) {
|
|
25
|
+
elements.push(_jsx(Text, { color: defaultColor, bold: true, children: boldMatch[1] }, key++));
|
|
26
|
+
remaining = remaining.slice(boldMatch[0].length);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Check for inline code `code`
|
|
30
|
+
const codeMatch = remaining.match(/^`([^`]+)`/);
|
|
31
|
+
if (codeMatch) {
|
|
32
|
+
elements.push(_jsx(Text, { color: theme.code, children: codeMatch[1] }, key++));
|
|
33
|
+
remaining = remaining.slice(codeMatch[0].length);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
// Check for italic *text* or _text_
|
|
37
|
+
const italicMatch = remaining.match(/^(\*|_)([^*_]+)\1/);
|
|
38
|
+
if (italicMatch) {
|
|
39
|
+
elements.push(_jsx(Text, { color: defaultColor, italic: true, children: italicMatch[2] }, key++));
|
|
40
|
+
remaining = remaining.slice(italicMatch[0].length);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Find next special character
|
|
44
|
+
const nextSpecial = remaining.search(/[\*`_]/);
|
|
45
|
+
if (nextSpecial === -1) {
|
|
46
|
+
// No more special chars, add rest as plain text
|
|
47
|
+
elements.push(_jsx(Text, { color: defaultColor, children: remaining }, key++));
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
else if (nextSpecial === 0) {
|
|
51
|
+
// Special char at start but didn't match pattern - treat as literal
|
|
52
|
+
elements.push(_jsx(Text, { color: defaultColor, children: remaining[0] }, key++));
|
|
53
|
+
remaining = remaining.slice(1);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Add text before special char
|
|
57
|
+
elements.push(_jsx(Text, { color: defaultColor, children: remaining.slice(0, nextSpecial) }, key++));
|
|
58
|
+
remaining = remaining.slice(nextSpecial);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return elements;
|
|
62
|
+
}
|
|
63
|
+
// Render a single line with markdown formatting
|
|
64
|
+
function renderLine(line, index, defaultColor) {
|
|
65
|
+
// Header detection (## Header)
|
|
66
|
+
const headerMatch = line.match(/^(#{1,3})\s+(.+)$/);
|
|
67
|
+
if (headerMatch) {
|
|
68
|
+
const level = headerMatch[1].length;
|
|
69
|
+
const content = headerMatch[2];
|
|
70
|
+
return (_jsx(Box, { children: _jsx(Text, { color: theme.header, bold: true, children: content }) }, index));
|
|
71
|
+
}
|
|
72
|
+
// List item detection (- item or * item)
|
|
73
|
+
const listMatch = line.match(/^(\s*)([-*])\s+(.+)$/);
|
|
74
|
+
if (listMatch) {
|
|
75
|
+
const indent = listMatch[1];
|
|
76
|
+
const content = listMatch[3];
|
|
77
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: defaultColor, children: [indent, "\u2022 "] }), parseInlineMarkdown(content, defaultColor)] }, index));
|
|
78
|
+
}
|
|
79
|
+
// Numbered list detection (1. item)
|
|
80
|
+
const numberedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
81
|
+
if (numberedMatch) {
|
|
82
|
+
const indent = numberedMatch[1];
|
|
83
|
+
const num = numberedMatch[2];
|
|
84
|
+
const content = numberedMatch[3];
|
|
85
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: defaultColor, children: [indent, num, ". "] }), parseInlineMarkdown(content, defaultColor)] }, index));
|
|
86
|
+
}
|
|
87
|
+
// Table row detection (| col | col |)
|
|
88
|
+
if (line.includes('|') && (line.trim().startsWith('|') || line.includes(' | '))) {
|
|
89
|
+
// Keep table formatting as-is but with subtle styling
|
|
90
|
+
const isSeparator = line.match(/^[\s|:-]+$/);
|
|
91
|
+
if (isSeparator) {
|
|
92
|
+
return (_jsx(Box, { children: _jsx(Text, { color: theme.dim, children: line }) }, index));
|
|
93
|
+
}
|
|
94
|
+
return (_jsx(Box, { children: _jsx(Text, { color: defaultColor, children: line }) }, index));
|
|
95
|
+
}
|
|
96
|
+
// Regular line with inline markdown
|
|
97
|
+
return (_jsx(Box, { children: parseInlineMarkdown(line, defaultColor) }, index));
|
|
98
|
+
}
|
|
14
99
|
export const ChatMessage = ({ role, agentName = 'Agent', content, tokens, }) => {
|
|
15
100
|
const isUser = role === 'user';
|
|
16
101
|
const isSystem = role === 'system';
|
|
17
102
|
const symbolColor = isUser ? theme.user : isSystem ? theme.system : theme.agent;
|
|
18
103
|
const title = isUser ? 'You' : agentName;
|
|
104
|
+
const textColor = theme.text;
|
|
19
105
|
const termWidth = process.stdout.columns || 80;
|
|
20
106
|
const contentWidth = termWidth - 6;
|
|
107
|
+
// Split content into lines and wrap long lines
|
|
21
108
|
const lines = wrapText(content, contentWidth);
|
|
22
|
-
return (_jsxs(Box, { flexDirection: "column", marginY: 1, marginLeft: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: symbolColor, children: '◆ ' }), _jsx(Text, { color: symbolColor, bold: true, children: title })] }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: lines.map((line, i) => (
|
|
109
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 1, marginLeft: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: symbolColor, children: '◆ ' }), _jsx(Text, { color: symbolColor, bold: true, children: title })] }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: lines.map((line, i) => renderLine(line, i, textColor)) }), tokens && tokens.input + tokens.output > 0 && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: theme.dim, children: ["\u2192 ", tokens.input + tokens.output, " tokens"] }) }))] }));
|
|
23
110
|
};
|
|
24
111
|
function wrapText(text, width) {
|
|
25
112
|
const lines = [];
|
|
26
113
|
const paragraphs = text.split('\n');
|
|
27
114
|
for (const para of paragraphs) {
|
|
115
|
+
// Don't wrap table lines or lines with special formatting
|
|
116
|
+
if (para.includes('|') || para.match(/^#{1,3}\s/) || para.match(/^[\s]*[-*]\s/) || para.match(/^[\s]*\d+\.\s/)) {
|
|
117
|
+
lines.push(para);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
28
120
|
if (para.length <= width) {
|
|
29
121
|
lines.push(para);
|
|
30
122
|
}
|
|
@@ -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;
|
|
@@ -29,7 +29,7 @@ const modelIcons = {
|
|
|
29
29
|
gemini: 'M',
|
|
30
30
|
claude: 'C',
|
|
31
31
|
};
|
|
32
|
-
export const StatusBar = ({ mode, executionMode, tokens, startTime, isProcessing = false, activeAgent, completedAgents = [], autoAccept = false, councilMode = 'off', councilStage = null, availableModels = {}, }) => {
|
|
32
|
+
export const StatusBar = ({ mode, executionMode, tokens, startTime, isProcessing = false, activeAgent, completedAgents = [], autoAccept = false, councilMode = 'off', councilStage = null, availableModels = {}, showExitHint = false, }) => {
|
|
33
33
|
const [elapsed, setElapsed] = useState('');
|
|
34
34
|
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
35
35
|
const [pulseFrame, setPulseFrame] = useState(0);
|
|
@@ -106,6 +106,6 @@ export const StatusBar = ({ mode, executionMode, tokens, startTime, isProcessing
|
|
|
106
106
|
const leftBracket = isActive ? pulseBrackets[pulseFrame] : '[';
|
|
107
107
|
const rightBracket = isActive ? pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '<' ? '>' : pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '{' ? '}' : pulseBrackets[(pulseFrame + 3) % pulseBrackets.length] === '(' ? ')' : ']' : ']';
|
|
108
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: [_jsxs(Text, { color: theme.accent, children: ["\u2191 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: " tokens " })] })] }));
|
|
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 " })] })] }));
|
|
110
110
|
};
|
|
111
111
|
export default StatusBar;
|
|
@@ -41,6 +41,6 @@ export const WelcomeBox = ({ version, mode }) => {
|
|
|
41
41
|
______\\ \\_______.--'. \`---..._____...---'
|
|
42
42
|
\`-------..__ \` ,/
|
|
43
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
|
|
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" })] })] }));
|
|
45
45
|
};
|
|
46
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
|
|