centaurus-cli 2.8.3 → 2.8.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-adapter.d.ts +14 -0
- package/dist/cli-adapter.d.ts.map +1 -1
- package/dist/cli-adapter.js +204 -35
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +14 -4
- package/dist/config/models.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/file-ops.d.ts.map +1 -1
- package/dist/tools/file-ops.js +69 -14
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/find-files.d.ts +1 -0
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +77 -13
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/grep-search.d.ts.map +1 -1
- package/dist/tools/grep-search.js +68 -15
- package/dist/tools/grep-search.js.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/ui/components/App.d.ts +2 -0
- package/dist/ui/components/App.d.ts.map +1 -1
- package/dist/ui/components/App.js +70 -6
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.d.ts +17 -0
- package/dist/ui/components/ConnectionStatusMessage.d.ts.map +1 -0
- package/dist/ui/components/ConnectionStatusMessage.js +66 -0
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -0
- package/dist/ui/components/InputBox.d.ts +1 -0
- package/dist/ui/components/InputBox.d.ts.map +1 -1
- package/dist/ui/components/InputBox.js +10 -2
- 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 +11 -2
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/MessageDisplay.d.ts.map +1 -1
- package/dist/ui/components/MessageDisplay.js +13 -0
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.d.ts.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +8 -0
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.js +66 -33
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/utils/editor-utils.d.ts +3 -3
- package/dist/utils/editor-utils.d.ts.map +1 -1
- package/dist/utils/editor-utils.js +25 -18
- package/dist/utils/editor-utils.js.map +1 -1
- package/dist/utils/file.d.ts +40 -0
- package/dist/utils/file.d.ts.map +1 -1
- package/dist/utils/file.js +164 -0
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/terminal-output.d.ts.map +1 -1
- package/dist/utils/terminal-output.js +55 -1
- package/dist/utils/terminal-output.js.map +1 -1
- package/models-config.json +24 -4
- package/package.json +1 -1
package/dist/cli-adapter.d.ts
CHANGED
|
@@ -34,8 +34,10 @@ export declare class CentaurusCLI {
|
|
|
34
34
|
private aiContextInjector;
|
|
35
35
|
private onSubshellContextChange?;
|
|
36
36
|
private currentAbortController?;
|
|
37
|
+
private requestIntentionallyAborted;
|
|
37
38
|
private mcpCommandHandler?;
|
|
38
39
|
private onInteractiveEditorMode?;
|
|
40
|
+
private onConnectionStatusUpdate?;
|
|
39
41
|
constructor();
|
|
40
42
|
setOnResponseCallback(callback: (message: string) => void): void;
|
|
41
43
|
setOnDirectMessageCallback(callback: (message: string) => void): void;
|
|
@@ -84,6 +86,12 @@ export declare class CentaurusCLI {
|
|
|
84
86
|
setOnSubshellContextChange(callback: (context: SubshellContext) => void): void;
|
|
85
87
|
setOnPasswordRequest(callback: (message: string) => Promise<string>): void;
|
|
86
88
|
setOnInteractiveEditorMode(callback: (active: boolean, command?: string, cwd?: string, remoteContext?: SubshellContext) => void): void;
|
|
89
|
+
setOnConnectionStatusUpdate(callback: (status: {
|
|
90
|
+
type: 'ssh' | 'wsl' | 'docker';
|
|
91
|
+
status: 'connecting' | 'connected' | 'error';
|
|
92
|
+
connectionString?: string;
|
|
93
|
+
error?: string;
|
|
94
|
+
}) => void): void;
|
|
87
95
|
private initializeMCP;
|
|
88
96
|
writeToShellStdin(input: string): void;
|
|
89
97
|
sendSignalToShell(signal: NodeJS.Signals): void;
|
|
@@ -125,6 +133,12 @@ export declare class CentaurusCLI {
|
|
|
125
133
|
* Cancel the current AI request
|
|
126
134
|
*/
|
|
127
135
|
cancelCurrentRequest(): void;
|
|
136
|
+
/**
|
|
137
|
+
* Clean up orphaned tool_calls from conversation history.
|
|
138
|
+
* This is called when a request is aborted to ensure the history remains consistent.
|
|
139
|
+
* Vertex AI requires that every assistant message with tool_calls has matching tool result messages.
|
|
140
|
+
*/
|
|
141
|
+
private cleanupOrphanedToolCalls;
|
|
128
142
|
handleMessage(message: string): Promise<void>;
|
|
129
143
|
private handleSlashCommand;
|
|
130
144
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-adapter.d.ts","sourceRoot":"","sources":["../src/cli-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAY/C,OAAO,EAA8H,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAalL,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AASrD,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,mBAAmB,CAAmB;IAC9C,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,kBAAkB,CAAC,CAA4B;IACvD,OAAO,CAAC,uBAAuB,CAAC,CAA4B;IAC5D,OAAO,CAAC,wBAAwB,CAAC,CAA0B;IAC3D,OAAO,CAAC,uBAAuB,CAAC,CAA4B;IAC5D,OAAO,CAAC,yBAAyB,CAAC,CAAoC;IACtE,OAAO,CAAC,mBAAmB,CAAC,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAwB;IAC5C,OAAO,CAAC,aAAa,CAAC,CAA8B;IACpD,OAAO,CAAC,oBAAoB,CAAC,CAA0G;IACvI,OAAO,CAAC,qBAAqB,CAAC,CAAoK;IAClM,OAAO,CAAC,qBAAqB,CAAC,CAAsP;IACpR,OAAO,CAAC,qBAAqB,CAAC,CAAmF;IACjH,OAAO,CAAC,gBAAgB,CAAC,CAA8B;IACvD,OAAO,CAAC,qBAAqB,CAAC,CAAmC;IACjE,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAC,CAA4F;IACpH,OAAO,CAAC,iBAAiB,CAAC,CAAuC;IACjE,OAAO,CAAC,yBAAyB,CAAC,CAAgC;IAClE,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,uBAAuB,CAAC,CAAqC;IACrE,OAAO,CAAC,sBAAsB,CAAC,CAAkB;IACjD,OAAO,CAAC,iBAAiB,CAAC,CAAoB;IAC9C,OAAO,CAAC,uBAAuB,CAAC,CAA6F;;
|
|
1
|
+
{"version":3,"file":"cli-adapter.d.ts","sourceRoot":"","sources":["../src/cli-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/cli-adapter.js
CHANGED
|
@@ -65,8 +65,10 @@ export class CentaurusCLI {
|
|
|
65
65
|
aiContextInjector;
|
|
66
66
|
onSubshellContextChange;
|
|
67
67
|
currentAbortController;
|
|
68
|
+
requestIntentionallyAborted = false;
|
|
68
69
|
mcpCommandHandler;
|
|
69
70
|
onInteractiveEditorMode;
|
|
71
|
+
onConnectionStatusUpdate;
|
|
70
72
|
constructor() {
|
|
71
73
|
this.configManager = new ConfigManager();
|
|
72
74
|
this.toolRegistry = new ToolRegistry();
|
|
@@ -149,6 +151,9 @@ export class CentaurusCLI {
|
|
|
149
151
|
setOnInteractiveEditorMode(callback) {
|
|
150
152
|
this.onInteractiveEditorMode = callback;
|
|
151
153
|
}
|
|
154
|
+
setOnConnectionStatusUpdate(callback) {
|
|
155
|
+
this.onConnectionStatusUpdate = callback;
|
|
156
|
+
}
|
|
152
157
|
async initializeMCP() {
|
|
153
158
|
try {
|
|
154
159
|
const mcpConfigManager = new MCPConfigManager();
|
|
@@ -240,10 +245,39 @@ export class CentaurusCLI {
|
|
|
240
245
|
*/
|
|
241
246
|
notifyToolStatus(toolName, status, args, result, error) {
|
|
242
247
|
if (this.onToolExecutionUpdate) {
|
|
243
|
-
//
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
// Get current context for remote prefix
|
|
249
|
+
const currentContext = this.contextManager.getCurrentContext();
|
|
250
|
+
// Build remote context prefix for SSH/Docker/WSL
|
|
251
|
+
let remoteContext;
|
|
252
|
+
if (currentContext.type !== 'local') {
|
|
253
|
+
const metadata = currentContext.metadata;
|
|
254
|
+
if (currentContext.type === 'ssh' && metadata) {
|
|
255
|
+
// SSH: user@hostname
|
|
256
|
+
const username = metadata.username || 'user';
|
|
257
|
+
const hostname = metadata.hostname || 'remote';
|
|
258
|
+
remoteContext = `${username}@${hostname}`;
|
|
259
|
+
}
|
|
260
|
+
else if (currentContext.type === 'wsl' && metadata) {
|
|
261
|
+
// WSL: distroName or just wsl
|
|
262
|
+
remoteContext = `wsl:${metadata.distroName || 'wsl'}`;
|
|
263
|
+
}
|
|
264
|
+
else if (currentContext.type === 'docker' && metadata) {
|
|
265
|
+
// Docker: container id (first 12 chars)
|
|
266
|
+
remoteContext = `docker:${metadata.containerId?.substring(0, 12) || 'container'}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Add cwd and remoteContext to arguments for execute_command tool
|
|
270
|
+
let toolArgs = args;
|
|
271
|
+
if (toolName === 'execute_command' && args) {
|
|
272
|
+
toolArgs = { ...args, cwd: this.cwd, remoteContext };
|
|
273
|
+
}
|
|
274
|
+
else if (remoteContext && args) {
|
|
275
|
+
// For other tools, also add remoteContext if in remote environment
|
|
276
|
+
toolArgs = { ...args, remoteContext };
|
|
277
|
+
}
|
|
278
|
+
else if (remoteContext) {
|
|
279
|
+
toolArgs = { remoteContext };
|
|
280
|
+
}
|
|
247
281
|
this.onToolExecutionUpdate({
|
|
248
282
|
toolName,
|
|
249
283
|
status,
|
|
@@ -389,10 +423,50 @@ Press Enter to continue...
|
|
|
389
423
|
*/
|
|
390
424
|
cancelCurrentRequest() {
|
|
391
425
|
if (this.currentAbortController) {
|
|
426
|
+
this.requestIntentionallyAborted = true;
|
|
392
427
|
this.currentAbortController.abort();
|
|
393
428
|
this.currentAbortController = undefined;
|
|
394
429
|
}
|
|
395
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Clean up orphaned tool_calls from conversation history.
|
|
433
|
+
* This is called when a request is aborted to ensure the history remains consistent.
|
|
434
|
+
* Vertex AI requires that every assistant message with tool_calls has matching tool result messages.
|
|
435
|
+
*/
|
|
436
|
+
cleanupOrphanedToolCalls() {
|
|
437
|
+
if (this.conversationHistory.length === 0)
|
|
438
|
+
return;
|
|
439
|
+
// Find the last assistant message with tool_calls
|
|
440
|
+
let lastAssistantWithToolCallsIndex = -1;
|
|
441
|
+
for (let i = this.conversationHistory.length - 1; i >= 0; i--) {
|
|
442
|
+
const msg = this.conversationHistory[i];
|
|
443
|
+
if (msg.role === 'assistant' && msg.tool_calls && msg.tool_calls.length > 0) {
|
|
444
|
+
lastAssistantWithToolCallsIndex = i;
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (lastAssistantWithToolCallsIndex === -1)
|
|
449
|
+
return; // No assistant messages with tool_calls
|
|
450
|
+
const assistantMsg = this.conversationHistory[lastAssistantWithToolCallsIndex];
|
|
451
|
+
const toolCallIds = new Set(assistantMsg.tool_calls.map((tc) => tc.id));
|
|
452
|
+
// Check if all tool_calls have matching tool result messages after this assistant message
|
|
453
|
+
for (let i = lastAssistantWithToolCallsIndex + 1; i < this.conversationHistory.length; i++) {
|
|
454
|
+
const msg = this.conversationHistory[i];
|
|
455
|
+
if (msg.role === 'tool' && msg.tool_call_id) {
|
|
456
|
+
toolCallIds.delete(msg.tool_call_id);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
// If there are orphaned tool_calls (no matching tool results), remove from history
|
|
460
|
+
if (toolCallIds.size > 0) {
|
|
461
|
+
// Log the cleanup for debugging
|
|
462
|
+
try {
|
|
463
|
+
fs.appendFileSync('cli_frontend_logs.txt', `[${new Date().toISOString()}] [CLI] Cleaning up orphaned tool_calls: ${Array.from(toolCallIds).join(', ')}\n`);
|
|
464
|
+
}
|
|
465
|
+
catch (e) { }
|
|
466
|
+
// Remove the orphaned assistant message and any partial tool results after it
|
|
467
|
+
this.conversationHistory.splice(lastAssistantWithToolCallsIndex);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
396
470
|
async handleMessage(message) {
|
|
397
471
|
// Handle command mode - execute commands directly
|
|
398
472
|
if (this.commandMode) {
|
|
@@ -408,6 +482,12 @@ Press Enter to continue...
|
|
|
408
482
|
if (!apiClient.isAuthenticated()) {
|
|
409
483
|
throw new Error('Authentication required. Please sign in to use AI features.');
|
|
410
484
|
}
|
|
485
|
+
// Cancel any active request when a new message comes in
|
|
486
|
+
// This enables "interrupt and replace" - new message takes priority
|
|
487
|
+
if (this.currentAbortController) {
|
|
488
|
+
this.currentAbortController.abort();
|
|
489
|
+
this.currentAbortController = undefined;
|
|
490
|
+
}
|
|
411
491
|
// Store original request if in planning mode (for execution phase after approval)
|
|
412
492
|
if (this.planMode && !this.pendingPlanRequest) {
|
|
413
493
|
this.pendingPlanRequest = message;
|
|
@@ -479,6 +559,10 @@ Press Enter to continue...
|
|
|
479
559
|
const MAX_IDENTICAL_TOOL_CALLS = 3; // Max times exact same tool call allowed
|
|
480
560
|
// Create AbortController for this request
|
|
481
561
|
this.currentAbortController = new AbortController();
|
|
562
|
+
this.requestIntentionallyAborted = false; // Reset abort flag for new request
|
|
563
|
+
// Clean up any orphaned tool_calls from a previous aborted request
|
|
564
|
+
// This prevents 400 Bad Request errors when sending to the backend
|
|
565
|
+
this.cleanupOrphanedToolCalls();
|
|
482
566
|
// Multi-turn tool execution loop
|
|
483
567
|
while (turnCount < MAX_TURNS) {
|
|
484
568
|
turnCount++;
|
|
@@ -511,6 +595,16 @@ Press Enter to continue...
|
|
|
511
595
|
for await (const chunk of aiServiceClient.streamChat(selectedModel, messages, tools, environmentContext, mode, selectedModelThinkingConfig, this.currentAbortController.signal)) {
|
|
512
596
|
// Handle error chunks
|
|
513
597
|
if (chunk.type === 'error') {
|
|
598
|
+
// Check if this is an abort situation (user cancelled or sent new message)
|
|
599
|
+
if (chunk.code === 'TIMEOUT' && this.requestIntentionallyAborted) {
|
|
600
|
+
// Reset the flag
|
|
601
|
+
this.requestIntentionallyAborted = false;
|
|
602
|
+
// Clean up orphaned tool_calls from conversation history
|
|
603
|
+
// This prevents 400 Bad Request errors when assistant has tool_calls without matching tool results
|
|
604
|
+
this.cleanupOrphanedToolCalls();
|
|
605
|
+
// Gracefully exit - request was intentionally cancelled
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
514
608
|
conversationLogger.logError('AI Stream', new Error(chunk.message));
|
|
515
609
|
throw new Error(chunk.message);
|
|
516
610
|
}
|
|
@@ -861,12 +955,26 @@ Press Enter to continue...
|
|
|
861
955
|
const effectiveCwd = currentCtx.type !== 'local'
|
|
862
956
|
? currentCtx.metadata?.workingDirectory || '~'
|
|
863
957
|
: this.cwd;
|
|
958
|
+
// Build remote context prefix for SSH/Docker/WSL (for path display in UI)
|
|
959
|
+
let remoteContext;
|
|
960
|
+
if (currentCtx.type !== 'local') {
|
|
961
|
+
const metadata = currentCtx.metadata;
|
|
962
|
+
if (currentCtx.type === 'ssh' && metadata) {
|
|
963
|
+
remoteContext = `${metadata.username || 'user'}@${metadata.hostname || 'remote'}`;
|
|
964
|
+
}
|
|
965
|
+
else if (currentCtx.type === 'wsl' && metadata) {
|
|
966
|
+
remoteContext = `wsl:${metadata.distroName || 'wsl'}`;
|
|
967
|
+
}
|
|
968
|
+
else if (currentCtx.type === 'docker' && metadata) {
|
|
969
|
+
remoteContext = `docker:${metadata.containerId?.substring(0, 12) || 'container'}`;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
864
972
|
// Notify UI: tool is executing (send before execution starts)
|
|
865
973
|
if (this.onToolExecutionUpdate) {
|
|
866
|
-
// Add cwd to arguments for execute_command tool
|
|
974
|
+
// Add cwd to arguments for execute_command tool, and remoteContext for all tools
|
|
867
975
|
const toolArgs = toolCall.name === 'execute_command'
|
|
868
|
-
? { ...toolCall.arguments, cwd: effectiveCwd }
|
|
869
|
-
: toolCall.arguments;
|
|
976
|
+
? { ...toolCall.arguments, cwd: effectiveCwd, remoteContext }
|
|
977
|
+
: { ...toolCall.arguments, remoteContext };
|
|
870
978
|
this.onToolExecutionUpdate({
|
|
871
979
|
toolName: toolCall.name,
|
|
872
980
|
status: 'executing',
|
|
@@ -882,10 +990,10 @@ Press Enter to continue...
|
|
|
882
990
|
conversationLogger.logToolResult(toolCall.name, toolCall.id, result.result, true);
|
|
883
991
|
// Notify UI: tool succeeded (send full result to UI)
|
|
884
992
|
if (this.onToolExecutionUpdate) {
|
|
885
|
-
// Add cwd to arguments for execute_command tool
|
|
993
|
+
// Add cwd to arguments for execute_command tool, and remoteContext for all tools
|
|
886
994
|
const toolArgs = toolCall.name === 'execute_command'
|
|
887
|
-
? { ...toolCall.arguments, cwd: effectiveCwd }
|
|
888
|
-
: toolCall.arguments;
|
|
995
|
+
? { ...toolCall.arguments, cwd: effectiveCwd, remoteContext }
|
|
996
|
+
: { ...toolCall.arguments, remoteContext };
|
|
889
997
|
this.onToolExecutionUpdate({
|
|
890
998
|
toolName: toolCall.name,
|
|
891
999
|
status: 'completed',
|
|
@@ -921,10 +1029,10 @@ Press Enter to continue...
|
|
|
921
1029
|
}
|
|
922
1030
|
// Notify UI: tool failed
|
|
923
1031
|
if (this.onToolExecutionUpdate) {
|
|
924
|
-
// Add cwd to arguments for execute_command tool
|
|
1032
|
+
// Add cwd to arguments for execute_command tool, and remoteContext for all tools
|
|
925
1033
|
const toolArgs = toolCall.name === 'execute_command'
|
|
926
|
-
? { ...toolCall.arguments, cwd: effectiveCwd }
|
|
927
|
-
: toolCall.arguments;
|
|
1034
|
+
? { ...toolCall.arguments, cwd: effectiveCwd, remoteContext }
|
|
1035
|
+
: { ...toolCall.arguments, remoteContext };
|
|
928
1036
|
this.onToolExecutionUpdate({
|
|
929
1037
|
toolName: toolCall.name,
|
|
930
1038
|
status: 'error',
|
|
@@ -950,12 +1058,27 @@ Press Enter to continue...
|
|
|
950
1058
|
if (error.message && error.message.includes('Operation cancelled by user')) {
|
|
951
1059
|
userCancelledOperation = true;
|
|
952
1060
|
}
|
|
1061
|
+
// Build remote context for error notification
|
|
1062
|
+
const catchCtx = this.contextManager.getCurrentContext();
|
|
1063
|
+
let catchRemoteContext;
|
|
1064
|
+
if (catchCtx.type !== 'local') {
|
|
1065
|
+
const metadata = catchCtx.metadata;
|
|
1066
|
+
if (catchCtx.type === 'ssh' && metadata) {
|
|
1067
|
+
catchRemoteContext = `${metadata.username || 'user'}@${metadata.hostname || 'remote'}`;
|
|
1068
|
+
}
|
|
1069
|
+
else if (catchCtx.type === 'wsl' && metadata) {
|
|
1070
|
+
catchRemoteContext = `wsl:${metadata.distroName || 'wsl'}`;
|
|
1071
|
+
}
|
|
1072
|
+
else if (catchCtx.type === 'docker' && metadata) {
|
|
1073
|
+
catchRemoteContext = `docker:${metadata.containerId?.substring(0, 12) || 'container'}`;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
953
1076
|
// Notify UI: tool failed
|
|
954
1077
|
if (this.onToolExecutionUpdate) {
|
|
955
|
-
// Add cwd to arguments for execute_command tool
|
|
1078
|
+
// Add cwd to arguments for execute_command tool, and remoteContext for all tools
|
|
956
1079
|
const toolArgs = toolCall.name === 'execute_command'
|
|
957
|
-
? { ...toolCall.arguments, cwd: this.cwd }
|
|
958
|
-
: toolCall.arguments;
|
|
1080
|
+
? { ...toolCall.arguments, cwd: this.cwd, remoteContext: catchRemoteContext }
|
|
1081
|
+
: { ...toolCall.arguments, remoteContext: catchRemoteContext };
|
|
959
1082
|
this.onToolExecutionUpdate({
|
|
960
1083
|
toolName: toolCall.name,
|
|
961
1084
|
status: 'error',
|
|
@@ -1852,9 +1975,34 @@ Once the user approves the plan:
|
|
|
1852
1975
|
// Detect subshell commands
|
|
1853
1976
|
const detection = this.commandDetector.detect(command);
|
|
1854
1977
|
if (detection) {
|
|
1855
|
-
//
|
|
1856
|
-
|
|
1857
|
-
|
|
1978
|
+
// Build connection string for display (e.g., "rohan@localhost" for SSH)
|
|
1979
|
+
let connectionString = '';
|
|
1980
|
+
if (detection.handler.type === 'ssh') {
|
|
1981
|
+
// Parse SSH command to get user@host
|
|
1982
|
+
const sshMatch = command.match(/ssh\s+(?:(?:-\w+\s+)+)?(?:(\S+)@)?(\S+)/);
|
|
1983
|
+
if (sshMatch) {
|
|
1984
|
+
const user = sshMatch[1] || 'user';
|
|
1985
|
+
const host = sshMatch[2] || 'remote';
|
|
1986
|
+
connectionString = `${user}@${host}`;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
else if (detection.handler.type === 'wsl') {
|
|
1990
|
+
// Parse WSL command to get distribution name
|
|
1991
|
+
const wslMatch = command.match(/wsl(?:\s+(?:-d|--distribution)\s+(\S+))?/);
|
|
1992
|
+
connectionString = wslMatch?.[1] || 'Ubuntu';
|
|
1993
|
+
}
|
|
1994
|
+
else if (detection.handler.type === 'docker') {
|
|
1995
|
+
// Parse Docker command to get container
|
|
1996
|
+
const dockerMatch = command.match(/docker\s+exec\s+(?:(?:-\w+\s+)+)?(\S+)/);
|
|
1997
|
+
connectionString = dockerMatch?.[1]?.substring(0, 12) || 'container';
|
|
1998
|
+
}
|
|
1999
|
+
// Show connecting message with spinner (dynamic)
|
|
2000
|
+
if (this.onConnectionStatusUpdate) {
|
|
2001
|
+
this.onConnectionStatusUpdate({
|
|
2002
|
+
type: detection.handler.type,
|
|
2003
|
+
status: 'connecting',
|
|
2004
|
+
connectionString
|
|
2005
|
+
});
|
|
1858
2006
|
}
|
|
1859
2007
|
// Update connection state
|
|
1860
2008
|
this.contextManager.updateConnectionState('connecting');
|
|
@@ -1862,19 +2010,26 @@ Once the user approves the plan:
|
|
|
1862
2010
|
// Connect to subshell
|
|
1863
2011
|
const context = await detection.handler.connect(command, this.cwd);
|
|
1864
2012
|
this.contextManager.pushContext(context);
|
|
1865
|
-
// Show success message
|
|
1866
|
-
if (this.
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2013
|
+
// Show success message (replaces the spinner with static message)
|
|
2014
|
+
if (this.onConnectionStatusUpdate) {
|
|
2015
|
+
this.onConnectionStatusUpdate({
|
|
2016
|
+
type: detection.handler.type,
|
|
2017
|
+
status: 'connected',
|
|
2018
|
+
connectionString
|
|
2019
|
+
});
|
|
1870
2020
|
}
|
|
1871
2021
|
return;
|
|
1872
2022
|
}
|
|
1873
2023
|
catch (error) {
|
|
1874
2024
|
// Connection failed
|
|
1875
2025
|
this.contextManager.updateConnectionState('error');
|
|
1876
|
-
if (this.
|
|
1877
|
-
this.
|
|
2026
|
+
if (this.onConnectionStatusUpdate) {
|
|
2027
|
+
this.onConnectionStatusUpdate({
|
|
2028
|
+
type: detection.handler.type,
|
|
2029
|
+
status: 'error',
|
|
2030
|
+
connectionString,
|
|
2031
|
+
error: error.message
|
|
2032
|
+
});
|
|
1878
2033
|
}
|
|
1879
2034
|
return;
|
|
1880
2035
|
}
|
|
@@ -1926,12 +2081,26 @@ Once the user approves the plan:
|
|
|
1926
2081
|
const effectiveCwd = currentContext.type !== 'local'
|
|
1927
2082
|
? currentContext.metadata?.workingDirectory || '~'
|
|
1928
2083
|
: this.cwd;
|
|
2084
|
+
// Build remote context prefix for SSH/Docker/WSL (for path display in UI)
|
|
2085
|
+
let remoteContext;
|
|
2086
|
+
if (currentContext.type !== 'local') {
|
|
2087
|
+
const metadata = currentContext.metadata;
|
|
2088
|
+
if (currentContext.type === 'ssh' && metadata) {
|
|
2089
|
+
remoteContext = `${metadata.username || 'user'}@${metadata.hostname || 'remote'}`;
|
|
2090
|
+
}
|
|
2091
|
+
else if (currentContext.type === 'wsl' && metadata) {
|
|
2092
|
+
remoteContext = `wsl:${metadata.distroName || 'wsl'}`;
|
|
2093
|
+
}
|
|
2094
|
+
else if (currentContext.type === 'docker' && metadata) {
|
|
2095
|
+
remoteContext = `docker:${metadata.containerId?.substring(0, 12) || 'container'}`;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
1929
2098
|
// Notify UI that command is executing
|
|
1930
2099
|
if (this.onToolExecutionUpdate) {
|
|
1931
2100
|
this.onToolExecutionUpdate({
|
|
1932
2101
|
toolName: 'execute_command',
|
|
1933
2102
|
status: 'executing',
|
|
1934
|
-
arguments: { command, cwd: effectiveCwd, isPty: shellUtils.isPtyAvailable() }
|
|
2103
|
+
arguments: { command, cwd: effectiveCwd, isPty: shellUtils.isPtyAvailable(), remoteContext }
|
|
1935
2104
|
});
|
|
1936
2105
|
}
|
|
1937
2106
|
// Execute with streaming support for local commands
|
|
@@ -1954,7 +2123,7 @@ Once the user approves the plan:
|
|
|
1954
2123
|
status: 'error',
|
|
1955
2124
|
result: output,
|
|
1956
2125
|
error: `Exit Code: ${exitCode}`,
|
|
1957
|
-
arguments: { command, cwd: this.cwd }
|
|
2126
|
+
arguments: { command, cwd: this.cwd, remoteContext }
|
|
1958
2127
|
});
|
|
1959
2128
|
}
|
|
1960
2129
|
else {
|
|
@@ -1962,7 +2131,7 @@ Once the user approves the plan:
|
|
|
1962
2131
|
toolName: 'execute_command',
|
|
1963
2132
|
status: 'completed',
|
|
1964
2133
|
result: output || 'Command executed successfully',
|
|
1965
|
-
arguments: { command, cwd: this.cwd }
|
|
2134
|
+
arguments: { command, cwd: this.cwd, remoteContext }
|
|
1966
2135
|
});
|
|
1967
2136
|
}
|
|
1968
2137
|
}
|
|
@@ -1992,7 +2161,7 @@ Once the user approves the plan:
|
|
|
1992
2161
|
status: 'error',
|
|
1993
2162
|
result: output,
|
|
1994
2163
|
error: `Exit Code: ${exitCode}`,
|
|
1995
|
-
arguments: { command, cwd: remoteCwd }
|
|
2164
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
1996
2165
|
});
|
|
1997
2166
|
}
|
|
1998
2167
|
else {
|
|
@@ -2000,7 +2169,7 @@ Once the user approves the plan:
|
|
|
2000
2169
|
toolName: 'execute_command',
|
|
2001
2170
|
status: 'completed',
|
|
2002
2171
|
result: output || 'Command executed successfully',
|
|
2003
|
-
arguments: { command, cwd: remoteCwd }
|
|
2172
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
2004
2173
|
});
|
|
2005
2174
|
}
|
|
2006
2175
|
}
|
|
@@ -2043,7 +2212,7 @@ Once the user approves the plan:
|
|
|
2043
2212
|
status: 'error',
|
|
2044
2213
|
result: output,
|
|
2045
2214
|
error: `Exit Code: ${exitCode}`,
|
|
2046
|
-
arguments: { command, cwd: remoteCwd }
|
|
2215
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
2047
2216
|
});
|
|
2048
2217
|
}
|
|
2049
2218
|
else {
|
|
@@ -2051,7 +2220,7 @@ Once the user approves the plan:
|
|
|
2051
2220
|
toolName: 'execute_command',
|
|
2052
2221
|
status: 'completed',
|
|
2053
2222
|
result: output || 'Command executed successfully',
|
|
2054
|
-
arguments: { command, cwd: remoteCwd }
|
|
2223
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
2055
2224
|
});
|
|
2056
2225
|
}
|
|
2057
2226
|
}
|
|
@@ -2097,7 +2266,7 @@ Once the user approves the plan:
|
|
|
2097
2266
|
status: 'error',
|
|
2098
2267
|
result: output,
|
|
2099
2268
|
error: `Exit Code: ${exitCode}`,
|
|
2100
|
-
arguments: { command, cwd: remoteCwd }
|
|
2269
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
2101
2270
|
});
|
|
2102
2271
|
}
|
|
2103
2272
|
else {
|
|
@@ -2105,7 +2274,7 @@ Once the user approves the plan:
|
|
|
2105
2274
|
toolName: 'execute_command',
|
|
2106
2275
|
status: 'completed',
|
|
2107
2276
|
result: output || 'Command executed successfully',
|
|
2108
|
-
arguments: { command, cwd: remoteCwd }
|
|
2277
|
+
arguments: { command, cwd: remoteCwd, remoteContext }
|
|
2109
2278
|
});
|
|
2110
2279
|
}
|
|
2111
2280
|
}
|