centaurus-cli 2.9.2 → 2.9.4
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-adapter.d.ts +78 -11
- package/dist/cli-adapter.d.ts.map +1 -1
- package/dist/cli-adapter.js +851 -215
- package/dist/cli-adapter.js.map +1 -1
- package/dist/commands/CommandParser.d.ts +1 -1
- package/dist/commands/CommandParser.d.ts.map +1 -1
- package/dist/commands/CommandParser.js +113 -0
- package/dist/commands/CommandParser.js.map +1 -1
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +2 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.d.ts +5 -0
- package/dist/config/slash-commands.d.ts.map +1 -1
- package/dist/config/slash-commands.js +63 -1
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.d.ts +2 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/context/context-manager.d.ts +1 -1
- package/dist/context/context-manager.d.ts.map +1 -1
- package/dist/context/context-manager.js +3 -1
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/handlers/docker-handler.d.ts +9 -0
- package/dist/context/handlers/docker-handler.d.ts.map +1 -1
- package/dist/context/handlers/docker-handler.js +99 -10
- package/dist/context/handlers/docker-handler.js.map +1 -1
- package/dist/context/handlers/ssh-handler.d.ts +20 -0
- package/dist/context/handlers/ssh-handler.d.ts.map +1 -1
- package/dist/context/handlers/ssh-handler.js +129 -1
- package/dist/context/handlers/ssh-handler.js.map +1 -1
- package/dist/context/subshell-handler.d.ts +15 -0
- package/dist/context/subshell-handler.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-autocomplete-agent.d.ts +39 -0
- package/dist/services/ai-autocomplete-agent.d.ts.map +1 -0
- package/dist/services/ai-autocomplete-agent.js +189 -0
- package/dist/services/ai-autocomplete-agent.js.map +1 -0
- package/dist/services/ai-service-client.d.ts +25 -0
- package/dist/services/ai-service-client.d.ts.map +1 -1
- package/dist/services/ai-service-client.js +195 -12
- package/dist/services/ai-service-client.js.map +1 -1
- package/dist/services/api-client.js +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/auth-handler.js +1 -1
- package/dist/services/auth-handler.js.map +1 -1
- package/dist/services/local-chat-storage.d.ts +21 -0
- package/dist/services/local-chat-storage.d.ts.map +1 -1
- package/dist/services/local-chat-storage.js +138 -43
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/ollama-service.d.ts +197 -0
- package/dist/services/ollama-service.d.ts.map +1 -0
- package/dist/services/ollama-service.js +324 -0
- package/dist/services/ollama-service.js.map +1 -0
- package/dist/services/warpify-detector.d.ts +43 -0
- package/dist/services/warpify-detector.d.ts.map +1 -0
- package/dist/services/warpify-detector.js +203 -0
- package/dist/services/warpify-detector.js.map +1 -0
- package/dist/services/workflow-storage.d.ts +72 -0
- package/dist/services/workflow-storage.d.ts.map +1 -0
- package/dist/services/workflow-storage.js +239 -0
- package/dist/services/workflow-storage.js.map +1 -0
- package/dist/tools/command.d.ts.map +1 -1
- package/dist/tools/command.js +14 -0
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/enter-remote-session.d.ts +13 -0
- package/dist/tools/enter-remote-session.d.ts.map +1 -0
- package/dist/tools/enter-remote-session.js +226 -0
- package/dist/tools/enter-remote-session.js.map +1 -0
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +9 -2
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/grep-search.d.ts +104 -31
- package/dist/tools/grep-search.d.ts.map +1 -1
- package/dist/tools/grep-search.js +699 -430
- package/dist/tools/grep-search.js.map +1 -1
- package/dist/tools/workflow-tool.d.ts +11 -0
- package/dist/tools/workflow-tool.d.ts.map +1 -0
- package/dist/tools/workflow-tool.js +87 -0
- package/dist/tools/workflow-tool.js.map +1 -0
- package/dist/types/workflow.d.ts +110 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +8 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/ui/components/App.d.ts +12 -3
- package/dist/ui/components/App.d.ts.map +1 -1
- package/dist/ui/components/App.js +162 -6
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/Breadcrumbs.d.ts +4 -3
- package/dist/ui/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/ui/components/Breadcrumbs.js +60 -54
- package/dist/ui/components/Breadcrumbs.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +2 -2
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/InputBox.d.ts +3 -0
- package/dist/ui/components/InputBox.d.ts.map +1 -1
- package/dist/ui/components/InputBox.js +488 -20
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.d.ts +2 -0
- package/dist/ui/components/InteractiveShell.d.ts.map +1 -1
- package/dist/ui/components/InteractiveShell.js +13 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/MultiLineInput.d.ts.map +1 -1
- package/dist/ui/components/MultiLineInput.js +68 -2
- package/dist/ui/components/MultiLineInput.js.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.js +169 -26
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.d.ts +25 -0
- package/dist/ui/components/WorkflowCreatorScreen.d.ts.map +1 -0
- package/dist/ui/components/WorkflowCreatorScreen.js +164 -0
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -0
- package/dist/utils/command-history.d.ts +12 -2
- package/dist/utils/command-history.d.ts.map +1 -1
- package/dist/utils/command-history.js +57 -13
- package/dist/utils/command-history.js.map +1 -1
- package/dist/utils/input-classifier.d.ts.map +1 -1
- package/dist/utils/input-classifier.js +3 -2
- package/dist/utils/input-classifier.js.map +1 -1
- package/package.json +1 -1
|
@@ -13,6 +13,8 @@ import { FileTagAutocomplete } from './FileTagAutocomplete.js';
|
|
|
13
13
|
import { filterCommands } from '../../config/slash-commands.js';
|
|
14
14
|
import { getClipboardImages } from '../../services/clipboard-service.js';
|
|
15
15
|
import { useTerminalDimensions, TERMINAL_HEIGHT_CONSTANTS } from '../../hooks/useTerminalDimensions.js';
|
|
16
|
+
import { AIAutocompleteAgent, AI_AUTOCOMPLETE_DEBOUNCE_MS } from '../../services/ai-autocomplete-agent.js';
|
|
17
|
+
import { workflowStorage } from '../../services/workflow-storage.js';
|
|
16
18
|
const getVisualLines = (text, width) => {
|
|
17
19
|
const logicalLines = text.split('\n');
|
|
18
20
|
const visualLines = [];
|
|
@@ -50,7 +52,7 @@ const getVisualLines = (text, width) => {
|
|
|
50
52
|
});
|
|
51
53
|
return visualLines;
|
|
52
54
|
};
|
|
53
|
-
export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...', autoAcceptMode, model, planMode = false, commandMode = false, backgroundMode = false, currentWorkingDirectory, commandHistory = [], onToggleAutoAccept, onToggleCommandMode, onToggleBackgroundMode, isActive = true, subshellContext, currentTokens = 0, maxTokens = 1000000, contextLimitReached = false, isShellRunning = false, backgroundTaskCount = 0, initialValue = '', onValueChange, onSetAutoModeSetup, sessionQuotaExhausted = false, sessionQuotaTimeRemaining = '', subAgentCount = 0 }) => {
|
|
55
|
+
export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...', autoAcceptMode, model, planMode = false, commandMode = false, backgroundMode = false, currentWorkingDirectory, commandHistory = [], onToggleAutoAccept, onToggleCommandMode, onToggleBackgroundMode, isActive = true, subshellContext, subshellContextStack, currentTokens = 0, maxTokens = 1000000, contextLimitReached = false, isShellRunning = false, backgroundTaskCount = 0, initialValue = '', onValueChange, onSetAutoModeSetup, sessionQuotaExhausted = false, sessionQuotaTimeRemaining = '', subAgentCount = 0, aiAutoSuggestEnabled = false, sessionCommands = [] }) => {
|
|
54
56
|
// Use initialValue for first mount, but manage state internally after that
|
|
55
57
|
const [value, setValueInternal] = useState(initialValue);
|
|
56
58
|
const [cursorOffset, setCursorOffset] = useState(0);
|
|
@@ -68,11 +70,18 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
68
70
|
const [detectedIntent, setDetectedIntent] = useState('ai');
|
|
69
71
|
// Autocomplete State
|
|
70
72
|
const [autocompleteSuggestion, setAutocompleteSuggestion] = useState(null);
|
|
73
|
+
// AI Autocomplete State
|
|
74
|
+
const [aiAutocompleteSuggestion, setAiAutocompleteSuggestion] = useState(null);
|
|
75
|
+
const [isAiAutocompleteLoading, setIsAiAutocompleteLoading] = useState(false);
|
|
76
|
+
const aiAutocompleteDebounceRef = useRef(null);
|
|
77
|
+
const aiAutocompleteAbortRef = useRef(null);
|
|
71
78
|
// Undo/Redo State
|
|
72
79
|
const [undoStack, setUndoStack] = useState([]);
|
|
73
80
|
const [redoStack, setRedoStack] = useState([]);
|
|
74
81
|
// Selection State
|
|
75
82
|
const [selection, setSelection] = useState(null);
|
|
83
|
+
// Platform Detection
|
|
84
|
+
const isMac = process.platform === 'darwin';
|
|
76
85
|
// Reject Flash State (turns border red when submission is blocked)
|
|
77
86
|
const [rejectFlash, setRejectFlash] = useState(false);
|
|
78
87
|
// Session Quota Message State (shows quota exhausted message)
|
|
@@ -188,6 +197,26 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
188
197
|
}
|
|
189
198
|
return cwd;
|
|
190
199
|
}, [currentWorkingDirectory]);
|
|
200
|
+
// Determine current environment for command history isolation
|
|
201
|
+
// Format: 'local', 'ssh:user@host', or 'wsl:distroName'
|
|
202
|
+
const currentEnvironment = useMemo(() => {
|
|
203
|
+
if (!subshellContext)
|
|
204
|
+
return 'local';
|
|
205
|
+
if (subshellContext.type === 'ssh') {
|
|
206
|
+
const user = subshellContext.metadata?.username || 'user';
|
|
207
|
+
const host = subshellContext.metadata?.hostname || 'host';
|
|
208
|
+
return `ssh:${user}@${host}`;
|
|
209
|
+
}
|
|
210
|
+
if (subshellContext.type === 'wsl') {
|
|
211
|
+
const distro = subshellContext.metadata?.distroName || 'Ubuntu';
|
|
212
|
+
return `wsl:${distro}`;
|
|
213
|
+
}
|
|
214
|
+
if (subshellContext.type === 'docker') {
|
|
215
|
+
const container = subshellContext.metadata?.containerId || 'container';
|
|
216
|
+
return `docker:${container}`;
|
|
217
|
+
}
|
|
218
|
+
return 'local';
|
|
219
|
+
}, [subshellContext]);
|
|
191
220
|
// Autocomplete Logic
|
|
192
221
|
useEffect(() => {
|
|
193
222
|
if (!value || value.trim() === '') {
|
|
@@ -198,7 +227,7 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
198
227
|
// OR if we are in Auto mode and it looks like a command
|
|
199
228
|
const shouldSuggest = commandMode || (isAutoMode && detectedIntent === 'command');
|
|
200
229
|
if (shouldSuggest) {
|
|
201
|
-
const matches = CommandHistoryManager.getInstance().getMatches(value, currentDir);
|
|
230
|
+
const matches = CommandHistoryManager.getInstance().getMatches(value, currentDir, currentEnvironment);
|
|
202
231
|
if (matches.length > 0) {
|
|
203
232
|
setAutocompleteSuggestion(matches[0]);
|
|
204
233
|
}
|
|
@@ -209,7 +238,137 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
209
238
|
else {
|
|
210
239
|
setAutocompleteSuggestion(null);
|
|
211
240
|
}
|
|
212
|
-
}, [value, commandMode, isAutoMode, detectedIntent, currentDir]);
|
|
241
|
+
}, [value, commandMode, isAutoMode, detectedIntent, currentDir, currentEnvironment]);
|
|
242
|
+
// AI Autocomplete Logic (5-second debounce)
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
// Clear AI suggestion when value changes
|
|
245
|
+
setAiAutocompleteSuggestion(null);
|
|
246
|
+
// Clear any existing debounce timer
|
|
247
|
+
if (aiAutocompleteDebounceRef.current) {
|
|
248
|
+
clearTimeout(aiAutocompleteDebounceRef.current);
|
|
249
|
+
aiAutocompleteDebounceRef.current = null;
|
|
250
|
+
}
|
|
251
|
+
// Abort any pending AI request
|
|
252
|
+
if (aiAutocompleteAbortRef.current) {
|
|
253
|
+
aiAutocompleteAbortRef.current.abort();
|
|
254
|
+
aiAutocompleteAbortRef.current = null;
|
|
255
|
+
}
|
|
256
|
+
// Debug logging for trigger ref
|
|
257
|
+
/*
|
|
258
|
+
try {
|
|
259
|
+
if (detectedIntent !== 'ai' || value.length > 5) {
|
|
260
|
+
quickLog(`[InputBox] AI Effect: val="${value}", enabled=${aiAutoSuggestEnabled}, mode=${commandMode}, auto=${isAutoMode}, intent=${detectedIntent}`);
|
|
261
|
+
}
|
|
262
|
+
} catch (e) {}
|
|
263
|
+
*/
|
|
264
|
+
// Don't trigger AI autocomplete if disabled or not in command mode
|
|
265
|
+
if (!aiAutoSuggestEnabled) {
|
|
266
|
+
// quickLog('[InputBox] AI skipped: disabled');
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const shouldSuggest = commandMode || (isAutoMode && detectedIntent === 'command');
|
|
270
|
+
if (!shouldSuggest) {
|
|
271
|
+
// if (value.length > 3) quickLog(`[InputBox] AI skipped: !shouldSuggest (cmd=${commandMode}, auto=${isAutoMode}, intent=${detectedIntent})`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// Don't suggest for empty, very short, or slash commands
|
|
275
|
+
if (!value || value.trim().length < 2 || value.startsWith('/')) {
|
|
276
|
+
// quickLog('[InputBox] AI skipped: too short or slash');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// quickLog('[InputBox] AI Triggering debounce...');
|
|
280
|
+
// Set up 5-second debounce timer
|
|
281
|
+
aiAutocompleteDebounceRef.current = setTimeout(async () => {
|
|
282
|
+
setIsAiAutocompleteLoading(true);
|
|
283
|
+
// Create abort controller for this request
|
|
284
|
+
const abortController = new AbortController();
|
|
285
|
+
aiAutocompleteAbortRef.current = abortController;
|
|
286
|
+
try {
|
|
287
|
+
if (!aiAutoSuggestEnabled)
|
|
288
|
+
return; // double check inside timeout
|
|
289
|
+
// Get directory history using the correct method
|
|
290
|
+
const directoryHistory = CommandHistoryManager.getInstance().getDirectoryHistory(currentDir, currentEnvironment);
|
|
291
|
+
// Get files in current directory (local or remote)
|
|
292
|
+
let files = [];
|
|
293
|
+
try {
|
|
294
|
+
if (subshellContext && subshellContext.type !== 'local' && subshellContext.handler) {
|
|
295
|
+
// Remote/Subshell environment
|
|
296
|
+
// Check if we can list files
|
|
297
|
+
try {
|
|
298
|
+
const dirEntries = await subshellContext.handler.listDirectory(currentDir);
|
|
299
|
+
files = dirEntries
|
|
300
|
+
.slice(0, 50)
|
|
301
|
+
.map((e) => e.name + (e.type === 'directory' ? '/' : ''));
|
|
302
|
+
}
|
|
303
|
+
catch (remoteErr) {
|
|
304
|
+
// quickLog('Remote list error: ' + remoteErr);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
// Local environment
|
|
309
|
+
const dir = currentDir || process.cwd();
|
|
310
|
+
if (fs.existsSync(dir)) {
|
|
311
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
312
|
+
files = entries
|
|
313
|
+
.slice(0, 50)
|
|
314
|
+
.map(e => e.name + (e.isDirectory() ? '/' : ''));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (e) {
|
|
319
|
+
// Ignore file access errors
|
|
320
|
+
}
|
|
321
|
+
// Determine OS and Platform from subshell context if available
|
|
322
|
+
let osContext = process.platform;
|
|
323
|
+
let platformContext = process.platform;
|
|
324
|
+
if (subshellContext && subshellContext.type !== 'local' && subshellContext.metadata) {
|
|
325
|
+
const metaOs = subshellContext.metadata.os;
|
|
326
|
+
if (metaOs === 'windows') {
|
|
327
|
+
osContext = 'win32';
|
|
328
|
+
platformContext = 'win32';
|
|
329
|
+
}
|
|
330
|
+
else if (metaOs === 'macos') {
|
|
331
|
+
osContext = 'darwin';
|
|
332
|
+
platformContext = 'darwin';
|
|
333
|
+
}
|
|
334
|
+
else if (metaOs === 'linux') {
|
|
335
|
+
osContext = 'linux';
|
|
336
|
+
platformContext = 'linux';
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const context = {
|
|
340
|
+
os: osContext,
|
|
341
|
+
platform: platformContext,
|
|
342
|
+
cwd: currentDir || process.cwd(),
|
|
343
|
+
directoryHistory: directoryHistory.slice(0, 10),
|
|
344
|
+
sessionCommands: sessionCommands.slice(-10),
|
|
345
|
+
files: files,
|
|
346
|
+
currentInput: value
|
|
347
|
+
};
|
|
348
|
+
const prediction = await AIAutocompleteAgent.predictCommand(context, abortController.signal);
|
|
349
|
+
if (prediction && !abortController.signal.aborted) {
|
|
350
|
+
setAiAutocompleteSuggestion(prediction);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
// Ignore errors (likely aborted)
|
|
355
|
+
}
|
|
356
|
+
finally {
|
|
357
|
+
setIsAiAutocompleteLoading(false);
|
|
358
|
+
if (aiAutocompleteAbortRef.current === abortController) {
|
|
359
|
+
aiAutocompleteAbortRef.current = null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}, AI_AUTOCOMPLETE_DEBOUNCE_MS);
|
|
363
|
+
return () => {
|
|
364
|
+
if (aiAutocompleteDebounceRef.current) {
|
|
365
|
+
clearTimeout(aiAutocompleteDebounceRef.current);
|
|
366
|
+
}
|
|
367
|
+
if (aiAutocompleteAbortRef.current) {
|
|
368
|
+
aiAutocompleteAbortRef.current.abort();
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}, [value, commandMode, isAutoMode, detectedIntent, aiAutoSuggestEnabled, currentDir, currentEnvironment, sessionCommands]);
|
|
213
372
|
// Auto-classification effect (Synchronous Heuristics Only)
|
|
214
373
|
useEffect(() => {
|
|
215
374
|
// Only run classification if in Auto Mode
|
|
@@ -398,6 +557,104 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
398
557
|
setCursorOffset(newValue.length);
|
|
399
558
|
setSlashAutocompleteVisible(false);
|
|
400
559
|
}
|
|
560
|
+
else if (value.startsWith('/models ') || value.startsWith('/model ')) {
|
|
561
|
+
// We're selecting a models subcommand
|
|
562
|
+
const prefix = value.startsWith('/models ') ? '/models ' : '/model ';
|
|
563
|
+
const newValue = `${prefix}${selected.name}`;
|
|
564
|
+
setValue(newValue);
|
|
565
|
+
setCursorOffset(newValue.length);
|
|
566
|
+
setSlashAutocompleteVisible(false);
|
|
567
|
+
}
|
|
568
|
+
else if (value.startsWith('/workflow new ') || value.startsWith('/wf new ')) {
|
|
569
|
+
// We're in workflow new subcommand mode (manual or learn-workflow)
|
|
570
|
+
const prefix = value.startsWith('/workflow new ') ? '/workflow new ' : '/wf new ';
|
|
571
|
+
const newValue = `${prefix}${selected.name}`;
|
|
572
|
+
setValue(newValue);
|
|
573
|
+
setCursorOffset(newValue.length);
|
|
574
|
+
setSlashAutocompleteVisible(false);
|
|
575
|
+
}
|
|
576
|
+
else if (value.startsWith('/workflow ') || value.startsWith('/wf ')) {
|
|
577
|
+
// Check if we're in workflow name selection mode (after run/view/delete)
|
|
578
|
+
const workflowNameMatch = value.match(/^\/(?:workflow|wf)\s+(run|view|delete)\s+/);
|
|
579
|
+
if (workflowNameMatch) {
|
|
580
|
+
// We're selecting a workflow name
|
|
581
|
+
const prefix = value.match(/^\/(?:workflow|wf)\s+(?:run|view|delete)\s+/)?.[0] || '';
|
|
582
|
+
const newValue = `${prefix}${selected.name}`;
|
|
583
|
+
setValue(newValue);
|
|
584
|
+
setCursorOffset(newValue.length);
|
|
585
|
+
setSlashAutocompleteVisible(false);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
// We're selecting a workflow subcommand
|
|
589
|
+
const prefix = value.startsWith('/workflow ') ? '/workflow ' : '/wf ';
|
|
590
|
+
const newValue = `${prefix}${selected.name} `;
|
|
591
|
+
setValue(newValue);
|
|
592
|
+
setCursorOffset(newValue.length);
|
|
593
|
+
// For run/view/delete, show workflow names immediately
|
|
594
|
+
if (selected.name === 'run' || selected.name === 'view' || selected.name === 'delete') {
|
|
595
|
+
const workflows = workflowStorage.list();
|
|
596
|
+
const matchingWorkflows = workflows
|
|
597
|
+
.slice(0, 10)
|
|
598
|
+
.map(wf => ({
|
|
599
|
+
name: wf.name,
|
|
600
|
+
description: wf.description || `${wf.stepCount} step${wf.stepCount !== 1 ? 's' : ''}`
|
|
601
|
+
}));
|
|
602
|
+
if (matchingWorkflows.length > 0) {
|
|
603
|
+
setSlashAutocompleteCommands(matchingWorkflows);
|
|
604
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
605
|
+
setSlashAutocompleteScrollOffset(0);
|
|
606
|
+
// Keep autocomplete visible
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
setSlashAutocompleteVisible(false);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
else if (selected.name === 'new') {
|
|
613
|
+
// For 'new' subcommand, show manual/learn-workflow options
|
|
614
|
+
const subcommandMatches = filterCommands('workflow new ');
|
|
615
|
+
if (subcommandMatches.length > 0) {
|
|
616
|
+
setSlashAutocompleteCommands(subcommandMatches);
|
|
617
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
618
|
+
setSlashAutocompleteScrollOffset(0);
|
|
619
|
+
// Keep autocomplete visible for next level
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
setSlashAutocompleteVisible(false);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
setSlashAutocompleteVisible(false);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else if (value.startsWith('/settings auto-suggest ')) {
|
|
631
|
+
// We're selecting an auto-suggest option (on/off)
|
|
632
|
+
const newValue = `/settings auto-suggest ${selected.name}`;
|
|
633
|
+
setValue(newValue);
|
|
634
|
+
setCursorOffset(newValue.length);
|
|
635
|
+
setSlashAutocompleteVisible(false);
|
|
636
|
+
}
|
|
637
|
+
else if (value.startsWith('/settings ')) {
|
|
638
|
+
// We're selecting a settings subcommand (e.g., auto-suggest)
|
|
639
|
+
const newValue = `/settings ${selected.name} `;
|
|
640
|
+
setValue(newValue);
|
|
641
|
+
setCursorOffset(newValue.length);
|
|
642
|
+
// Show the next level options (on/off for auto-suggest)
|
|
643
|
+
if (selected.name === 'auto-suggest') {
|
|
644
|
+
const optionMatches = filterCommands('settings auto-suggest ');
|
|
645
|
+
if (optionMatches.length > 0) {
|
|
646
|
+
setSlashAutocompleteCommands(optionMatches);
|
|
647
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
648
|
+
setSlashAutocompleteScrollOffset(0);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
setSlashAutocompleteVisible(false);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
setSlashAutocompleteVisible(false);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
401
658
|
else {
|
|
402
659
|
// Regular slash command, replace everything
|
|
403
660
|
const newValue = `/${selected.name} `;
|
|
@@ -465,6 +722,42 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
465
722
|
setSlashAutocompleteVisible(false);
|
|
466
723
|
}
|
|
467
724
|
}
|
|
725
|
+
else if (selected.name === 'models' || selected.name === 'model') {
|
|
726
|
+
const subcommandMatches = filterCommands('models ');
|
|
727
|
+
if (subcommandMatches.length > 0) {
|
|
728
|
+
setSlashAutocompleteCommands(subcommandMatches);
|
|
729
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
730
|
+
setSlashAutocompleteScrollOffset(0);
|
|
731
|
+
// Keep autocomplete visible for subcommands
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
setSlashAutocompleteVisible(false);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else if (selected.name === 'settings') {
|
|
738
|
+
const subcommandMatches = filterCommands('settings ');
|
|
739
|
+
if (subcommandMatches.length > 0) {
|
|
740
|
+
setSlashAutocompleteCommands(subcommandMatches);
|
|
741
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
742
|
+
setSlashAutocompleteScrollOffset(0);
|
|
743
|
+
// Keep autocomplete visible for subcommands
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
setSlashAutocompleteVisible(false);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
else if (selected.name === 'workflow' || selected.name === 'wf') {
|
|
750
|
+
const subcommandMatches = filterCommands('workflow ');
|
|
751
|
+
if (subcommandMatches.length > 0) {
|
|
752
|
+
setSlashAutocompleteCommands(subcommandMatches);
|
|
753
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
754
|
+
setSlashAutocompleteScrollOffset(0);
|
|
755
|
+
// Keep autocomplete visible for subcommands
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
setSlashAutocompleteVisible(false);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
468
761
|
else {
|
|
469
762
|
setSlashAutocompleteVisible(false);
|
|
470
763
|
}
|
|
@@ -688,6 +981,73 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
688
981
|
setSlashAutocompleteVisible(false);
|
|
689
982
|
}
|
|
690
983
|
}
|
|
984
|
+
else if (newValue.startsWith('/models ') || newValue.startsWith('/model ')) {
|
|
985
|
+
// Models subcommands
|
|
986
|
+
const fullQuery = newValue.slice(1);
|
|
987
|
+
const matches = filterCommands(fullQuery);
|
|
988
|
+
if (matches.length > 0) {
|
|
989
|
+
setSlashAutocompleteCommands(matches);
|
|
990
|
+
setSlashAutocompleteVisible(true);
|
|
991
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
992
|
+
setSlashAutocompleteScrollOffset(0);
|
|
993
|
+
}
|
|
994
|
+
else {
|
|
995
|
+
setSlashAutocompleteVisible(false);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
else if (newValue.match(/^\/workflow\s+(run|view|delete)\s+/) ||
|
|
999
|
+
newValue.match(/^\/wf\s+(run|view|delete)\s+/)) {
|
|
1000
|
+
// Workflow name autocomplete (when user types "/workflow run " or similar)
|
|
1001
|
+
// This MUST come before the /workflow subcommand check since it's more specific
|
|
1002
|
+
const match = newValue.match(/^\/(?:workflow|wf)\s+(?:run|view|delete)\s+(.*)$/);
|
|
1003
|
+
const partialName = match ? match[1].toLowerCase() : '';
|
|
1004
|
+
const workflows = workflowStorage.list();
|
|
1005
|
+
const matchingWorkflows = workflows
|
|
1006
|
+
.filter(wf => wf.name.toLowerCase().includes(partialName))
|
|
1007
|
+
.slice(0, 10)
|
|
1008
|
+
.map(wf => ({
|
|
1009
|
+
name: wf.name,
|
|
1010
|
+
description: wf.description || `${wf.stepCount} step${wf.stepCount !== 1 ? 's' : ''}`
|
|
1011
|
+
}));
|
|
1012
|
+
if (matchingWorkflows.length > 0) {
|
|
1013
|
+
setSlashAutocompleteCommands(matchingWorkflows);
|
|
1014
|
+
setSlashAutocompleteVisible(true);
|
|
1015
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1016
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
setSlashAutocompleteVisible(false);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
else if (newValue.match(/^\/workflow\s+new\s+/) ||
|
|
1023
|
+
newValue.match(/^\/wf\s+new\s+/)) {
|
|
1024
|
+
// Workflow new subcommand autocomplete (manual, learn-workflow)
|
|
1025
|
+
const fullQuery = newValue.slice(1);
|
|
1026
|
+
const matches = filterCommands(fullQuery);
|
|
1027
|
+
if (matches.length > 0) {
|
|
1028
|
+
setSlashAutocompleteCommands(matches);
|
|
1029
|
+
setSlashAutocompleteVisible(true);
|
|
1030
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1031
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1032
|
+
}
|
|
1033
|
+
else {
|
|
1034
|
+
setSlashAutocompleteVisible(false);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
else if (newValue.startsWith('/workflow ') || newValue.startsWith('/wf ')) {
|
|
1038
|
+
// Workflow subcommands (when user types "/workflow " or "/wf ")
|
|
1039
|
+
const fullQuery = newValue.slice(1);
|
|
1040
|
+
const matches = filterCommands(fullQuery);
|
|
1041
|
+
if (matches.length > 0) {
|
|
1042
|
+
setSlashAutocompleteCommands(matches);
|
|
1043
|
+
setSlashAutocompleteVisible(true);
|
|
1044
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1045
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
setSlashAutocompleteVisible(false);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
691
1051
|
else {
|
|
692
1052
|
setSlashAutocompleteVisible(false);
|
|
693
1053
|
}
|
|
@@ -743,17 +1103,52 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
743
1103
|
}
|
|
744
1104
|
return;
|
|
745
1105
|
}
|
|
746
|
-
// Ctrl+Z: Undo
|
|
747
|
-
if (key.ctrl && input.toLowerCase() === 'z') {
|
|
1106
|
+
// Ctrl+Z / Cmd+Z: Undo
|
|
1107
|
+
if ((key.ctrl && input.toLowerCase() === 'z') || (key.meta && input.toLowerCase() === 'z')) {
|
|
748
1108
|
handleUndo();
|
|
749
1109
|
return;
|
|
750
1110
|
}
|
|
751
|
-
// Ctrl+A: Select All
|
|
752
|
-
if (key.ctrl && input.toLowerCase() === 'a') {
|
|
1111
|
+
// Ctrl+A / Cmd+A: Select All
|
|
1112
|
+
if ((key.ctrl && input.toLowerCase() === 'a') || (key.meta && input.toLowerCase() === 'a')) {
|
|
753
1113
|
setSelection({ start: 0, end: value.length });
|
|
754
1114
|
setCursorOffset(value.length);
|
|
755
1115
|
return;
|
|
756
1116
|
}
|
|
1117
|
+
// Home: Start of Line
|
|
1118
|
+
// Note: In single-line inputs, this goes to start of text.
|
|
1119
|
+
// In multi-line wrapped view, we ideally want start of logical line or start of text?
|
|
1120
|
+
// Standard terminal Home = Start of command. Editor Home = Start of line.
|
|
1121
|
+
// Let's stick to Start of Text for now as it's a single "input box".
|
|
1122
|
+
// Home: Start of Line
|
|
1123
|
+
// @ts-ignore
|
|
1124
|
+
if (key.home) {
|
|
1125
|
+
const width = (process.stdout.columns || 80) - 6;
|
|
1126
|
+
const visualLines = getVisualLines(value, width);
|
|
1127
|
+
const currentLine = visualLines.find(line => (cursorOffset >= line.start && cursorOffset < line.end) ||
|
|
1128
|
+
(cursorOffset === line.end && line.isHardEnd));
|
|
1129
|
+
if (currentLine) {
|
|
1130
|
+
setCursorOffset(currentLine.start);
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
setCursorOffset(0);
|
|
1134
|
+
}
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
// End: End of Line
|
|
1138
|
+
// @ts-ignore
|
|
1139
|
+
if (key.end) {
|
|
1140
|
+
const width = (process.stdout.columns || 80) - 6;
|
|
1141
|
+
const visualLines = getVisualLines(value, width);
|
|
1142
|
+
const currentLine = visualLines.find(line => (cursorOffset >= line.start && cursorOffset < line.end) ||
|
|
1143
|
+
(cursorOffset === line.end && line.isHardEnd));
|
|
1144
|
+
if (currentLine) {
|
|
1145
|
+
setCursorOffset(currentLine.end);
|
|
1146
|
+
}
|
|
1147
|
+
else {
|
|
1148
|
+
setCursorOffset(value.length);
|
|
1149
|
+
}
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
757
1152
|
// Note: Clipboard images are handled via Alt+V keyboard shortcut
|
|
758
1153
|
// DELETE CHAR - Only runs if Delete Word did NOT trigger
|
|
759
1154
|
// Triggers on:
|
|
@@ -870,6 +1265,20 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
870
1265
|
setSlashAutocompleteVisible(false);
|
|
871
1266
|
}
|
|
872
1267
|
}
|
|
1268
|
+
else if (newValue.startsWith('/models ') || newValue.startsWith('/model ')) {
|
|
1269
|
+
// Models subcommands
|
|
1270
|
+
const fullQuery = newValue.slice(1);
|
|
1271
|
+
const matches = filterCommands(fullQuery);
|
|
1272
|
+
if (matches.length > 0) {
|
|
1273
|
+
setSlashAutocompleteCommands(matches);
|
|
1274
|
+
setSlashAutocompleteVisible(true);
|
|
1275
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1276
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1277
|
+
}
|
|
1278
|
+
else {
|
|
1279
|
+
setSlashAutocompleteVisible(false);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
873
1282
|
else {
|
|
874
1283
|
setSlashAutocompleteVisible(false);
|
|
875
1284
|
}
|
|
@@ -1043,8 +1452,8 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1043
1452
|
return;
|
|
1044
1453
|
}
|
|
1045
1454
|
if (key.leftArrow) {
|
|
1046
|
-
if (key.ctrl) {
|
|
1047
|
-
// Ctrl+Left: Move word backwards
|
|
1455
|
+
if (key.ctrl || key.meta) {
|
|
1456
|
+
// Ctrl+Left / Meta+Left (Option+Left): Move word backwards
|
|
1048
1457
|
let newOffset = cursorOffset;
|
|
1049
1458
|
if (newOffset > 0) {
|
|
1050
1459
|
// Skip whitespace backwards
|
|
@@ -1065,17 +1474,20 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1065
1474
|
}
|
|
1066
1475
|
if (key.rightArrow) {
|
|
1067
1476
|
// Autocomplete Logic (Only at end of line)
|
|
1068
|
-
|
|
1477
|
+
// AI suggestion takes priority over passive suggestion
|
|
1478
|
+
const effectiveSuggestion = aiAutocompleteSuggestion || autocompleteSuggestion;
|
|
1479
|
+
if (effectiveSuggestion && cursorOffset === value.length) {
|
|
1069
1480
|
if (key.ctrl) {
|
|
1070
1481
|
// Ctrl+Right: Accept FULL suggestion
|
|
1071
|
-
setValue(
|
|
1072
|
-
setCursorOffset(
|
|
1482
|
+
setValue(effectiveSuggestion);
|
|
1483
|
+
setCursorOffset(effectiveSuggestion.length);
|
|
1073
1484
|
setAutocompleteSuggestion(null);
|
|
1485
|
+
setAiAutocompleteSuggestion(null);
|
|
1074
1486
|
return;
|
|
1075
1487
|
}
|
|
1076
1488
|
else {
|
|
1077
1489
|
// Right: Accept NEXT WORD
|
|
1078
|
-
const remaining =
|
|
1490
|
+
const remaining = effectiveSuggestion.slice(value.length);
|
|
1079
1491
|
// Match next chunk of non-whitespace (including preceding whitespace)
|
|
1080
1492
|
const match = remaining.match(/^(\s*\S+)/);
|
|
1081
1493
|
if (match) {
|
|
@@ -1095,8 +1507,8 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1095
1507
|
}
|
|
1096
1508
|
}
|
|
1097
1509
|
// Navigation Logic (if not completing)
|
|
1098
|
-
if (key.ctrl) {
|
|
1099
|
-
// Ctrl+Right: Move word forwards
|
|
1510
|
+
if (key.ctrl || key.meta) {
|
|
1511
|
+
// Ctrl+Right / Meta+Right (Option+Right): Move word forwards
|
|
1100
1512
|
let newOffset = cursorOffset;
|
|
1101
1513
|
if (newOffset < value.length) {
|
|
1102
1514
|
// Skip non-whitespace forwards
|
|
@@ -1239,6 +1651,58 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1239
1651
|
setSlashAutocompleteVisible(false);
|
|
1240
1652
|
}
|
|
1241
1653
|
}
|
|
1654
|
+
else if (newValue.startsWith('/models ') || newValue.startsWith('/model ')) {
|
|
1655
|
+
// Models subcommands (when user types "/models " or "/model ")
|
|
1656
|
+
const fullQuery = newValue.slice(1); // Remove leading "/", pass "models <subquery>" to filterCommands
|
|
1657
|
+
const matches = filterCommands(fullQuery);
|
|
1658
|
+
if (matches.length > 0) {
|
|
1659
|
+
setSlashAutocompleteCommands(matches);
|
|
1660
|
+
setSlashAutocompleteVisible(true);
|
|
1661
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1662
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1663
|
+
}
|
|
1664
|
+
else {
|
|
1665
|
+
setSlashAutocompleteVisible(false);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
else if (newValue.match(/^\/workflow\s+(run|view|delete)\s+/) ||
|
|
1669
|
+
newValue.match(/^\/wf\s+(run|view|delete)\s+/)) {
|
|
1670
|
+
// Workflow name autocomplete (when user types "/workflow run " or similar)
|
|
1671
|
+
// This MUST come before the /workflow subcommand check since it's more specific
|
|
1672
|
+
const match = newValue.match(/^\/(?:workflow|wf)\s+(?:run|view|delete)\s+(.*)$/);
|
|
1673
|
+
const partialName = match ? match[1].toLowerCase() : '';
|
|
1674
|
+
const workflows = workflowStorage.list();
|
|
1675
|
+
const matchingWorkflows = workflows
|
|
1676
|
+
.filter(wf => wf.name.toLowerCase().includes(partialName))
|
|
1677
|
+
.slice(0, 10)
|
|
1678
|
+
.map(wf => ({
|
|
1679
|
+
name: wf.name,
|
|
1680
|
+
description: wf.description || `${wf.stepCount} step${wf.stepCount !== 1 ? 's' : ''}`
|
|
1681
|
+
}));
|
|
1682
|
+
if (matchingWorkflows.length > 0) {
|
|
1683
|
+
setSlashAutocompleteCommands(matchingWorkflows);
|
|
1684
|
+
setSlashAutocompleteVisible(true);
|
|
1685
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1686
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1687
|
+
}
|
|
1688
|
+
else {
|
|
1689
|
+
setSlashAutocompleteVisible(false);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
else if (newValue.startsWith('/workflow ') || newValue.startsWith('/wf ')) {
|
|
1693
|
+
// Workflow subcommands (when user types "/workflow " or "/wf ")
|
|
1694
|
+
const fullQuery = newValue.slice(1); // Remove leading "/", pass "workflow <subquery>" to filterCommands
|
|
1695
|
+
const matches = filterCommands(fullQuery);
|
|
1696
|
+
if (matches.length > 0) {
|
|
1697
|
+
setSlashAutocompleteCommands(matches);
|
|
1698
|
+
setSlashAutocompleteVisible(true);
|
|
1699
|
+
setSlashAutocompleteSelectedIndex(0);
|
|
1700
|
+
setSlashAutocompleteScrollOffset(0);
|
|
1701
|
+
}
|
|
1702
|
+
else {
|
|
1703
|
+
setSlashAutocompleteVisible(false);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1242
1706
|
else {
|
|
1243
1707
|
setSlashAutocompleteVisible(false);
|
|
1244
1708
|
}
|
|
@@ -1324,7 +1788,7 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1324
1788
|
if (trimmedValue) {
|
|
1325
1789
|
// Save to history if it was a command
|
|
1326
1790
|
if (commandMode) {
|
|
1327
|
-
CommandHistoryManager.getInstance().addCommand(trimmedValue, currentDir);
|
|
1791
|
+
CommandHistoryManager.getInstance().addCommand(trimmedValue, currentDir, currentEnvironment);
|
|
1328
1792
|
}
|
|
1329
1793
|
// Resolve file tags (@filename -> absolute path)
|
|
1330
1794
|
let resolvedValue = trimmedValue;
|
|
@@ -1491,10 +1955,14 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1491
1955
|
}
|
|
1492
1956
|
// Render Autocomplete Ghost Text
|
|
1493
1957
|
// Only on the last line, if suggestion exists and matches start
|
|
1494
|
-
|
|
1495
|
-
|
|
1958
|
+
// AI suggestion takes priority over passive suggestion
|
|
1959
|
+
const effectiveSuggestion = aiAutocompleteSuggestion || autocompleteSuggestion;
|
|
1960
|
+
if (isLastLine && effectiveSuggestion && effectiveSuggestion.startsWith(value)) {
|
|
1961
|
+
const suffix = effectiveSuggestion.slice(value.length);
|
|
1496
1962
|
if (suffix) {
|
|
1497
|
-
|
|
1963
|
+
// Use slightly different color for AI suggestion to differentiate
|
|
1964
|
+
const ghostColor = aiAutocompleteSuggestion ? '#888888' : 'gray';
|
|
1965
|
+
renderedChars.push(React.createElement(Text, { key: "ghost", color: ghostColor }, suffix));
|
|
1498
1966
|
}
|
|
1499
1967
|
}
|
|
1500
1968
|
if (renderedChars.length === 0) {
|
|
@@ -1512,7 +1980,7 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
1512
1980
|
"#257aa5ff", paddingX: 1, paddingY: 0, width: "100%" },
|
|
1513
1981
|
React.createElement(Box, { marginY: 1, justifyContent: "space-between", width: "100%" },
|
|
1514
1982
|
React.createElement(Box, null,
|
|
1515
|
-
subshellContext && subshellContext.type !== 'local' && (React.createElement(Breadcrumbs, { context: subshellContext })),
|
|
1983
|
+
subshellContext && subshellContext.type !== 'local' && (React.createElement(Breadcrumbs, { context: subshellContext, stack: subshellContextStack })),
|
|
1516
1984
|
React.createElement(Text, { color: "#666666" }, "CWD: "),
|
|
1517
1985
|
React.createElement(Text, { color: "#00ccff", bold: true }, currentDir)),
|
|
1518
1986
|
React.createElement(Box, null,
|