agentk8 2.3.3 → 2.3.5

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
@@ -27,8 +27,14 @@ const cli = meow(`
27
27
  /exit Exit AGENT-K
28
28
 
29
29
  Keyboard
30
- Esc Esc Exit (double-press)
30
+ Esc Cancel operation (when processing)
31
+ Esc Esc Exit (double-press when idle)
31
32
  Ctrl+U Clear input line
33
+
34
+ Modes (/normal, /plan, /auto)
35
+ normal Execute, confirm edits (default)
36
+ plan Plan first, then execute
37
+ auto No confirmations
32
38
  `, {
33
39
  importMeta: import.meta,
34
40
  flags: {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from 'react';
2
+ import { useState, useEffect, useRef } from 'react';
3
3
  import { Box, Text, useApp, useInput, Static } from 'ink';
4
4
  import { WelcomeBox } from './WelcomeBox.js';
5
5
  import { ChatMessage } from './ChatMessage.js';
@@ -25,7 +25,7 @@ export const App = ({ mode, version }) => {
25
25
  const [totalTokens, setTotalTokens] = useState(0);
26
26
  const [startTime] = useState(new Date());
27
27
  const [error, setError] = useState(null);
28
- const [executionMode, setExecutionMode] = useState('plan');
28
+ const [executionMode, setExecutionMode] = useState('normal');
29
29
  const [activeAgent, setActiveAgent] = useState(undefined);
30
30
  const [completedAgents, setCompletedAgents] = useState([]);
31
31
  const [confirmationState, setConfirmationState] = useState(null);
@@ -37,6 +37,9 @@ export const App = ({ mode, version }) => {
37
37
  const [lastEscapeTime, setLastEscapeTime] = useState(0);
38
38
  const [showExitHint, setShowExitHint] = useState(false);
39
39
  const [questionWizardState, setQuestionWizardState] = useState(null);
40
+ const [showCancelHint, setShowCancelHint] = useState(false);
41
+ // Ref to track cancellation (can be checked inside async operations)
42
+ const cancelledRef = useRef(false);
40
43
  // Clean orchestrator internal tags from response
41
44
  const cleanOrchestratorTags = (response) => {
42
45
  let cleaned = response;
@@ -133,11 +136,13 @@ export const App = ({ mode, version }) => {
133
136
  await generatePlan(input);
134
137
  }
135
138
  else {
139
+ // normal or auto mode - executeTask handles autoAccept
136
140
  await executeTask(input);
137
141
  }
138
142
  };
139
143
  // Execute via Council
140
144
  const executeCouncil = async (input) => {
145
+ cancelledRef.current = false;
141
146
  setIsProcessing(true);
142
147
  setProcessingStartTime(new Date());
143
148
  setActiveAgent('Orchestrator');
@@ -185,6 +190,7 @@ export const App = ({ mode, version }) => {
185
190
  };
186
191
  // Generate a plan for approval
187
192
  const generatePlan = async (input) => {
193
+ cancelledRef.current = false;
188
194
  setIsProcessing(true);
189
195
  setProcessingStartTime(new Date());
190
196
  setActiveAgent('Orchestrator');
@@ -278,6 +284,7 @@ Format your response clearly with headers.`;
278
284
  };
279
285
  // Execute task directly
280
286
  const executeTask = async (input) => {
287
+ cancelledRef.current = false;
281
288
  setIsProcessing(true);
282
289
  setProcessingStartTime(new Date());
283
290
  setActiveAgent('Orchestrator');
@@ -366,35 +373,36 @@ Format your response clearly with headers.`;
366
373
  setActiveAgent(undefined);
367
374
  setCompletedAgents([]);
368
375
  break;
376
+ case 'normal':
377
+ setExecutionMode('normal');
378
+ setAutoAccept(false);
379
+ addSystemMessage('Normal mode. I will execute and ask for confirmation on edits.');
380
+ break;
369
381
  case 'plan':
370
382
  setExecutionMode('plan');
371
- addSystemMessage('Plan mode enabled. I will show plans for approval before executing.');
383
+ setAutoAccept(false);
384
+ addSystemMessage('Plan mode. I will create a plan for approval before executing.');
372
385
  break;
373
386
  case 'auto':
374
387
  setConfirmationState({
375
- message: '⚠️ Are you sure you want to enable Auto Mode? This will execute actions without further approval.',
388
+ message: '⚠️ Enable Auto Mode? This executes everything without any confirmations.',
376
389
  options: [
377
- { label: 'Yes, enable auto mode', value: 'yes' },
378
- { label: 'No, stay in plan mode', value: 'no' },
390
+ { label: 'Yes, enable auto', value: 'yes' },
391
+ { label: 'No, keep current mode', value: 'no' },
379
392
  ],
380
393
  onSelect: (value) => {
381
394
  setConfirmationState(null);
382
395
  if (value === 'yes') {
383
396
  setExecutionMode('auto');
384
- addSystemMessage('Auto mode enabled. I will execute tasks directly without approval.');
385
- }
386
- else {
387
- addSystemMessage('Kept in plan mode.');
397
+ setAutoAccept(true);
398
+ addSystemMessage('Auto mode. No confirmations, executing everything directly.');
388
399
  }
389
400
  },
390
- onCancel: () => {
391
- setConfirmationState(null);
392
- addSystemMessage('Kept in plan mode.');
393
- },
401
+ onCancel: () => setConfirmationState(null),
394
402
  });
395
403
  break;
396
404
  case 'mode':
397
- addSystemMessage(`Current execution mode: ${executionMode}\nUse /plan or /auto to switch.`);
405
+ addSystemMessage(`Current mode: ${executionMode}\nUse /normal, /plan, or /auto to switch.`);
398
406
  break;
399
407
  case 'agents':
400
408
  if (!activeAgent && completedAgents.length === 0) {
@@ -451,9 +459,10 @@ Format your response clearly with headers.`;
451
459
  /help - Show this help
452
460
  /clear - Clear chat history
453
461
  /status - Show session status
454
- /plan - Enable plan mode (ask before executing)
455
- /auto - Enable auto mode (execute directly)
456
- /mode - Show current execution mode
462
+ /normal - Normal mode (execute, confirm edits)
463
+ /plan - Plan mode (plan first, then execute)
464
+ /auto - Auto mode (no confirmations)
465
+ /mode - Show current mode
457
466
  /agents - Show active agents
458
467
  /council - Toggle council mode (multi-LLM consensus)
459
468
  /solo - Enable solo council (multi-Claude personas)
@@ -463,8 +472,8 @@ Format your response clearly with headers.`;
463
472
  Keyboard shortcuts:
464
473
  ↑/↓ - Browse command history
465
474
  Tab - Autocomplete commands
466
- Shift+Tab - Toggle auto-accept edits
467
- Esc Esc - Exit
475
+ Esc - Cancel operation (when processing)
476
+ Esc Esc - Exit (when idle)
468
477
  Ctrl+U - Clear input line`,
469
478
  timestamp: new Date(),
470
479
  };
@@ -494,9 +503,29 @@ Ctrl+U - Clear input line`,
494
503
  };
495
504
  // Handle keyboard shortcuts
496
505
  useInput((input, key) => {
497
- // Double-escape to exit (like Claude Code)
506
+ // Escape key handling
498
507
  if (key.escape) {
499
508
  const now = Date.now();
509
+ // If processing, single Esc cancels the operation
510
+ if (isProcessing) {
511
+ cancelledRef.current = true;
512
+ setIsProcessing(false);
513
+ setProcessingStartTime(null);
514
+ setActiveAgent(undefined);
515
+ setCouncilStage(null);
516
+ setShowCancelHint(true);
517
+ setTimeout(() => setShowCancelHint(false), 2000);
518
+ // Add cancellation message
519
+ const cancelMessage = {
520
+ id: Date.now().toString(),
521
+ role: 'system',
522
+ content: '⚠ Operation cancelled',
523
+ timestamp: new Date(),
524
+ };
525
+ setMessages(prev => [...prev, cancelMessage]);
526
+ return;
527
+ }
528
+ // Double-escape to exit (like Claude Code)
500
529
  if (now - lastEscapeTime < 500) {
501
530
  // Double escape - exit
502
531
  exit();
@@ -510,30 +539,6 @@ Ctrl+U - Clear input line`,
510
539
  }
511
540
  }
512
541
  }
513
- // Shift+Tab to toggle auto-accept
514
- if (key.shift && key.tab) {
515
- if (autoAccept) {
516
- // Disable silently
517
- setAutoAccept(false);
518
- }
519
- else {
520
- // Show confirmation prompt
521
- setConfirmationState({
522
- message: 'Enable auto-accept for code edits?',
523
- options: [
524
- { label: 'Yes, enable auto-accept', value: 'yes' },
525
- { label: 'No, keep asking', value: 'no' },
526
- ],
527
- onSelect: (value) => {
528
- setConfirmationState(null);
529
- if (value === 'yes') {
530
- setAutoAccept(true);
531
- }
532
- },
533
- onCancel: () => setConfirmationState(null),
534
- });
535
- }
536
- }
537
542
  });
538
543
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: messages, children: (item) => {
539
544
  if ('isWelcome' in item && item.isWelcome) {
@@ -3,7 +3,7 @@ import { AgentName } from './AgentPanel.js';
3
3
  type CouncilMode = 'solo' | 'council' | 'off';
4
4
  interface StatusBarProps {
5
5
  mode: 'dev' | 'ml';
6
- executionMode: 'plan' | 'auto';
6
+ executionMode: 'normal' | 'plan' | 'auto';
7
7
  tokens: number;
8
8
  startTime: Date;
9
9
  isProcessing?: boolean;
@@ -95,7 +95,7 @@ export const StatusBar = ({ mode, executionMode, tokens, startTime, isProcessing
95
95
  };
96
96
  return stages[councilStage] || councilStage;
97
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) => {
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 " }), councilMode !== 'off' ? (_jsxs(_Fragment, { children: [Object.entries(modelIcons).map(([model, icon], i) => {
99
99
  const isAvailable = availableModels[model];
100
100
  const color = isAvailable ? theme.done : theme.dim;
101
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));
@@ -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: [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 " })] })] }));
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' })] })), executionMode !== 'normal' && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.border, children: " \u2502 " }), _jsx(Text, { color: executionMode === 'auto' ? theme.active : theme.accent, children: executionMode.toUpperCase() })] })), 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;
@@ -54,6 +54,6 @@ export const ThinkingIndicator = ({ startTime, tokens = 0, }) => {
54
54
  return `${(t / 1000).toFixed(1)}k`;
55
55
  return t.toString();
56
56
  };
57
- return (_jsxs(Box, { marginY: 1, marginLeft: 1, children: [_jsxs(Text, { color: theme.purple, bold: true, children: [symbols[frame], " "] }), _jsxs(Text, { color: theme.highlight, italic: true, children: [verb, "\u2026"] }), _jsx(Text, { color: theme.dim, children: " (" }), _jsx(Text, { color: theme.dim, children: "esc esc to exit" }), _jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsx(Text, { color: theme.accent, children: elapsed }), tokens > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsxs(Text, { color: theme.accent, children: ["\u2193 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: " tokens" })] })), _jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsx(Text, { color: theme.purple, children: "thinking" }), _jsx(Text, { color: theme.dim, children: ")" })] }));
57
+ return (_jsxs(Box, { marginY: 1, marginLeft: 1, children: [_jsxs(Text, { color: theme.purple, bold: true, children: [symbols[frame], " "] }), _jsxs(Text, { color: theme.highlight, italic: true, children: [verb, "\u2026"] }), _jsx(Text, { color: theme.dim, children: " (" }), _jsx(Text, { color: theme.dim, children: "Esc to cancel" }), _jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsx(Text, { color: theme.accent, children: elapsed }), tokens > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsxs(Text, { color: theme.accent, children: ["\u2193 ", formatTokens(tokens)] }), _jsx(Text, { color: theme.dim, children: " tokens" })] })), _jsx(Text, { color: theme.dim, children: " \u00B7 " }), _jsx(Text, { color: theme.purple, children: "thinking" }), _jsx(Text, { color: theme.dim, children: ")" })] }));
58
58
  };
59
59
  export default ThinkingIndicator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentk8",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "Multi-LLM Council Terminal Suite - Three-stage consensus with GPT, Gemini, and Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",