centaurus-cli 2.9.8 → 2.9.9

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 (45) hide show
  1. package/dist/cli-adapter.d.ts.map +1 -1
  2. package/dist/cli-adapter.js +11 -2
  3. package/dist/cli-adapter.js.map +1 -1
  4. package/dist/services/clipboard-service.d.ts +9 -14
  5. package/dist/services/clipboard-service.d.ts.map +1 -1
  6. package/dist/services/clipboard-service.js +83 -83
  7. package/dist/services/clipboard-service.js.map +1 -1
  8. package/dist/tools/read-binary-file.js +6 -6
  9. package/dist/tools/read-binary-file.js.map +1 -1
  10. package/dist/ui/components/App.d.ts.map +1 -1
  11. package/dist/ui/components/App.js +51 -48
  12. package/dist/ui/components/App.js.map +1 -1
  13. package/dist/ui/components/ClipboardFileAutocomplete.d.ts +10 -0
  14. package/dist/ui/components/ClipboardFileAutocomplete.d.ts.map +1 -0
  15. package/dist/ui/components/{ClipboardImageAutocomplete.js → ClipboardFileAutocomplete.js} +14 -12
  16. package/dist/ui/components/ClipboardFileAutocomplete.js.map +1 -0
  17. package/dist/ui/components/DetailedPlanReviewScreen.js +1 -1
  18. package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
  19. package/dist/ui/components/InputBox.d.ts +2 -2
  20. package/dist/ui/components/InputBox.d.ts.map +1 -1
  21. package/dist/ui/components/InputBox.js +41 -21
  22. package/dist/ui/components/InputBox.js.map +1 -1
  23. package/dist/ui/components/KeyboardHelp.d.ts.map +1 -1
  24. package/dist/ui/components/KeyboardHelp.js +2 -0
  25. package/dist/ui/components/KeyboardHelp.js.map +1 -1
  26. package/dist/ui/components/MessageDisplay.d.ts +4 -4
  27. package/dist/ui/components/MessageDisplay.d.ts.map +1 -1
  28. package/dist/ui/components/MessageDisplay.js +33 -31
  29. package/dist/ui/components/MessageDisplay.js.map +1 -1
  30. package/dist/ui/components/PlanAcceptedMessage.js +2 -2
  31. package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
  32. package/dist/ui/components/TaskCompletedMessage.js +2 -2
  33. package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
  34. package/dist/ui/components/ToolExecutionMessage.js +6 -6
  35. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  36. package/dist/ui/components/ToolResult.js +1 -1
  37. package/dist/ui/components/ToolResult.js.map +1 -1
  38. package/dist/utils/context-sanitizer.d.ts +50 -0
  39. package/dist/utils/context-sanitizer.d.ts.map +1 -0
  40. package/dist/utils/context-sanitizer.js +119 -0
  41. package/dist/utils/context-sanitizer.js.map +1 -0
  42. package/package.json +1 -1
  43. package/dist/ui/components/ClipboardImageAutocomplete.d.ts +0 -14
  44. package/dist/ui/components/ClipboardImageAutocomplete.d.ts.map +0 -1
  45. package/dist/ui/components/ClipboardImageAutocomplete.js.map +0 -1
@@ -8,7 +8,7 @@ import * as path from 'path';
8
8
  import { quickLog } from '../../utils/conversation-logger.js';
9
9
  import { WelcomeBanner } from './WelcomeBanner.js';
10
10
  import { InputBox } from './InputBox.js';
11
- import { MessageDisplay, countImagesInMessage } from './MessageDisplay.js';
11
+ import { MessageDisplay, countFilesInMessage } from './MessageDisplay.js';
12
12
  import { StreamingMessageDisplay } from './StreamingMessageDisplay.js';
13
13
  import { LoadingIndicator } from './LoadingIndicator.js';
14
14
  import { AgentTimer } from './AgentTimer.js';
@@ -69,21 +69,21 @@ const MessageList = React.memo(({ history, current, showBanner }) => {
69
69
  const staticItems = React.useMemo(() => {
70
70
  return showBanner ? [BANNER_ITEM, ...history] : history;
71
71
  }, [history, showBanner]);
72
- // Calculate cumulative image counts for each message (for global numbering)
73
- const imageCountsUpTo = React.useMemo(() => {
72
+ // Calculate cumulative file counts for each message (for global numbering)
73
+ const fileCountsUpTo = React.useMemo(() => {
74
74
  const counts = [];
75
75
  let cumulative = 0;
76
76
  for (const msg of history) {
77
77
  counts.push(cumulative);
78
78
  if (msg.role === 'user') {
79
- cumulative += countImagesInMessage(msg.content);
79
+ cumulative += countFilesInMessage(msg.content);
80
80
  }
81
81
  }
82
82
  return counts;
83
83
  }, [history]);
84
- // Get image count for current message (all images in history)
85
- const totalHistoryImages = imageCountsUpTo.length > 0
86
- ? imageCountsUpTo[imageCountsUpTo.length - 1] + (history[history.length - 1]?.role === 'user' ? countImagesInMessage(history[history.length - 1].content) : 0)
84
+ // Get file count for current message (all files in history)
85
+ const totalHistoryFiles = fileCountsUpTo.length > 0
86
+ ? fileCountsUpTo[fileCountsUpTo.length - 1] + (history[history.length - 1]?.role === 'user' ? countFilesInMessage(history[history.length - 1].content) : 0)
87
87
  : 0;
88
88
  return (React.createElement(Box, { flexDirection: "column", marginY: 1 },
89
89
  React.createElement(Static, { items: staticItems }, (item, index) => {
@@ -94,7 +94,7 @@ const MessageList = React.memo(({ history, current, showBanner }) => {
94
94
  const msg = item;
95
95
  // Calculate history index (account for banner if present)
96
96
  const historyIndex = showBanner ? index - 1 : index;
97
- const imageCountBefore = imageCountsUpTo[historyIndex] || 0;
97
+ const fileCountBefore = fileCountsUpTo[historyIndex] || 0;
98
98
  if (msg.taskCompletion) {
99
99
  return (React.createElement(TaskCompletedMessage, { key: item.id, taskNumber: msg.taskCompletion.taskNumber, totalTasks: msg.taskCompletion.totalTasks, taskDescription: msg.taskCompletion.taskDescription, completionNote: msg.taskCompletion.completionNote }));
100
100
  }
@@ -102,7 +102,7 @@ const MessageList = React.memo(({ history, current, showBanner }) => {
102
102
  if (msg.planAccepted) {
103
103
  return (React.createElement(PlanAcceptedMessage, { key: item.id, planTitle: msg.planAccepted.planTitle, totalTasks: msg.planAccepted.totalTasks, tasks: msg.planAccepted.tasks }));
104
104
  }
105
- return React.createElement(MessageDisplay, { key: item.id, message: item, imageCountBefore: imageCountBefore });
105
+ return React.createElement(MessageDisplay, { key: item.id, message: item, fileCountBefore: fileCountBefore });
106
106
  }),
107
107
  current && !history.some(msg => msg.id === current.id) && (() => {
108
108
  // Get terminal dimensions to determine if streaming should be enabled
@@ -114,7 +114,7 @@ const MessageList = React.memo(({ history, current, showBanner }) => {
114
114
  return (React.createElement(StreamingMessageDisplay, { key: current.id, message: current, maxLines: dimensions.maxStreamingLines }));
115
115
  }
116
116
  else {
117
- return React.createElement(MessageDisplay, { key: current.id, message: current, imageCountBefore: totalHistoryImages });
117
+ return React.createElement(MessageDisplay, { key: current.id, message: current, fileCountBefore: totalHistoryFiles });
118
118
  }
119
119
  })()));
120
120
  }, (prevProps, nextProps) => {
@@ -2268,7 +2268,7 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2268
2268
  return;
2269
2269
  }
2270
2270
  }, { isActive: !state.isInteractiveEditorMode });
2271
- const handleSubmit = useCallback(async (value, clipboardImages) => {
2271
+ const handleSubmit = useCallback(async (value, clipboardFiles) => {
2272
2272
  // Trim the value to remove any leading/trailing whitespace or newlines
2273
2273
  const trimmedValue = value.trim();
2274
2274
  if (!trimmedValue)
@@ -2379,18 +2379,19 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2379
2379
  };
2380
2380
  });
2381
2381
  }
2382
- // Show user message IMMEDIATELY with image breadcrumbs (uploading state)
2383
- // Images will be uploaded in background, then AI will be called
2384
- const hasImagesToUpload = clipboardImages && clipboardImages.length > 0;
2385
- // Build initial content with placeholder image markers for immediate display
2382
+ // Show user message IMMEDIATELY with file breadcrumbs (uploading state)
2383
+ // Files will be uploaded in background, then AI will be called
2384
+ const hasFilesToUpload = clipboardFiles && clipboardFiles.length > 0;
2385
+ // Build initial content with placeholder file markers for immediate display
2386
2386
  let initialDisplayContent = trimmedValue;
2387
- if (hasImagesToUpload) {
2387
+ if (hasFilesToUpload) {
2388
2388
  // Add placeholder markers that will be shown immediately
2389
- for (let i = 0; i < clipboardImages.length; i++) {
2390
- const image = clipboardImages[i];
2389
+ for (let i = 0; i < clipboardFiles.length; i++) {
2390
+ const file = clipboardFiles[i];
2391
2391
  // Use a placeholder format that MessageDisplay can render as breadcrumb
2392
- // Format: [IMAGE: filename (uploading...)] - will be updated after upload
2393
- initialDisplayContent = `${initialDisplayContent} [IMAGE: ${image.displayName} (gs://uploading)]`;
2392
+ // Format: [FILE: filename (uploading...)] - will be updated after upload
2393
+ const markerType = file.mimeType?.startsWith('image/') ? 'IMAGE' : 'FILE';
2394
+ initialDisplayContent = `${initialDisplayContent} [${markerType}: ${file.displayName} (gs://uploading)]`;
2394
2395
  }
2395
2396
  }
2396
2397
  // Generate a stable message ID that we can use to update the message later
@@ -2410,7 +2411,7 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2410
2411
  messageHistory: [...newHistory, userMessage],
2411
2412
  currentMessage: null,
2412
2413
  isLoading: true,
2413
- loadingMessage: hasImagesToUpload ? 'Uploading image(s)...' : 'Processing your request...',
2414
+ loadingMessage: hasFilesToUpload ? 'Uploading file(s)...' : 'Processing your request...',
2414
2415
  isAiWorking: true
2415
2416
  };
2416
2417
  });
@@ -2432,12 +2433,12 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2432
2433
  : [...prev.commandHistory, trimmedValue]
2433
2434
  }));
2434
2435
  try {
2435
- // Upload clipboard images if present
2436
- let messageWithImages = trimmedValue;
2437
- // Debug logging for clipboard images
2438
- logDebug(`[CLIPBOARD] clipboardImages count: ${clipboardImages?.length || 0}`);
2436
+ // Upload clipboard files if present
2437
+ let messageWithFiles = trimmedValue;
2438
+ // Debug logging for clipboard files
2439
+ logDebug(`[CLIPBOARD] clipboardFiles count: ${clipboardFiles?.length || 0}`);
2439
2440
  logDebug(`[CLIPBOARD] currentChatId: ${state.currentChatId || 'null'}`);
2440
- if (clipboardImages && clipboardImages.length > 0) {
2441
+ if (clipboardFiles && clipboardFiles.length > 0) {
2441
2442
  // Check for existing conversation ID - conversationManager is the single source of truth
2442
2443
  // This ensures we use the same conversation that cli-adapter uses
2443
2444
  let conversationId = conversationManager.getCurrentConversationId() || state.currentChatId;
@@ -2446,7 +2447,7 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2446
2447
  if (!conversationId) {
2447
2448
  // No conversation exists anywhere - create one via conversationManager
2448
2449
  // This will set the internal state that cli-adapter's ensureConversationStarted checks
2449
- logDebug(`[CLIPBOARD] No existing conversation - creating new one for image upload`);
2450
+ logDebug(`[CLIPBOARD] No existing conversation - creating new one for file upload`);
2450
2451
  try {
2451
2452
  const newConversation = await conversationManager.startNewConversation('New Chat', state.currentModel || 'gemini-2-flash-preview', 'google', undefined // workingDirectory - will use process.cwd()
2452
2453
  );
@@ -2461,38 +2462,40 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2461
2462
  logDebug(`[CLIPBOARD] Proceeding with upload`);
2462
2463
  }
2463
2464
  catch (createError) {
2464
- logError('Failed to create conversation for image upload', createError instanceof Error ? createError : undefined);
2465
+ logError('Failed to create conversation for file upload', createError instanceof Error ? createError : undefined);
2465
2466
  // Mark the upload as failed - don't use temp IDs that will fail FK constraint
2466
- for (let i = 0; i < clipboardImages.length; i++) {
2467
- messageWithImages = messageWithImages.replace(/#image\b/i, '[IMAGE UPLOAD FAILED - No conversation]');
2467
+ for (let i = 0; i < clipboardFiles.length; i++) {
2468
+ messageWithFiles = messageWithFiles.replace(/#image\b/i, '[FILE UPLOAD FAILED - No conversation]');
2468
2469
  }
2469
2470
  logDebug(`[CLIPBOARD] Skipping upload due to conversation creation failure`);
2470
2471
  }
2471
2472
  }
2472
2473
  // Only attempt upload if we have a valid conversation ID
2473
2474
  if (conversationId && !conversationId.startsWith('temp_')) {
2474
- logDebug(`[CLIPBOARD] Starting upload for ${clipboardImages.length} images with conversationId: ${conversationId}`);
2475
- // Upload each clipboard image and build the final message content
2476
- const uploadedImageMarkers = [];
2477
- for (const image of clipboardImages) {
2475
+ logDebug(`[CLIPBOARD] Starting upload for ${clipboardFiles.length} files with conversationId: ${conversationId}`);
2476
+ // Upload each clipboard file and build the final message content
2477
+ const uploadedFileMarkers = [];
2478
+ for (const file of clipboardFiles) {
2478
2479
  try {
2479
- logDebug(`[CLIPBOARD] Uploading image: ${image.displayName}, size: ${image.sizeBytes} bytes`);
2480
- const uploadResult = await apiClient.uploadFile(conversationId, image.displayName, image.mimeType, image.base64Data);
2480
+ logDebug(`[CLIPBOARD] Uploading file: ${file.displayName}, size: ${file.sizeBytes} bytes`);
2481
+ const uploadResult = await apiClient.uploadFile(conversationId, file.displayName, file.mimeType, file.base64Data);
2481
2482
  logDebug(`[CLIPBOARD] Upload success! gcsUri: ${uploadResult.gcsUri || 'none'}`);
2482
- // Append image reference info to message (for AI to know an image was attached)
2483
+ const markerType = file.mimeType?.startsWith('image/') ? 'IMAGE' : 'FILE';
2484
+ // Append file reference info to message (for AI to know a file was attached)
2483
2485
  // The backend will use gcsUri for Vertex AI multimodal input
2484
2486
  if (uploadResult.gcsUri) {
2485
- // Build the real image marker with actual GCS URI
2486
- messageWithImages = `${messageWithImages} [IMAGE: ${uploadResult.fileName} (${uploadResult.gcsUri})]`;
2487
- uploadedImageMarkers.push(`[IMAGE: ${uploadResult.fileName} (${uploadResult.gcsUri})]`);
2488
- logDebug(`[CLIPBOARD] Appended image marker: [IMAGE: ${uploadResult.fileName} (${uploadResult.gcsUri})]`);
2487
+ // Build the real file marker with actual GCS URI
2488
+ messageWithFiles = `${messageWithFiles} [${markerType}: ${uploadResult.fileName} (${uploadResult.gcsUri})]`;
2489
+ uploadedFileMarkers.push(`[${markerType}: ${uploadResult.fileName} (${uploadResult.gcsUri})]`);
2490
+ logDebug(`[CLIPBOARD] Appended file marker: [${markerType}: ${uploadResult.fileName} (${uploadResult.gcsUri})]`);
2489
2491
  }
2490
2492
  }
2491
2493
  catch (uploadError) {
2492
- // Log error but continue - image upload is optional
2493
- logError('Failed to upload clipboard image', uploadError instanceof Error ? uploadError : undefined);
2494
+ // Log error but continue - file upload is optional
2495
+ const markerType = file.mimeType?.startsWith('image/') ? 'IMAGE' : 'FILE';
2496
+ logError('Failed to upload clipboard file', uploadError instanceof Error ? uploadError : undefined);
2494
2497
  // Add a failed marker so user knows upload failed
2495
- uploadedImageMarkers.push(`[IMAGE: ${image.displayName} (upload failed)]`);
2498
+ uploadedFileMarkers.push(`[${markerType}: ${file.displayName} (upload failed)]`);
2496
2499
  }
2497
2500
  }
2498
2501
  // Update the user message in history with actual GCS URIs
@@ -2501,9 +2504,9 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2501
2504
  const updatedHistory = prev.messageHistory.map(msg => {
2502
2505
  // Find the user message we just added (it has placeholder markers)
2503
2506
  if (msg.role === 'user' && msg.content.includes('(gs://uploading)')) {
2504
- // Build new content: original text + real image markers
2507
+ // Build new content: original text + real file markers
2505
2508
  let newContent = trimmedValue;
2506
- for (const marker of uploadedImageMarkers) {
2509
+ for (const marker of uploadedFileMarkers) {
2507
2510
  newContent = `${newContent} ${marker}`;
2508
2511
  }
2509
2512
  return { ...msg, content: newContent };
@@ -2527,8 +2530,8 @@ export const App = ({ onMessage, onCancelRequest, initialModel, initialPlanMode,
2527
2530
  return { ...prev, messageHistory: updatedHistory };
2528
2531
  });
2529
2532
  } // End: if (conversationId && !startsWith temp_)
2530
- } // End: if (clipboardImages && clipboardImages.length > 0)
2531
- await onMessage(messageWithImages);
2533
+ } // End: if (clipboardFiles && clipboardFiles.length > 0)
2534
+ await onMessage(messageWithFiles);
2532
2535
  }
2533
2536
  catch (error) {
2534
2537
  // Add error message