@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3
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/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +14 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,2304 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TerminalTool - Execute terminal/command line operations
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Execute system commands safely
|
|
6
|
-
* - Handle directory navigation
|
|
7
|
-
* - Manage command output and errors
|
|
8
|
-
* - Support both synchronous and asynchronous execution
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { BaseTool } from './baseTool.js';
|
|
12
|
-
import TagParser from '../utilities/tagParser.js';
|
|
13
|
-
import DirectoryAccessManager from '../utilities/directoryAccessManager.js';
|
|
14
|
-
import { spawn, exec } from 'child_process';
|
|
15
|
-
import path from 'path';
|
|
16
|
-
import fs from 'fs/promises';
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
TOOL_STATUS,
|
|
20
|
-
SYSTEM_DEFAULTS
|
|
21
|
-
} from '../utilities/constants.js';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* PromptDetector - Detects interactive prompts in command output
|
|
25
|
-
* Phase 2: Prompt Detection System
|
|
26
|
-
*/
|
|
27
|
-
class PromptDetector {
|
|
28
|
-
constructor() {
|
|
29
|
-
// Common prompt patterns (case-insensitive)
|
|
30
|
-
this.promptPatterns = [
|
|
31
|
-
// Yes/No prompts
|
|
32
|
-
{ pattern: /\(y\/n\)/i, type: 'yes-no', description: 'Yes/No question' },
|
|
33
|
-
{ pattern: /\(Y\/n\)/i, type: 'yes-no-default-yes', description: 'Yes/No (default Yes)' },
|
|
34
|
-
{ pattern: /\(y\/N\)/i, type: 'yes-no-default-no', description: 'Yes/No (default No)' },
|
|
35
|
-
{ pattern: /\[y\/n\]/i, type: 'yes-no', description: 'Yes/No question' },
|
|
36
|
-
{ pattern: /\[Y\/n\]/i, type: 'yes-no-default-yes', description: 'Yes/No (default Yes)' },
|
|
37
|
-
{ pattern: /\[y\/N\]/i, type: 'yes-no-default-no', description: 'Yes/No (default No)' },
|
|
38
|
-
|
|
39
|
-
// Continue prompts
|
|
40
|
-
{ pattern: /continue\?/i, type: 'continue', description: 'Continue prompt' },
|
|
41
|
-
{ pattern: /proceed\?/i, type: 'continue', description: 'Proceed prompt' },
|
|
42
|
-
{ pattern: /press any key to continue/i, type: 'keypress', description: 'Press any key' },
|
|
43
|
-
{ pattern: /press enter to continue/i, type: 'keypress', description: 'Press enter' },
|
|
44
|
-
{ pattern: /hit enter to continue/i, type: 'keypress', description: 'Hit enter' },
|
|
45
|
-
|
|
46
|
-
// Password/Authentication prompts
|
|
47
|
-
{ pattern: /password:/i, type: 'password', description: 'Password prompt' },
|
|
48
|
-
{ pattern: /enter password/i, type: 'password', description: 'Password prompt' },
|
|
49
|
-
{ pattern: /passphrase:/i, type: 'password', description: 'Passphrase prompt' },
|
|
50
|
-
{ pattern: /username:/i, type: 'username', description: 'Username prompt' },
|
|
51
|
-
{ pattern: /enter username/i, type: 'username', description: 'Username prompt' },
|
|
52
|
-
|
|
53
|
-
// Input prompts
|
|
54
|
-
{ pattern: /enter\s+\w+:/i, type: 'input', description: 'Generic input prompt' },
|
|
55
|
-
{ pattern: /please enter/i, type: 'input', description: 'Generic input prompt' },
|
|
56
|
-
{ pattern: /input:/i, type: 'input', description: 'Generic input prompt' },
|
|
57
|
-
|
|
58
|
-
// Confirmation prompts
|
|
59
|
-
{ pattern: /are you sure\?/i, type: 'confirmation', description: 'Confirmation prompt' },
|
|
60
|
-
{ pattern: /do you want to/i, type: 'confirmation', description: 'Confirmation prompt' },
|
|
61
|
-
{ pattern: /would you like to/i, type: 'confirmation', description: 'Confirmation prompt' },
|
|
62
|
-
|
|
63
|
-
// Selection prompts
|
|
64
|
-
{ pattern: /select an option/i, type: 'selection', description: 'Selection prompt' },
|
|
65
|
-
{ pattern: /choose/i, type: 'selection', description: 'Selection prompt' },
|
|
66
|
-
{ pattern: /\d+\)\s+\w+/g, type: 'menu', description: 'Menu selection' } // Matches: 1) Option
|
|
67
|
-
];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Analyze output for prompt patterns
|
|
72
|
-
* @param {string} output - Output text to analyze (stdout or stderr)
|
|
73
|
-
* @param {string} source - Source of output ('stdout' or 'stderr')
|
|
74
|
-
* @returns {Object|null} Prompt detection result or null
|
|
75
|
-
*/
|
|
76
|
-
detectPrompt(output, source = 'stdout') {
|
|
77
|
-
if (!output || output.trim().length === 0) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Get the last few lines (prompts are usually at the end)
|
|
82
|
-
const lines = output.split('\n');
|
|
83
|
-
const lastLines = lines.slice(-5).join('\n'); // Check last 5 lines
|
|
84
|
-
|
|
85
|
-
// Check each pattern
|
|
86
|
-
for (const promptDef of this.promptPatterns) {
|
|
87
|
-
const match = lastLines.match(promptDef.pattern);
|
|
88
|
-
if (match) {
|
|
89
|
-
return {
|
|
90
|
-
detected: true,
|
|
91
|
-
type: promptDef.type,
|
|
92
|
-
description: promptDef.description,
|
|
93
|
-
matchedText: match[0],
|
|
94
|
-
matchIndex: match.index,
|
|
95
|
-
source: source,
|
|
96
|
-
fullContext: lastLines,
|
|
97
|
-
timestamp: Date.now()
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Check for generic prompt indicators
|
|
103
|
-
// Look for lines ending with : or ? without newline after
|
|
104
|
-
const lastLine = lines[lines.length - 1] || '';
|
|
105
|
-
if (lastLine.trim().length > 0) {
|
|
106
|
-
const endsWithColon = /:\s*$/.test(lastLine);
|
|
107
|
-
const endsWithQuestion = /\?\s*$/.test(lastLine);
|
|
108
|
-
|
|
109
|
-
if (endsWithColon || endsWithQuestion) {
|
|
110
|
-
// Might be a prompt - check if it's asking for input
|
|
111
|
-
const looksLikePrompt = /\b(enter|type|provide|specify|input)\b/i.test(lastLine);
|
|
112
|
-
if (looksLikePrompt) {
|
|
113
|
-
return {
|
|
114
|
-
detected: true,
|
|
115
|
-
type: 'generic',
|
|
116
|
-
description: 'Generic input prompt detected',
|
|
117
|
-
matchedText: lastLine.trim(),
|
|
118
|
-
source: source,
|
|
119
|
-
fullContext: lastLines,
|
|
120
|
-
timestamp: Date.now(),
|
|
121
|
-
confidence: 0.7 // Lower confidence for generic detection
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Check if output indicates command is waiting (no prompt but no output)
|
|
132
|
-
* @param {number} lastOutputTime - Timestamp of last output
|
|
133
|
-
* @param {number} hangThresholdMs - Milliseconds to consider as hanging
|
|
134
|
-
* @returns {Object} Hang detection result
|
|
135
|
-
*/
|
|
136
|
-
detectHang(lastOutputTime, hangThresholdMs = 30000) {
|
|
137
|
-
const now = Date.now();
|
|
138
|
-
const timeSinceLastOutput = now - lastOutputTime;
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
isHanging: timeSinceLastOutput >= hangThresholdMs,
|
|
142
|
-
timeSinceLastOutput: timeSinceLastOutput,
|
|
143
|
-
threshold: hangThresholdMs,
|
|
144
|
-
likelyWaiting: timeSinceLastOutput >= hangThresholdMs / 2 // 50% threshold
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
class TerminalTool extends BaseTool {
|
|
150
|
-
constructor(config = {}, logger = null) {
|
|
151
|
-
super(config, logger);
|
|
152
|
-
|
|
153
|
-
// Tool metadata
|
|
154
|
-
this.requiresProject = false;
|
|
155
|
-
this.isAsync = false; // Most commands are quick, use sync execution
|
|
156
|
-
this.timeout = config.timeout || 120000; // 2 minutes default
|
|
157
|
-
this.maxConcurrentOperations = config.maxConcurrentOperations || 3;
|
|
158
|
-
|
|
159
|
-
// Current working directories per context
|
|
160
|
-
this.workingDirectories = new Map();
|
|
161
|
-
|
|
162
|
-
// Command history
|
|
163
|
-
this.commandHistory = [];
|
|
164
|
-
|
|
165
|
-
// Security settings
|
|
166
|
-
this.allowedCommands = config.allowedCommands || null; // null = all allowed
|
|
167
|
-
this.blockedCommands = config.blockedCommands || [
|
|
168
|
-
'rm -rf /',
|
|
169
|
-
'format',
|
|
170
|
-
'del /f /q',
|
|
171
|
-
'shutdown',
|
|
172
|
-
'reboot',
|
|
173
|
-
'halt'
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
// Directory access manager
|
|
177
|
-
this.directoryAccessManager = new DirectoryAccessManager(config, logger);
|
|
178
|
-
|
|
179
|
-
// Prompt detector (Phase 2)
|
|
180
|
-
this.promptDetector = new PromptDetector();
|
|
181
|
-
|
|
182
|
-
// Phase 3 & 4: Background command tracking
|
|
183
|
-
this.commandTracker = new Map(); // commandId -> { agentId, pid, process, state, buffers, timestamps }
|
|
184
|
-
this.commandIdCounter = 0;
|
|
185
|
-
|
|
186
|
-
// Resource limits
|
|
187
|
-
this.MAX_BACKGROUND_COMMANDS_PER_AGENT = config.maxBackgroundCommandsPerAgent || 5;
|
|
188
|
-
this.MAX_BACKGROUND_COMMANDS_GLOBAL = config.maxBackgroundCommandsGlobal || 20;
|
|
189
|
-
this.MAX_COMMAND_AGE_MINUTES = config.maxCommandAgeMinutes || 60;
|
|
190
|
-
|
|
191
|
-
// Terminal detection
|
|
192
|
-
this.detectedTerminal = null;
|
|
193
|
-
this.platformType = null;
|
|
194
|
-
this.initializeTerminalDetection();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Get tool description for LLM consumption
|
|
199
|
-
* @returns {string} Tool description
|
|
200
|
-
*/
|
|
201
|
-
getDescription() {
|
|
202
|
-
return `
|
|
203
|
-
Terminal Tool: Execute system commands and manage terminal operations safely.
|
|
204
|
-
|
|
205
|
-
IMPORTANT: For file and directory creation, prefer using the FileSystem tool.
|
|
206
|
-
Reserve the Terminal tool for command-line operations like npm, git, curl, etc.
|
|
207
|
-
|
|
208
|
-
USAGE:
|
|
209
|
-
[tool id="terminal"]
|
|
210
|
-
<run-command>npm install express</run-command>
|
|
211
|
-
<change-directory>project/backend</change-directory>
|
|
212
|
-
[/tool]
|
|
213
|
-
|
|
214
|
-
ALTERNATIVE JSON FORMAT:
|
|
215
|
-
\`\`\`json
|
|
216
|
-
{
|
|
217
|
-
"toolId": "terminal",
|
|
218
|
-
"actions": [
|
|
219
|
-
{
|
|
220
|
-
"type": "run-command",
|
|
221
|
-
"command": "npm install express"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"type": "change-directory",
|
|
225
|
-
"directory": "project/backend"
|
|
226
|
-
}
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
\`\`\`
|
|
230
|
-
|
|
231
|
-
SUPPORTED ACTIONS:
|
|
232
|
-
- run-command: Execute a command in the current directory
|
|
233
|
-
- change-directory: Change current working directory
|
|
234
|
-
- list-directory: List contents of current or specified directory
|
|
235
|
-
- create-directory: Create a new directory (prefer FileSystem tool)
|
|
236
|
-
- get-working-directory: Get current working directory
|
|
237
|
-
|
|
238
|
-
PARAMETERS:
|
|
239
|
-
- command: The command to execute
|
|
240
|
-
- directory: Directory path for navigation/operations
|
|
241
|
-
- timeout: Optional timeout in milliseconds (max ${this.timeout}ms)
|
|
242
|
-
- async: Whether to run command asynchronously (true/false)
|
|
243
|
-
|
|
244
|
-
BACKGROUND COMMAND MANAGEMENT (Advanced):
|
|
245
|
-
For long-running commands (npm install, git operations, builds), use background command tracking:
|
|
246
|
-
|
|
247
|
-
**startBackgroundCommand(command, workingDir, {agentId, context})**
|
|
248
|
-
- Starts command in background with stdin kept open
|
|
249
|
-
- Returns commandId for tracking
|
|
250
|
-
- Max ${this.MAX_BACKGROUND_COMMANDS_PER_AGENT} per agent, ${this.MAX_BACKGROUND_COMMANDS_GLOBAL} global
|
|
251
|
-
- Auto-detects prompts and updates state to 'waiting_for_input'
|
|
252
|
-
|
|
253
|
-
**getCommandStatus(commandId, agentId)**
|
|
254
|
-
- Get real-time status: running, waiting_for_input, completed, failed
|
|
255
|
-
- Returns stdout/stderr buffers, exit code, timestamps
|
|
256
|
-
- Shows prompt detection info if interactive prompt detected
|
|
257
|
-
|
|
258
|
-
**sendInput(commandId, input, agentId)**
|
|
259
|
-
- Send input to command's stdin (answers prompts)
|
|
260
|
-
- Automatically adds newline if not present
|
|
261
|
-
- Updates state from 'waiting_for_input' to 'running'
|
|
262
|
-
|
|
263
|
-
**killCommand(commandId, agentId)**
|
|
264
|
-
- Terminate background command (SIGTERM → SIGKILL)
|
|
265
|
-
- Safe to call on already-completed commands
|
|
266
|
-
|
|
267
|
-
**listAgentCommands(agentId)**
|
|
268
|
-
- List all commands (running and completed) for agent
|
|
269
|
-
- Useful for monitoring multiple background processes
|
|
270
|
-
|
|
271
|
-
BACKGROUND COMMAND WORKFLOW:
|
|
272
|
-
1. Start: const {commandId} = await terminal.startBackgroundCommand('npm install', dir, {agentId})
|
|
273
|
-
2. Wait: Use agent-delay tool to wait while command runs
|
|
274
|
-
3. Check: const status = terminal.getCommandStatus(commandId, agentId)
|
|
275
|
-
4. If prompt detected: terminal.sendInput(commandId, 'y', agentId)
|
|
276
|
-
5. Verify: Check status.state === 'completed' && status.exitCode === 0
|
|
277
|
-
|
|
278
|
-
EXAMPLES:
|
|
279
|
-
Basic command execution:
|
|
280
|
-
[tool id="terminal"]
|
|
281
|
-
<run-command>npm install</run-command>
|
|
282
|
-
[/tool]
|
|
283
|
-
|
|
284
|
-
Execute curl command:
|
|
285
|
-
[tool id="terminal"]
|
|
286
|
-
<run-command>curl -s https://api.github.com/zen</run-command>
|
|
287
|
-
[/tool]
|
|
288
|
-
|
|
289
|
-
Change directory and run command:
|
|
290
|
-
[tool id="terminal"]
|
|
291
|
-
<change-directory>../frontend</change-directory>
|
|
292
|
-
<run-command>npm run build</run-command>
|
|
293
|
-
[/tool]
|
|
294
|
-
|
|
295
|
-
Package management:
|
|
296
|
-
[tool id="terminal"]
|
|
297
|
-
<run-command>pip install -r requirements.txt</run-command>
|
|
298
|
-
[/tool]
|
|
299
|
-
|
|
300
|
-
Git operations:
|
|
301
|
-
[tool id="terminal"]
|
|
302
|
-
<run-command>git status</run-command>
|
|
303
|
-
[/tool]
|
|
304
|
-
|
|
305
|
-
[tool id="terminal"]
|
|
306
|
-
<run-command>git add .</run-command>
|
|
307
|
-
<run-command>git commit -m "Update files"</run-command>
|
|
308
|
-
[/tool]
|
|
309
|
-
|
|
310
|
-
Directory operations (if FileSystem tool unavailable):
|
|
311
|
-
[tool id="terminal"]
|
|
312
|
-
<create-directory>backend</create-directory>
|
|
313
|
-
[/tool]
|
|
314
|
-
|
|
315
|
-
SECURITY NOTES:
|
|
316
|
-
- Dangerous commands are blocked for safety
|
|
317
|
-
- Commands execute in isolated environment
|
|
318
|
-
- Output is captured and returned safely
|
|
319
|
-
- Long-running commands may time out - use agent-delay tool to wait
|
|
320
|
-
|
|
321
|
-
BEST PRACTICES:
|
|
322
|
-
- Use FileSystem tool for file/directory creation and management
|
|
323
|
-
- Use Terminal tool for command-line utilities (npm, git, curl, grep, etc.)
|
|
324
|
-
- After starting long-running commands, use agent-delay tool to pause checking
|
|
325
|
-
- Always check command output to verify success
|
|
326
|
-
|
|
327
|
-
CURRENT DIRECTORY:
|
|
328
|
-
The tool maintains a current working directory context per agent.
|
|
329
|
-
Use change-directory to navigate, and subsequent commands will execute from that location.
|
|
330
|
-
`;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Parse parameters from tool command content
|
|
335
|
-
* @param {string} content - Raw tool command content
|
|
336
|
-
* @returns {Object} Parsed parameters
|
|
337
|
-
*/
|
|
338
|
-
parseParameters(content) {
|
|
339
|
-
try {
|
|
340
|
-
const params = {};
|
|
341
|
-
|
|
342
|
-
// Extract individual action parameters
|
|
343
|
-
const runCommandMatches = TagParser.extractContent(content, 'run-command');
|
|
344
|
-
const changeDirMatches = TagParser.extractContent(content, 'change-directory');
|
|
345
|
-
const listDirMatches = TagParser.extractContent(content, 'list-directory');
|
|
346
|
-
const createDirMatches = TagParser.extractContent(content, 'create-directory');
|
|
347
|
-
const getWdMatches = TagParser.extractContent(content, 'get-working-directory');
|
|
348
|
-
const timeoutMatches = TagParser.extractContent(content, 'timeout');
|
|
349
|
-
const asyncMatches = TagParser.extractContent(content, 'async');
|
|
350
|
-
|
|
351
|
-
// Build actions array
|
|
352
|
-
const actions = [];
|
|
353
|
-
|
|
354
|
-
if (runCommandMatches.length > 0) {
|
|
355
|
-
actions.push({
|
|
356
|
-
type: 'run-command',
|
|
357
|
-
command: runCommandMatches[0].trim()
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (changeDirMatches.length > 0) {
|
|
362
|
-
actions.push({
|
|
363
|
-
type: 'change-directory',
|
|
364
|
-
directory: changeDirMatches[0].trim()
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (listDirMatches.length > 0) {
|
|
369
|
-
actions.push({
|
|
370
|
-
type: 'list-directory',
|
|
371
|
-
directory: listDirMatches[0].trim() || '.'
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (createDirMatches.length > 0) {
|
|
376
|
-
actions.push({
|
|
377
|
-
type: 'create-directory',
|
|
378
|
-
directory: createDirMatches[0].trim()
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (getWdMatches.length > 0) {
|
|
383
|
-
actions.push({
|
|
384
|
-
type: 'get-working-directory'
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
params.actions = actions;
|
|
389
|
-
|
|
390
|
-
// Parse additional options
|
|
391
|
-
if (timeoutMatches.length > 0) {
|
|
392
|
-
params.timeout = parseInt(timeoutMatches[0], 10);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (asyncMatches.length > 0) {
|
|
396
|
-
params.async = asyncMatches[0].toLowerCase() === 'true';
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
params.rawContent = content.trim();
|
|
400
|
-
|
|
401
|
-
return params;
|
|
402
|
-
|
|
403
|
-
} catch (error) {
|
|
404
|
-
throw new Error(`Failed to parse terminal parameters: ${error.message}`);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Get required parameters
|
|
410
|
-
* @returns {Array<string>} Array of required parameter names
|
|
411
|
-
*/
|
|
412
|
-
getRequiredParameters() {
|
|
413
|
-
return ['actions'];
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* Custom parameter validation
|
|
418
|
-
* @param {Object} params - Parameters to validate
|
|
419
|
-
* @returns {Object} Validation result
|
|
420
|
-
*/
|
|
421
|
-
customValidateParameters(params) {
|
|
422
|
-
const errors = [];
|
|
423
|
-
|
|
424
|
-
if (!params.actions || !Array.isArray(params.actions) || params.actions.length === 0) {
|
|
425
|
-
errors.push('At least one action is required');
|
|
426
|
-
} else {
|
|
427
|
-
// Validate each action
|
|
428
|
-
for (const [index, action] of params.actions.entries()) {
|
|
429
|
-
if (!action.type) {
|
|
430
|
-
errors.push(`Action ${index + 1}: type is required`);
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
switch (action.type) {
|
|
435
|
-
case 'run-command':
|
|
436
|
-
if (!action.command || !action.command.trim()) {
|
|
437
|
-
errors.push(`Action ${index + 1}: command is required for run-command`);
|
|
438
|
-
} else if (this.isBlockedCommand(action.command)) {
|
|
439
|
-
errors.push(`Action ${index + 1}: command is blocked for security: ${action.command}`);
|
|
440
|
-
} else if (this.allowedCommands && !this.isAllowedCommand(action.command)) {
|
|
441
|
-
errors.push(`Action ${index + 1}: command is not in allowed list: ${action.command}`);
|
|
442
|
-
}
|
|
443
|
-
break;
|
|
444
|
-
|
|
445
|
-
case 'change-directory':
|
|
446
|
-
case 'list-directory':
|
|
447
|
-
case 'create-directory':
|
|
448
|
-
if (!action.directory || !action.directory.trim()) {
|
|
449
|
-
errors.push(`Action ${index + 1}: directory is required for ${action.type}`);
|
|
450
|
-
}
|
|
451
|
-
break;
|
|
452
|
-
|
|
453
|
-
case 'get-working-directory':
|
|
454
|
-
// No additional validation needed
|
|
455
|
-
break;
|
|
456
|
-
|
|
457
|
-
default:
|
|
458
|
-
errors.push(`Action ${index + 1}: unknown action type: ${action.type}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (params.timeout && (params.timeout < 1000 || params.timeout > this.timeout)) {
|
|
464
|
-
errors.push(`Timeout must be between 1000 and ${this.timeout} milliseconds`);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
return {
|
|
468
|
-
valid: errors.length === 0,
|
|
469
|
-
errors
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Execute tool with parsed parameters
|
|
475
|
-
* @param {Object} params - Parsed parameters
|
|
476
|
-
* @param {Object} context - Execution context
|
|
477
|
-
* @returns {Promise<Object>} Execution result
|
|
478
|
-
*/
|
|
479
|
-
async execute(params, context) {
|
|
480
|
-
const { actions, timeout: customTimeout, async: forceAsync } = params;
|
|
481
|
-
const { agentId, projectDir, directoryAccess } = context;
|
|
482
|
-
|
|
483
|
-
// Get directory access configuration from agent or create default
|
|
484
|
-
const accessConfig = directoryAccess ||
|
|
485
|
-
this.directoryAccessManager.createDirectoryAccess({
|
|
486
|
-
workingDirectory: projectDir || process.cwd(),
|
|
487
|
-
writeEnabledDirectories: [projectDir || process.cwd()],
|
|
488
|
-
restrictToProject: true
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
// IMPORTANT: If the agent has directoryAccess configured, use its workingDirectory
|
|
492
|
-
// This ensures UI-configured project directories are respected
|
|
493
|
-
if (directoryAccess && directoryAccess.workingDirectory) {
|
|
494
|
-
// Agent has explicitly configured working directory from UI - use it
|
|
495
|
-
console.log('Terminal DEBUG: Using agent configured working directory:', directoryAccess.workingDirectory);
|
|
496
|
-
} else {
|
|
497
|
-
// Using fallback to projectDir or process.cwd()
|
|
498
|
-
console.log('Terminal DEBUG: Using fallback working directory:', projectDir || process.cwd());
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Get or set current working directory for this agent
|
|
502
|
-
const contextKey = `${agentId}-${projectDir || 'default'}`;
|
|
503
|
-
let currentWorkingDir = this.workingDirectories.get(contextKey) ||
|
|
504
|
-
this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
505
|
-
|
|
506
|
-
const results = [];
|
|
507
|
-
|
|
508
|
-
for (const action of actions) {
|
|
509
|
-
try {
|
|
510
|
-
let result;
|
|
511
|
-
|
|
512
|
-
switch (action.type) {
|
|
513
|
-
case 'run-command':
|
|
514
|
-
result = await this.executeCommand(action.command, currentWorkingDir, {
|
|
515
|
-
timeout: customTimeout || this.timeout,
|
|
516
|
-
async: forceAsync || false,
|
|
517
|
-
agentId,
|
|
518
|
-
context: {
|
|
519
|
-
toolsRegistry: context.toolsRegistry,
|
|
520
|
-
aiService: context.aiService,
|
|
521
|
-
apiKey: context.apiKey,
|
|
522
|
-
customApiKeys: context.customApiKeys,
|
|
523
|
-
platformProvided: context.platformProvided
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
break;
|
|
527
|
-
|
|
528
|
-
case 'change-directory':
|
|
529
|
-
result = await this.changeDirectory(action.directory, currentWorkingDir, accessConfig);
|
|
530
|
-
currentWorkingDir = result.newDirectory;
|
|
531
|
-
this.workingDirectories.set(contextKey, currentWorkingDir);
|
|
532
|
-
break;
|
|
533
|
-
|
|
534
|
-
case 'list-directory':
|
|
535
|
-
result = await this.listDirectory(action.directory === '.' ? currentWorkingDir : action.directory);
|
|
536
|
-
break;
|
|
537
|
-
|
|
538
|
-
case 'create-directory':
|
|
539
|
-
result = await this.createDirectory(action.directory, currentWorkingDir);
|
|
540
|
-
break;
|
|
541
|
-
|
|
542
|
-
case 'get-working-directory':
|
|
543
|
-
result = {
|
|
544
|
-
success: true,
|
|
545
|
-
action: 'get-working-directory',
|
|
546
|
-
workingDirectory: currentWorkingDir,
|
|
547
|
-
message: `Current working directory: ${currentWorkingDir}`
|
|
548
|
-
};
|
|
549
|
-
break;
|
|
550
|
-
|
|
551
|
-
default:
|
|
552
|
-
throw new Error(`Unknown action type: ${action.type}`);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
results.push(result);
|
|
556
|
-
|
|
557
|
-
// Add to command history
|
|
558
|
-
this.addToHistory(action, result, agentId);
|
|
559
|
-
|
|
560
|
-
} catch (error) {
|
|
561
|
-
const errorResult = {
|
|
562
|
-
success: false,
|
|
563
|
-
action: action.type,
|
|
564
|
-
error: error.message,
|
|
565
|
-
command: action.command || action.directory,
|
|
566
|
-
workingDirectory: currentWorkingDir
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
results.push(errorResult);
|
|
570
|
-
this.addToHistory(action, errorResult, agentId);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Determine overall success based on individual action results
|
|
575
|
-
const overallSuccess = results.every(result => result.success);
|
|
576
|
-
const failedActions = results.filter(result => !result.success);
|
|
577
|
-
|
|
578
|
-
return {
|
|
579
|
-
success: overallSuccess,
|
|
580
|
-
actions: results,
|
|
581
|
-
workingDirectory: currentWorkingDir,
|
|
582
|
-
executedActions: actions.length,
|
|
583
|
-
failedActions: failedActions.length,
|
|
584
|
-
toolUsed: 'terminal',
|
|
585
|
-
message: overallSuccess
|
|
586
|
-
? `All ${actions.length} actions completed successfully`
|
|
587
|
-
: `${failedActions.length} of ${actions.length} actions failed`
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* Execute a command in the specified directory
|
|
593
|
-
* @private
|
|
594
|
-
*/
|
|
595
|
-
async executeCommand(command, workingDir, options = {}) {
|
|
596
|
-
const { timeout = this.timeout, async: isAsync = false, agentId, context } = options;
|
|
597
|
-
|
|
598
|
-
// Translate command for current terminal (now async with AI support)
|
|
599
|
-
const originalCommand = command;
|
|
600
|
-
let translatedCommand;
|
|
601
|
-
|
|
602
|
-
try {
|
|
603
|
-
translatedCommand = await this.translateCommand(command, {
|
|
604
|
-
agentId,
|
|
605
|
-
toolsRegistry: context?.toolsRegistry,
|
|
606
|
-
messageProcessor: context?.messageProcessor,
|
|
607
|
-
aiService: context?.aiService,
|
|
608
|
-
apiKey: context?.apiKey,
|
|
609
|
-
customApiKeys: context?.customApiKeys,
|
|
610
|
-
platformProvided: context?.platformProvided
|
|
611
|
-
});
|
|
612
|
-
} catch (error) {
|
|
613
|
-
this.logger?.warn('Command translation failed, using original command', {
|
|
614
|
-
originalCommand,
|
|
615
|
-
error: error.message
|
|
616
|
-
});
|
|
617
|
-
translatedCommand = command;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
return new Promise((resolve, reject) => {
|
|
621
|
-
const startTime = Date.now();
|
|
622
|
-
|
|
623
|
-
this.logger?.info(`Executing command: ${translatedCommand}`, {
|
|
624
|
-
originalCommand,
|
|
625
|
-
translatedCommand,
|
|
626
|
-
terminal: this.detectedTerminal,
|
|
627
|
-
workingDirectory: workingDir,
|
|
628
|
-
timeout,
|
|
629
|
-
agentId
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
const childProcess = exec(translatedCommand, {
|
|
633
|
-
cwd: workingDir,
|
|
634
|
-
timeout,
|
|
635
|
-
maxBuffer: 1024 * 1024, // 1MB buffer
|
|
636
|
-
env: { ...process.env }
|
|
637
|
-
}, (error, stdout, stderr) => {
|
|
638
|
-
const executionTime = Date.now() - startTime;
|
|
639
|
-
|
|
640
|
-
if (error) {
|
|
641
|
-
this.logger?.error(`Command failed: ${translatedCommand}`, {
|
|
642
|
-
originalCommand,
|
|
643
|
-
translatedCommand,
|
|
644
|
-
error: error.message,
|
|
645
|
-
workingDirectory: workingDir,
|
|
646
|
-
executionTime
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
resolve({
|
|
650
|
-
success: false,
|
|
651
|
-
action: 'run-command',
|
|
652
|
-
command: originalCommand,
|
|
653
|
-
translatedCommand: translatedCommand !== originalCommand ? translatedCommand : undefined,
|
|
654
|
-
error: error.message,
|
|
655
|
-
stderr: stderr.trim(),
|
|
656
|
-
stdout: stdout.trim(),
|
|
657
|
-
exitCode: error.code,
|
|
658
|
-
executionTime,
|
|
659
|
-
workingDirectory: workingDir
|
|
660
|
-
});
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
this.logger?.info(`Command completed: ${translatedCommand}`, {
|
|
665
|
-
originalCommand,
|
|
666
|
-
translatedCommand,
|
|
667
|
-
executionTime,
|
|
668
|
-
stdoutLength: stdout.length,
|
|
669
|
-
stderrLength: stderr.length
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
resolve({
|
|
673
|
-
success: true,
|
|
674
|
-
action: 'run-command',
|
|
675
|
-
command: originalCommand,
|
|
676
|
-
translatedCommand: translatedCommand !== originalCommand ? translatedCommand : undefined,
|
|
677
|
-
stdout: stdout.trim(),
|
|
678
|
-
stderr: stderr.trim(),
|
|
679
|
-
exitCode: 0,
|
|
680
|
-
executionTime,
|
|
681
|
-
workingDirectory: workingDir,
|
|
682
|
-
message: `Command executed successfully in ${executionTime}ms`
|
|
683
|
-
});
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
// Handle timeout
|
|
687
|
-
setTimeout(() => {
|
|
688
|
-
if (!childProcess.killed) {
|
|
689
|
-
childProcess.kill('SIGTERM');
|
|
690
|
-
reject(new Error(`Command timed out after ${timeout}ms: ${translatedCommand} (original: ${originalCommand})`));
|
|
691
|
-
}
|
|
692
|
-
}, timeout);
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Execute a command using spawn() for streaming output
|
|
698
|
-
* @param {string} command - Command to execute
|
|
699
|
-
* @param {string} workingDir - Working directory
|
|
700
|
-
* @param {Object} options - Execution options
|
|
701
|
-
* @returns {Promise<Object>} Execution result
|
|
702
|
-
* @private
|
|
703
|
-
*/
|
|
704
|
-
async executeCommandWithSpawn(command, workingDir, options = {}) {
|
|
705
|
-
const { timeout = this.timeout, agentId, context } = options;
|
|
706
|
-
|
|
707
|
-
// Translate command for current terminal
|
|
708
|
-
const originalCommand = command;
|
|
709
|
-
let translatedCommand;
|
|
710
|
-
|
|
711
|
-
try {
|
|
712
|
-
translatedCommand = await this.translateCommand(command, {
|
|
713
|
-
agentId,
|
|
714
|
-
toolsRegistry: context?.toolsRegistry,
|
|
715
|
-
messageProcessor: context?.messageProcessor,
|
|
716
|
-
aiService: context?.aiService,
|
|
717
|
-
apiKey: context?.apiKey,
|
|
718
|
-
customApiKeys: context?.customApiKeys,
|
|
719
|
-
platformProvided: context?.platformProvided
|
|
720
|
-
});
|
|
721
|
-
} catch (error) {
|
|
722
|
-
this.logger?.warn('Command translation failed, using original command', {
|
|
723
|
-
originalCommand,
|
|
724
|
-
error: error.message
|
|
725
|
-
});
|
|
726
|
-
translatedCommand = command;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
return new Promise((resolve, reject) => {
|
|
730
|
-
const startTime = Date.now();
|
|
731
|
-
|
|
732
|
-
this.logger?.info(`Executing command with spawn: ${translatedCommand}`, {
|
|
733
|
-
originalCommand,
|
|
734
|
-
translatedCommand,
|
|
735
|
-
terminal: this.detectedTerminal,
|
|
736
|
-
workingDirectory: workingDir,
|
|
737
|
-
timeout,
|
|
738
|
-
agentId
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
// Parse command into program and args
|
|
742
|
-
// For shell commands, we need to run them through a shell
|
|
743
|
-
let childProcess;
|
|
744
|
-
|
|
745
|
-
if (this.detectedTerminal === 'cmd' || this.detectedTerminal === 'powershell') {
|
|
746
|
-
// Windows: Use cmd /c or powershell -Command
|
|
747
|
-
const shell = this.detectedTerminal === 'powershell' ? 'powershell' : 'cmd';
|
|
748
|
-
const shellArgs = this.detectedTerminal === 'powershell'
|
|
749
|
-
? ['-Command', translatedCommand]
|
|
750
|
-
: ['/c', translatedCommand];
|
|
751
|
-
|
|
752
|
-
childProcess = spawn(shell, shellArgs, {
|
|
753
|
-
cwd: workingDir,
|
|
754
|
-
env: { ...process.env },
|
|
755
|
-
windowsHide: true
|
|
756
|
-
});
|
|
757
|
-
} else {
|
|
758
|
-
// Unix: Use sh -c
|
|
759
|
-
childProcess = spawn('sh', ['-c', translatedCommand], {
|
|
760
|
-
cwd: workingDir,
|
|
761
|
-
env: { ...process.env }
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// Buffers for stdout and stderr
|
|
766
|
-
let stdoutData = '';
|
|
767
|
-
let stderrData = '';
|
|
768
|
-
let isTimedOut = false;
|
|
769
|
-
let exitCode = null;
|
|
770
|
-
|
|
771
|
-
// Phase 2: Prompt detection tracking
|
|
772
|
-
let lastOutputTime = Date.now();
|
|
773
|
-
let promptDetectionResult = null;
|
|
774
|
-
|
|
775
|
-
// Set up timeout
|
|
776
|
-
const timeoutId = setTimeout(() => {
|
|
777
|
-
if (!childProcess.killed && exitCode === null) {
|
|
778
|
-
isTimedOut = true;
|
|
779
|
-
this.logger?.warn(`Command timed out, killing process: ${translatedCommand}`, {
|
|
780
|
-
timeout,
|
|
781
|
-
agentId
|
|
782
|
-
});
|
|
783
|
-
childProcess.kill('SIGTERM');
|
|
784
|
-
|
|
785
|
-
// If SIGTERM doesn't work, try SIGKILL after 5s
|
|
786
|
-
setTimeout(() => {
|
|
787
|
-
if (!childProcess.killed) {
|
|
788
|
-
childProcess.kill('SIGKILL');
|
|
789
|
-
}
|
|
790
|
-
}, 5000);
|
|
791
|
-
}
|
|
792
|
-
}, timeout);
|
|
793
|
-
|
|
794
|
-
// Stream stdout
|
|
795
|
-
childProcess.stdout.on('data', (chunk) => {
|
|
796
|
-
const data = chunk.toString();
|
|
797
|
-
stdoutData += data;
|
|
798
|
-
lastOutputTime = Date.now(); // Update last output time
|
|
799
|
-
|
|
800
|
-
this.logger?.debug(`Command output chunk: ${data.substring(0, 100)}`, {
|
|
801
|
-
agentId,
|
|
802
|
-
command: originalCommand.substring(0, 50)
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
// Phase 2: Check for prompts in stdout
|
|
806
|
-
if (!promptDetectionResult) {
|
|
807
|
-
const detection = this.promptDetector.detectPrompt(stdoutData, 'stdout');
|
|
808
|
-
if (detection) {
|
|
809
|
-
promptDetectionResult = detection;
|
|
810
|
-
this.logger?.info('Prompt detected in stdout', {
|
|
811
|
-
type: detection.type,
|
|
812
|
-
description: detection.description,
|
|
813
|
-
matchedText: detection.matchedText,
|
|
814
|
-
agentId,
|
|
815
|
-
command: originalCommand.substring(0, 50)
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
// Stream stderr
|
|
822
|
-
childProcess.stderr.on('data', (chunk) => {
|
|
823
|
-
const data = chunk.toString();
|
|
824
|
-
stderrData += data;
|
|
825
|
-
lastOutputTime = Date.now(); // Update last output time
|
|
826
|
-
|
|
827
|
-
this.logger?.debug(`Command error chunk: ${data.substring(0, 100)}`, {
|
|
828
|
-
agentId,
|
|
829
|
-
command: originalCommand.substring(0, 50)
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
// Phase 2: Check for prompts in stderr
|
|
833
|
-
if (!promptDetectionResult) {
|
|
834
|
-
const detection = this.promptDetector.detectPrompt(stderrData, 'stderr');
|
|
835
|
-
if (detection) {
|
|
836
|
-
promptDetectionResult = detection;
|
|
837
|
-
this.logger?.info('Prompt detected in stderr', {
|
|
838
|
-
type: detection.type,
|
|
839
|
-
description: detection.description,
|
|
840
|
-
matchedText: detection.matchedText,
|
|
841
|
-
agentId,
|
|
842
|
-
command: originalCommand.substring(0, 50)
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
// Handle process exit
|
|
849
|
-
childProcess.on('exit', (code, signal) => {
|
|
850
|
-
clearTimeout(timeoutId);
|
|
851
|
-
exitCode = code;
|
|
852
|
-
const executionTime = Date.now() - startTime;
|
|
853
|
-
|
|
854
|
-
// Phase 2: Calculate time since last output
|
|
855
|
-
const timeSinceLastOutput = Date.now() - lastOutputTime;
|
|
856
|
-
|
|
857
|
-
this.logger?.info(`Command process exited: ${translatedCommand}`, {
|
|
858
|
-
exitCode: code,
|
|
859
|
-
signal,
|
|
860
|
-
executionTime,
|
|
861
|
-
timedOut: isTimedOut,
|
|
862
|
-
stdoutLength: stdoutData.length,
|
|
863
|
-
stderrLength: stderrData.length,
|
|
864
|
-
promptDetected: !!promptDetectionResult,
|
|
865
|
-
timeSinceLastOutput
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
// Build common result object with Phase 2 additions
|
|
869
|
-
const baseResult = {
|
|
870
|
-
action: 'run-command',
|
|
871
|
-
command: originalCommand,
|
|
872
|
-
translatedCommand: translatedCommand !== originalCommand ? translatedCommand : undefined,
|
|
873
|
-
stdout: stdoutData.trim(),
|
|
874
|
-
stderr: stderrData.trim(),
|
|
875
|
-
exitCode: code,
|
|
876
|
-
executionTime,
|
|
877
|
-
workingDirectory: workingDir,
|
|
878
|
-
// Phase 2: Prompt detection fields
|
|
879
|
-
promptDetected: !!promptDetectionResult,
|
|
880
|
-
promptInfo: promptDetectionResult || undefined,
|
|
881
|
-
lastOutputTime: lastOutputTime,
|
|
882
|
-
timeSinceLastOutput: timeSinceLastOutput
|
|
883
|
-
};
|
|
884
|
-
|
|
885
|
-
// If timed out, reject
|
|
886
|
-
if (isTimedOut) {
|
|
887
|
-
resolve({
|
|
888
|
-
...baseResult,
|
|
889
|
-
success: false,
|
|
890
|
-
error: `Command timed out after ${timeout}ms`,
|
|
891
|
-
exitCode: code || -1,
|
|
892
|
-
timedOut: true
|
|
893
|
-
});
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// If exit code is not 0, consider it a failure
|
|
898
|
-
if (code !== 0) {
|
|
899
|
-
this.logger?.error(`Command failed with exit code ${code}: ${translatedCommand}`, {
|
|
900
|
-
originalCommand,
|
|
901
|
-
translatedCommand,
|
|
902
|
-
exitCode: code,
|
|
903
|
-
stderr: stderrData.substring(0, 200),
|
|
904
|
-
executionTime,
|
|
905
|
-
promptDetected: !!promptDetectionResult
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
resolve({
|
|
909
|
-
...baseResult,
|
|
910
|
-
success: false,
|
|
911
|
-
error: `Command exited with code ${code}`
|
|
912
|
-
});
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// Success
|
|
917
|
-
this.logger?.info(`Command completed successfully: ${translatedCommand}`, {
|
|
918
|
-
originalCommand,
|
|
919
|
-
executionTime,
|
|
920
|
-
stdoutLength: stdoutData.length,
|
|
921
|
-
stderrLength: stderrData.length,
|
|
922
|
-
promptDetected: !!promptDetectionResult
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
resolve({
|
|
926
|
-
...baseResult,
|
|
927
|
-
success: true,
|
|
928
|
-
exitCode: 0,
|
|
929
|
-
message: `Command executed successfully in ${executionTime}ms`
|
|
930
|
-
});
|
|
931
|
-
});
|
|
932
|
-
|
|
933
|
-
// Handle spawn errors
|
|
934
|
-
childProcess.on('error', (error) => {
|
|
935
|
-
clearTimeout(timeoutId);
|
|
936
|
-
const executionTime = Date.now() - startTime;
|
|
937
|
-
const timeSinceLastOutput = Date.now() - lastOutputTime;
|
|
938
|
-
|
|
939
|
-
this.logger?.error(`Command spawn error: ${translatedCommand}`, {
|
|
940
|
-
originalCommand,
|
|
941
|
-
error: error.message,
|
|
942
|
-
executionTime,
|
|
943
|
-
promptDetected: !!promptDetectionResult
|
|
944
|
-
});
|
|
945
|
-
|
|
946
|
-
resolve({
|
|
947
|
-
success: false,
|
|
948
|
-
action: 'run-command',
|
|
949
|
-
command: originalCommand,
|
|
950
|
-
translatedCommand: translatedCommand !== originalCommand ? translatedCommand : undefined,
|
|
951
|
-
error: error.message,
|
|
952
|
-
stderr: stderrData.trim(),
|
|
953
|
-
stdout: stdoutData.trim(),
|
|
954
|
-
exitCode: -1,
|
|
955
|
-
executionTime,
|
|
956
|
-
workingDirectory: workingDir,
|
|
957
|
-
// Phase 2: Prompt detection fields
|
|
958
|
-
promptDetected: !!promptDetectionResult,
|
|
959
|
-
promptInfo: promptDetectionResult || undefined,
|
|
960
|
-
lastOutputTime: lastOutputTime,
|
|
961
|
-
timeSinceLastOutput: timeSinceLastOutput
|
|
962
|
-
});
|
|
963
|
-
});
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
/**
|
|
968
|
-
* Change current working directory
|
|
969
|
-
* @private
|
|
970
|
-
*/
|
|
971
|
-
async changeDirectory(targetDir, currentDir, accessConfig) {
|
|
972
|
-
try {
|
|
973
|
-
let newDirectory;
|
|
974
|
-
|
|
975
|
-
if (path.isAbsolute(targetDir)) {
|
|
976
|
-
newDirectory = targetDir;
|
|
977
|
-
} else {
|
|
978
|
-
newDirectory = path.resolve(currentDir, targetDir);
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
// Verify directory exists
|
|
982
|
-
const stats = await fs.stat(newDirectory);
|
|
983
|
-
if (!stats.isDirectory()) {
|
|
984
|
-
throw new Error(`Not a directory: ${newDirectory}`);
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
// Security check: validate directory access using DirectoryAccessManager
|
|
988
|
-
const accessResult = this.directoryAccessManager.validateReadAccess(newDirectory, accessConfig);
|
|
989
|
-
if (!accessResult.allowed) {
|
|
990
|
-
this.logger?.warn(`Directory change blocked: ${accessResult.reason}`, {
|
|
991
|
-
targetDirectory: newDirectory,
|
|
992
|
-
reason: accessResult.reason,
|
|
993
|
-
category: accessResult.category
|
|
994
|
-
});
|
|
995
|
-
throw new Error(`Access denied: ${accessResult.reason}`);
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
return {
|
|
999
|
-
success: true,
|
|
1000
|
-
action: 'change-directory',
|
|
1001
|
-
previousDirectory: currentDir,
|
|
1002
|
-
newDirectory,
|
|
1003
|
-
message: `Changed directory to ${newDirectory}`
|
|
1004
|
-
};
|
|
1005
|
-
|
|
1006
|
-
} catch (error) {
|
|
1007
|
-
throw new Error(`Failed to change directory to ${targetDir}: ${error.message}`);
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
/**
|
|
1012
|
-
* List directory contents
|
|
1013
|
-
* @private
|
|
1014
|
-
*/
|
|
1015
|
-
async listDirectory(dirPath) {
|
|
1016
|
-
try {
|
|
1017
|
-
const files = await fs.readdir(dirPath, { withFileTypes: true });
|
|
1018
|
-
|
|
1019
|
-
const contents = files.map(file => ({
|
|
1020
|
-
name: file.name,
|
|
1021
|
-
type: file.isDirectory() ? 'directory' : 'file',
|
|
1022
|
-
isSymlink: file.isSymbolicLink()
|
|
1023
|
-
}));
|
|
1024
|
-
|
|
1025
|
-
return {
|
|
1026
|
-
success: true,
|
|
1027
|
-
action: 'list-directory',
|
|
1028
|
-
directory: dirPath,
|
|
1029
|
-
contents,
|
|
1030
|
-
totalItems: contents.length,
|
|
1031
|
-
directories: contents.filter(item => item.type === 'directory').length,
|
|
1032
|
-
files: contents.filter(item => item.type === 'file').length,
|
|
1033
|
-
message: `Listed ${contents.length} items in ${dirPath}`
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
} catch (error) {
|
|
1037
|
-
throw new Error(`Failed to list directory ${dirPath}: ${error.message}`);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
/**
|
|
1042
|
-
* Create directory
|
|
1043
|
-
* @private
|
|
1044
|
-
*/
|
|
1045
|
-
async createDirectory(dirPath, currentDir) {
|
|
1046
|
-
try {
|
|
1047
|
-
let fullPath;
|
|
1048
|
-
|
|
1049
|
-
if (path.isAbsolute(dirPath)) {
|
|
1050
|
-
fullPath = dirPath;
|
|
1051
|
-
} else {
|
|
1052
|
-
fullPath = path.resolve(currentDir, dirPath);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
await fs.mkdir(fullPath, { recursive: true });
|
|
1056
|
-
|
|
1057
|
-
return {
|
|
1058
|
-
success: true,
|
|
1059
|
-
action: 'create-directory',
|
|
1060
|
-
directory: fullPath,
|
|
1061
|
-
relativePath: path.relative(currentDir, fullPath),
|
|
1062
|
-
message: `Created directory: ${fullPath}`
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
} catch (error) {
|
|
1066
|
-
throw new Error(`Failed to create directory ${dirPath}: ${error.message}`);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
/**
|
|
1071
|
-
* Check if command is blocked for security
|
|
1072
|
-
* @private
|
|
1073
|
-
*/
|
|
1074
|
-
isBlockedCommand(command) {
|
|
1075
|
-
const cmdLower = command.toLowerCase().trim();
|
|
1076
|
-
|
|
1077
|
-
return this.blockedCommands.some(blocked => {
|
|
1078
|
-
const blockedLower = blocked.toLowerCase();
|
|
1079
|
-
return cmdLower === blockedLower || cmdLower.startsWith(blockedLower + ' ');
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* Check if command is in allowed list
|
|
1085
|
-
* @private
|
|
1086
|
-
*/
|
|
1087
|
-
isAllowedCommand(command) {
|
|
1088
|
-
if (!this.allowedCommands) return true;
|
|
1089
|
-
|
|
1090
|
-
const cmdLower = command.toLowerCase().trim();
|
|
1091
|
-
const cmdBase = cmdLower.split(' ')[0];
|
|
1092
|
-
|
|
1093
|
-
return this.allowedCommands.some(allowed =>
|
|
1094
|
-
allowed.toLowerCase() === cmdBase ||
|
|
1095
|
-
cmdLower.startsWith(allowed.toLowerCase() + ' ')
|
|
1096
|
-
);
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
/**
|
|
1100
|
-
* Add command to history
|
|
1101
|
-
* @private
|
|
1102
|
-
*/
|
|
1103
|
-
addToHistory(action, result, agentId) {
|
|
1104
|
-
const historyEntry = {
|
|
1105
|
-
timestamp: new Date().toISOString(),
|
|
1106
|
-
agentId,
|
|
1107
|
-
action: action.type,
|
|
1108
|
-
command: action.command || action.directory,
|
|
1109
|
-
success: result.success,
|
|
1110
|
-
executionTime: result.executionTime || 0,
|
|
1111
|
-
workingDirectory: result.workingDirectory
|
|
1112
|
-
};
|
|
1113
|
-
|
|
1114
|
-
this.commandHistory.push(historyEntry);
|
|
1115
|
-
|
|
1116
|
-
// Keep only last 100 entries
|
|
1117
|
-
if (this.commandHistory.length > 100) {
|
|
1118
|
-
this.commandHistory = this.commandHistory.slice(-100);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
/**
|
|
1123
|
-
* Get supported actions for this tool
|
|
1124
|
-
* @returns {Array<string>} Array of supported action names
|
|
1125
|
-
*/
|
|
1126
|
-
getSupportedActions() {
|
|
1127
|
-
return ['run-command', 'change-directory', 'list-directory', 'create-directory', 'get-working-directory'];
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
/**
|
|
1131
|
-
* Get parameter schema for validation
|
|
1132
|
-
* @returns {Object} Parameter schema
|
|
1133
|
-
*/
|
|
1134
|
-
getParameterSchema() {
|
|
1135
|
-
return {
|
|
1136
|
-
type: 'object',
|
|
1137
|
-
properties: {
|
|
1138
|
-
actions: {
|
|
1139
|
-
type: 'array',
|
|
1140
|
-
minItems: 1,
|
|
1141
|
-
items: {
|
|
1142
|
-
type: 'object',
|
|
1143
|
-
properties: {
|
|
1144
|
-
type: {
|
|
1145
|
-
type: 'string',
|
|
1146
|
-
enum: this.getSupportedActions()
|
|
1147
|
-
},
|
|
1148
|
-
command: { type: 'string' },
|
|
1149
|
-
directory: { type: 'string' }
|
|
1150
|
-
},
|
|
1151
|
-
required: ['type']
|
|
1152
|
-
}
|
|
1153
|
-
},
|
|
1154
|
-
timeout: {
|
|
1155
|
-
type: 'integer',
|
|
1156
|
-
minimum: 1000,
|
|
1157
|
-
maximum: this.timeout
|
|
1158
|
-
},
|
|
1159
|
-
async: {
|
|
1160
|
-
type: 'boolean'
|
|
1161
|
-
}
|
|
1162
|
-
},
|
|
1163
|
-
required: ['actions']
|
|
1164
|
-
};
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
/**
|
|
1168
|
-
* Get command history for debugging
|
|
1169
|
-
* @returns {Array} Command history
|
|
1170
|
-
*/
|
|
1171
|
-
getCommandHistory(agentId = null) {
|
|
1172
|
-
if (agentId) {
|
|
1173
|
-
return this.commandHistory.filter(entry => entry.agentId === agentId);
|
|
1174
|
-
}
|
|
1175
|
-
return [...this.commandHistory];
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
/**
|
|
1179
|
-
* Clear working directory context for agent
|
|
1180
|
-
* @param {string} agentId - Agent identifier
|
|
1181
|
-
*/
|
|
1182
|
-
clearWorkingDirectory(agentId) {
|
|
1183
|
-
for (const [key] of this.workingDirectories) {
|
|
1184
|
-
if (key.startsWith(`${agentId}-`)) {
|
|
1185
|
-
this.workingDirectories.delete(key);
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
/**
|
|
1191
|
-
* Get current working directory for agent
|
|
1192
|
-
* @param {string} agentId - Agent identifier
|
|
1193
|
-
* @param {string} projectDir - Project directory
|
|
1194
|
-
* @returns {string} Current working directory
|
|
1195
|
-
*/
|
|
1196
|
-
getCurrentWorkingDirectory(agentId, projectDir = null) {
|
|
1197
|
-
const contextKey = `${agentId}-${projectDir || 'default'}`;
|
|
1198
|
-
return this.workingDirectories.get(contextKey) || projectDir || process.cwd();
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
/**
|
|
1202
|
-
* Initialize terminal detection
|
|
1203
|
-
* @private
|
|
1204
|
-
*/
|
|
1205
|
-
initializeTerminalDetection() {
|
|
1206
|
-
// Detect platform
|
|
1207
|
-
this.platformType = process.platform;
|
|
1208
|
-
|
|
1209
|
-
// Detect terminal type based on environment
|
|
1210
|
-
if (process.platform === 'win32') {
|
|
1211
|
-
// Windows detection
|
|
1212
|
-
if (process.env.PSModulePath) {
|
|
1213
|
-
this.detectedTerminal = 'powershell';
|
|
1214
|
-
} else if (process.env.SHELL && process.env.SHELL.includes('bash')) {
|
|
1215
|
-
this.detectedTerminal = 'bash'; // Git Bash or WSL
|
|
1216
|
-
} else {
|
|
1217
|
-
this.detectedTerminal = 'cmd'; // Windows Command Prompt
|
|
1218
|
-
}
|
|
1219
|
-
} else if (process.platform === 'darwin') {
|
|
1220
|
-
this.detectedTerminal = 'bash'; // macOS
|
|
1221
|
-
} else {
|
|
1222
|
-
this.detectedTerminal = 'bash'; // Linux/Unix
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
this.logger?.info('Terminal detected', {
|
|
1226
|
-
platform: this.platformType,
|
|
1227
|
-
terminal: this.detectedTerminal,
|
|
1228
|
-
shell: process.env.SHELL
|
|
1229
|
-
});
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
/**
|
|
1233
|
-
* Translate command for current terminal using AI if needed
|
|
1234
|
-
* @param {string} command - Original command
|
|
1235
|
-
* @param {Object} context - Execution context with aiService access
|
|
1236
|
-
* @returns {Promise<string>} Translated command
|
|
1237
|
-
* @private
|
|
1238
|
-
*/
|
|
1239
|
-
async translateCommand(command, context = {}) {
|
|
1240
|
-
const trimmedCommand = command.trim();
|
|
1241
|
-
|
|
1242
|
-
// Perform comprehensive command analysis
|
|
1243
|
-
const analysis = this.analyzeCommandCompatibility(trimmedCommand);
|
|
1244
|
-
|
|
1245
|
-
this.logger?.info('Command compatibility analysis', {
|
|
1246
|
-
command: trimmedCommand,
|
|
1247
|
-
detectedTerminal: analysis.detectedTerminal,
|
|
1248
|
-
commandType: analysis.commandType,
|
|
1249
|
-
commandCategory: analysis.commandCategory,
|
|
1250
|
-
compatible: analysis.compatible,
|
|
1251
|
-
issues: analysis.specificIssues,
|
|
1252
|
-
suggestedAction: analysis.suggestedAction,
|
|
1253
|
-
confidence: analysis.confidence
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
if (analysis.compatible) {
|
|
1257
|
-
return command;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
// Try simple translations first (fast path)
|
|
1261
|
-
let simpleTranslation = null;
|
|
1262
|
-
if (this.detectedTerminal === 'cmd') {
|
|
1263
|
-
simpleTranslation = this.translateToWindowsCmd(trimmedCommand);
|
|
1264
|
-
} else if (this.detectedTerminal === 'powershell') {
|
|
1265
|
-
simpleTranslation = this.translateToPowerShell(trimmedCommand);
|
|
1266
|
-
} else if (this.detectedTerminal === 'bash') {
|
|
1267
|
-
simpleTranslation = this.translateToBash(trimmedCommand);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
// If simple translation looks sufficient and command is simple, use it
|
|
1271
|
-
if (simpleTranslation && this.isSimpleCommand(trimmedCommand)) {
|
|
1272
|
-
this.logger?.info('Using simple translation', {
|
|
1273
|
-
original: command,
|
|
1274
|
-
translated: simpleTranslation,
|
|
1275
|
-
method: 'simple'
|
|
1276
|
-
});
|
|
1277
|
-
return simpleTranslation;
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
// For complex commands, use AI translation
|
|
1281
|
-
if (context.aiService || (context.toolsRegistry && context.agentId)) {
|
|
1282
|
-
this.logger?.info('Attempting AI translation for complex command', {
|
|
1283
|
-
command: command.substring(0, 100) + '...',
|
|
1284
|
-
hasAiService: !!context.aiService,
|
|
1285
|
-
hasToolsRegistry: !!context.toolsRegistry,
|
|
1286
|
-
agentId: context.agentId
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
try {
|
|
1290
|
-
const aiTranslation = await this.translateCommandWithAI(command, context);
|
|
1291
|
-
if (aiTranslation && aiTranslation.trim() !== command.trim()) {
|
|
1292
|
-
this.logger?.info('Using AI translation', {
|
|
1293
|
-
original: command,
|
|
1294
|
-
translated: aiTranslation,
|
|
1295
|
-
method: 'ai'
|
|
1296
|
-
});
|
|
1297
|
-
return aiTranslation;
|
|
1298
|
-
} else {
|
|
1299
|
-
this.logger?.warn('AI translation returned same command', {
|
|
1300
|
-
original: command,
|
|
1301
|
-
translated: aiTranslation
|
|
1302
|
-
});
|
|
1303
|
-
}
|
|
1304
|
-
} catch (error) {
|
|
1305
|
-
this.logger?.warn('AI translation failed, falling back to simple translation', {
|
|
1306
|
-
original: command,
|
|
1307
|
-
error: error.message,
|
|
1308
|
-
stack: error.stack
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
|
-
} else {
|
|
1312
|
-
this.logger?.warn('AI translation not available - missing context', {
|
|
1313
|
-
hasAiService: !!context.aiService,
|
|
1314
|
-
hasToolsRegistry: !!context.toolsRegistry,
|
|
1315
|
-
hasAgentId: !!context.agentId,
|
|
1316
|
-
contextKeys: Object.keys(context)
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
// Fallback to simple translation or original command
|
|
1321
|
-
return simpleTranslation || command;
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
/**
|
|
1325
|
-
* Check if command is simple enough for regex translation
|
|
1326
|
-
* @param {string} command - Command to check
|
|
1327
|
-
* @returns {boolean} Whether command is simple
|
|
1328
|
-
* @private
|
|
1329
|
-
*/
|
|
1330
|
-
isSimpleCommand(command) {
|
|
1331
|
-
// Check for complex command patterns using simple string methods
|
|
1332
|
-
const cmd = command.toLowerCase();
|
|
1333
|
-
|
|
1334
|
-
// Multi-line or escape sequences
|
|
1335
|
-
if (command.includes('\\n') || command.includes('\\r') || command.includes('\\t')) return false;
|
|
1336
|
-
if (command.includes('\n') || command.includes('\r')) return false;
|
|
1337
|
-
|
|
1338
|
-
// Code content
|
|
1339
|
-
if (command.includes('#include') || command.includes('printf') || command.includes('main()')) return false;
|
|
1340
|
-
if (command.includes('def ') || command.includes('function ') || command.includes('class ')) return false;
|
|
1341
|
-
|
|
1342
|
-
// Single quotes (problematic on Windows CMD)
|
|
1343
|
-
if (command.includes("echo '") && !command.includes('echo "')) return false;
|
|
1344
|
-
|
|
1345
|
-
// Long complex strings (likely contain complex content)
|
|
1346
|
-
const singleQuoteMatch = command.match(/'([^']*)'/);
|
|
1347
|
-
if (singleQuoteMatch && singleQuoteMatch[1].length > 50) return false;
|
|
1348
|
-
|
|
1349
|
-
// Unix-style paths in redirections on Windows
|
|
1350
|
-
if (this.detectedTerminal === 'cmd' && command.includes('>') && command.includes('/') && !command.includes('\\')) {
|
|
1351
|
-
return false;
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
// Multiple commands
|
|
1355
|
-
if (command.includes(' && ') || command.includes(' || ') || command.includes('; ')) return false;
|
|
1356
|
-
|
|
1357
|
-
// Command substitution or complex shell features
|
|
1358
|
-
if (command.includes('$(') || command.includes('`') || command.includes('{') || command.includes('[')) return false;
|
|
1359
|
-
|
|
1360
|
-
// Loops and conditionals
|
|
1361
|
-
if (cmd.includes('for ') || cmd.includes('while ') || cmd.includes('if ')) return false;
|
|
1362
|
-
if (cmd.includes('export ') || cmd.includes('source ')) return false;
|
|
1363
|
-
|
|
1364
|
-
// Pipes and redirections
|
|
1365
|
-
if (command.includes(' | ') || command.includes(' > &')) return false;
|
|
1366
|
-
|
|
1367
|
-
return true; // Command is simple
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* Translate command using AI service
|
|
1372
|
-
* @param {string} command - Original command
|
|
1373
|
-
* @param {Object} context - Execution context
|
|
1374
|
-
* @returns {Promise<string>} AI-translated command
|
|
1375
|
-
* @private
|
|
1376
|
-
*/
|
|
1377
|
-
async translateCommandWithAI(command, context) {
|
|
1378
|
-
// Get AI service - either directly provided or through tools registry
|
|
1379
|
-
let aiService = context.aiService;
|
|
1380
|
-
if (!aiService && context.toolsRegistry && context.agentId) {
|
|
1381
|
-
// Try to get AI service through the system (this would need to be passed through context)
|
|
1382
|
-
const messageProcessor = context.messageProcessor; // Would need to be passed in context
|
|
1383
|
-
if (messageProcessor && messageProcessor.aiService) {
|
|
1384
|
-
aiService = messageProcessor.aiService;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
if (!aiService) {
|
|
1389
|
-
throw new Error('AI service not available for command translation');
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
const translationPrompt = this.buildTranslationPrompt(command);
|
|
1393
|
-
|
|
1394
|
-
// Use a lightweight model for translation
|
|
1395
|
-
const model = 'gpt-4-mini'; // Fast and cost-effective for simple translations
|
|
1396
|
-
|
|
1397
|
-
try {
|
|
1398
|
-
const response = await aiService.sendMessage(model, translationPrompt, {
|
|
1399
|
-
agentId: context.agentId,
|
|
1400
|
-
temperature: 0.1, // Low temperature for consistent translations
|
|
1401
|
-
maxTokens: 200, // Short response expected
|
|
1402
|
-
apiKey: context.apiKey,
|
|
1403
|
-
customApiKeys: context.customApiKeys,
|
|
1404
|
-
platformProvided: context.platformProvided
|
|
1405
|
-
});
|
|
1406
|
-
|
|
1407
|
-
// Extract the translated command from the response
|
|
1408
|
-
const translatedCommand = this.extractTranslatedCommand(response.content);
|
|
1409
|
-
|
|
1410
|
-
this.logger?.debug('AI command translation completed', {
|
|
1411
|
-
original: command,
|
|
1412
|
-
translated: translatedCommand,
|
|
1413
|
-
model: model,
|
|
1414
|
-
terminal: this.detectedTerminal
|
|
1415
|
-
});
|
|
1416
|
-
|
|
1417
|
-
return translatedCommand;
|
|
1418
|
-
|
|
1419
|
-
} catch (error) {
|
|
1420
|
-
this.logger?.error('AI command translation failed', {
|
|
1421
|
-
command,
|
|
1422
|
-
terminal: this.detectedTerminal,
|
|
1423
|
-
error: error.message
|
|
1424
|
-
});
|
|
1425
|
-
throw error;
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
/**
|
|
1430
|
-
* Build translation prompt for AI service
|
|
1431
|
-
* @param {string} command - Command to translate
|
|
1432
|
-
* @returns {string} Translation prompt
|
|
1433
|
-
* @private
|
|
1434
|
-
*/
|
|
1435
|
-
buildTranslationPrompt(command) {
|
|
1436
|
-
const terminalInfo = {
|
|
1437
|
-
'cmd': 'Windows Command Prompt (cmd.exe)',
|
|
1438
|
-
'powershell': 'Windows PowerShell',
|
|
1439
|
-
'bash': 'Bash shell (Linux/Unix/macOS)'
|
|
1440
|
-
};
|
|
1441
|
-
|
|
1442
|
-
const currentTerminal = terminalInfo[this.detectedTerminal] || this.detectedTerminal;
|
|
1443
|
-
|
|
1444
|
-
// Get detailed analysis for better translation context
|
|
1445
|
-
const analysis = this.analyzeCommandCompatibility(command);
|
|
1446
|
-
|
|
1447
|
-
let prompt = `Translate this command to work correctly in ${currentTerminal}:
|
|
1448
|
-
|
|
1449
|
-
ORIGINAL COMMAND:
|
|
1450
|
-
\`\`\`
|
|
1451
|
-
${command}
|
|
1452
|
-
\`\`\`
|
|
1453
|
-
|
|
1454
|
-
COMMAND ANALYSIS:
|
|
1455
|
-
- Command Type: ${analysis.commandType}
|
|
1456
|
-
- Category: ${analysis.commandCategory}
|
|
1457
|
-
- Target Terminal: ${currentTerminal}
|
|
1458
|
-
- Compatibility Issues: ${analysis.specificIssues.join(', ') || 'None detected'}`;
|
|
1459
|
-
|
|
1460
|
-
// Add alternative suggestions if available
|
|
1461
|
-
if (analysis.commandType === 'unix' && analysis.alternatives && analysis.alternatives[this.detectedTerminal]) {
|
|
1462
|
-
prompt += `\n- Suggested Alternative: ${analysis.alternatives[this.detectedTerminal]}`;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
prompt += `
|
|
1466
|
-
|
|
1467
|
-
REQUIREMENTS:
|
|
1468
|
-
1. Make the command work correctly in ${currentTerminal}
|
|
1469
|
-
2. Preserve the original intent and functionality
|
|
1470
|
-
3. Handle file paths, quoting, and syntax correctly
|
|
1471
|
-
4. If creating files, ensure proper encoding and line endings
|
|
1472
|
-
5. Address the specific compatibility issues identified above
|
|
1473
|
-
6. Return ONLY the translated command, nothing else
|
|
1474
|
-
|
|
1475
|
-
TRANSLATED COMMAND:`;
|
|
1476
|
-
|
|
1477
|
-
return prompt;
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
/**
|
|
1481
|
-
* Extract translated command from AI response
|
|
1482
|
-
* @param {string} response - AI response content
|
|
1483
|
-
* @returns {string} Extracted command
|
|
1484
|
-
* @private
|
|
1485
|
-
*/
|
|
1486
|
-
extractTranslatedCommand(response) {
|
|
1487
|
-
// Remove markdown code blocks if present
|
|
1488
|
-
let extracted = response.replace(/```[a-z]*\n?(.*?)\n?```/s, '$1');
|
|
1489
|
-
|
|
1490
|
-
// Remove common prefixes
|
|
1491
|
-
extracted = extracted.replace(/^(TRANSLATED COMMAND:|Command:|Result:)\s*/i, '');
|
|
1492
|
-
|
|
1493
|
-
// Take first line if multiple lines (unless it's intentionally multiline)
|
|
1494
|
-
const lines = extracted.trim().split('\n');
|
|
1495
|
-
if (lines.length > 1 && !extracted.includes('&&') && !extracted.includes('||')) {
|
|
1496
|
-
extracted = lines[0].trim();
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
return extracted.trim();
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
/**
|
|
1503
|
-
* Analyze command compatibility with current terminal
|
|
1504
|
-
* @param {string} command - Command to check
|
|
1505
|
-
* @returns {Object} Compatibility analysis result
|
|
1506
|
-
* @private
|
|
1507
|
-
*/
|
|
1508
|
-
analyzeCommandCompatibility(command) {
|
|
1509
|
-
const analysis = this.classifyCommand(command);
|
|
1510
|
-
const isCompatible = this.isCommandCompatibleWithTerminal(analysis, this.detectedTerminal);
|
|
1511
|
-
|
|
1512
|
-
return {
|
|
1513
|
-
compatible: isCompatible,
|
|
1514
|
-
detectedTerminal: this.detectedTerminal,
|
|
1515
|
-
commandType: analysis.type,
|
|
1516
|
-
commandCategory: analysis.category,
|
|
1517
|
-
specificIssues: analysis.issues,
|
|
1518
|
-
suggestedAction: isCompatible ? 'execute' : 'translate',
|
|
1519
|
-
confidence: analysis.confidence
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
/**
|
|
1524
|
-
* Legacy wrapper for backward compatibility
|
|
1525
|
-
* @param {string} command - Command to check
|
|
1526
|
-
* @returns {boolean} Whether command is compatible
|
|
1527
|
-
* @private
|
|
1528
|
-
*/
|
|
1529
|
-
isCommandCompatible(command) {
|
|
1530
|
-
return this.analyzeCommandCompatibility(command).compatible;
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
/**
|
|
1534
|
-
* Classify command type and detect potential issues
|
|
1535
|
-
* @param {string} command - Command to analyze
|
|
1536
|
-
* @returns {Object} Command classification
|
|
1537
|
-
* @private
|
|
1538
|
-
*/
|
|
1539
|
-
classifyCommand(command) {
|
|
1540
|
-
const cmd = command.toLowerCase().trim();
|
|
1541
|
-
const firstWord = cmd.split(' ')[0];
|
|
1542
|
-
const issues = [];
|
|
1543
|
-
let confidence = 0.9;
|
|
1544
|
-
|
|
1545
|
-
// Unix/Linux commands
|
|
1546
|
-
const unixCommands = {
|
|
1547
|
-
// File operations
|
|
1548
|
-
'ls': { category: 'file-listing', alternatives: { cmd: 'dir', powershell: 'Get-ChildItem' }},
|
|
1549
|
-
'cat': { category: 'file-viewing', alternatives: { cmd: 'type', powershell: 'Get-Content' }},
|
|
1550
|
-
'grep': { category: 'text-search', alternatives: { cmd: 'findstr', powershell: 'Select-String' }},
|
|
1551
|
-
'find': { category: 'file-search', alternatives: { cmd: 'dir /s', powershell: 'Get-ChildItem -Recurse' }},
|
|
1552
|
-
'head': { category: 'file-viewing', alternatives: { cmd: 'more', powershell: 'Get-Content -Head' }},
|
|
1553
|
-
'tail': { category: 'file-viewing', alternatives: { cmd: 'more +n', powershell: 'Get-Content -Tail' }},
|
|
1554
|
-
'wc': { category: 'text-analysis', alternatives: { cmd: 'find /c', powershell: 'Measure-Object' }},
|
|
1555
|
-
|
|
1556
|
-
// File manipulation
|
|
1557
|
-
'cp': { category: 'file-copy', alternatives: { cmd: 'copy', powershell: 'Copy-Item' }},
|
|
1558
|
-
'mv': { category: 'file-move', alternatives: { cmd: 'move', powershell: 'Move-Item' }},
|
|
1559
|
-
'rm': { category: 'file-delete', alternatives: { cmd: 'del', powershell: 'Remove-Item' }},
|
|
1560
|
-
'mkdir': { category: 'directory-create', alternatives: { cmd: 'mkdir', powershell: 'New-Item -Type Directory' }},
|
|
1561
|
-
'rmdir': { category: 'directory-delete', alternatives: { cmd: 'rmdir', powershell: 'Remove-Item' }},
|
|
1562
|
-
'touch': { category: 'file-create', alternatives: { cmd: 'type nul >', powershell: 'New-Item -Type File' }},
|
|
1563
|
-
|
|
1564
|
-
// Permissions and ownership
|
|
1565
|
-
'chmod': { category: 'permissions', alternatives: { cmd: 'icacls', powershell: 'Set-Acl' }},
|
|
1566
|
-
'chown': { category: 'ownership', alternatives: { cmd: 'takeown', powershell: 'Set-Acl' }},
|
|
1567
|
-
|
|
1568
|
-
// Process management
|
|
1569
|
-
'ps': { category: 'process-list', alternatives: { cmd: 'tasklist', powershell: 'Get-Process' }},
|
|
1570
|
-
'kill': { category: 'process-kill', alternatives: { cmd: 'taskkill', powershell: 'Stop-Process' }},
|
|
1571
|
-
'killall': { category: 'process-kill', alternatives: { cmd: 'taskkill /f /im', powershell: 'Get-Process | Stop-Process' }},
|
|
1572
|
-
'top': { category: 'process-monitor', alternatives: { cmd: 'tasklist', powershell: 'Get-Process | Sort-Object CPU' }},
|
|
1573
|
-
|
|
1574
|
-
// Network
|
|
1575
|
-
'wget': { category: 'download', alternatives: { cmd: 'curl', powershell: 'Invoke-WebRequest' }},
|
|
1576
|
-
'curl': { category: 'http-client', alternatives: { cmd: 'curl', powershell: 'Invoke-RestMethod' }},
|
|
1577
|
-
'ping': { category: 'network-test', alternatives: { cmd: 'ping', powershell: 'Test-NetConnection' }},
|
|
1578
|
-
|
|
1579
|
-
// Text processing
|
|
1580
|
-
'awk': { category: 'text-processing', alternatives: { cmd: 'for /f', powershell: 'ForEach-Object' }},
|
|
1581
|
-
'sed': { category: 'text-edit', alternatives: { cmd: 'powershell -c', powershell: 'native' }},
|
|
1582
|
-
'sort': { category: 'text-sort', alternatives: { cmd: 'sort', powershell: 'Sort-Object' }},
|
|
1583
|
-
'uniq': { category: 'text-dedupe', alternatives: { cmd: 'sort /unique', powershell: 'Sort-Object -Unique' }},
|
|
1584
|
-
|
|
1585
|
-
// Environment
|
|
1586
|
-
'pwd': { category: 'directory-current', alternatives: { cmd: 'cd', powershell: 'Get-Location' }},
|
|
1587
|
-
'whoami': { category: 'user-info', alternatives: { cmd: 'echo %USERNAME%', powershell: 'whoami' }},
|
|
1588
|
-
'env': { category: 'environment', alternatives: { cmd: 'set', powershell: 'Get-ChildItem Env:' }},
|
|
1589
|
-
'export': { category: 'environment', alternatives: { cmd: 'set', powershell: '$env:' }},
|
|
1590
|
-
'source': { category: 'script-execute', alternatives: { cmd: 'call', powershell: '. ' }},
|
|
1591
|
-
|
|
1592
|
-
// Archives
|
|
1593
|
-
'tar': { category: 'archive', alternatives: { cmd: '7z', powershell: 'Compress-Archive' }},
|
|
1594
|
-
'zip': { category: 'archive', alternatives: { cmd: 'powershell Compress-Archive', powershell: 'Compress-Archive' }},
|
|
1595
|
-
'unzip': { category: 'archive', alternatives: { cmd: 'powershell Expand-Archive', powershell: 'Expand-Archive' }},
|
|
1596
|
-
|
|
1597
|
-
// System info
|
|
1598
|
-
'df': { category: 'disk-info', alternatives: { cmd: 'fsutil volume diskfree', powershell: 'Get-WmiObject -Class Win32_LogicalDisk' }},
|
|
1599
|
-
'du': { category: 'disk-usage', alternatives: { cmd: 'dir /s', powershell: 'Get-ChildItem -Recurse | Measure-Object' }},
|
|
1600
|
-
'free': { category: 'memory-info', alternatives: { cmd: 'systeminfo', powershell: 'Get-WmiObject -Class Win32_PhysicalMemory' }},
|
|
1601
|
-
'uname': { category: 'system-info', alternatives: { cmd: 'systeminfo', powershell: 'Get-ComputerInfo' }}
|
|
1602
|
-
};
|
|
1603
|
-
|
|
1604
|
-
// Windows CMD commands
|
|
1605
|
-
const cmdCommands = {
|
|
1606
|
-
'dir': { category: 'file-listing', alternatives: { unix: 'ls', powershell: 'Get-ChildItem' }},
|
|
1607
|
-
'type': { category: 'file-viewing', alternatives: { unix: 'cat', powershell: 'Get-Content' }},
|
|
1608
|
-
'copy': { category: 'file-copy', alternatives: { unix: 'cp', powershell: 'Copy-Item' }},
|
|
1609
|
-
'move': { category: 'file-move', alternatives: { unix: 'mv', powershell: 'Move-Item' }},
|
|
1610
|
-
'del': { category: 'file-delete', alternatives: { unix: 'rm', powershell: 'Remove-Item' }},
|
|
1611
|
-
'tasklist': { category: 'process-list', alternatives: { unix: 'ps', powershell: 'Get-Process' }},
|
|
1612
|
-
'taskkill': { category: 'process-kill', alternatives: { unix: 'kill', powershell: 'Stop-Process' }},
|
|
1613
|
-
'findstr': { category: 'text-search', alternatives: { unix: 'grep', powershell: 'Select-String' }}
|
|
1614
|
-
};
|
|
1615
|
-
|
|
1616
|
-
// PowerShell commands
|
|
1617
|
-
const powershellCommands = {
|
|
1618
|
-
'get-childitem': { category: 'file-listing', alternatives: { unix: 'ls', cmd: 'dir' }},
|
|
1619
|
-
'get-content': { category: 'file-viewing', alternatives: { unix: 'cat', cmd: 'type' }},
|
|
1620
|
-
'copy-item': { category: 'file-copy', alternatives: { unix: 'cp', cmd: 'copy' }},
|
|
1621
|
-
'move-item': { category: 'file-move', alternatives: { unix: 'mv', cmd: 'move' }},
|
|
1622
|
-
'remove-item': { category: 'file-delete', alternatives: { unix: 'rm', cmd: 'del' }},
|
|
1623
|
-
'get-process': { category: 'process-list', alternatives: { unix: 'ps', cmd: 'tasklist' }},
|
|
1624
|
-
'stop-process': { category: 'process-kill', alternatives: { unix: 'kill', cmd: 'taskkill' }}
|
|
1625
|
-
};
|
|
1626
|
-
|
|
1627
|
-
// Determine command type
|
|
1628
|
-
let commandType = 'unknown';
|
|
1629
|
-
let category = 'unknown';
|
|
1630
|
-
let alternatives = {};
|
|
1631
|
-
|
|
1632
|
-
if (unixCommands[firstWord]) {
|
|
1633
|
-
commandType = 'unix';
|
|
1634
|
-
category = unixCommands[firstWord].category;
|
|
1635
|
-
alternatives = unixCommands[firstWord].alternatives;
|
|
1636
|
-
} else if (cmdCommands[firstWord]) {
|
|
1637
|
-
commandType = 'windows-cmd';
|
|
1638
|
-
category = cmdCommands[firstWord].category;
|
|
1639
|
-
alternatives = cmdCommands[firstWord].alternatives;
|
|
1640
|
-
} else if (powershellCommands[firstWord]) {
|
|
1641
|
-
commandType = 'powershell';
|
|
1642
|
-
category = powershellCommands[firstWord].category;
|
|
1643
|
-
alternatives = powershellCommands[firstWord].alternatives;
|
|
1644
|
-
} else {
|
|
1645
|
-
// Check for built-in commands that work everywhere
|
|
1646
|
-
const universalCommands = ['echo', 'cd', 'exit', 'help'];
|
|
1647
|
-
if (universalCommands.includes(firstWord)) {
|
|
1648
|
-
commandType = 'universal';
|
|
1649
|
-
category = 'builtin';
|
|
1650
|
-
} else {
|
|
1651
|
-
commandType = 'unknown';
|
|
1652
|
-
confidence = 0.3;
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
// Check for syntax issues
|
|
1657
|
-
if (command.includes("'") && !command.includes('"')) {
|
|
1658
|
-
issues.push('single-quotes-problematic');
|
|
1659
|
-
}
|
|
1660
|
-
if (command.includes('/') && !command.includes('\\') && !command.includes('http') && command.includes('>')) {
|
|
1661
|
-
issues.push('unix-style-paths');
|
|
1662
|
-
}
|
|
1663
|
-
if (command.includes('\\n') || command.includes('\\t')) {
|
|
1664
|
-
issues.push('escape-sequences');
|
|
1665
|
-
}
|
|
1666
|
-
if (command.includes(' && ') || command.includes(' || ') || command.includes(';')) {
|
|
1667
|
-
issues.push('command-chaining');
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
return {
|
|
1671
|
-
type: commandType,
|
|
1672
|
-
category: category,
|
|
1673
|
-
alternatives: alternatives,
|
|
1674
|
-
issues: issues,
|
|
1675
|
-
confidence: confidence,
|
|
1676
|
-
firstWord: firstWord,
|
|
1677
|
-
fullCommand: command
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
/**
|
|
1682
|
-
* Check if classified command is compatible with terminal
|
|
1683
|
-
* @param {Object} analysis - Command analysis
|
|
1684
|
-
* @param {string} terminal - Target terminal type
|
|
1685
|
-
* @returns {boolean} Whether compatible
|
|
1686
|
-
* @private
|
|
1687
|
-
*/
|
|
1688
|
-
isCommandCompatibleWithTerminal(analysis, terminal) {
|
|
1689
|
-
switch (terminal) {
|
|
1690
|
-
case 'cmd':
|
|
1691
|
-
if (analysis.type === 'unix') return false;
|
|
1692
|
-
if (analysis.issues.includes('single-quotes-problematic')) return false;
|
|
1693
|
-
if (analysis.issues.includes('unix-style-paths')) return false;
|
|
1694
|
-
return analysis.type === 'windows-cmd' || analysis.type === 'universal';
|
|
1695
|
-
|
|
1696
|
-
case 'powershell':
|
|
1697
|
-
if (analysis.type === 'unix' && !analysis.alternatives.powershell) return false;
|
|
1698
|
-
return true; // PowerShell is quite compatible
|
|
1699
|
-
|
|
1700
|
-
case 'bash':
|
|
1701
|
-
if (analysis.type === 'windows-cmd') return false;
|
|
1702
|
-
return analysis.type === 'unix' || analysis.type === 'universal';
|
|
1703
|
-
|
|
1704
|
-
default:
|
|
1705
|
-
return false;
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
/**
|
|
1710
|
-
* Translate command to Windows CMD syntax
|
|
1711
|
-
* @param {string} command - Original command
|
|
1712
|
-
* @returns {string} Windows CMD equivalent
|
|
1713
|
-
* @private
|
|
1714
|
-
*/
|
|
1715
|
-
translateToWindowsCmd(command) {
|
|
1716
|
-
let translated = command;
|
|
1717
|
-
|
|
1718
|
-
// Common Unix to Windows translations
|
|
1719
|
-
const translations = new Map([
|
|
1720
|
-
// Directory listing
|
|
1721
|
-
[/^ls\s*$/, 'dir'],
|
|
1722
|
-
[/^ls\s+-la?$/, 'dir'],
|
|
1723
|
-
[/^ls\s+-l$/, 'dir'],
|
|
1724
|
-
[/^ls\s+-a$/, 'dir /a'],
|
|
1725
|
-
|
|
1726
|
-
// File operations
|
|
1727
|
-
[/^cat\s+(.+)$/, 'type $1'],
|
|
1728
|
-
[/^cp\s+(.+)\s+(.+)$/, 'copy $1 $2'],
|
|
1729
|
-
[/^mv\s+(.+)\s+(.+)$/, 'move $1 $2'],
|
|
1730
|
-
[/^rm\s+(.+)$/, 'del $1'],
|
|
1731
|
-
[/^mkdir\s+(.+)$/, 'mkdir $1'],
|
|
1732
|
-
[/^rmdir\s+(.+)$/, 'rmdir $1'],
|
|
1733
|
-
|
|
1734
|
-
// Process management
|
|
1735
|
-
[/^ps\s*$/, 'tasklist'],
|
|
1736
|
-
[/^kill\s+(.+)$/, 'taskkill /PID $1'],
|
|
1737
|
-
|
|
1738
|
-
// Environment
|
|
1739
|
-
[/^pwd\s*$/, 'cd'],
|
|
1740
|
-
[/^whoami\s*$/, 'echo %USERNAME%'],
|
|
1741
|
-
|
|
1742
|
-
// Network
|
|
1743
|
-
[/^ping\s+(.+)$/, 'ping $1'],
|
|
1744
|
-
[/^wget\s+(.+)$/, 'curl -O $1'],
|
|
1745
|
-
[/^curl\s+(.+)$/, 'curl $1']
|
|
1746
|
-
]);
|
|
1747
|
-
|
|
1748
|
-
// Apply translations
|
|
1749
|
-
for (const [regex, replacement] of translations) {
|
|
1750
|
-
if (regex.test(translated)) {
|
|
1751
|
-
translated = translated.replace(regex, replacement);
|
|
1752
|
-
break;
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
// Fix echo command with single quotes
|
|
1757
|
-
translated = translated.replace(/echo\s+'([^']+)'\s*>/g, 'echo "$1" >');
|
|
1758
|
-
translated = translated.replace(/echo\s+'([^']+)'$/g, 'echo "$1"');
|
|
1759
|
-
|
|
1760
|
-
// Fix multi-line echo commands
|
|
1761
|
-
if (translated.includes("echo '") && translated.includes("\\n")) {
|
|
1762
|
-
// Convert multi-line echo to multiple echo commands or use different approach
|
|
1763
|
-
const match = translated.match(/echo\s+'(.+?)'\s*>\s*(.+)$/);
|
|
1764
|
-
if (match) {
|
|
1765
|
-
const content = match[1].replace(/\\n/g, '\n');
|
|
1766
|
-
const filename = match[2];
|
|
1767
|
-
const lines = content.split('\n');
|
|
1768
|
-
|
|
1769
|
-
// Create a batch file approach for multi-line content
|
|
1770
|
-
translated = `(${lines.map(line => `echo ${line}`).join(' & ')}) > ${filename}`;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
this.logger?.info('Command translated for Windows CMD', {
|
|
1775
|
-
original: command,
|
|
1776
|
-
translated: translated
|
|
1777
|
-
});
|
|
1778
|
-
|
|
1779
|
-
return translated;
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
/**
|
|
1783
|
-
* Translate command to PowerShell syntax
|
|
1784
|
-
* @param {string} command - Original command
|
|
1785
|
-
* @returns {string} PowerShell equivalent
|
|
1786
|
-
* @private
|
|
1787
|
-
*/
|
|
1788
|
-
translateToPowerShell(command) {
|
|
1789
|
-
let translated = command;
|
|
1790
|
-
|
|
1791
|
-
const translations = new Map([
|
|
1792
|
-
[/^ls\s*$/, 'Get-ChildItem'],
|
|
1793
|
-
[/^ls\s+-la?$/, 'Get-ChildItem -Force'],
|
|
1794
|
-
[/^cat\s+(.+)$/, 'Get-Content $1'],
|
|
1795
|
-
[/^cp\s+(.+)\s+(.+)$/, 'Copy-Item $1 $2'],
|
|
1796
|
-
[/^mv\s+(.+)\s+(.+)$/, 'Move-Item $1 $2'],
|
|
1797
|
-
[/^rm\s+(.+)$/, 'Remove-Item $1'],
|
|
1798
|
-
[/^pwd\s*$/, 'Get-Location'],
|
|
1799
|
-
[/^ps\s*$/, 'Get-Process']
|
|
1800
|
-
]);
|
|
1801
|
-
|
|
1802
|
-
for (const [regex, replacement] of translations) {
|
|
1803
|
-
if (regex.test(translated)) {
|
|
1804
|
-
translated = translated.replace(regex, replacement);
|
|
1805
|
-
break;
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
this.logger?.info('Command translated for PowerShell', {
|
|
1810
|
-
original: command,
|
|
1811
|
-
translated: translated
|
|
1812
|
-
});
|
|
1813
|
-
|
|
1814
|
-
return translated;
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
/**
|
|
1818
|
-
* Translate command to Bash syntax
|
|
1819
|
-
* @param {string} command - Original command
|
|
1820
|
-
* @returns {string} Bash equivalent
|
|
1821
|
-
* @private
|
|
1822
|
-
*/
|
|
1823
|
-
translateToBash(command) {
|
|
1824
|
-
// For bash, mainly fix Windows-specific commands
|
|
1825
|
-
let translated = command;
|
|
1826
|
-
|
|
1827
|
-
const translations = new Map([
|
|
1828
|
-
[/^dir\s*$/, 'ls'],
|
|
1829
|
-
[/^dir\s+\/a$/, 'ls -a'],
|
|
1830
|
-
[/^type\s+(.+)$/, 'cat $1'],
|
|
1831
|
-
[/^copy\s+(.+)\s+(.+)$/, 'cp $1 $2'],
|
|
1832
|
-
[/^move\s+(.+)\s+(.+)$/, 'mv $1 $2'],
|
|
1833
|
-
[/^del\s+(.+)$/, 'rm $1'],
|
|
1834
|
-
[/^tasklist\s*$/, 'ps'],
|
|
1835
|
-
[/^cd\s*$/, 'pwd']
|
|
1836
|
-
]);
|
|
1837
|
-
|
|
1838
|
-
for (const [regex, replacement] of translations) {
|
|
1839
|
-
if (regex.test(translated)) {
|
|
1840
|
-
translated = translated.replace(regex, replacement);
|
|
1841
|
-
break;
|
|
1842
|
-
}
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
return translated;
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
/**
|
|
1849
|
-
* Resource cleanup
|
|
1850
|
-
* @param {string} operationId - Operation identifier
|
|
1851
|
-
*/
|
|
1852
|
-
async cleanup(operationId) {
|
|
1853
|
-
// Clean up any hanging processes or temporary resources
|
|
1854
|
-
// This would be expanded based on specific needs
|
|
1855
|
-
}
|
|
1856
|
-
|
|
1857
|
-
/**
|
|
1858
|
-
* Phase 3 & 4: Start a background command
|
|
1859
|
-
* @param {string} command - Command to execute
|
|
1860
|
-
* @param {string} workingDir - Working directory
|
|
1861
|
-
* @param {Object} options - Execution options
|
|
1862
|
-
* @returns {Promise<Object>} Command info with commandId
|
|
1863
|
-
*/
|
|
1864
|
-
async startBackgroundCommand(command, workingDir, options = {}) {
|
|
1865
|
-
const { agentId, context } = options;
|
|
1866
|
-
|
|
1867
|
-
if (!agentId) {
|
|
1868
|
-
throw new Error('agentId is required for background commands');
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
// Check agent resource limits (only count active commands: running or waiting_for_input)
|
|
1872
|
-
const agentCommands = this.getAgentCommands(agentId);
|
|
1873
|
-
const activeAgentCommands = agentCommands.filter(cmd =>
|
|
1874
|
-
cmd.state === 'running' || cmd.state === 'waiting_for_input'
|
|
1875
|
-
);
|
|
1876
|
-
if (activeAgentCommands.length >= this.MAX_BACKGROUND_COMMANDS_PER_AGENT) {
|
|
1877
|
-
throw new Error(`Maximum background commands per agent exceeded (${this.MAX_BACKGROUND_COMMANDS_PER_AGENT})`);
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
// Check global resource limits (only count active commands)
|
|
1881
|
-
const allCommands = Array.from(this.commandTracker.values());
|
|
1882
|
-
const activeGlobalCommands = allCommands.filter(cmd =>
|
|
1883
|
-
cmd.state === 'running' || cmd.state === 'waiting_for_input'
|
|
1884
|
-
);
|
|
1885
|
-
if (activeGlobalCommands.length >= this.MAX_BACKGROUND_COMMANDS_GLOBAL) {
|
|
1886
|
-
throw new Error(`Maximum global background commands exceeded (${this.MAX_BACKGROUND_COMMANDS_GLOBAL})`);
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
// Generate unique command ID
|
|
1890
|
-
const commandId = `${agentId}-cmd-${Date.now()}-${++this.commandIdCounter}`;
|
|
1891
|
-
|
|
1892
|
-
// Translate command
|
|
1893
|
-
const originalCommand = command;
|
|
1894
|
-
let translatedCommand;
|
|
1895
|
-
|
|
1896
|
-
try {
|
|
1897
|
-
translatedCommand = await this.translateCommand(command, {
|
|
1898
|
-
agentId,
|
|
1899
|
-
toolsRegistry: context?.toolsRegistry,
|
|
1900
|
-
messageProcessor: context?.messageProcessor,
|
|
1901
|
-
aiService: context?.aiService,
|
|
1902
|
-
apiKey: context?.apiKey,
|
|
1903
|
-
customApiKeys: context?.customApiKeys,
|
|
1904
|
-
platformProvided: context?.platformProvided
|
|
1905
|
-
});
|
|
1906
|
-
} catch (error) {
|
|
1907
|
-
this.logger?.warn('Command translation failed, using original command', {
|
|
1908
|
-
originalCommand,
|
|
1909
|
-
error: error.message
|
|
1910
|
-
});
|
|
1911
|
-
translatedCommand = command;
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
this.logger?.info(`Starting background command: ${translatedCommand}`, {
|
|
1915
|
-
commandId,
|
|
1916
|
-
agentId,
|
|
1917
|
-
originalCommand,
|
|
1918
|
-
workingDirectory: workingDir
|
|
1919
|
-
});
|
|
1920
|
-
|
|
1921
|
-
// Spawn process with stdin kept open
|
|
1922
|
-
let childProcess;
|
|
1923
|
-
|
|
1924
|
-
if (this.detectedTerminal === 'cmd' || this.detectedTerminal === 'powershell') {
|
|
1925
|
-
const shell = this.detectedTerminal === 'powershell' ? 'powershell' : 'cmd';
|
|
1926
|
-
const shellArgs = this.detectedTerminal === 'powershell'
|
|
1927
|
-
? ['-Command', translatedCommand]
|
|
1928
|
-
: ['/c', translatedCommand];
|
|
1929
|
-
|
|
1930
|
-
childProcess = spawn(shell, shellArgs, {
|
|
1931
|
-
cwd: workingDir,
|
|
1932
|
-
env: { ...process.env },
|
|
1933
|
-
windowsHide: true,
|
|
1934
|
-
stdio: ['pipe', 'pipe', 'pipe'] // Keep stdin open
|
|
1935
|
-
});
|
|
1936
|
-
} else {
|
|
1937
|
-
childProcess = spawn('sh', ['-c', translatedCommand], {
|
|
1938
|
-
cwd: workingDir,
|
|
1939
|
-
env: { ...process.env },
|
|
1940
|
-
stdio: ['pipe', 'pipe', 'pipe'] // Keep stdin open
|
|
1941
|
-
});
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
// Initialize command tracking
|
|
1945
|
-
const commandInfo = {
|
|
1946
|
-
commandId,
|
|
1947
|
-
agentId,
|
|
1948
|
-
pid: childProcess.pid,
|
|
1949
|
-
command: originalCommand,
|
|
1950
|
-
translatedCommand,
|
|
1951
|
-
workingDirectory: workingDir,
|
|
1952
|
-
startTime: new Date().toISOString(),
|
|
1953
|
-
state: 'running',
|
|
1954
|
-
exitCode: null,
|
|
1955
|
-
stdoutBuffer: '',
|
|
1956
|
-
stderrBuffer: '',
|
|
1957
|
-
lastOutputTime: Date.now(),
|
|
1958
|
-
promptDetected: null,
|
|
1959
|
-
process: childProcess
|
|
1960
|
-
};
|
|
1961
|
-
|
|
1962
|
-
this.commandTracker.set(commandId, commandInfo);
|
|
1963
|
-
|
|
1964
|
-
// Set up stream handlers
|
|
1965
|
-
childProcess.stdout.on('data', (chunk) => {
|
|
1966
|
-
const data = chunk.toString();
|
|
1967
|
-
commandInfo.stdoutBuffer += data;
|
|
1968
|
-
commandInfo.lastOutputTime = Date.now();
|
|
1969
|
-
|
|
1970
|
-
// Check for prompts
|
|
1971
|
-
if (!commandInfo.promptDetected) {
|
|
1972
|
-
const detection = this.promptDetector.detectPrompt(commandInfo.stdoutBuffer, 'stdout');
|
|
1973
|
-
if (detection) {
|
|
1974
|
-
commandInfo.promptDetected = detection;
|
|
1975
|
-
commandInfo.state = 'waiting_for_input';
|
|
1976
|
-
this.logger?.info('Prompt detected in background command', {
|
|
1977
|
-
commandId,
|
|
1978
|
-
agentId,
|
|
1979
|
-
type: detection.type,
|
|
1980
|
-
matchedText: detection.matchedText
|
|
1981
|
-
});
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
});
|
|
1985
|
-
|
|
1986
|
-
childProcess.stderr.on('data', (chunk) => {
|
|
1987
|
-
const data = chunk.toString();
|
|
1988
|
-
commandInfo.stderrBuffer += data;
|
|
1989
|
-
commandInfo.lastOutputTime = Date.now();
|
|
1990
|
-
|
|
1991
|
-
// Check for prompts in stderr too
|
|
1992
|
-
if (!commandInfo.promptDetected) {
|
|
1993
|
-
const detection = this.promptDetector.detectPrompt(commandInfo.stderrBuffer, 'stderr');
|
|
1994
|
-
if (detection) {
|
|
1995
|
-
commandInfo.promptDetected = detection;
|
|
1996
|
-
commandInfo.state = 'waiting_for_input';
|
|
1997
|
-
this.logger?.info('Prompt detected in background command stderr', {
|
|
1998
|
-
commandId,
|
|
1999
|
-
agentId,
|
|
2000
|
-
type: detection.type,
|
|
2001
|
-
matchedText: detection.matchedText
|
|
2002
|
-
});
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
});
|
|
2006
|
-
|
|
2007
|
-
childProcess.on('exit', (code, signal) => {
|
|
2008
|
-
commandInfo.exitCode = code;
|
|
2009
|
-
commandInfo.state = code === 0 ? 'completed' : 'failed';
|
|
2010
|
-
commandInfo.endTime = new Date().toISOString();
|
|
2011
|
-
|
|
2012
|
-
this.logger?.info('Background command exited', {
|
|
2013
|
-
commandId,
|
|
2014
|
-
agentId,
|
|
2015
|
-
exitCode: code,
|
|
2016
|
-
signal,
|
|
2017
|
-
state: commandInfo.state
|
|
2018
|
-
});
|
|
2019
|
-
});
|
|
2020
|
-
|
|
2021
|
-
childProcess.on('error', (error) => {
|
|
2022
|
-
commandInfo.state = 'failed';
|
|
2023
|
-
commandInfo.error = error.message;
|
|
2024
|
-
commandInfo.endTime = new Date().toISOString();
|
|
2025
|
-
|
|
2026
|
-
this.logger?.error('Background command error', {
|
|
2027
|
-
commandId,
|
|
2028
|
-
agentId,
|
|
2029
|
-
error: error.message
|
|
2030
|
-
});
|
|
2031
|
-
});
|
|
2032
|
-
|
|
2033
|
-
// Return command info
|
|
2034
|
-
return {
|
|
2035
|
-
success: true,
|
|
2036
|
-
commandId,
|
|
2037
|
-
pid: childProcess.pid,
|
|
2038
|
-
command: originalCommand,
|
|
2039
|
-
translatedCommand,
|
|
2040
|
-
workingDirectory: workingDir,
|
|
2041
|
-
message: `Background command started with ID: ${commandId}`
|
|
2042
|
-
};
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
/**
|
|
2046
|
-
* Phase 3: Send input to a background command (stdin)
|
|
2047
|
-
* @param {string} commandId - Command identifier
|
|
2048
|
-
* @param {string} input - Input to send (will add newline automatically)
|
|
2049
|
-
* @param {string} agentId - Agent identifier for ownership validation
|
|
2050
|
-
* @returns {Object} Result
|
|
2051
|
-
*/
|
|
2052
|
-
sendInput(commandId, input, agentId) {
|
|
2053
|
-
// Validate ownership
|
|
2054
|
-
const commandInfo = this.validateCommandOwnership(commandId, agentId);
|
|
2055
|
-
|
|
2056
|
-
if (commandInfo.state === 'completed' || commandInfo.state === 'failed') {
|
|
2057
|
-
throw new Error(`Cannot send input to ${commandInfo.state} command`);
|
|
2058
|
-
}
|
|
2059
|
-
|
|
2060
|
-
if (!commandInfo.process || commandInfo.process.killed) {
|
|
2061
|
-
throw new Error('Command process is not running');
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
// Send input with newline
|
|
2065
|
-
const inputWithNewline = input.endsWith('\n') ? input : input + '\n';
|
|
2066
|
-
commandInfo.process.stdin.write(inputWithNewline);
|
|
2067
|
-
|
|
2068
|
-
this.logger?.info('Input sent to background command', {
|
|
2069
|
-
commandId,
|
|
2070
|
-
agentId,
|
|
2071
|
-
inputLength: input.length
|
|
2072
|
-
});
|
|
2073
|
-
|
|
2074
|
-
// Update state if it was waiting
|
|
2075
|
-
if (commandInfo.state === 'waiting_for_input') {
|
|
2076
|
-
commandInfo.state = 'running';
|
|
2077
|
-
commandInfo.promptDetected = null; // Clear prompt after answering
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
return {
|
|
2081
|
-
success: true,
|
|
2082
|
-
commandId,
|
|
2083
|
-
message: 'Input sent successfully'
|
|
2084
|
-
};
|
|
2085
|
-
}
|
|
2086
|
-
|
|
2087
|
-
/**
|
|
2088
|
-
* Phase 4: Get status of a background command
|
|
2089
|
-
* @param {string} commandId - Command identifier
|
|
2090
|
-
* @param {string} agentId - Agent identifier for ownership validation
|
|
2091
|
-
* @returns {Object} Command status
|
|
2092
|
-
*/
|
|
2093
|
-
getCommandStatus(commandId, agentId) {
|
|
2094
|
-
const commandInfo = this.validateCommandOwnership(commandId, agentId);
|
|
2095
|
-
|
|
2096
|
-
const timeSinceLastOutput = Date.now() - commandInfo.lastOutputTime;
|
|
2097
|
-
|
|
2098
|
-
return {
|
|
2099
|
-
success: true,
|
|
2100
|
-
commandId,
|
|
2101
|
-
pid: commandInfo.pid,
|
|
2102
|
-
command: commandInfo.command,
|
|
2103
|
-
state: commandInfo.state,
|
|
2104
|
-
exitCode: commandInfo.exitCode,
|
|
2105
|
-
startTime: commandInfo.startTime,
|
|
2106
|
-
endTime: commandInfo.endTime,
|
|
2107
|
-
workingDirectory: commandInfo.workingDirectory,
|
|
2108
|
-
stdout: commandInfo.stdoutBuffer,
|
|
2109
|
-
stderr: commandInfo.stderrBuffer,
|
|
2110
|
-
stdoutLength: commandInfo.stdoutBuffer.length,
|
|
2111
|
-
stderrLength: commandInfo.stderrBuffer.length,
|
|
2112
|
-
lastOutputTime: commandInfo.lastOutputTime,
|
|
2113
|
-
timeSinceLastOutput,
|
|
2114
|
-
promptDetected: !!commandInfo.promptDetected,
|
|
2115
|
-
promptInfo: commandInfo.promptDetected || undefined
|
|
2116
|
-
};
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
/**
|
|
2120
|
-
* Phase 4: Kill a background command
|
|
2121
|
-
* @param {string} commandId - Command identifier
|
|
2122
|
-
* @param {string} agentId - Agent identifier for ownership validation
|
|
2123
|
-
* @returns {Object} Result
|
|
2124
|
-
*/
|
|
2125
|
-
killCommand(commandId, agentId) {
|
|
2126
|
-
const commandInfo = this.validateCommandOwnership(commandId, agentId);
|
|
2127
|
-
|
|
2128
|
-
if (commandInfo.state === 'completed' || commandInfo.state === 'failed') {
|
|
2129
|
-
return {
|
|
2130
|
-
success: true,
|
|
2131
|
-
commandId,
|
|
2132
|
-
message: 'Command already terminated',
|
|
2133
|
-
state: commandInfo.state
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2137
|
-
if (commandInfo.process && !commandInfo.process.killed) {
|
|
2138
|
-
commandInfo.process.kill('SIGTERM');
|
|
2139
|
-
|
|
2140
|
-
// If SIGTERM doesn't work, try SIGKILL after 5s
|
|
2141
|
-
setTimeout(() => {
|
|
2142
|
-
if (commandInfo.process && !commandInfo.process.killed) {
|
|
2143
|
-
commandInfo.process.kill('SIGKILL');
|
|
2144
|
-
}
|
|
2145
|
-
}, 5000);
|
|
2146
|
-
|
|
2147
|
-
this.logger?.info('Background command killed', {
|
|
2148
|
-
commandId,
|
|
2149
|
-
agentId
|
|
2150
|
-
});
|
|
2151
|
-
|
|
2152
|
-
return {
|
|
2153
|
-
success: true,
|
|
2154
|
-
commandId,
|
|
2155
|
-
message: 'Command killed successfully'
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
return {
|
|
2160
|
-
success: false,
|
|
2161
|
-
commandId,
|
|
2162
|
-
error: 'Command process not found or already killed'
|
|
2163
|
-
};
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
/**
|
|
2167
|
-
* Phase 4: List all commands for an agent
|
|
2168
|
-
* @param {string} agentId - Agent identifier
|
|
2169
|
-
* @returns {Array} List of command info objects
|
|
2170
|
-
*/
|
|
2171
|
-
listAgentCommands(agentId) {
|
|
2172
|
-
const commands = this.getAgentCommands(agentId);
|
|
2173
|
-
|
|
2174
|
-
return commands.map(cmd => ({
|
|
2175
|
-
commandId: cmd.commandId,
|
|
2176
|
-
command: cmd.command,
|
|
2177
|
-
state: cmd.state,
|
|
2178
|
-
pid: cmd.pid,
|
|
2179
|
-
exitCode: cmd.exitCode,
|
|
2180
|
-
startTime: cmd.startTime,
|
|
2181
|
-
endTime: cmd.endTime,
|
|
2182
|
-
promptDetected: !!cmd.promptDetected,
|
|
2183
|
-
timeSinceLastOutput: Date.now() - cmd.lastOutputTime
|
|
2184
|
-
}));
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
|
-
/**
|
|
2188
|
-
* Phase 4: Get agent's commands (helper method)
|
|
2189
|
-
* @param {string} agentId - Agent identifier
|
|
2190
|
-
* @returns {Array} Array of command info objects
|
|
2191
|
-
* @private
|
|
2192
|
-
*/
|
|
2193
|
-
getAgentCommands(agentId) {
|
|
2194
|
-
return Array.from(this.commandTracker.values())
|
|
2195
|
-
.filter(cmd => cmd.agentId === agentId);
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
/**
|
|
2199
|
-
* Phase 4: Validate command ownership
|
|
2200
|
-
* @param {string} commandId - Command identifier
|
|
2201
|
-
* @param {string} agentId - Agent identifier
|
|
2202
|
-
* @returns {Object} Command info if valid
|
|
2203
|
-
* @throws {Error} If command not found or access denied
|
|
2204
|
-
* @private
|
|
2205
|
-
*/
|
|
2206
|
-
validateCommandOwnership(commandId, agentId) {
|
|
2207
|
-
const commandInfo = this.commandTracker.get(commandId);
|
|
2208
|
-
|
|
2209
|
-
if (!commandInfo) {
|
|
2210
|
-
throw new Error(`Command not found: ${commandId}`);
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
if (commandInfo.agentId !== agentId) {
|
|
2214
|
-
throw new Error(`Access denied: Command belongs to agent ${commandInfo.agentId}`);
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
return commandInfo;
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
/**
|
|
2221
|
-
* Phase 4: Cleanup all commands for an agent (called when agent is deleted)
|
|
2222
|
-
* @param {string} agentId - Agent identifier
|
|
2223
|
-
* @returns {Promise<Object>} Cleanup result
|
|
2224
|
-
*/
|
|
2225
|
-
async cleanupAgent(agentId) {
|
|
2226
|
-
const commands = this.getAgentCommands(agentId);
|
|
2227
|
-
|
|
2228
|
-
let killedCount = 0;
|
|
2229
|
-
let removedCount = 0;
|
|
2230
|
-
|
|
2231
|
-
for (const commandInfo of commands) {
|
|
2232
|
-
// Kill process if still running
|
|
2233
|
-
if (commandInfo.process && !commandInfo.process.killed) {
|
|
2234
|
-
commandInfo.process.kill('SIGTERM');
|
|
2235
|
-
killedCount++;
|
|
2236
|
-
|
|
2237
|
-
// Force kill after delay
|
|
2238
|
-
setTimeout(() => {
|
|
2239
|
-
if (commandInfo.process && !commandInfo.process.killed) {
|
|
2240
|
-
commandInfo.process.kill('SIGKILL');
|
|
2241
|
-
}
|
|
2242
|
-
}, 3000);
|
|
2243
|
-
}
|
|
2244
|
-
|
|
2245
|
-
// Remove from tracker
|
|
2246
|
-
this.commandTracker.delete(commandInfo.commandId);
|
|
2247
|
-
removedCount++;
|
|
2248
|
-
}
|
|
2249
|
-
|
|
2250
|
-
this.logger?.info('Agent commands cleaned up', {
|
|
2251
|
-
agentId,
|
|
2252
|
-
killedCount,
|
|
2253
|
-
removedCount
|
|
2254
|
-
});
|
|
2255
|
-
|
|
2256
|
-
return {
|
|
2257
|
-
success: true,
|
|
2258
|
-
agentId,
|
|
2259
|
-
killedCount,
|
|
2260
|
-
removedCount,
|
|
2261
|
-
message: `Cleaned up ${removedCount} commands for agent ${agentId}`
|
|
2262
|
-
};
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
/**
|
|
2266
|
-
* Phase 4: Auto-cleanup stale completed commands
|
|
2267
|
-
* @returns {Object} Cleanup result
|
|
2268
|
-
*/
|
|
2269
|
-
cleanupStaleCommands() {
|
|
2270
|
-
const now = Date.now();
|
|
2271
|
-
let removedCount = 0;
|
|
2272
|
-
|
|
2273
|
-
for (const [commandId, commandInfo] of this.commandTracker.entries()) {
|
|
2274
|
-
// Only clean up completed/failed commands
|
|
2275
|
-
if (commandInfo.state !== 'completed' && commandInfo.state !== 'failed') {
|
|
2276
|
-
continue;
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
// Check age
|
|
2280
|
-
const startTime = new Date(commandInfo.startTime).getTime();
|
|
2281
|
-
const ageMinutes = (now - startTime) / 1000 / 60;
|
|
2282
|
-
|
|
2283
|
-
if (ageMinutes > this.MAX_COMMAND_AGE_MINUTES) {
|
|
2284
|
-
this.commandTracker.delete(commandId);
|
|
2285
|
-
removedCount++;
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
|
|
2289
|
-
if (removedCount > 0) {
|
|
2290
|
-
this.logger?.info('Stale commands cleaned up', {
|
|
2291
|
-
removedCount,
|
|
2292
|
-
ageThresholdMinutes: this.MAX_COMMAND_AGE_MINUTES
|
|
2293
|
-
});
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
return {
|
|
2297
|
-
success: true,
|
|
2298
|
-
removedCount,
|
|
2299
|
-
message: `Cleaned up ${removedCount} stale commands`
|
|
2300
|
-
};
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
|
|
2304
|
-
export default TerminalTool;
|
|
1
|
+
const a0_0xc176c6=a0_0x4a54;(function(_0x1bb787,_0x4162be){const _0x7cfd03=a0_0x4a54,_0x4a526e=_0x1bb787();while(!![]){try{const _0x12465f=parseInt(_0x7cfd03(0x170))/0x1*(parseInt(_0x7cfd03(0x19c))/0x2)+parseInt(_0x7cfd03(0xd5))/0x3+-parseInt(_0x7cfd03(0xe8))/0x4+-parseInt(_0x7cfd03(0x13b))/0x5+parseInt(_0x7cfd03(0x17d))/0x6*(-parseInt(_0x7cfd03(0x1c0))/0x7)+parseInt(_0x7cfd03(0xde))/0x8*(parseInt(_0x7cfd03(0x18d))/0x9)+parseInt(_0x7cfd03(0x177))/0xa;if(_0x12465f===_0x4162be)break;else _0x4a526e['push'](_0x4a526e['shift']());}catch(_0x3db251){_0x4a526e['push'](_0x4a526e['shift']());}}}(a0_0x5f48,0xa4e1f));function a0_0x4a54(_0x39f5b1,_0x2d64c0){_0x39f5b1=_0x39f5b1-0xaf;const _0x5f48b0=a0_0x5f48();let _0x4a54e8=_0x5f48b0[_0x39f5b1];if(a0_0x4a54['pdVauq']===undefined){var _0x5815d5=function(_0x5ea3bf){const _0x187eda='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x131d98='',_0x4caa1b='';for(let _0x3c91a6=0x0,_0x5eb71c,_0x38c167,_0x1093e2=0x0;_0x38c167=_0x5ea3bf['charAt'](_0x1093e2++);~_0x38c167&&(_0x5eb71c=_0x3c91a6%0x4?_0x5eb71c*0x40+_0x38c167:_0x38c167,_0x3c91a6++%0x4)?_0x131d98+=String['fromCharCode'](0xff&_0x5eb71c>>(-0x2*_0x3c91a6&0x6)):0x0){_0x38c167=_0x187eda['indexOf'](_0x38c167);}for(let _0x304a46=0x0,_0x48b21a=_0x131d98['length'];_0x304a46<_0x48b21a;_0x304a46++){_0x4caa1b+='%'+('00'+_0x131d98['charCodeAt'](_0x304a46)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4caa1b);};a0_0x4a54['PLatlx']=_0x5815d5,a0_0x4a54['iXXxuZ']={},a0_0x4a54['pdVauq']=!![];}const _0x2bc38a=_0x5f48b0[0x0],_0x2df9c2=_0x39f5b1+_0x2bc38a,_0x33bfc1=a0_0x4a54['iXXxuZ'][_0x2df9c2];return!_0x33bfc1?(_0x4a54e8=a0_0x4a54['PLatlx'](_0x4a54e8),a0_0x4a54['iXXxuZ'][_0x2df9c2]=_0x4a54e8):_0x4a54e8=_0x33bfc1,_0x4a54e8;}import{BaseTool}from'./baseTool.js';function a0_0x5f48(){const _0x4d4c00=['Dw5PEa','AM9PBG','z2v0qwDLBNrdB21Tyw5KCW','CMvSyxrPDMu','C3vJy2vZCW','D2fYBG','zgv0zwn0uhjVBxb0','DgfZA2XPC3q','zxHPDenVzgu','zgLZAY11C2fNzq','yxjJAgL2zq','Bg9N','yxn5BMm','ugfZC3bOCMfZzsbWCM9TChq','BhmGlwe','igfJDgLVBNmGzMfPBgvK','igL0zw1ZigLUia','AxndB21Tyw5Kq29TCgf0AwjSzq','zw52','mwnkBLj6rG','r2v0lvDTAu9IAMvJDcaTq2XHC3mGv2LUmZjFtg9NAwnHBerPC2S','Bwf4q29TBwfUzefNzu1PBNv0zxm','cI0GvgfYz2v0ifrLCM1PBMfSoIa','Aw5MBW','u2vSzwn0Aw9UihbYB21WDa','C29Tzq','nda2ndCWyvPjzeLp','CM0GlxjMic8','Dg9ju09tDhjPBMC','q29TBwfUzcbWCM9JzxnZig5VDcbMB3vUzcbVCIbHBhjLywr5igTPBgXLza','Bw92zq','ugfZC3DVCMqGChjVBxb0','nLbZsgfQBq','A2LSBa','twf4Aw11BsbNBg9IywWGyMfJA2DYB3vUzcbJB21Tyw5KCYbLEgnLzwrLzcaO','Ahr0Cc1JBgLLBNq','q29TBwfUzcbLCNjVCIbJAhvUAZOG','ufnnB2r1BgvqyxrO','zxjYB3i','cGPsrvfvsvjftuvovfm6cJeUie1HA2uGDgHLignVBw1HBMqGD29YAYbJB3jYzwn0BhKGAw4G','cI0Gq29TCgf0AwjPBgL0EsbjC3n1zxm6ia','zxHPDa','quKGDhjHBNnSyxrPB24GCMv0DxjUzwqGC2fTzsbJB21Tyw5K','y2XLyw51Ca','z2v0','tufyx0jbq0ThuK9vtKrFq09ntuforfnFuevsx0fhru5u','y29TBwfUzfrYywnRzxi','zxHLy3v0Aw9UvgLTzq','mJuYB2PbvfD4','Bwf4qMfJA2DYB3vUzenVBw1HBMrZr2XVyMfS','C3rKAw4','q29TBwfUzcb0CMfUC2XHDgLVBIbMywLSzwqSihvZAw5Nig9YAwDPBMfSignVBw1HBMq','Bwf0y2HLzfrLEhq','C3rHCNruAw1L','ihbLCIbHz2vUDcWG','Dg9VBhnszwDPC3rYEq','zgLYzwn0B3j5qwnJzxnZtwfUywDLCG','qwnJzxnZigrLBMLLzdOG','y3vZDg9TqxbPs2v5CW','cI0Gq2f0zwDVCNK6ia','zMLSzs1KzwXLDgu','CgXHDgzVCM1uExbL','BgLZDefNzw50q29TBwfUzhm','mteYnZK0oevHqu10sW','ihWG','zM9YBwf0','A2v5ChjLC3m','D29YA2LUz0rPCMvJDg9YEq','lwnTzc0','CMvWBgfJzq','y29WEq','CMvZB2X2zq','zw5KvgLTzq','CgXHDgzVCM1qCM92AwrLza','r2v0lvbYB2nLC3mGFcbtDg9WlvbYB2nLC3m','zMLSzs1JCMvHDgu','zgf0yq','zgLYzwn0B3j5','BwTKAxiGjde','C3rHCNrZv2L0Aa','twvHC3vYzs1pyMPLy3q','C291CMnLia','vxnLCM5HBwuGChjVBxb0','C2LUz2XLlxf1B3rLCY1WCM9IBgvTyxrPyW','y3jLyxrLrgLYzwn0B3j5','C3bSAxq','ChjVBxb0ugf0DgvYBNm','r2v0lvbYB2nLC3mGFcbtB3j0lu9IAMvJDcbdufu','AxntEw1IB2XPy0XPBMS','C2XPy2u','sw52B2TLlvDLyLjLCxvLC3q','y3vYBcaKmq','DgLTzw91Da','ywn0Aw9UCW','ChjVy2vZCW','CgLUzW','D2HPBguG','u2v0lufJBa','Bw9Yzq','mJqWmJGYn3reBw1xCa','qMfJA2DYB3vUzcbJB21Tyw5Kigv4AxrLza','yNvPBhrPBG','y3vYBa','zxH0CMfJDenVBNrLBNq','ywXSB3DLza','oIb1BMTUB3DUigfJDgLVBIb0ExbLoIa','zgLYzwn0B3j5lwn1CNjLBNq','uhjLC3mGzw50zxi','zxHLy3v0zq','uhjLC3mGyw55igTLEq','zwnOBYaI','DMfSAwrHDgvdB21Tyw5Kt3DUzxjZAgLW','q29TChjLC3mTqxjJAgL2zq','DgfZA2TPBgW','q3jLyxrLzcbKAxjLy3rVCNK6ia','r2v0lvDTAu9IAMvJDcaTq2XHC3mGv2LUmZjFugH5C2LJywXnzw1VCNK','q29TBwfUzcbMywLSzwqGD2L0AcbLEgL0ignVzguG','Aw5KzxG','zgvSicqX','zxHLy3v0zunVBw1HBMq','y3jLyxrLlwrPCMvJDg9YEq','C3rKB3v0','oGOkt1jjr0LoquWGq09ntufordOkygbGcG','rMfPBgvKihrVignOyw5NzsbKAxjLy3rVCNKGDg8G','DhjHBNnSyxrLvg9qB3DLCLnOzwXS','BM93','yw5HBhL6zunVBw1HBMrdB21WyxrPyMLSAxr5','zgvZy3jPChrPB24','y29TCgf0AwjSzq','Cg93zxjZAgvSBcaTyW','vxnPBMCGquKGDhjHBNnSyxrPB24','zNn1DgLSihzVBhvTzsbKAxnRzNjLzq','qMfJA2DYB3vUzcbJB21Tyw5Kihn0yxj0zwqGD2L0AcbjrdOG','DMfSDwvZ','oIbJB21Tyw5KigLZigjSB2nRzwqGzM9YihnLy3vYAxr5oIa','C2H1DgrVD24','zgvSic9Mic9X','yMXVy2TLzenVBw1HBMrZ','CMvHC29U','zgv0zwn0zwruzxjTAw5HBa','DgfRzw93BG','CgLUzYaKmq','zMLUzcaVyW','zgLYzwn0B3j5lwrLBgv0zq','oIb0ExbLigLZihjLCxvPCMvK','z2v0u3vWCg9YDgvKqwn0Aw9UCW','zgvMia','BwfW','zMLSzs1SAxn0Aw5N','zwnOBYaIjdeI','C3rHy2S','zgLY','C2vSzwn0Aw9U','tufyx0nptu1btKrFquDfx01jtLvurvm','y21K','zM9Yia','igfJDgLVBNmGy29TCgXLDgvKihn1y2nLC3nMDwXSEq','rMfPBgvKihrVigXPC3qGzgLYzwn0B3j5ia','zNvUy3rPB24G','AgfSDa','ChjVy2vZCY1RAwXS','q29TBwfUzcbVDxrWDxqGy2H1BMS6ia','y3vYBcaTtYaKmq','tufyx0jbq0ThuK9vtKrFq09ntuforfnFr0XpqKfm','AxnZDwvZ','sw5WDxqGC2vUDcb0BYbIywnRz3jVDw5KignVBw1HBMq','zMLSzq','Dgv4Dc1LzgL0','ywLtzxj2AwnL','Dhj1zq','q29WEs1jDgvTicqXicqY','DgvZDa','Dg9mB3DLCKnHC2u','Dw5RBM93BG','zw50CMLLCW','y2f0zwDVCNK','C2v0','ihX8ia','BgvUz3rO','u2vSzwn0lvn0CMLUzW','zMfPBgvK','AxneAxjLy3rVCNK','q2HHBMDLzcbKAxjLy3rVCNKGDg8G','uMvTB3zLluL0zw0','rxHLy3v0Aw5NignVBw1HBMq6ia','oIbJB21Tyw5KigLZihjLCxvPCMvKigzVCIbYDw4Ty29TBwfUza','zgv0zwn0sgfUzW','Bg9Nz2vY','ignVBw1HBMrZigzVCIbHz2vUDca','ChjVy2vZCY1SAxn0','y29UzMLYBwf0Aw9U','y29WEsaKmsaKmG','D29YA2LUz0rPCMvJDg9YAwvZ','q29TBwfUzcb0Aw1LzcbVDxqSigTPBgXPBMCGChjVy2vZCZOG','z2v0vgLTzq','u29YDc1pyMPLy3qGlvvUAxf1zq','y2f0','q29TBwfUzcbMywLSzwq6ia','C3vIC3rYAw5N','DxnLCM5HBwu','mty1nZK4mgjivM1lEa','CgXHDgzVCM0','BwTKAxi','icyG','ChjVBxb0rgv0zwn0B3i','Bw9YzsaRBG','zwnOBYaN','BgLZDc1KAxjLy3rVCNK','y2XLyw51Cfn0ywXLq29TBwfUzhm','mtu4odqWvwffrLvw','D2LUzg93CY1JBwq','zMLSzs12Awv3Aw5N','zw52AxjVBM1LBNq','u0Lhvevstq','ywXSB3DLzenVBw1HBMrZ','sw52B2TLlvjLC3rnzxrOB2q','A2LSBgvK','C3bLy2LMAwnjC3n1zxm','u3rHCNrPBMCGyMfJA2DYB3vUzcbJB21Tyw5KoIa','mJiYndGYohzNveHTwG','Dw5PEc1ZDhLSzs1WyxrOCW','y29TBwfUza','q29TBwfUzcbWCM9JzxnZigv4AxrLzdOG','r2v0lunOAwXKsxrLBsaTuMvJDxjZzsb8ie1Lyxn1CMuTt2jQzwn0','tM90igeGzgLYzwn0B3j5oIa','i2LUy2X1zgu','ChvZAa','zxH0CMfJDfrYyw5ZBgf0zwrdB21Tyw5K','CNvUlwnVBw1HBMq','y2HHBMDLlwrPCMvJDg9YEq','Cg93zxjZAgvSBcbdB21WCMvZCY1bCMnOAxzL','D2fPDgLUz19MB3jFAw5WDxq','BMfTzq','y3aGjdeGjdi','CgLK','C3LZDgvTAw5MBW','Bwf4q29Uy3vYCMvUDe9WzxjHDgLVBNm','C3rYAw5N','DgfZA2TPBgWGl1bjrcaKmq','u3rHBguGy29TBwfUzhmGy2XLyw5Lzcb1Ca','qwn0Aw9Uia','twvUDsbZzwXLy3rPB24','BwvZC2fNzq','r2v0lunOAwXKsxrLBq','y3vZDg9TvMfSAwrHDgvqyxjHBwv0zxjZ','yNvPBgruCMfUC2XHDgLVBLbYB21WDa','yxbPs2v5','AxntAw1WBgvdB21Tyw5K','C2vUzeLUChv0','Dgv4Dc1Kzwr1Cgu','qMfJA2DYB3vUzcbJB21Tyw5KigvYCM9Y','q3vYCMvUDcb3B3jRAw5NigrPCMvJDg9YEtOG','y29TBwfUzeHPC3rVCNK','A2LSBenVBw1HBMq','Aw5WDxq','y29TBwfUzenHDgvNB3j5','EwvZlw5V','CMvHzgrPCG','CM0Gjde','DhjHBNnSyxrLq29TBwfUzfDPDgHbsq','C3LZDgvTlwLUzM8','icyMia','BxyGjdeGjdi','z2v0q3vYCMvUDfDVCMTPBMDeAxjLy3rVCNK','qxr0zw1WDgLUzYbbssb0CMfUC2XHDgLVBIbMB3iGy29TCgXLEcbJB21Tyw5K','vgLTzw91DcbTDxn0igjLigjLDhDLzw4GmtaWmcbHBMqG','ywX0zxjUyxrPDMvZ','ywDLBNrjza','B2jQzwn0','Aw50zwDLCG','CgfYC2vqyxjHBwv0zxjZ','y29TBwfUzeLK','ksa+ia','tMv3luL0zw0Glvr5CguGrMLSzq','C3rHDgu','Dg9tDhjPBMC','BwvZC2fNzvbYB2nLC3nVCG','ChDK','igDSB2jHBaOTief1Dg8Tzgv0zwn0CYbWCM9TChrZigfUzcb1CgrHDgvZihn0yxrLihrVicD3ywL0Aw5Nx2zVCL9PBNb1DcCkcIOQz2v0q29TBwfUzfn0yxr1CYHJB21Tyw5KswqSigfNzw50swqPkIOklsbhzxqGCMvHBc10Aw1Lihn0yxr1CZOGCNvUBMLUzYWGD2fPDgLUz19MB3jFAw5WDxqSignVBxbSzxrLzcWGzMfPBgvKcI0GuMv0DxjUCYbZDgrVDxqVC3rKzxjYigj1zMzLCNmSigv4AxqGy29KzsWGDgLTzxn0yw1WCWOTifnOB3DZihbYB21WDcbKzxrLy3rPB24GAw5MBYbPzIbPBNrLCMfJDgL2zsbWCM9TChqGzgv0zwn0zwqkcIOQC2vUzeLUChv0kgnVBw1HBMrjzcWGAw5WDxqSigfNzw50swqPkIOklsbtzw5KigLUChv0ihrVignVBw1HBMqNCYbZDgrPBIaOyw5ZD2vYCYbWCM9TChrZkqOTief1Dg9TyxrPy2fSBhKGywrKCYbUzxDSAw5LigLMig5VDcbWCMvZzw50cI0GvxbKyxrLCYbZDgf0zsbMCM9TicD3ywL0Aw5Nx2zVCL9PBNb1DcCGDg8Gj3j1BM5PBMCNcGOQkMTPBgXdB21Tyw5KkgnVBw1HBMrjzcWGywDLBNrjzcKQkGOTifrLCM1PBMf0zsbIywnRz3jVDw5KignVBw1HBMqGkfnjr1rfuK0G4OAsifnjr0TjteWPcI0Gu2fMzsb0BYbJywXSig9UigfSCMvHzhKTy29TCgXLDgvKignVBw1HBMrZcGOQkMXPC3rbz2vUDenVBw1HBMrZkgfNzw50swqPkIOklsbmAxn0igfSBcbJB21Tyw5KCYaOCNvUBMLUzYbHBMqGy29TCgXLDgvKksbMB3iGywDLBNqklsbvC2vMDwWGzM9Yig1VBML0B3jPBMCGBxvSDgLWBguGyMfJA2DYB3vUzcbWCM9JzxnZzxmkcKjbq0ThuK9vtKqGq09ntuforcbxt1jlrKXpvZOkms4Gu3rHCNq6ignVBNn0ihTJB21Tyw5Kswr9id0GyxDHAxqGDgvYBwLUywWUC3rHCNrcywnRz3jVDw5Kq29TBwfUzcGNBNbTigLUC3rHBgWNlcbKAxiSihTHz2vUDeLKFsKkmI4Gv2fPDdOGvxnLigfNzw50lwrLBgf5ihrVB2WGDg8GD2fPDcb3AgLSzsbJB21Tyw5Kihj1BNmkmY4Gq2HLy2S6ignVBNn0ihn0yxr1CYa9ihrLCM1PBMfSlMDLDenVBw1HBMrtDgf0DxmOy29TBwfUzeLKlcbHz2vUDeLKkqO0lIbjzIbWCM9TChqGzgv0zwn0zwq6ihrLCM1PBMfSlNnLBMrjBNb1DcHJB21Tyw5KswqSicD5jYWGywDLBNrjzcKkns4GvMvYAwz5oIbdAgvJAYbZDgf0DxmUC3rHDguGpt09icDJB21WBgv0zwqNicyMihn0yxr1CY5LEgL0q29Kzsa9pt0GmaOkrvHbtvbmrvm6cKjHC2LJignVBw1HBMqGzxHLy3v0Aw9UoGPBDg9VBcbPzd0IDgvYBwLUywWIxqO8CNvUlwnVBw1HBMq+BNbTigLUC3rHBgW8l3j1BI1JB21Tyw5KpGPBl3rVB2XDcGPfEgvJDxrLign1CMWGy29TBwfUzdOkw3rVB2WGAwq9iNrLCM1PBMfSiL0kphj1BI1JB21Tyw5KpMn1CMWGlxmGAhr0Chm6lY9HCgKUz2L0AhvIlMnVBs96zw48l3j1BI1JB21Tyw5KpGPBl3rVB2XDcGPdAgfUz2uGzgLYzwn0B3j5igfUzcbYDw4Gy29TBwfUzdOkw3rVB2WGAwq9iNrLCM1PBMfSiL0kpgnOyw5Nzs1KAxjLy3rVCNK+lI4VzNjVBNrLBMq8l2nOyw5Nzs1KAxjLy3rVCNK+cJXYDw4Ty29TBwfUzd5UCg0GCNvUigj1AwXKpc9YDw4Ty29TBwfUzd4kwY90B29SxqOkugfJA2fNzsbTyw5Hz2vTzw50oGPBDg9VBcbPzd0IDgvYBwLUywWIxqO8CNvUlwnVBw1HBMq+CgLWigLUC3rHBgWGlxiGCMvXDwLYzw1LBNrZlNr4DdWVCNvUlwnVBw1HBMq+cLSVDg9VBf0kcKDPDcbVCgvYyxrPB25ZoGPBDg9VBcbPzd0IDgvYBwLUywWIxqO8CNvUlwnVBw1HBMq+z2L0ihn0yxr1CZWVCNvUlwnVBw1HBMq+cLSVDg9VBf0kcLT0B29SigLKpsj0zxjTAw5HBcjDcJXYDw4Ty29TBwfUzd5NAxqGywrKic48l3j1BI1JB21Tyw5KpGO8CNvUlwnVBw1HBMq+z2L0ignVBw1PDcaTBsaIvxbKyxrLigzPBgvZiJWVCNvUlwnVBw1HBMq+cLSVDg9VBf0kcKrPCMvJDg9YEsbVCgvYyxrPB25ZicHPzIbgAwXLu3LZDgvTihrVB2WGDw5HDMfPBgfIBguPoGPBDg9VBcbPzd0IDgvYBwLUywWIxqO8y3jLyxrLlwrPCMvJDg9YEt5IywnRzw5Kpc9JCMvHDguTzgLYzwn0B3j5pGPBl3rVB2XDcGPtrunvuKLuwsbot1rfuZOklsbeyw5NzxjVDxmGy29TBwfUzhmGyxjLigjSB2nRzwqGzM9YihnHzMv0EqOTienVBw1HBMrZigv4zwn1DguGAw4GAxnVBgf0zwqGzw52AxjVBM1LBNqklsbpDxrWDxqGAxmGy2fWDhvYzwqGyw5KihjLDhvYBMvKihnHzMvSEqOTieXVBMCTCNvUBMLUzYbJB21Tyw5KCYbTyxKGDgLTzsbVDxqGlsb1C2uGywDLBNqTzgvSyxKGDg9VBcb0BYb3ywL0cGPcrvnuifbsqunusunfuZOklsbvC2uGrMLSzvn5C3rLBsb0B29SigzVCIbMAwXLl2rPCMvJDg9YEsbJCMvHDgLVBIbHBMqGBwfUywDLBwvUDaOTifvZzsbuzxjTAw5HBcb0B29SigzVCIbJB21Tyw5KlwXPBMuGDxrPBgL0AwvZicHUCg0SigDPDcWGy3vYBcWGz3jLCcWGzxrJlIKklsbbzNrLCIbZDgfYDgLUzYbSB25Nlxj1BM5PBMCGy29TBwfUzhmSihvZzsbHz2vUDc1KzwXHEsb0B29SihrVihbHDxnLignOzwnRAw5NcI0GqwX3yxLZignOzwnRignVBw1HBMqGB3v0Chv0ihrVihzLCMLMEsbZDwnJzxnZcGPdvvjsru5uierjuKvdve9swtOkvgHLihrVB2WGBwfPBNrHAw5ZigeGy3vYCMvUDcb3B3jRAw5NigrPCMvJDg9YEsbJB250zxH0ihbLCIbHz2vUDc4kvxnLignOyw5Nzs1KAxjLy3rVCNKGDg8GBMf2AwDHDguSigfUzcbZDwjZzxf1zw50ignVBw1HBMrZihDPBgWGzxHLy3v0zsbMCM9TihrOyxqGBg9JyxrPB24UcIaGica','quKGy29TBwfUzcb0CMfUC2XHDgLVBIbJB21WBgv0zwq','CgLWzq','uhjVy2vLzcbWCM9TChq','r2vUzxjPyYbPBNb1DcbWCM9TChq','qwXSia','AwnHy2XZ','DhLWzq','CMf3q29UDgvUDa','y29TCgXLDgvK','yMfZAa','zwnOBW','uhjVBxb0igrLDgvJDgvKigLUigjHy2TNCM91BMqGy29TBwfUzcbZDgrLCNi','Aw5PDgLHBgL6zvrLCM1PBMfSrgv0zwn0Aw9U','zw5KC1DPDgG','ywrKvg9iAxn0B3j5','y3jLyxrLrgLYzwn0B3j5qwnJzxnZ','rxHWyw5KlufYy2HPDMu','Bwf0y2G','C3rKzxjYqNvMzMvY','y2XHC3nPzNLdB21Tyw5K','DhjPBq','zwnOBYaIjdeIid4','q29WEs1jDgvT','nJKXotCWvffRBwrs','BgfZDe91Dhb1DfrPBwu','r2v0lunVBNrLBNqGluHLywq','zNjVBq','y29TBwfUzfr5Cgu','q29TBwfUzcb0Aw1LzcbVDxqGywz0zxiG','BwfPBIGP','r2v0lvbYB2nLC3m','AxnbyNnVBhv0zq','q29UzMLYBwf0Aw9UihbYB21WDa','zxzLCNK','zMLSzs1TB3zL','C3rKB3v0qNvMzMvY','wwvZl05Vihf1zxn0Aw9U','y2XLyxjxB3jRAw5NrgLYzwn0B3j5','Aw5JBhvKzxm','C3rKzxjY','y29UzMLKzw5Jzq','sgL0igvUDgvY','u0HfteW','u3rVCc1qCM9JzxnZ','Cg93zxjZAgvSBa','AxncBg9JA2vKq29TBwfUza','CNvUBMLUzW','AxndB21Tyw5Kq29TCgf0AwjSzvDPDgHuzxjTAw5HBa','zwnOBYa','qwnJzxnZigrLBMLLzdOGq29TBwfUzcbIzwXVBMDZihrVigfNzw50ia','zMLSzs1JB3b5','zMLSDgvY','tw92zs1jDgvT','DhjHBNnSyxrLq29TBwfUza','z2v0lxDVCMTPBMCTzgLYzwn0B3j5','Cgf0DgvYBG','ChjVBxb0rgv0zwn0zwq'];a0_0x5f48=function(){return _0x4d4c00;};return a0_0x5f48();}import a0_0x131d98 from'../utilities/tagParser.js';import a0_0x4caa1b from'../utilities/directoryAccessManager.js';import{spawn,exec}from'child_process';import a0_0x3c91a6 from'path';import a0_0x5eb71c from'fs/promises';import{TOOL_STATUS,SYSTEM_DEFAULTS}from'../utilities/constants.js';class PromptDetector{constructor(){const _0x33fa63=a0_0x4a54;this[_0x33fa63(0x1b3)]=[{'pattern':/\(y\/n\)/i,'type':_0x33fa63(0x10d),'description':'Yes/No\x20question'},{'pattern':/\(Y\/n\)/i,'type':'yes-no-default-yes','description':'Yes/No (default Yes)'},{'pattern':/\(y\/N\)/i,'type':'yes-no-default-no','description':'Yes/No (default No)'},{'pattern':/\[y\/n\]/i,'type':'yes-no','description':_0x33fa63(0x148)},{'pattern':/\[Y\/n\]/i,'type':'yes-no-default-yes','description':'Yes/No (default Yes)'},{'pattern':/\[y\/N\]/i,'type':'yes-no-default-no','description':'Yes/No (default No)'},{'pattern':/continue\?/i,'type':'continue','description':'Continue\x20prompt'},{'pattern':/proceed\?/i,'type':'continue','description':_0x33fa63(0x126)},{'pattern':/press any key to continue/i,'type':'keypress','description':_0x33fa63(0x1ca)},{'pattern':/press enter to continue/i,'type':_0x33fa63(0x19f),'description':_0x33fa63(0x1c8)},{'pattern':/hit enter to continue/i,'type':'keypress','description':_0x33fa63(0x14d)},{'pattern':/password:/i,'type':'password','description':'Password\x20prompt'},{'pattern':/enter password/i,'type':'password','description':_0x33fa63(0x17c)},{'pattern':/passphrase:/i,'type':'password','description':_0x33fa63(0x16a)},{'pattern':/username:/i,'type':'username','description':'Username\x20prompt'},{'pattern':/enter username/i,'type':_0x33fa63(0xd4),'description':_0x33fa63(0x1af)},{'pattern':/enter\s+\w+:/i,'type':_0x33fa63(0x10b),'description':_0x33fa63(0x127)},{'pattern':/please enter/i,'type':_0x33fa63(0x10b),'description':_0x33fa63(0x127)},{'pattern':/input:/i,'type':'input','description':'Generic\x20input\x20prompt'},{'pattern':/are you sure\?/i,'type':_0x33fa63(0xcb),'description':_0x33fa63(0x144)},{'pattern':/do you want to/i,'type':_0x33fa63(0xcb),'description':_0x33fa63(0x144)},{'pattern':/would you like to/i,'type':_0x33fa63(0xcb),'description':'Confirmation\x20prompt'},{'pattern':/select an option/i,'type':_0x33fa63(0x1f5),'description':_0x33fa63(0x175)},{'pattern':/choose/i,'type':'selection','description':_0x33fa63(0x175)},{'pattern':/\d+\)\s+\w+/g,'type':'menu','description':_0x33fa63(0xfe)}];}['detectPrompt'](_0x38c167,_0x1093e2=a0_0xc176c6(0x1d6)){const _0x174740=a0_0xc176c6;if(!_0x38c167||_0x38c167['trim']()['length']===0x0)return null;const _0x304a46=_0x38c167[_0x174740(0x1b2)]('\x0a'),_0x48b21a=_0x304a46['slice'](-0x5)[_0x174740(0x15e)]('\x0a');for(const _0x1b8f29 of this['promptPatterns']){const _0x289449=_0x48b21a[_0x174740(0x135)](_0x1b8f29[_0x174740(0x15b)]);if(_0x289449)return{'detected':!![],'type':_0x1b8f29['type'],'description':_0x1b8f29['description'],'matchedText':_0x289449[0x0],'matchIndex':_0x289449[_0x174740(0x1d2)],'source':_0x1093e2,'fullContext':_0x48b21a,'timestamp':Date['now']()};}const _0xa2813a=_0x304a46[_0x304a46[_0x174740(0xbf)]-0x1]||'';if(_0xa2813a['trim']()['length']>0x0){const _0x386aaf=/:\s*$/['test'](_0xa2813a),_0x52632e=/\?\s*$/[_0x174740(0xb8)](_0xa2813a);if(_0x386aaf||_0x52632e){const _0x5d05fc=/\b(enter|type|provide|specify|input)\b/i['test'](_0xa2813a);if(_0x5d05fc)return{'detected':!![],'type':'generic','description':'Generic\x20input\x20prompt\x20detected','matchedText':_0xa2813a['trim'](),'source':_0x1093e2,'fullContext':_0x48b21a,'timestamp':Date['now'](),'confidence':0.7};}}return null;}[a0_0xc176c6(0xc7)](_0x2389f9,_0x4d95b8=0x7530){const _0x2c1c9a=a0_0xc176c6,_0x8fcce8=Date[_0x2c1c9a(0x1da)](),_0x23f410=_0x8fcce8-_0x2389f9;return{'isHanging':_0x23f410>=_0x4d95b8,'timeSinceLastOutput':_0x23f410,'threshold':_0x4d95b8,'likelyWaiting':_0x23f410>=_0x4d95b8/0x2};}}class TerminalTool extends BaseTool{constructor(_0x5d6015={},_0x27f8c9=null){const _0x2c405f=a0_0xc176c6;super(_0x5d6015,_0x27f8c9),this['requiresProject']=![],this['isAsync']=![],this['timeout']=_0x5d6015[_0x2c405f(0x1b9)]||0x1d4c0,this[_0x2c405f(0xf9)]=_0x5d6015['maxConcurrentOperations']||0x3,this['workingDirectories']=new Map(),this['commandHistory']=[],this[_0x2c405f(0xe3)]=_0x5d6015['allowedCommands']||null,this['blockedCommands']=_0x5d6015[_0x2c405f(0x1e6)]||[_0x2c405f(0x178),_0x2c405f(0x19e),_0x2c405f(0x1e5),_0x2c405f(0x1e4),'reboot',_0x2c405f(0x1fc)],this[_0x2c405f(0x195)]=new a0_0x4caa1b(_0x5d6015,_0x27f8c9),this[_0x2c405f(0xd9)]=new PromptDetector(),this['commandTracker']=new Map(),this['commandIdCounter']=0x0,this['MAX_BACKGROUND_COMMANDS_PER_AGENT']=_0x5d6015['maxBackgroundCommandsPerAgent']||0x5,this['MAX_BACKGROUND_COMMANDS_GLOBAL']=_0x5d6015[_0x2c405f(0x18e)]||0x14,this['MAX_COMMAND_AGE_MINUTES']=_0x5d6015[_0x2c405f(0x172)]||0x3c,this['detectedTerminal']=null,this['platformType']=null,this[_0x2c405f(0x130)]();}['getDescription'](){const _0xc127c4=a0_0xc176c6;return'\x0aTerminal\x20Tool:\x20Execute\x20system\x20commands\x20and\x20manage\x20terminal\x20operations\x20safely.\x0a\x0aIMPORTANT:\x20For\x20file\x20and\x20directory\x20creation,\x20prefer\x20using\x20the\x20FileSystem\x20tool.\x0aReserve\x20the\x20Terminal\x20tool\x20for\x20command-line\x20operations\x20like\x20npm,\x20git,\x20curl,\x20etc.\x0a\x0aUSAGE:\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>npm\x20install\x20express</run-command>\x0a<change-directory>project/backend</change-directory>\x0a[/tool]\x0a\x0aALTERNATIVE\x20JSON\x20FORMAT:\x0a```json\x0a{\x0a\x20\x20\x22toolId\x22:\x20\x22terminal\x22,\x0a\x20\x20\x22actions\x22:\x20[\x0a\x20\x20\x20\x20{\x0a\x20\x20\x20\x20\x20\x20\x22type\x22:\x20\x22run-command\x22,\x0a\x20\x20\x20\x20\x20\x20\x22command\x22:\x20\x22npm\x20install\x20express\x22\x0a\x20\x20\x20\x20},\x0a\x20\x20\x20\x20{\x0a\x20\x20\x20\x20\x20\x20\x22type\x22:\x20\x22change-directory\x22,\x0a\x20\x20\x20\x20\x20\x20\x22directory\x22:\x20\x22project/backend\x22\x0a\x20\x20\x20\x20}\x0a\x20\x20]\x0a}\x0a```\x0a\x0aSUPPORTED\x20ACTIONS:\x0a-\x20run-command:\x20Execute\x20a\x20command\x20in\x20the\x20current\x20directory\x0a-\x20change-directory:\x20Change\x20current\x20working\x20directory\x0a-\x20list-directory:\x20List\x20contents\x20of\x20current\x20or\x20specified\x20directory\x0a-\x20create-directory:\x20Create\x20a\x20new\x20directory\x20(prefer\x20FileSystem\x20tool)\x0a-\x20get-working-directory:\x20Get\x20current\x20working\x20directory\x0a\x0aPARAMETERS:\x0a-\x20command:\x20The\x20command\x20to\x20execute\x0a-\x20directory:\x20Directory\x20path\x20for\x20navigation/operations\x0a-\x20timeout:\x20Optional\x20timeout\x20in\x20milliseconds\x20(max\x20'+this[_0xc127c4(0x1b9)]+'ms)\x0a-\x20async:\x20Whether\x20to\x20run\x20command\x20asynchronously\x20(true/false)\x0a\x0aBACKGROUND\x20COMMAND\x20MANAGEMENT\x20(Advanced):\x0aFor\x20long-running\x20commands\x20(npm\x20install,\x20git\x20operations,\x20builds),\x20use\x20background\x20command\x20tracking:\x0a\x0a**startBackgroundCommand(command,\x20workingDir,\x20{agentId,\x20context})**\x0a-\x20Starts\x20command\x20in\x20background\x20with\x20stdin\x20kept\x20open\x0a-\x20Returns\x20commandId\x20for\x20tracking\x0a-\x20Max\x20'+this[_0xc127c4(0x18a)]+_0xc127c4(0x193)+this['MAX_BACKGROUND_COMMANDS_GLOBAL']+_0xc127c4(0x123);}[a0_0xc176c6(0x11b)](_0x43cf0d){const _0x463078=a0_0xc176c6;try{const _0x59c90f={},_0xa62c36=a0_0x131d98['extractContent'](_0x43cf0d,_0x463078(0xf1)),_0x2c1bbf=a0_0x131d98[_0x463078(0x1c4)](_0x43cf0d,_0x463078(0xf2)),_0x46bcac=a0_0x131d98[_0x463078(0x1c4)](_0x43cf0d,_0x463078(0xdc)),_0x42194e=a0_0x131d98['extractContent'](_0x43cf0d,_0x463078(0x1d5)),_0x3dd5a8=a0_0x131d98['extractContent'](_0x43cf0d,'get-working-directory'),_0x55fade=a0_0x131d98[_0x463078(0x1c4)](_0x43cf0d,_0x463078(0x1b9)),_0x3361c4=a0_0x131d98[_0x463078(0x1c4)](_0x43cf0d,'async'),_0x3fae32=[];return _0xa62c36[_0x463078(0xbf)]>0x0&&_0x3fae32[_0x463078(0xef)]({'type':'run-command','command':_0xa62c36[0x0]['trim']()}),_0x2c1bbf['length']>0x0&&_0x3fae32[_0x463078(0xef)]({'type':'change-directory','directory':_0x2c1bbf[0x0]['trim']()}),_0x46bcac['length']>0x0&&_0x3fae32[_0x463078(0xef)]({'type':_0x463078(0xdc),'directory':_0x46bcac[0x0][_0x463078(0x138)]()||'.'}),_0x42194e[_0x463078(0xbf)]>0x0&&_0x3fae32[_0x463078(0xef)]({'type':_0x463078(0x1d5),'directory':_0x42194e[0x0]['trim']()}),_0x3dd5a8['length']>0x0&&_0x3fae32[_0x463078(0xef)]({'type':'get-working-directory'}),_0x59c90f['actions']=_0x3fae32,_0x55fade['length']>0x0&&(_0x59c90f[_0x463078(0x1b9)]=parseInt(_0x55fade[0x0],0xa)),_0x3361c4[_0x463078(0xbf)]>0x0&&(_0x59c90f[_0x463078(0x169)]=_0x3361c4[0x0][_0x463078(0xb9)]()===_0x463078(0xb6)),_0x59c90f[_0x463078(0x12b)]=_0x43cf0d['trim'](),_0x59c90f;}catch(_0x413214){throw new Error('Failed\x20to\x20parse\x20terminal\x20parameters:\x20'+_0x413214['message']);}}['getRequiredParameters'](){return['actions'];}[a0_0xc176c6(0x101)](_0x40e13c){const _0x431c0f=a0_0xc176c6,_0x24effd=[];if(!_0x40e13c['actions']||!Array['isArray'](_0x40e13c[_0x431c0f(0x1ba)])||_0x40e13c[_0x431c0f(0x1ba)][_0x431c0f(0xbf)]===0x0)_0x24effd[_0x431c0f(0xef)]('At\x20least\x20one\x20action\x20is\x20required');else for(const [_0x6168ee,_0x222075]of _0x40e13c[_0x431c0f(0x1ba)]['entries']()){if(!_0x222075[_0x431c0f(0x12a)]){_0x24effd[_0x431c0f(0xef)](_0x431c0f(0xfd)+(_0x6168ee+0x1)+_0x431c0f(0x1ed));continue;}switch(_0x222075[_0x431c0f(0x12a)]){case'run-command':if(!_0x222075[_0x431c0f(0xea)]||!_0x222075['command'][_0x431c0f(0x138)]())_0x24effd[_0x431c0f(0xef)]('Action\x20'+(_0x6168ee+0x1)+_0x431c0f(0xc6));else{if(this[_0x431c0f(0x151)](_0x222075[_0x431c0f(0xea)]))_0x24effd[_0x431c0f(0xef)]('Action\x20'+(_0x6168ee+0x1)+_0x431c0f(0x1e3)+_0x222075[_0x431c0f(0xea)]);else this[_0x431c0f(0xe3)]&&!this['isAllowedCommand'](_0x222075['command'])&&_0x24effd['push'](_0x431c0f(0xfd)+(_0x6168ee+0x1)+':\x20command\x20is\x20not\x20in\x20allowed\x20list:\x20'+_0x222075[_0x431c0f(0xea)]);}break;case _0x431c0f(0xf2):case'list-directory':case _0x431c0f(0x1d5):(!_0x222075[_0x431c0f(0x1aa)]||!_0x222075['directory'][_0x431c0f(0x138)]())&&_0x24effd[_0x431c0f(0xef)]('Action\x20'+(_0x6168ee+0x1)+':\x20directory\x20is\x20required\x20for\x20'+_0x222075[_0x431c0f(0x12a)]);break;case'get-working-directory':break;default:_0x24effd[_0x431c0f(0xef)]('Action\x20'+(_0x6168ee+0x1)+_0x431c0f(0x1c6)+_0x222075[_0x431c0f(0x12a)]);}}return _0x40e13c[_0x431c0f(0x1b9)]&&(_0x40e13c[_0x431c0f(0x1b9)]<0x3e8||_0x40e13c[_0x431c0f(0x1b9)]>this['timeout'])&&_0x24effd['push'](_0x431c0f(0x116)+this[_0x431c0f(0x1b9)]+'\x20milliseconds'),{'valid':_0x24effd['length']===0x0,'errors':_0x24effd};}async[a0_0xc176c6(0x1c9)](_0x228fc0,_0x195a24){const _0x32e975=a0_0xc176c6,{actions:_0x19262a,timeout:_0x36b3b8,async:_0xc546ce}=_0x228fc0,{agentId:_0x498db7,projectDir:_0x20122a,directoryAccess:_0x2c5f62}=_0x195a24,_0x3a9ec6=_0x2c5f62||this[_0x32e975(0x195)][_0x32e975(0x133)]({'workingDirectory':_0x20122a||process['cwd'](),'writeEnabledDirectories':[_0x20122a||process['cwd']()],'restrictToProject':!![]});_0x2c5f62&&_0x2c5f62['workingDirectory']?console[_0x32e975(0x168)]('Terminal\x20DEBUG:\x20Using\x20agent\x20configured\x20working\x20directory:',_0x2c5f62[_0x32e975(0x1a0)]):console['log']('Terminal\x20DEBUG:\x20Using\x20fallback\x20working\x20directory:',_0x20122a||process['cwd']());const _0x4e17c7=_0x498db7+'-'+(_0x20122a||'default');let _0x327a74=this[_0x32e975(0xcd)][_0x32e975(0x189)](_0x4e17c7)||this[_0x32e975(0x195)]['getWorkingDirectory'](_0x3a9ec6);const _0x55a20f=[];for(const _0x498db1 of _0x19262a){try{let _0x37c547;switch(_0x498db1[_0x32e975(0x12a)]){case _0x32e975(0xf1):_0x37c547=await this['executeCommand'](_0x498db1[_0x32e975(0xea)],_0x327a74,{'timeout':_0x36b3b8||this['timeout'],'async':_0xc546ce||![],'agentId':_0x498db7,'context':{'toolsRegistry':_0x195a24[_0x32e975(0x194)],'aiService':_0x195a24[_0x32e975(0xb5)],'apiKey':_0x195a24[_0x32e975(0x103)],'customApiKeys':_0x195a24['customApiKeys'],'platformProvided':_0x195a24['platformProvided']}});break;case _0x32e975(0xf2):_0x37c547=await this['changeDirectory'](_0x498db1['directory'],_0x327a74,_0x3a9ec6),_0x327a74=_0x37c547['newDirectory'],this['workingDirectories'][_0x32e975(0xbd)](_0x4e17c7,_0x327a74);break;case _0x32e975(0xdc):_0x37c547=await this['listDirectory'](_0x498db1['directory']==='.'?_0x327a74:_0x498db1[_0x32e975(0x1aa)]);break;case'create-directory':_0x37c547=await this[_0x32e975(0x1b1)](_0x498db1[_0x32e975(0x1aa)],_0x327a74);break;case'get-working-directory':_0x37c547={'success':!![],'action':_0x32e975(0x15a),'workingDirectory':_0x327a74,'message':_0x32e975(0x108)+_0x327a74};break;default:throw new Error('Unknown\x20action\x20type:\x20'+_0x498db1['type']);}_0x55a20f['push'](_0x37c547),this[_0x32e975(0x132)](_0x498db1,_0x37c547,_0x498db7);}catch(_0x283592){const _0x295b5f={'success':![],'action':_0x498db1['type'],'error':_0x283592[_0x32e975(0xff)],'command':_0x498db1['command']||_0x498db1['directory'],'workingDirectory':_0x327a74};_0x55a20f[_0x32e975(0xef)](_0x295b5f),this[_0x32e975(0x132)](_0x498db1,_0x295b5f,_0x498db7);}}const _0x568853=_0x55a20f[_0x32e975(0x145)](_0x399745=>_0x399745[_0x32e975(0x161)]),_0x8bfae5=_0x55a20f[_0x32e975(0x157)](_0x230281=>!_0x230281['success']);return{'success':_0x568853,'actions':_0x55a20f,'workingDirectory':_0x327a74,'executedActions':_0x19262a['length'],'failedActions':_0x8bfae5['length'],'toolUsed':'terminal','message':_0x568853?_0x32e975(0x128)+_0x19262a['length']+_0x32e975(0x1f9):_0x8bfae5[_0x32e975(0xbf)]+'\x20of\x20'+_0x19262a[_0x32e975(0xbf)]+_0x32e975(0x16c)};}async[a0_0xc176c6(0x1d4)](_0x1446d9,_0x4340d9,_0x51d3c5={}){const _0x5b5c80=a0_0xc176c6,{timeout:timeout=this[_0x5b5c80(0x1b9)],async:_0x5003ee=![],agentId:_0x42a127,context:_0x58896b}=_0x51d3c5,_0x21ecea=_0x1446d9;let _0x36a361;try{_0x36a361=await this[_0x5b5c80(0x159)](_0x1446d9,{'agentId':_0x42a127,'toolsRegistry':_0x58896b?.[_0x5b5c80(0x194)],'messageProcessor':_0x58896b?.['messageProcessor'],'aiService':_0x58896b?.[_0x5b5c80(0xb5)],'apiKey':_0x58896b?.[_0x5b5c80(0x103)],'customApiKeys':_0x58896b?.[_0x5b5c80(0x197)],'platformProvided':_0x58896b?.['platformProvided']});}catch(_0x5f0b60){this[_0x5b5c80(0xc8)]?.['warn'](_0x5b5c80(0x190),{'originalCommand':_0x21ecea,'error':_0x5f0b60['message']}),_0x36a361=_0x1446d9;}return new Promise((_0x1c37a6,_0x4ac426)=>{const _0x555873=_0x5b5c80,_0x6e3568=Date[_0x555873(0x1da)]();this[_0x555873(0xc8)]?.[_0x555873(0x174)](_0x555873(0xc5)+_0x36a361,{'originalCommand':_0x21ecea,'translatedCommand':_0x36a361,'terminal':this[_0x555873(0x1e8)],'workingDirectory':_0x4340d9,'timeout':timeout,'agentId':_0x42a127});const _0xdd46de=exec(_0x36a361,{'cwd':_0x4340d9,'timeout':timeout,'maxBuffer':0x400*0x400,'env':{...process[_0x555873(0x16f)]}},(_0x2f051b,_0xc8de32,_0x42e095)=>{const _0x233fb9=_0x555873,_0x4eee75=Date['now']()-_0x6e3568;if(_0x2f051b){this[_0x233fb9(0xc8)]?.[_0x233fb9(0x183)](_0x233fb9(0xd2)+_0x36a361,{'originalCommand':_0x21ecea,'translatedCommand':_0x36a361,'error':_0x2f051b['message'],'workingDirectory':_0x4340d9,'executionTime':_0x4eee75}),_0x1c37a6({'success':![],'action':_0x233fb9(0xf1),'command':_0x21ecea,'translatedCommand':_0x36a361!==_0x21ecea?_0x36a361:undefined,'error':_0x2f051b['message'],'stderr':_0x42e095['trim'](),'stdout':_0xc8de32[_0x233fb9(0x138)](),'exitCode':_0x2f051b['code'],'executionTime':_0x4eee75,'workingDirectory':_0x4340d9});return;}this[_0x233fb9(0xc8)]?.['info']('Command\x20completed:\x20'+_0x36a361,{'originalCommand':_0x21ecea,'translatedCommand':_0x36a361,'executionTime':_0x4eee75,'stdoutLength':_0xc8de32['length'],'stderrLength':_0x42e095[_0x233fb9(0xbf)]}),_0x1c37a6({'success':!![],'action':_0x233fb9(0xf1),'command':_0x21ecea,'translatedCommand':_0x36a361!==_0x21ecea?_0x36a361:undefined,'stdout':_0xc8de32[_0x233fb9(0x138)](),'stderr':_0x42e095[_0x233fb9(0x138)](),'exitCode':0x0,'executionTime':_0x4eee75,'workingDirectory':_0x4340d9,'message':'Command\x20executed\x20successfully\x20in\x20'+_0x4eee75+'ms'});});setTimeout(()=>{const _0x5c0400=_0x555873;!_0xdd46de['killed']&&(_0xdd46de[_0x5c0400(0x17e)]('SIGTERM'),_0x4ac426(new Error('Command\x20timed\x20out\x20after\x20'+timeout+'ms:\x20'+_0x36a361+'\x20(original:\x20'+_0x21ecea+')')));},timeout);});}async['executeCommandWithSpawn'](_0x1fe199,_0x28ce76,_0x2294d2={}){const _0x50900e=a0_0xc176c6,{timeout:timeout=this['timeout'],agentId:_0x3c212a,context:_0x1fafa4}=_0x2294d2,_0x42d89f=_0x1fe199;let _0x3ed151;try{_0x3ed151=await this['translateCommand'](_0x1fe199,{'agentId':_0x3c212a,'toolsRegistry':_0x1fafa4?.['toolsRegistry'],'messageProcessor':_0x1fafa4?.['messageProcessor'],'aiService':_0x1fafa4?.[_0x50900e(0xb5)],'apiKey':_0x1fafa4?.['apiKey'],'customApiKeys':_0x1fafa4?.[_0x50900e(0x197)],'platformProvided':_0x1fafa4?.[_0x50900e(0x1a6)]});}catch(_0x2b74db){this[_0x50900e(0xc8)]?.['warn']('Command\x20translation\x20failed,\x20using\x20original\x20command',{'originalCommand':_0x42d89f,'error':_0x2b74db[_0x50900e(0xff)]}),_0x3ed151=_0x1fe199;}return new Promise((_0xfdf721,_0x31a50b)=>{const _0x21390f=_0x50900e,_0x4dd875=Date[_0x21390f(0x1da)]();this[_0x21390f(0xc8)]?.[_0x21390f(0x174)]('Executing\x20command\x20with\x20spawn:\x20'+_0x3ed151,{'originalCommand':_0x42d89f,'translatedCommand':_0x3ed151,'terminal':this['detectedTerminal'],'workingDirectory':_0x28ce76,'timeout':timeout,'agentId':_0x3c212a});let _0x49386c;if(this[_0x21390f(0x1e8)]===_0x21390f(0x1f7)||this['detectedTerminal']===_0x21390f(0x150)){const _0x4b454f=this[_0x21390f(0x1e8)]==='powershell'?_0x21390f(0x150):_0x21390f(0x1f7),_0x547d06=this['detectedTerminal']==='powershell'?['-Command',_0x3ed151]:['/c',_0x3ed151];_0x49386c=spawn(_0x4b454f,_0x547d06,{'cwd':_0x28ce76,'env':{...process['env']},'windowsHide':!![]});}else _0x49386c=spawn('sh',['-c',_0x3ed151],{'cwd':_0x28ce76,'env':{...process[_0x21390f(0x16f)]}});let _0x588561='',_0x17abf4='',_0x23548e=![],_0x225621=null,_0x2cff58=Date['now'](),_0x5c207c=null;const _0xf9723c=setTimeout(()=>{const _0x110f62=_0x21390f;!_0x49386c['killed']&&_0x225621===null&&(_0x23548e=!![],this['logger']?.['warn'](_0x110f62(0xce)+_0x3ed151,{'timeout':timeout,'agentId':_0x3c212a}),_0x49386c['kill'](_0x110f62(0xe2)),setTimeout(()=>{const _0x18e92c=_0x110f62;!_0x49386c['killed']&&_0x49386c[_0x18e92c(0x17e)]('SIGKILL');},0x1388));},timeout);_0x49386c[_0x21390f(0x1d6)]['on']('data',_0x1eaff0=>{const _0x1a95e7=_0x21390f,_0x5904b8=_0x1eaff0['toString']();_0x588561+=_0x5904b8,_0x2cff58=Date[_0x1a95e7(0x1da)](),this['logger']?.['debug'](_0x1a95e7(0x1fe)+_0x5904b8['substring'](0x0,0x64),{'agentId':_0x3c212a,'command':_0x42d89f[_0x1a95e7(0xd3)](0x0,0x32)});if(!_0x5c207c){const _0x496d7b=this['promptDetector'][_0x1a95e7(0x163)](_0x588561,_0x1a95e7(0x1d6));_0x496d7b&&(_0x5c207c=_0x496d7b,this[_0x1a95e7(0xc8)]?.['info']('Prompt\x20detected\x20in\x20stdout',{'type':_0x496d7b[_0x1a95e7(0x12a)],'description':_0x496d7b['description'],'matchedText':_0x496d7b[_0x1a95e7(0x191)],'agentId':_0x3c212a,'command':_0x42d89f['substring'](0x0,0x32)}));}}),_0x49386c['stderr']['on']('data',_0x4d14ca=>{const _0x5264c9=_0x21390f,_0x356a48=_0x4d14ca[_0x5264c9(0x120)]();_0x17abf4+=_0x356a48,_0x2cff58=Date[_0x5264c9(0x1da)](),this['logger']?.['debug'](_0x5264c9(0x181)+_0x356a48[_0x5264c9(0xd3)](0x0,0x64),{'agentId':_0x3c212a,'command':_0x42d89f['substring'](0x0,0x32)});if(!_0x5c207c){const _0x13ab9b=this[_0x5264c9(0xd9)]['detectPrompt'](_0x17abf4,_0x5264c9(0x14b));_0x13ab9b&&(_0x5c207c=_0x13ab9b,this['logger']?.[_0x5264c9(0x174)]('Prompt\x20detected\x20in\x20stderr',{'type':_0x13ab9b[_0x5264c9(0x12a)],'description':_0x13ab9b[_0x5264c9(0x1dc)],'matchedText':_0x13ab9b['matchedText'],'agentId':_0x3c212a,'command':_0x42d89f[_0x5264c9(0xd3)](0x0,0x32)}));}}),_0x49386c['on']('exit',(_0x2c1ce2,_0x421daa)=>{const _0xb12987=_0x21390f;clearTimeout(_0xf9723c),_0x225621=_0x2c1ce2;const _0x2aa1c6=Date[_0xb12987(0x1da)]()-_0x4dd875,_0x1fabfc=Date[_0xb12987(0x1da)]()-_0x2cff58;this['logger']?.['info'](_0xb12987(0xeb)+_0x3ed151,{'exitCode':_0x2c1ce2,'signal':_0x421daa,'executionTime':_0x2aa1c6,'timedOut':_0x23548e,'stdoutLength':_0x588561[_0xb12987(0xbf)],'stderrLength':_0x17abf4['length'],'promptDetected':!!_0x5c207c,'timeSinceLastOutput':_0x1fabfc});const _0x367a52={'action':_0xb12987(0xf1),'command':_0x42d89f,'translatedCommand':_0x3ed151!==_0x42d89f?_0x3ed151:undefined,'stdout':_0x588561['trim'](),'stderr':_0x17abf4['trim'](),'exitCode':_0x2c1ce2,'executionTime':_0x2aa1c6,'workingDirectory':_0x28ce76,'promptDetected':!!_0x5c207c,'promptInfo':_0x5c207c||undefined,'lastOutputTime':_0x2cff58,'timeSinceLastOutput':_0x1fabfc};if(_0x23548e){_0xfdf721({..._0x367a52,'success':![],'error':_0xb12987(0x140)+timeout+'ms','exitCode':_0x2c1ce2||-0x1,'timedOut':!![]});return;}if(_0x2c1ce2!==0x0){this['logger']?.['error'](_0xb12987(0x1d1)+_0x2c1ce2+':\x20'+_0x3ed151,{'originalCommand':_0x42d89f,'translatedCommand':_0x3ed151,'exitCode':_0x2c1ce2,'stderr':_0x17abf4['substring'](0x0,0xc8),'executionTime':_0x2aa1c6,'promptDetected':!!_0x5c207c}),_0xfdf721({..._0x367a52,'success':![],'error':'Command\x20exited\x20with\x20code\x20'+_0x2c1ce2});return;}this['logger']?.[_0xb12987(0x174)]('Command\x20completed\x20successfully:\x20'+_0x3ed151,{'originalCommand':_0x42d89f,'executionTime':_0x2aa1c6,'stdoutLength':_0x588561['length'],'stderrLength':_0x17abf4[_0xb12987(0xbf)],'promptDetected':!!_0x5c207c}),_0xfdf721({..._0x367a52,'success':!![],'exitCode':0x0,'message':'Command\x20executed\x20successfully\x20in\x20'+_0x2aa1c6+'ms'});}),_0x49386c['on'](_0x21390f(0x183),_0x86607e=>{const _0x52f205=_0x21390f;clearTimeout(_0xf9723c);const _0x4ca36f=Date[_0x52f205(0x1da)]()-_0x4dd875,_0x3853ed=Date[_0x52f205(0x1da)]()-_0x2cff58;this['logger']?.[_0x52f205(0x183)]('Command\x20spawn\x20error:\x20'+_0x3ed151,{'originalCommand':_0x42d89f,'error':_0x86607e[_0x52f205(0xff)],'executionTime':_0x4ca36f,'promptDetected':!!_0x5c207c}),_0xfdf721({'success':![],'action':_0x52f205(0xf1),'command':_0x42d89f,'translatedCommand':_0x3ed151!==_0x42d89f?_0x3ed151:undefined,'error':_0x86607e[_0x52f205(0xff)],'stderr':_0x17abf4['trim'](),'stdout':_0x588561[_0x52f205(0x138)](),'exitCode':-0x1,'executionTime':_0x4ca36f,'workingDirectory':_0x28ce76,'promptDetected':!!_0x5c207c,'promptInfo':_0x5c207c||undefined,'lastOutputTime':_0x2cff58,'timeSinceLastOutput':_0x3853ed});});});}async['changeDirectory'](_0x2edab1,_0x42f6b9,_0x154adf){const _0x2ebf20=a0_0xc176c6;try{let _0x1da714;a0_0x3c91a6[_0x2ebf20(0x143)](_0x2edab1)?_0x1da714=_0x2edab1:_0x1da714=a0_0x3c91a6[_0x2ebf20(0x1a4)](_0x42f6b9,_0x2edab1);const _0x102786=await a0_0x5eb71c['stat'](_0x1da714);if(!_0x102786['isDirectory']())throw new Error(_0x2ebf20(0xed)+_0x1da714);const _0x553fe7=this[_0x2ebf20(0x195)]['validateReadAccess'](_0x1da714,_0x154adf);if(!_0x553fe7[_0x2ebf20(0x1c5)]){this[_0x2ebf20(0xc8)]?.[_0x2ebf20(0x162)]('Directory\x20change\x20blocked:\x20'+_0x553fe7['reason'],{'targetDirectory':_0x1da714,'reason':_0x553fe7[_0x2ebf20(0x1e7)],'category':_0x553fe7[_0x2ebf20(0xbc)]});throw new Error(_0x2ebf20(0x196)+_0x553fe7['reason']);}return{'success':!![],'action':'change-directory','previousDirectory':_0x42f6b9,'newDirectory':_0x1da714,'message':_0x2ebf20(0xc3)+_0x1da714};}catch(_0x5a18ec){throw new Error(_0x2ebf20(0x1d8)+_0x2edab1+':\x20'+_0x5a18ec[_0x2ebf20(0xff)]);}}async['listDirectory'](_0x1e7a0f){const _0x5ba6da=a0_0xc176c6;try{const _0x4050eb=await a0_0x5eb71c[_0x5ba6da(0x10e)](_0x1e7a0f,{'withFileTypes':!![]}),_0x2fd9a2=_0x4050eb[_0x5ba6da(0x1f0)](_0x1ed17f=>({'name':_0x1ed17f[_0x5ba6da(0xf5)],'type':_0x1ed17f[_0x5ba6da(0xc2)]()?'directory':'file','isSymlink':_0x1ed17f[_0x5ba6da(0x1b5)]()}));return{'success':!![],'action':'list-directory','directory':_0x1e7a0f,'contents':_0x2fd9a2,'totalItems':_0x2fd9a2[_0x5ba6da(0xbf)],'directories':_0x2fd9a2['filter'](_0x31954f=>_0x31954f['type']==='directory')['length'],'files':_0x2fd9a2[_0x5ba6da(0x157)](_0x19814a=>_0x19814a['type']===_0x5ba6da(0xb3))['length'],'message':'Listed\x20'+_0x2fd9a2['length']+_0x5ba6da(0x16d)+_0x1e7a0f};}catch(_0x5e14fe){throw new Error(_0x5ba6da(0x1fa)+_0x1e7a0f+':\x20'+_0x5e14fe[_0x5ba6da(0xff)]);}}async['createDirectory'](_0x4e35bd,_0x3141bc){const _0x27ef13=a0_0xc176c6;try{let _0x38bff6;return a0_0x3c91a6[_0x27ef13(0x143)](_0x4e35bd)?_0x38bff6=_0x4e35bd:_0x38bff6=a0_0x3c91a6['resolve'](_0x3141bc,_0x4e35bd),await a0_0x5eb71c[_0x27ef13(0xd7)](_0x38bff6,{'recursive':!![]}),{'success':!![],'action':'create-directory','directory':_0x38bff6,'relativePath':a0_0x3c91a6[_0x27ef13(0x160)](_0x3141bc,_0x38bff6),'message':_0x27ef13(0x1cf)+_0x38bff6};}catch(_0x590ca6){throw new Error('Failed\x20to\x20create\x20directory\x20'+_0x4e35bd+':\x20'+_0x590ca6[_0x27ef13(0xff)]);}}[a0_0xc176c6(0x151)](_0x30442a){const _0x465697=a0_0xc176c6,_0x3f663c=_0x30442a['toLowerCase']()['trim']();return this[_0x465697(0x1e6)][_0x465697(0x176)](_0x29f874=>{const _0x53c420=_0x465697,_0x34171d=_0x29f874['toLowerCase']();return _0x3f663c===_0x34171d||_0x3f663c[_0x53c420(0x1ac)](_0x34171d+'\x20');});}['isAllowedCommand'](_0x57ef7c){const _0x374815=a0_0xc176c6;if(!this[_0x374815(0xe3)])return!![];const _0x4c6021=_0x57ef7c[_0x374815(0xb9)]()[_0x374815(0x138)](),_0x4caf0c=_0x4c6021['split']('\x20')[0x0];return this[_0x374815(0xe3)]['some'](_0x12950c=>_0x12950c[_0x374815(0xb9)]()===_0x4caf0c||_0x4c6021['startsWith'](_0x12950c['toLowerCase']()+'\x20'));}['addToHistory'](_0x884d45,_0xcd2e4d,_0x4d05d4){const _0x3690b8=a0_0xc176c6,_0x5105d0={'timestamp':new Date()['toISOString'](),'agentId':_0x4d05d4,'action':_0x884d45['type'],'command':_0x884d45['command']||_0x884d45['directory'],'success':_0xcd2e4d['success'],'executionTime':_0xcd2e4d[_0x3690b8(0x18c)]||0x0,'workingDirectory':_0xcd2e4d[_0x3690b8(0x1a0)]};this[_0x3690b8(0x109)][_0x3690b8(0xef)](_0x5105d0),this['commandHistory'][_0x3690b8(0xbf)]>0x64&&(this['commandHistory']=this['commandHistory'][_0x3690b8(0x1b6)](-0x64));}['getSupportedActions'](){const _0x174b8f=a0_0xc176c6;return[_0x174b8f(0xf1),_0x174b8f(0xf2),_0x174b8f(0xdc),_0x174b8f(0x1d5),'get-working-directory'];}['getParameterSchema'](){const _0x2d71e1=a0_0xc176c6;return{'type':'object','properties':{'actions':{'type':'array','minItems':0x1,'items':{'type':_0x2d71e1(0x119),'properties':{'type':{'type':'string','enum':this[_0x2d71e1(0x1ee)]()},'command':{'type':_0x2d71e1(0xfa)},'directory':{'type':_0x2d71e1(0xfa)}},'required':['type']}},'timeout':{'type':_0x2d71e1(0x11a),'minimum':0x3e8,'maximum':this[_0x2d71e1(0x1b9)]},'async':{'type':'boolean'}},'required':['actions']};}['getCommandHistory'](_0x19071d=null){const _0x596f41=a0_0xc176c6;if(_0x19071d)return this[_0x596f41(0x109)]['filter'](_0x358297=>_0x358297[_0x596f41(0x118)]===_0x19071d);return[...this[_0x596f41(0x109)]];}[a0_0xc176c6(0x149)](_0x1c8718){const _0x964b25=a0_0xc176c6;for(const [_0x3c8b1d]of this['workingDirectories']){_0x3c8b1d[_0x964b25(0x1ac)](_0x1c8718+'-')&&this[_0x964b25(0xcd)]['delete'](_0x3c8b1d);}}[a0_0xc176c6(0x114)](_0x23d3c5,_0x70fb3=null){const _0x298ce4=a0_0xc176c6,_0x571123=_0x23d3c5+'-'+(_0x70fb3||'default');return this[_0x298ce4(0xcd)]['get'](_0x571123)||_0x70fb3||process['cwd']();}[a0_0xc176c6(0x130)](){const _0x19d9d2=a0_0xc176c6;this[_0x19d9d2(0x19a)]=process['platform'];if(process[_0x19d9d2(0xd6)]==='win32'){if(process['env'][_0x19d9d2(0x182)])this[_0x19d9d2(0x1e8)]='powershell';else process['env']['SHELL']&&process['env'][_0x19d9d2(0x14e)]['includes']('bash')?this[_0x19d9d2(0x1e8)]='bash':this[_0x19d9d2(0x1e8)]='cmd';}else process['platform']==='darwin'?this[_0x19d9d2(0x1e8)]=_0x19d9d2(0x12d):this['detectedTerminal']=_0x19d9d2(0x12d);this['logger']?.['info']('Terminal\x20detected',{'platform':this[_0x19d9d2(0x19a)],'terminal':this['detectedTerminal'],'shell':process[_0x19d9d2(0x16f)]['SHELL']});}async[a0_0xc176c6(0x159)](_0x3f4111,_0x195510={}){const _0x5e480c=a0_0xc176c6,_0x303a8c=_0x3f4111['trim'](),_0x4d8831=this['analyzeCommandCompatibility'](_0x303a8c);this['logger']?.[_0x5e480c(0x174)]('Command\x20compatibility\x20analysis',{'command':_0x303a8c,'detectedTerminal':_0x4d8831[_0x5e480c(0x1e8)],'commandType':_0x4d8831['commandType'],'commandCategory':_0x4d8831[_0x5e480c(0x10c)],'compatible':_0x4d8831[_0x5e480c(0x1dd)],'issues':_0x4d8831[_0x5e480c(0xe6)],'suggestedAction':_0x4d8831['suggestedAction'],'confidence':_0x4d8831['confidence']});if(_0x4d8831['compatible'])return _0x3f4111;let _0x2027a4=null;if(this['detectedTerminal']==='cmd')_0x2027a4=this['translateToWindowsCmd'](_0x303a8c);else{if(this[_0x5e480c(0x1e8)]==='powershell')_0x2027a4=this['translateToPowerShell'](_0x303a8c);else this['detectedTerminal']===_0x5e480c(0x12d)&&(_0x2027a4=this['translateToBash'](_0x303a8c));}if(_0x2027a4&&this[_0x5e480c(0x104)](_0x303a8c))return this['logger']?.[_0x5e480c(0x174)]('Using\x20simple\x20translation',{'original':_0x3f4111,'translated':_0x2027a4,'method':'simple'}),_0x2027a4;if(_0x195510['aiService']||_0x195510[_0x5e480c(0x194)]&&_0x195510['agentId']){this[_0x5e480c(0xc8)]?.[_0x5e480c(0x174)](_0x5e480c(0x115),{'command':_0x3f4111['substring'](0x0,0x64)+'...','hasAiService':!!_0x195510['aiService'],'hasToolsRegistry':!!_0x195510['toolsRegistry'],'agentId':_0x195510[_0x5e480c(0x118)]});try{const _0x55150d=await this['translateCommandWithAI'](_0x3f4111,_0x195510);if(_0x55150d&&_0x55150d[_0x5e480c(0x138)]()!==_0x3f4111[_0x5e480c(0x138)]())return this['logger']?.[_0x5e480c(0x174)](_0x5e480c(0x1df),{'original':_0x3f4111,'translated':_0x55150d,'method':'ai'}),_0x55150d;else this[_0x5e480c(0xc8)]?.[_0x5e480c(0x162)](_0x5e480c(0x187),{'original':_0x3f4111,'translated':_0x55150d});}catch(_0x2c0d9f){this['logger']?.[_0x5e480c(0x162)]('AI\x20translation\x20failed,\x20falling\x20back\x20to\x20simple\x20translation',{'original':_0x3f4111,'error':_0x2c0d9f['message'],'stack':_0x2c0d9f[_0x5e480c(0x1f3)]});}}else this[_0x5e480c(0xc8)]?.[_0x5e480c(0x162)]('AI\x20translation\x20not\x20available\x20-\x20missing\x20context',{'hasAiService':!!_0x195510['aiService'],'hasToolsRegistry':!!_0x195510[_0x5e480c(0x194)],'hasAgentId':!!_0x195510[_0x5e480c(0x118)],'contextKeys':Object['keys'](_0x195510)});return _0x2027a4||_0x3f4111;}['isSimpleCommand'](_0x561044){const _0x3109db=a0_0xc176c6,_0x110abc=_0x561044[_0x3109db(0xb9)]();if(_0x561044[_0x3109db(0x14a)]('\x5cn')||_0x561044[_0x3109db(0x14a)]('\x5cr')||_0x561044['includes']('\x5ct'))return![];if(_0x561044['includes']('\x0a')||_0x561044['includes']('\x0d'))return![];if(_0x561044[_0x3109db(0x14a)](_0x3109db(0xee))||_0x561044[_0x3109db(0x14a)]('printf')||_0x561044['includes'](_0x3109db(0x141)))return![];if(_0x561044[_0x3109db(0x14a)](_0x3109db(0x1ef))||_0x561044['includes'](_0x3109db(0x1fb))||_0x561044['includes']('class\x20'))return![];if(_0x561044[_0x3109db(0x14a)](_0x3109db(0xdb))&&!_0x561044['includes'](_0x3109db(0x1cb)))return![];const _0x3e9f68=_0x561044[_0x3109db(0x135)](/'([^']*)'/);if(_0x3e9f68&&_0x3e9f68[0x1]['length']>0x32)return![];if(this[_0x3109db(0x1e8)]===_0x3109db(0x1f7)&&_0x561044['includes']('>')&&_0x561044[_0x3109db(0x14a)]('/')&&!_0x561044['includes']('\x5c'))return![];if(_0x561044[_0x3109db(0x14a)](_0x3109db(0x112))||_0x561044['includes']('\x20||\x20')||_0x561044[_0x3109db(0x14a)](';\x20'))return![];if(_0x561044['includes']('$(')||_0x561044['includes']('`')||_0x561044[_0x3109db(0x14a)]('{')||_0x561044[_0x3109db(0x14a)]('['))return![];if(_0x110abc['includes'](_0x3109db(0x1f8))||_0x110abc[_0x3109db(0x14a)](_0x3109db(0x1bd))||_0x110abc[_0x3109db(0x14a)]('if\x20'))return![];if(_0x110abc['includes']('export ')||_0x110abc['includes'](_0x3109db(0x1ae)))return![];if(_0x561044[_0x3109db(0x14a)](_0x3109db(0x19d))||_0x561044['includes']('\x20>\x20&'))return![];return!![];}async[a0_0xc176c6(0x110)](_0x23004a,_0x54ec1f){const _0x159ef5=a0_0xc176c6;let _0x2103e3=_0x54ec1f[_0x159ef5(0xb5)];if(!_0x2103e3&&_0x54ec1f[_0x159ef5(0x194)]&&_0x54ec1f['agentId']){const _0x51428c=_0x54ec1f[_0x159ef5(0x121)];_0x51428c&&_0x51428c[_0x159ef5(0xb5)]&&(_0x2103e3=_0x51428c['aiService']);}if(!_0x2103e3)throw new Error('AI\x20service\x20not\x20available\x20for\x20command\x20translation');const _0x41af10=this[_0x159ef5(0x102)](_0x23004a),_0x1f6d14='gpt-4-mini';try{const _0x1497cf=await _0x2103e3['sendMessage'](_0x1f6d14,_0x41af10,{'agentId':_0x54ec1f[_0x159ef5(0x118)],'temperature':0.1,'maxTokens':0xc8,'apiKey':_0x54ec1f[_0x159ef5(0x103)],'customApiKeys':_0x54ec1f[_0x159ef5(0x197)],'platformProvided':_0x54ec1f[_0x159ef5(0x1a6)]}),_0x1ac16d=this[_0x159ef5(0xf0)](_0x1497cf['content']);return this[_0x159ef5(0xc8)]?.['debug'](_0x159ef5(0x124),{'original':_0x23004a,'translated':_0x1ac16d,'model':_0x1f6d14,'terminal':this['detectedTerminal']}),_0x1ac16d;}catch(_0x88ccd1){this[_0x159ef5(0xc8)]?.[_0x159ef5(0x183)]('AI\x20command\x20translation\x20failed',{'command':_0x23004a,'terminal':this[_0x159ef5(0x1e8)],'error':_0x88ccd1['message']});throw _0x88ccd1;}}['buildTranslationPrompt'](_0x30f302){const _0x5c67e7=a0_0xc176c6,_0x102b5d={'cmd':'Windows\x20Command\x20Prompt\x20(cmd.exe)','powershell':'Windows\x20PowerShell','bash':'Bash\x20shell\x20(Linux/Unix/macOS)'},_0x5887d0=_0x102b5d[this['detectedTerminal']]||this['detectedTerminal'],_0x554bc8=this[_0x5c67e7(0x1db)](_0x30f302);let _0x1d06b2='Translate\x20this\x20command\x20to\x20work\x20correctly\x20in\x20'+_0x5887d0+_0x5c67e7(0x1d7)+_0x30f302+'\x0a```\x0a\x0aCOMMAND\x20ANALYSIS:\x0a-\x20Command\x20Type:\x20'+_0x554bc8[_0x5c67e7(0x13f)]+_0x5c67e7(0x198)+_0x554bc8[_0x5c67e7(0x10c)]+_0x5c67e7(0x173)+_0x5887d0+_0x5c67e7(0x185)+(_0x554bc8['specificIssues'][_0x5c67e7(0x15e)](',\x20')||'None\x20detected');return _0x554bc8[_0x5c67e7(0x13f)]===_0x5c67e7(0x15d)&&_0x554bc8['alternatives']&&_0x554bc8['alternatives'][this[_0x5c67e7(0x1e8)]]&&(_0x1d06b2+='\x0a-\x20Suggested\x20Alternative:\x20'+_0x554bc8[_0x5c67e7(0x117)][this['detectedTerminal']]),_0x1d06b2+=_0x5c67e7(0x184)+_0x5887d0+'\x0a2.\x20Preserve\x20the\x20original\x20intent\x20and\x20functionality\x0a3.\x20Handle\x20file\x20paths,\x20quoting,\x20and\x20syntax\x20correctly\x0a4.\x20If\x20creating\x20files,\x20ensure\x20proper\x20encoding\x20and\x20line\x20endings\x0a5.\x20Address\x20the\x20specific\x20compatibility\x20issues\x20identified\x20above\x0a6.\x20Return\x20ONLY\x20the\x20translated\x20command,\x20nothing\x20else\x0a\x0aTRANSLATED\x20COMMAND:',_0x1d06b2;}['extractTranslatedCommand'](_0x32ae5a){const _0x56b705=a0_0xc176c6;let _0x1ff764=_0x32ae5a['replace'](/```[a-z]*\n?(.*?)\n?```/s,'$1');_0x1ff764=_0x1ff764['replace'](/^(TRANSLATED COMMAND:|Command:|Result:)\s*/i,'');const _0x3fa6fb=_0x1ff764['trim']()[_0x56b705(0x1b2)]('\x0a');return _0x3fa6fb['length']>0x1&&!_0x1ff764['includes']('&&')&&!_0x1ff764['includes']('||')&&(_0x1ff764=_0x3fa6fb[0x0]['trim']()),_0x1ff764[_0x56b705(0x138)]();}['analyzeCommandCompatibility'](_0x591fa8){const _0x240def=a0_0xc176c6,_0x3c8588=this[_0x240def(0x137)](_0x591fa8),_0x4c6710=this[_0x240def(0x153)](_0x3c8588,this[_0x240def(0x1e8)]);return{'compatible':_0x4c6710,'detectedTerminal':this[_0x240def(0x1e8)],'commandType':_0x3c8588['type'],'commandCategory':_0x3c8588['category'],'specificIssues':_0x3c8588['issues'],'suggestedAction':_0x4c6710?'execute':'translate','confidence':_0x3c8588[_0x240def(0x14c)]};}[a0_0xc176c6(0x16e)](_0x268881){const _0x17e93e=a0_0xc176c6;return this[_0x17e93e(0x1db)](_0x268881)[_0x17e93e(0x1dd)];}['classifyCommand'](_0x548ed3){const _0x2e430d=a0_0xc176c6,_0x1aaf36=_0x548ed3['toLowerCase']()['trim'](),_0x1c2c2f=_0x1aaf36['split']('\x20')[0x0],_0x41207f=[];let _0x18b6e2=0.9;const _0x2e1489={'ls':{'category':'file-listing','alternatives':{'cmd':'dir','powershell':_0x2e430d(0x100)}},'cat':{'category':_0x2e430d(0xe0),'alternatives':{'cmd':'type','powershell':'Get-Content'}},'grep':{'category':'text-search','alternatives':{'cmd':'findstr','powershell':_0x2e430d(0xc0)}},'find':{'category':'file-search','alternatives':{'cmd':'dir\x20/s','powershell':'Get-ChildItem\x20-Recurse'}},'head':{'category':'file-viewing','alternatives':{'cmd':_0x2e430d(0x1bf),'powershell':_0x2e430d(0x13d)}},'tail':{'category':'file-viewing','alternatives':{'cmd':_0x2e430d(0xda),'powershell':'Get-Content\x20-Tail'}},'wc':{'category':'text-analysis','alternatives':{'cmd':_0x2e430d(0x1eb),'powershell':_0x2e430d(0x1ad)}},'cp':{'category':_0x2e430d(0x156),'alternatives':{'cmd':'copy','powershell':_0x2e430d(0x13a)}},'mv':{'category':'file-move','alternatives':{'cmd':'move','powershell':_0x2e430d(0x158)}},'rm':{'category':_0x2e430d(0x199),'alternatives':{'cmd':'del','powershell':'Remove-Item'}},'mkdir':{'category':'directory-create','alternatives':{'cmd':_0x2e430d(0xd7),'powershell':'New-Item\x20-Type\x20Directory'}},'rmdir':{'category':_0x2e430d(0x1ec),'alternatives':{'cmd':'rmdir','powershell':_0x2e430d(0xc4)}},'touch':{'category':_0x2e430d(0x1a8),'alternatives':{'cmd':'type\x20nul\x20>','powershell':_0x2e430d(0x11e)}},'chmod':{'category':'permissions','alternatives':{'cmd':_0x2e430d(0x129),'powershell':_0x2e430d(0x1be)}},'chown':{'category':'ownership','alternatives':{'cmd':_0x2e430d(0x1e9),'powershell':_0x2e430d(0x1be)}},'ps':{'category':'process-list','alternatives':{'cmd':'tasklist','powershell':'Get-Process'}},'kill':{'category':'process-kill','alternatives':{'cmd':_0x2e430d(0x1ce),'powershell':_0x2e430d(0x14f)}},'killall':{'category':'process-kill','alternatives':{'cmd':'taskkill\x20/f\x20/im','powershell':_0x2e430d(0x1a7)}},'top':{'category':'process-monitor','alternatives':{'cmd':_0x2e430d(0x164),'powershell':_0x2e430d(0x1b4)}},'wget':{'category':'download','alternatives':{'cmd':'curl','powershell':_0x2e430d(0x1b7)}},'curl':{'category':_0x2e430d(0x180),'alternatives':{'cmd':_0x2e430d(0x1c3),'powershell':_0x2e430d(0xe4)}},'ping':{'category':'network-test','alternatives':{'cmd':_0x2e430d(0x1bc),'powershell':'Test-NetConnection'}},'awk':{'category':'text-processing','alternatives':{'cmd':'for\x20/f','powershell':'ForEach-Object'}},'sed':{'category':_0x2e430d(0xb4),'alternatives':{'cmd':_0x2e430d(0x1de),'powershell':'native'}},'sort':{'category':'text-sort','alternatives':{'cmd':'sort','powershell':'Sort-Object'}},'uniq':{'category':_0x2e430d(0x106),'alternatives':{'cmd':'sort\x20/unique','powershell':_0x2e430d(0xd0)}},'pwd':{'category':_0x2e430d(0x1c7),'alternatives':{'cmd':'cd','powershell':'Get-Location'}},'whoami':{'category':'user-info','alternatives':{'cmd':'echo\x20%USERNAME%','powershell':'whoami'}},'env':{'category':_0x2e430d(0xe1),'alternatives':{'cmd':'set','powershell':'Get-ChildItem\x20Env:'}},'export':{'category':_0x2e430d(0xe1),'alternatives':{'cmd':_0x2e430d(0xbd),'powershell':'$env:'}},'source':{'category':'script-execute','alternatives':{'cmd':'call','powershell':'.\x20'}},'tar':{'category':'archive','alternatives':{'cmd':'7z','powershell':_0x2e430d(0x1cd)}},'zip':{'category':'archive','alternatives':{'cmd':_0x2e430d(0xf3),'powershell':'Compress-Archive'}},'unzip':{'category':_0x2e430d(0x167),'alternatives':{'cmd':'powershell\x20Expand-Archive','powershell':_0x2e430d(0x134)}},'df':{'category':'disk-info','alternatives':{'cmd':_0x2e430d(0x1e0),'powershell':_0x2e430d(0x171)}},'du':{'category':_0x2e430d(0x166),'alternatives':{'cmd':'dir\x20/s','powershell':_0x2e430d(0xec)}},'free':{'category':'memory-info','alternatives':{'cmd':_0x2e430d(0xf8),'powershell':_0x2e430d(0x1d0)}},'uname':{'category':_0x2e430d(0x111),'alternatives':{'cmd':'systeminfo','powershell':'Get-ComputerInfo'}}},_0x76095={'dir':{'category':_0x2e430d(0x1f1),'alternatives':{'unix':'ls','powershell':_0x2e430d(0x100)}},'type':{'category':'file-viewing','alternatives':{'unix':_0x2e430d(0xd1),'powershell':'Get-Content'}},'copy':{'category':'file-copy','alternatives':{'unix':'cp','powershell':_0x2e430d(0x13a)}},'move':{'category':'file-move','alternatives':{'unix':'mv','powershell':'Move-Item'}},'del':{'category':_0x2e430d(0x199),'alternatives':{'unix':'rm','powershell':'Remove-Item'}},'tasklist':{'category':_0x2e430d(0xca),'alternatives':{'unix':'ps','powershell':_0x2e430d(0x142)}},'taskkill':{'category':_0x2e430d(0x1fd),'alternatives':{'unix':'kill','powershell':'Stop-Process'}},'findstr':{'category':'text-search','alternatives':{'unix':'grep','powershell':_0x2e430d(0xc0)}}},_0x5e217e={'get-childitem':{'category':_0x2e430d(0x1f1),'alternatives':{'unix':'ls','cmd':_0x2e430d(0x1f4)}},'get-content':{'category':'file-viewing','alternatives':{'unix':_0x2e430d(0xd1),'cmd':_0x2e430d(0x12a)}},'copy-item':{'category':_0x2e430d(0x156),'alternatives':{'unix':'cp','cmd':_0x2e430d(0x1a3)}},'move-item':{'category':_0x2e430d(0x146),'alternatives':{'unix':'mv','cmd':_0x2e430d(0x17b)}},'remove-item':{'category':'file-delete','alternatives':{'unix':'rm','cmd':'del'}},'get-process':{'category':'process-list','alternatives':{'unix':'ps','cmd':'tasklist'}},'stop-process':{'category':_0x2e430d(0x1fd),'alternatives':{'unix':_0x2e430d(0x17e),'cmd':_0x2e430d(0x1ce)}}};let _0x364aa6='unknown',_0x409c6f=_0x2e430d(0xba),_0x11f0c7={};if(_0x2e1489[_0x1c2c2f])_0x364aa6='unix',_0x409c6f=_0x2e1489[_0x1c2c2f]['category'],_0x11f0c7=_0x2e1489[_0x1c2c2f][_0x2e430d(0x117)];else{if(_0x76095[_0x1c2c2f])_0x364aa6='windows-cmd',_0x409c6f=_0x76095[_0x1c2c2f][_0x2e430d(0xbc)],_0x11f0c7=_0x76095[_0x1c2c2f]['alternatives'];else{if(_0x5e217e[_0x1c2c2f])_0x364aa6='powershell',_0x409c6f=_0x5e217e[_0x1c2c2f]['category'],_0x11f0c7=_0x5e217e[_0x1c2c2f][_0x2e430d(0x117)];else{const _0x17ba47=[_0x2e430d(0x12e),'cd',_0x2e430d(0x186),'help'];_0x17ba47[_0x2e430d(0x14a)](_0x1c2c2f)?(_0x364aa6='universal',_0x409c6f=_0x2e430d(0x1c2)):(_0x364aa6=_0x2e430d(0xba),_0x18b6e2=0.3);}}}return _0x548ed3[_0x2e430d(0x14a)]('\x27')&&!_0x548ed3['includes']('\x22')&&_0x41207f[_0x2e430d(0xef)]('single-quotes-problematic'),_0x548ed3['includes']('/')&&!_0x548ed3[_0x2e430d(0x14a)]('\x5c')&&!_0x548ed3[_0x2e430d(0x14a)]('http')&&_0x548ed3[_0x2e430d(0x14a)]('>')&&_0x41207f[_0x2e430d(0xef)](_0x2e430d(0xe9)),(_0x548ed3[_0x2e430d(0x14a)]('\x5cn')||_0x548ed3['includes']('\x5ct'))&&_0x41207f[_0x2e430d(0xef)]('escape-sequences'),(_0x548ed3['includes'](_0x2e430d(0x112))||_0x548ed3[_0x2e430d(0x14a)](_0x2e430d(0xbe))||_0x548ed3[_0x2e430d(0x14a)](';'))&&_0x41207f[_0x2e430d(0xef)]('command-chaining'),{'type':_0x364aa6,'category':_0x409c6f,'alternatives':_0x11f0c7,'issues':_0x41207f,'confidence':_0x18b6e2,'firstWord':_0x1c2c2f,'fullCommand':_0x548ed3};}[a0_0xc176c6(0x153)](_0x55d2a5,_0x68cd0e){const _0x4b911b=a0_0xc176c6;switch(_0x68cd0e){case'cmd':if(_0x55d2a5['type']===_0x4b911b(0x15d))return![];if(_0x55d2a5['issues']['includes'](_0x4b911b(0x1b0)))return![];if(_0x55d2a5[_0x4b911b(0xb1)][_0x4b911b(0x14a)](_0x4b911b(0xe9)))return![];return _0x55d2a5[_0x4b911b(0x12a)]===_0x4b911b(0xdf)||_0x55d2a5[_0x4b911b(0x12a)]==='universal';case _0x4b911b(0x150):if(_0x55d2a5[_0x4b911b(0x12a)]===_0x4b911b(0x15d)&&!_0x55d2a5['alternatives']['powershell'])return![];return!![];case'bash':if(_0x55d2a5[_0x4b911b(0x12a)]===_0x4b911b(0xdf))return![];return _0x55d2a5[_0x4b911b(0x12a)]===_0x4b911b(0x15d)||_0x55d2a5['type']==='universal';default:return![];}}['translateToWindowsCmd'](_0x13229b){const _0x79a123=a0_0xc176c6;let _0x32a178=_0x13229b;const _0x33c00b=new Map([[/^ls\s*$/,_0x79a123(0x1f4)],[/^ls\s+-la?$/,_0x79a123(0x1f4)],[/^ls\s+-l$/,'dir'],[/^ls\s+-a$/,'dir\x20/a'],[/^cat\s+(.+)$/,'type\x20$1'],[/^cp\s+(.+)\s+(.+)$/,_0x79a123(0xcc)],[/^mv\s+(.+)\s+(.+)$/,'move\x20$1\x20$2'],[/^rm\s+(.+)$/,_0x79a123(0x1d3)],[/^mkdir\s+(.+)$/,_0x79a123(0x1ab)],[/^rmdir\s+(.+)$/,'rmdir\x20$1'],[/^ps\s*$/,'tasklist'],[/^kill\s+(.+)$/,_0x79a123(0xfb)],[/^pwd\s*$/,'cd'],[/^whoami\s*$/,'echo\x20%USERNAME%'],[/^ping\s+(.+)$/,_0x79a123(0x1ea)],[/^wget\s+(.+)$/,_0x79a123(0xaf)],[/^curl\s+(.+)$/,_0x79a123(0x1b8)]]);for(const [_0x4ee9dd,_0x484faa]of _0x33c00b){if(_0x4ee9dd['test'](_0x32a178)){_0x32a178=_0x32a178['replace'](_0x4ee9dd,_0x484faa);break;}}_0x32a178=_0x32a178[_0x79a123(0x1a2)](/echo\s+'([^']+)'\s*>/g,_0x79a123(0x139)),_0x32a178=_0x32a178['replace'](/echo\s+'([^']+)'$/g,_0x79a123(0x1f2));if(_0x32a178[_0x79a123(0x14a)]('echo\x20\x27')&&_0x32a178['includes']('\x5cn')){const _0x4c20c6=_0x32a178['match'](/echo\s+'(.+?)'\s*>\s*(.+)$/);if(_0x4c20c6){const _0x2e7100=_0x4c20c6[0x1][_0x79a123(0x1a2)](/\\n/g,'\x0a'),_0x2ac397=_0x4c20c6[0x2],_0x2762b1=_0x2e7100['split']('\x0a');_0x32a178='('+_0x2762b1['map'](_0x1b44d4=>_0x79a123(0x154)+_0x1b44d4)['join'](_0x79a123(0xd8))+_0x79a123(0x11d)+_0x2ac397;}}return this['logger']?.['info']('Command\x20translated\x20for\x20Windows\x20CMD',{'original':_0x13229b,'translated':_0x32a178}),_0x32a178;}[a0_0xc176c6(0x1d9)](_0x2da7dd){const _0xb4f655=a0_0xc176c6;let _0x1eca2a=_0x2da7dd;const _0x593032=new Map([[/^ls\s*$/,_0xb4f655(0x100)],[/^ls\s+-la?$/,'Get-ChildItem\x20-Force'],[/^cat\s+(.+)$/,'Get-Content\x20$1'],[/^cp\s+(.+)\s+(.+)$/,_0xb4f655(0xb7)],[/^mv\s+(.+)\s+(.+)$/,'Move-Item\x20$1\x20$2'],[/^rm\s+(.+)$/,'Remove-Item\x20$1'],[/^pwd\s*$/,'Get-Location'],[/^ps\s*$/,'Get-Process']]);for(const [_0x27de94,_0x16aa82]of _0x593032){if(_0x27de94[_0xb4f655(0xb8)](_0x1eca2a)){_0x1eca2a=_0x1eca2a[_0xb4f655(0x1a2)](_0x27de94,_0x16aa82);break;}}return this['logger']?.[_0xb4f655(0x174)]('Command\x20translated\x20for\x20PowerShell',{'original':_0x2da7dd,'translated':_0x1eca2a}),_0x1eca2a;}['translateToBash'](_0x2029cc){const _0x5bffff=a0_0xc176c6;let _0x200cff=_0x2029cc;const _0x1b8ec5=new Map([[/^dir\s*$/,'ls'],[/^dir\s+\/a$/,_0x5bffff(0x16b)],[/^type\s+(.+)$/,'cat\x20$1'],[/^copy\s+(.+)\s+(.+)$/,_0x5bffff(0xf6)],[/^move\s+(.+)\s+(.+)$/,_0x5bffff(0x113)],[/^del\s+(.+)$/,_0x5bffff(0x10f)],[/^tasklist\s*$/,'ps'],[/^cd\s*$/,_0x5bffff(0x122)]]);for(const [_0x23500f,_0x4cf4af]of _0x1b8ec5){if(_0x23500f['test'](_0x200cff)){_0x200cff=_0x200cff[_0x5bffff(0x1a2)](_0x23500f,_0x4cf4af);break;}}return _0x200cff;}async[a0_0xc176c6(0x188)](_0x2a4e39){}async['startBackgroundCommand'](_0xd7bd41,_0x171132,_0x31e233={}){const _0x3e89ab=a0_0xc176c6,{agentId:_0x58a4bc,context:_0x255cd3}=_0x31e233;if(!_0x58a4bc)throw new Error('agentId\x20is\x20required\x20for\x20background\x20commands');const _0x24155b=this[_0x3e89ab(0x15f)](_0x58a4bc),_0x1bf374=_0x24155b[_0x3e89ab(0x157)](_0x563c9e=>_0x563c9e['state']==='running'||_0x563c9e[_0x3e89ab(0x11f)]===_0x3e89ab(0xf4));if(_0x1bf374['length']>=this[_0x3e89ab(0x18a)])throw new Error('Maximum\x20background\x20commands\x20per\x20agent\x20exceeded\x20('+this['MAX_BACKGROUND_COMMANDS_PER_AGENT']+')');const _0x35878e=Array['from'](this['commandTracker'][_0x3e89ab(0x1e2)]()),_0xace7df=_0x35878e['filter'](_0x47beba=>_0x47beba[_0x3e89ab(0x11f)]===_0x3e89ab(0x152)||_0x47beba['state']===_0x3e89ab(0xf4));if(_0xace7df[_0x3e89ab(0xbf)]>=this[_0x3e89ab(0xb0)])throw new Error(_0x3e89ab(0x17f)+this[_0x3e89ab(0xb0)]+')');const _0x2b52f1=_0x58a4bc+_0x3e89ab(0x1a1)+Date[_0x3e89ab(0x1da)]()+'-'+ ++this['commandIdCounter'],_0x1a2788=_0xd7bd41;let _0x4075b1;try{_0x4075b1=await this['translateCommand'](_0xd7bd41,{'agentId':_0x58a4bc,'toolsRegistry':_0x255cd3?.[_0x3e89ab(0x194)],'messageProcessor':_0x255cd3?.[_0x3e89ab(0x121)],'aiService':_0x255cd3?.[_0x3e89ab(0xb5)],'apiKey':_0x255cd3?.[_0x3e89ab(0x103)],'customApiKeys':_0x255cd3?.[_0x3e89ab(0x197)],'platformProvided':_0x255cd3?.['platformProvided']});}catch(_0x50a45d){this['logger']?.['warn']('Command\x20translation\x20failed,\x20using\x20original\x20command',{'originalCommand':_0x1a2788,'error':_0x50a45d['message']}),_0x4075b1=_0xd7bd41;}this[_0x3e89ab(0xc8)]?.['info'](_0x3e89ab(0xe7)+_0x4075b1,{'commandId':_0x2b52f1,'agentId':_0x58a4bc,'originalCommand':_0x1a2788,'workingDirectory':_0x171132});let _0x4cd0cf;if(this['detectedTerminal']===_0x3e89ab(0x1f7)||this[_0x3e89ab(0x1e8)]===_0x3e89ab(0x150)){const _0x27e03d=this['detectedTerminal']===_0x3e89ab(0x150)?'powershell':'cmd',_0x1c54e5=this['detectedTerminal']==='powershell'?['-Command',_0x4075b1]:['/c',_0x4075b1];_0x4cd0cf=spawn(_0x27e03d,_0x1c54e5,{'cwd':_0x171132,'env':{...process[_0x3e89ab(0x16f)]},'windowsHide':!![],'stdio':[_0x3e89ab(0x125),_0x3e89ab(0x125),_0x3e89ab(0x125)]});}else _0x4cd0cf=spawn('sh',['-c',_0x4075b1],{'cwd':_0x171132,'env':{...process[_0x3e89ab(0x16f)]},'stdio':[_0x3e89ab(0x125),'pipe',_0x3e89ab(0x125)]});const _0x25738e={'commandId':_0x2b52f1,'agentId':_0x58a4bc,'pid':_0x4cd0cf['pid'],'command':_0x1a2788,'translatedCommand':_0x4075b1,'workingDirectory':_0x171132,'startTime':new Date()[_0x3e89ab(0x179)](),'state':'running','exitCode':null,'stdoutBuffer':'','stderrBuffer':'','lastOutputTime':Date['now'](),'promptDetected':null,'process':_0x4cd0cf};return this[_0x3e89ab(0x18b)][_0x3e89ab(0xbd)](_0x2b52f1,_0x25738e),_0x4cd0cf[_0x3e89ab(0x1d6)]['on']('data',_0x24c85a=>{const _0x3680bf=_0x3e89ab,_0x2c6fc7=_0x24c85a[_0x3680bf(0x120)]();_0x25738e['stdoutBuffer']+=_0x2c6fc7,_0x25738e[_0x3680bf(0x13c)]=Date[_0x3680bf(0x1da)]();if(!_0x25738e[_0x3680bf(0x15c)]){const _0xf0de5c=this['promptDetector']['detectPrompt'](_0x25738e['stdoutBuffer'],'stdout');_0xf0de5c&&(_0x25738e[_0x3680bf(0x15c)]=_0xf0de5c,_0x25738e['state']=_0x3680bf(0xf4),this[_0x3680bf(0xc8)]?.[_0x3680bf(0x174)]('Prompt\x20detected\x20in\x20background\x20command',{'commandId':_0x2b52f1,'agentId':_0x58a4bc,'type':_0xf0de5c[_0x3680bf(0x12a)],'matchedText':_0xf0de5c[_0x3680bf(0x191)]}));}}),_0x4cd0cf['stderr']['on'](_0x3e89ab(0x1a9),_0x2fe117=>{const _0x4bd431=_0x3e89ab,_0x407417=_0x2fe117['toString']();_0x25738e['stderrBuffer']+=_0x407417,_0x25738e[_0x4bd431(0x13c)]=Date[_0x4bd431(0x1da)]();if(!_0x25738e[_0x4bd431(0x15c)]){const _0x40436d=this['promptDetector'][_0x4bd431(0x163)](_0x25738e[_0x4bd431(0x136)],_0x4bd431(0x14b));_0x40436d&&(_0x25738e['promptDetected']=_0x40436d,_0x25738e['state']='waiting_for_input',this[_0x4bd431(0xc8)]?.['info'](_0x4bd431(0x12f),{'commandId':_0x2b52f1,'agentId':_0x58a4bc,'type':_0x40436d['type'],'matchedText':_0x40436d[_0x4bd431(0x191)]}));}}),_0x4cd0cf['on'](_0x3e89ab(0x186),(_0x5217bb,_0x532007)=>{const _0x5e3471=_0x3e89ab;_0x25738e[_0x5e3471(0x165)]=_0x5217bb,_0x25738e['state']=_0x5217bb===0x0?_0x5e3471(0x12c):'failed',_0x25738e[_0x5e3471(0x1a5)]=new Date()[_0x5e3471(0x179)](),this['logger']?.[_0x5e3471(0x174)](_0x5e3471(0x1c1),{'commandId':_0x2b52f1,'agentId':_0x58a4bc,'exitCode':_0x5217bb,'signal':_0x532007,'state':_0x25738e[_0x5e3471(0x11f)]});}),_0x4cd0cf['on']('error',_0xb1c236=>{const _0x3bacab=_0x3e89ab;_0x25738e['state']='failed',_0x25738e[_0x3bacab(0x183)]=_0xb1c236[_0x3bacab(0xff)],_0x25738e[_0x3bacab(0x1a5)]=new Date()['toISOString'](),this['logger']?.['error'](_0x3bacab(0x107),{'commandId':_0x2b52f1,'agentId':_0x58a4bc,'error':_0xb1c236['message']});}),{'success':!![],'commandId':_0x2b52f1,'pid':_0x4cd0cf[_0x3e89ab(0xf7)],'command':_0x1a2788,'translatedCommand':_0x4075b1,'workingDirectory':_0x171132,'message':_0x3e89ab(0x1e1)+_0x2b52f1};}[a0_0xc176c6(0x105)](_0x340d06,_0x56d253,_0x2b36b6){const _0x20d925=a0_0xc176c6,_0x5c7cac=this[_0x20d925(0x1cc)](_0x340d06,_0x2b36b6);if(_0x5c7cac[_0x20d925(0x11f)]==='completed'||_0x5c7cac[_0x20d925(0x11f)]===_0x20d925(0xc1))throw new Error('Cannot\x20send\x20input\x20to\x20'+_0x5c7cac[_0x20d925(0x11f)]+'\x20command');if(!_0x5c7cac['process']||_0x5c7cac['process']['killed'])throw new Error('Command\x20process\x20is\x20not\x20running');const _0x31201d=_0x56d253[_0x20d925(0x131)]('\x0a')?_0x56d253:_0x56d253+'\x0a';return _0x5c7cac['process'][_0x20d925(0x18f)]['write'](_0x31201d),this['logger']?.['info'](_0x20d925(0xb2),{'commandId':_0x340d06,'agentId':_0x2b36b6,'inputLength':_0x56d253[_0x20d925(0xbf)]}),_0x5c7cac['state']===_0x20d925(0xf4)&&(_0x5c7cac[_0x20d925(0x11f)]=_0x20d925(0x152),_0x5c7cac[_0x20d925(0x15c)]=null),{'success':!![],'commandId':_0x340d06,'message':'Input\x20sent\x20successfully'};}['getCommandStatus'](_0x3af1de,_0x46c98f){const _0x5d0d18=a0_0xc176c6,_0x183f2e=this['validateCommandOwnership'](_0x3af1de,_0x46c98f),_0x16ffe8=Date[_0x5d0d18(0x1da)]()-_0x183f2e['lastOutputTime'];return{'success':!![],'commandId':_0x3af1de,'pid':_0x183f2e[_0x5d0d18(0xf7)],'command':_0x183f2e['command'],'state':_0x183f2e['state'],'exitCode':_0x183f2e['exitCode'],'startTime':_0x183f2e[_0x5d0d18(0x192)],'endTime':_0x183f2e[_0x5d0d18(0x1a5)],'workingDirectory':_0x183f2e['workingDirectory'],'stdout':_0x183f2e[_0x5d0d18(0x147)],'stderr':_0x183f2e[_0x5d0d18(0x136)],'stdoutLength':_0x183f2e[_0x5d0d18(0x147)][_0x5d0d18(0xbf)],'stderrLength':_0x183f2e[_0x5d0d18(0x136)]['length'],'lastOutputTime':_0x183f2e[_0x5d0d18(0x13c)],'timeSinceLastOutput':_0x16ffe8,'promptDetected':!!_0x183f2e[_0x5d0d18(0x15c)],'promptInfo':_0x183f2e['promptDetected']||undefined};}[a0_0xc176c6(0x10a)](_0x5e603b,_0x57e83c){const _0x16d6be=a0_0xc176c6,_0x358ded=this[_0x16d6be(0x1cc)](_0x5e603b,_0x57e83c);if(_0x358ded['state']==='completed'||_0x358ded['state']===_0x16d6be(0xc1))return{'success':!![],'commandId':_0x5e603b,'message':'Command\x20already\x20terminated','state':_0x358ded['state']};if(_0x358ded['process']&&!_0x358ded[_0x16d6be(0x1bb)][_0x16d6be(0xe5)])return _0x358ded[_0x16d6be(0x1bb)]['kill'](_0x16d6be(0xe2)),setTimeout(()=>{const _0x389fd7=_0x16d6be;_0x358ded[_0x389fd7(0x1bb)]&&!_0x358ded[_0x389fd7(0x1bb)]['killed']&&_0x358ded['process']['kill']('SIGKILL');},0x1388),this[_0x16d6be(0xc8)]?.['info']('Background\x20command\x20killed',{'commandId':_0x5e603b,'agentId':_0x57e83c}),{'success':!![],'commandId':_0x5e603b,'message':'Command\x20killed\x20successfully'};return{'success':![],'commandId':_0x5e603b,'error':_0x16d6be(0x17a)};}[a0_0xc176c6(0x19b)](_0x413ff2){const _0x3a5da4=a0_0xc176c6,_0x4f5d9b=this[_0x3a5da4(0x15f)](_0x413ff2);return _0x4f5d9b[_0x3a5da4(0x1f0)](_0x37dede=>({'commandId':_0x37dede['commandId'],'command':_0x37dede['command'],'state':_0x37dede[_0x3a5da4(0x11f)],'pid':_0x37dede['pid'],'exitCode':_0x37dede[_0x3a5da4(0x165)],'startTime':_0x37dede['startTime'],'endTime':_0x37dede[_0x3a5da4(0x1a5)],'promptDetected':!!_0x37dede[_0x3a5da4(0x15c)],'timeSinceLastOutput':Date[_0x3a5da4(0x1da)]()-_0x37dede[_0x3a5da4(0x13c)]}));}['getAgentCommands'](_0x524f2d){const _0x147c19=a0_0xc176c6;return Array[_0x147c19(0x13e)](this[_0x147c19(0x18b)][_0x147c19(0x1e2)]())['filter'](_0x3d24cb=>_0x3d24cb['agentId']===_0x524f2d);}[a0_0xc176c6(0x1cc)](_0x26c80b,_0x1a2e8c){const _0x8e0231=a0_0xc176c6,_0x47cb8e=this['commandTracker']['get'](_0x26c80b);if(!_0x47cb8e)throw new Error('Command\x20not\x20found:\x20'+_0x26c80b);if(_0x47cb8e['agentId']!==_0x1a2e8c)throw new Error(_0x8e0231(0x155)+_0x47cb8e[_0x8e0231(0x118)]);return _0x47cb8e;}async['cleanupAgent'](_0x15328d){const _0xc54fc=a0_0xc176c6,_0x3a8d7a=this[_0xc54fc(0x15f)](_0x15328d);let _0x5be609=0x0,_0x194ca2=0x0;for(const _0x3561dd of _0x3a8d7a){_0x3561dd[_0xc54fc(0x1bb)]&&!_0x3561dd['process'][_0xc54fc(0xe5)]&&(_0x3561dd['process']['kill']('SIGTERM'),_0x5be609++,setTimeout(()=>{const _0x2a2a8b=_0xc54fc;_0x3561dd['process']&&!_0x3561dd[_0x2a2a8b(0x1bb)][_0x2a2a8b(0xe5)]&&_0x3561dd[_0x2a2a8b(0x1bb)]['kill']('SIGKILL');},0xbb8)),this[_0xc54fc(0x18b)]['delete'](_0x3561dd[_0xc54fc(0x11c)]),_0x194ca2++;}return this['logger']?.['info']('Agent\x20commands\x20cleaned\x20up',{'agentId':_0x15328d,'killedCount':_0x5be609,'removedCount':_0x194ca2}),{'success':!![],'agentId':_0x15328d,'killedCount':_0x5be609,'removedCount':_0x194ca2,'message':'Cleaned\x20up\x20'+_0x194ca2+_0xc54fc(0xc9)+_0x15328d};}[a0_0xc176c6(0xdd)](){const _0x45f2dc=a0_0xc176c6,_0x130cf9=Date['now']();let _0x29f2aa=0x0;for(const [_0x4e4358,_0x561751]of this['commandTracker'][_0x45f2dc(0xbb)]()){if(_0x561751[_0x45f2dc(0x11f)]!=='completed'&&_0x561751[_0x45f2dc(0x11f)]!=='failed')continue;const _0x128765=new Date(_0x561751[_0x45f2dc(0x192)])[_0x45f2dc(0xcf)](),_0x5a6ee9=(_0x130cf9-_0x128765)/0x3e8/0x3c;_0x5a6ee9>this[_0x45f2dc(0x1f6)]&&(this['commandTracker']['delete'](_0x4e4358),_0x29f2aa++);}return _0x29f2aa>0x0&&this['logger']?.['info'](_0x45f2dc(0xfc),{'removedCount':_0x29f2aa,'ageThresholdMinutes':this['MAX_COMMAND_AGE_MINUTES']}),{'success':!![],'removedCount':_0x29f2aa,'message':'Cleaned\x20up\x20'+_0x29f2aa+'\x20stale\x20commands'};}}export default TerminalTool;
|