centaurus-cli 2.9.9 → 3.0.0

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.
Files changed (52) hide show
  1. package/dist/cli-adapter.d.ts +7 -0
  2. package/dist/cli-adapter.d.ts.map +1 -1
  3. package/dist/cli-adapter.js +238 -153
  4. package/dist/cli-adapter.js.map +1 -1
  5. package/dist/context/handlers/docker-handler.d.ts.map +1 -1
  6. package/dist/context/handlers/docker-handler.js +2 -2
  7. package/dist/context/handlers/docker-handler.js.map +1 -1
  8. package/dist/context/handlers/ssh-handler.d.ts.map +1 -1
  9. package/dist/context/handlers/ssh-handler.js +3 -0
  10. package/dist/context/handlers/ssh-handler.js.map +1 -1
  11. package/dist/context/handlers/wsl-handler.d.ts.map +1 -1
  12. package/dist/context/handlers/wsl-handler.js +9 -3
  13. package/dist/context/handlers/wsl-handler.js.map +1 -1
  14. package/dist/index.js +49 -7
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp/mcp-server-manager.d.ts.map +1 -1
  17. package/dist/mcp/mcp-server-manager.js +17 -3
  18. package/dist/mcp/mcp-server-manager.js.map +1 -1
  19. package/dist/services/api-client.d.ts +4 -0
  20. package/dist/services/api-client.d.ts.map +1 -1
  21. package/dist/services/api-client.js +27 -18
  22. package/dist/services/api-client.js.map +1 -1
  23. package/dist/services/conversation-manager.d.ts.map +1 -1
  24. package/dist/services/conversation-manager.js +3 -2
  25. package/dist/services/conversation-manager.js.map +1 -1
  26. package/dist/tools/enter-remote-session.d.ts +35 -0
  27. package/dist/tools/enter-remote-session.d.ts.map +1 -1
  28. package/dist/tools/enter-remote-session.js +5 -5
  29. package/dist/tools/enter-remote-session.js.map +1 -1
  30. package/dist/ui/components/App.d.ts +2 -0
  31. package/dist/ui/components/App.d.ts.map +1 -1
  32. package/dist/ui/components/App.js +55 -48
  33. package/dist/ui/components/App.js.map +1 -1
  34. package/dist/ui/components/ToolExecutionMessage.js +1 -1
  35. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  36. package/dist/utils/shell.d.ts.map +1 -1
  37. package/dist/utils/shell.js +12 -1
  38. package/dist/utils/shell.js.map +1 -1
  39. package/dist/utils/syntax-checker.d.ts.map +1 -1
  40. package/dist/utils/syntax-checker.js +26 -0
  41. package/dist/utils/syntax-checker.js.map +1 -1
  42. package/dist/utils/terminal-output.d.ts.map +1 -1
  43. package/dist/utils/terminal-output.js +10 -8
  44. package/dist/utils/terminal-output.js.map +1 -1
  45. package/dist/utils/text-clipboard.d.ts.map +1 -1
  46. package/dist/utils/text-clipboard.js +21 -8
  47. package/dist/utils/text-clipboard.js.map +1 -1
  48. package/package.json +6 -2
  49. package/dist/config/ConfigManager.d.ts +0 -62
  50. package/dist/config/ConfigManager.d.ts.map +0 -1
  51. package/dist/config/ConfigManager.js +0 -234
  52. package/dist/config/ConfigManager.js.map +0 -1
@@ -175,7 +175,7 @@ const RenameInputScreen = ({ currentTitle, onRename, onCancel }) => {
175
175
  React.createElement(Box, { marginTop: 1 },
176
176
  React.createElement(Text, { dimColor: true }, "Press Enter to save, ESC to cancel"))));
177
177
  };
178
- export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode, onResponseReceived, onDirectMessage, onResponseStream, onClearStreamedResponse, onThoughtStream, onThoughtComplete, onPickerSetup, onPickerSelection, onToolExecutionUpdate, onToolApprovalRequest, onToolStreamingOutput, onPlanModeChange, onPlanApprovalRequest, onPlanCreated, onTaskCompleted, onCommandModeChange, onToggleCommandMode, onBackgroundModeChange, onToggleBackgroundMode, onBackgroundTaskCountChange, onSubAgentCountChange, onSetAutoModeSetup, onCwdChange, onModelChange, onSubshellContextChange, onPasswordRequest, onShellInput, onShellSignal, onKillProcess, onInteractiveEditorMode, onConnectionStatusUpdate, onTokenCountUpdate, onContextLimitReached, onChatPickerSetup, onChatPickerSelection, onChatDeletePickerSetup, onChatDeletePickerSelection, onChatListSetup, onChatRenamePickerSetup, onChatRename, onRestoreMessagesSetup, onUIMessageHistoryUpdate, onBackgroundTaskListSetup, onBackgroundTaskSelection, onBackgroundTaskCancelSetup, onBackgroundTaskCancel, onBackgroundTaskViewSetup, onSessionQuotaUpdate, onMCPAddScreenSetup, onMCPRemoveScreenSetup, onMCPEnableScreenSetup, onMCPDisableScreenSetup, onMCPListScreenSetup, onMCPAddServer, onMCPRemoveServer, onMCPEnableServer, onMCPDisableServer, onMCPValidateConfig, onPromptAnswered, getMainConversation, onWarpifySession, onAiAutoSuggestChange, onWorkflowCreatorSetup, onWorkflowSave, getCheckpoints, onRevertToCheckpointSetup, onSetInputSetup }) => {
178
+ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode, onResponseReceived, onDirectMessage, onResponseStream, onClearStreamedResponse, onThoughtStream, onThoughtComplete, onPickerSetup, onPickerSelection, onToolExecutionUpdate, onToolApprovalRequest, onToolStreamingOutput, onPlanModeChange, onPlanApprovalRequest, onPlanCreated, onTaskCompleted, onCommandModeChange, onToggleCommandMode, onBackgroundModeChange, onToggleBackgroundMode, onBackgroundTaskCountChange, onSubAgentCountChange, onSetAutoModeSetup, onCwdChange, onModelChange, onSubshellContextChange, onPasswordRequest, onShellInput, onShellSignal, onKillProcess, onInteractiveEditorMode, onConnectionStatusUpdate, onTokenCountUpdate, onContextLimitReached, onChatPickerSetup, onChatPickerSelection, onChatDeletePickerSetup, onChatDeletePickerSelection, onChatListSetup, onChatRenamePickerSetup, onChatRename, onRestoreMessagesSetup, onUIMessageHistoryUpdate, onBackgroundTaskListSetup, onBackgroundTaskSelection, onBackgroundTaskCancelSetup, onBackgroundTaskCancel, onBackgroundTaskViewSetup, onSessionQuotaUpdate, onMCPAddScreenSetup, onMCPRemoveScreenSetup, onMCPEnableScreenSetup, onMCPDisableScreenSetup, onMCPListScreenSetup, onMCPAddServer, onMCPRemoveServer, onMCPEnableServer, onMCPDisableServer, onMCPValidateConfig, onPromptAnswered, getMainConversation, onWarpifySession, onAiAutoSuggestChange, onWorkflowCreatorSetup, onWorkflowSave, getCheckpoints, onRevertToCheckpointSetup, onSetInputSetup, onInterruptQueueUpdate, onQueuedMessageDispatched }) => {
179
179
  const { exit } = useApp();
180
180
  // Calculate limit for paginated lists (75% of terminal height)
181
181
  const listLimit = Math.max(5, Math.floor((process.stdout.rows || 24) * 0.75));
@@ -254,6 +254,7 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
254
254
  sessionQuotaExhausted: false,
255
255
  sessionQuotaTimeRemaining: '',
256
256
  aiAutoSuggest: false,
257
+ interruptQueue: [],
257
258
  });
258
259
  // Track last terminal width to detect actual width changes
259
260
  const lastTerminalWidthRef = React.useRef(process.stdout.columns || 80);
@@ -405,6 +406,38 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
405
406
  InputDetectionAgent.updateOutput(state.shellState.shellId, state.shellState.output);
406
407
  }
407
408
  }, [state.shellState?.output, state.shellState?.isAgentControlled, state.shellState?.shellId]);
409
+ // Handle interrupt queue updates
410
+ React.useEffect(() => {
411
+ onInterruptQueueUpdate((queue) => {
412
+ setState(prev => ({ ...prev, interruptQueue: [...queue] }));
413
+ });
414
+ }, [onInterruptQueueUpdate]);
415
+ // Handle queued message dispatch: add user message to history when it's actually being processed
416
+ // This ensures the correct order: only show the message when it's the AI's next turn, not when queued
417
+ React.useEffect(() => {
418
+ onQueuedMessageDispatched((message) => {
419
+ setState(prev => {
420
+ const userMessage = {
421
+ id: `user-queued-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
422
+ role: 'user',
423
+ content: message,
424
+ timestamp: new Date()
425
+ };
426
+ // Move current message to history if present (skip thought-only)
427
+ const newHistory = prev.currentMessage && !shouldSkipMessage(prev.currentMessage)
428
+ ? [...prev.messageHistory, prev.currentMessage, userMessage]
429
+ : [...prev.messageHistory, userMessage];
430
+ return {
431
+ ...prev,
432
+ messageHistory: newHistory,
433
+ currentMessage: null,
434
+ isLoading: true,
435
+ loadingMessage: 'Processing your request...',
436
+ isAiWorking: true
437
+ };
438
+ });
439
+ });
440
+ }, [onQueuedMessageDispatched]);
408
441
  // Ref to track if we should strictly block incoming AI updates (Zombie Agent Protection)
409
442
  // This is set to true when an Agent-Controlled shell exits, essentially killing the "AI Agent"
410
443
  // associated with it from the UI perspective. It is reset when the user manually inputs a new message.
@@ -2351,34 +2384,10 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2351
2384
  });
2352
2385
  }
2353
2386
  else if (!isSlashCommand) {
2354
- // Only add user message to display if it's not a slash command
2355
- // INTERRUPT HANDLING: If AI is currently working, cancel and clean up first
2356
- // This allows the new message to replace the interrupted turn
2357
- if (state.isAiWorking || state.isLoading) {
2358
- // Cancel current request (cli-adapter will clean up its history)
2359
- onCancelRequest();
2360
- // Small delay to allow abort to propagate before new request starts
2361
- await new Promise(resolve => setTimeout(resolve, 50));
2362
- // Clean up UI state: remove any partial/interrupted messages
2363
- setState(prev => {
2364
- // Filter out the last user message (the one we're replacing)
2365
- let cleanedHistory = [...prev.messageHistory];
2366
- for (let i = cleanedHistory.length - 1; i >= 0; i--) {
2367
- if (cleanedHistory[i].role === 'user') {
2368
- cleanedHistory.splice(i, 1);
2369
- break; // Only remove the most recent user message
2370
- }
2371
- }
2372
- return {
2373
- ...prev,
2374
- messageHistory: cleanedHistory,
2375
- currentMessage: null,
2376
- isLoading: false,
2377
- isAiWorking: false,
2378
- approvalRequest: undefined, // Clear any pending approval
2379
- };
2380
- });
2381
- }
2387
+ // Only add user message to display if it's not a slash command.
2388
+ // The user message is added to messageHistory via the onQueuedMessageDispatched
2389
+ // callback (fired by cli-adapter at the very start of processing, for both direct
2390
+ // messages and queued interrupts). This ensures correct ordering and no duplicates.
2382
2391
  // Show user message IMMEDIATELY with file breadcrumbs (uploading state)
2383
2392
  // Files will be uploaded in background, then AI will be called
2384
2393
  const hasFilesToUpload = clipboardFiles && clipboardFiles.length > 0;
@@ -2396,25 +2405,16 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2396
2405
  }
2397
2406
  // Generate a stable message ID that we can use to update the message later
2398
2407
  const userMessageId = `user-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
2399
- setState(prev => {
2400
- const newHistory = prev.currentMessage && !shouldSkipMessage(prev.currentMessage)
2401
- ? [...prev.messageHistory, prev.currentMessage]
2402
- : prev.messageHistory;
2403
- const userMessage = {
2404
- id: userMessageId,
2405
- role: 'user',
2406
- content: initialDisplayContent,
2407
- timestamp: new Date()
2408
- };
2409
- return {
2410
- ...prev,
2411
- messageHistory: [...newHistory, userMessage],
2412
- currentMessage: null,
2413
- isLoading: true,
2414
- loadingMessage: hasFilesToUpload ? 'Uploading file(s)...' : 'Processing your request...',
2415
- isAiWorking: true
2416
- };
2417
- });
2408
+ // Update loading state immediately so the UI shows "processing" feedback.
2409
+ // Note: we do NOT add to messageHistory here — that is handled by the
2410
+ // onQueuedMessageDispatched callback which fires synchronously inside
2411
+ // cli-adapter.handleMessage before AI processing begins.
2412
+ setState(prev => ({
2413
+ ...prev,
2414
+ isLoading: true,
2415
+ loadingMessage: hasFilesToUpload ? 'Uploading file(s)...' : 'Processing your request...',
2416
+ isAiWorking: true
2417
+ }));
2418
2418
  }
2419
2419
  else {
2420
2420
  // For slash commands, just show loading state
@@ -2775,6 +2775,13 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2775
2775
  !(state.currentMessage?.toolExecution?.status === 'executing') && (React.createElement(Box, { marginBottom: 1, paddingLeft: 1 },
2776
2776
  React.createElement(LoadingIndicator, { key: "loading-indicator" }),
2777
2777
  React.createElement(AgentTimer, { key: "agent-timer" }))),
2778
+ state.interruptQueue && state.interruptQueue.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, state.interruptQueue.map((msg, i) => (React.createElement(Text, { key: `interrupt-${i}`, color: "gray", dimColor: true },
2779
+ "[Queued Interrupt ",
2780
+ i + 1,
2781
+ "/",
2782
+ state.interruptQueue.length,
2783
+ "] ",
2784
+ msg))))),
2778
2785
  !state.shellState?.isFocused && (state.passwordRequest ? (React.createElement(PasswordPrompt, { message: state.passwordRequest.message, onSubmit: (password) => {
2779
2786
  const resolve = state.passwordRequest?.resolve;
2780
2787
  if (resolve) {