@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +15 -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_0x492ede=a0_0x51ec;(function(_0x7c0f5,_0x29b2b2){const _0x51cd94=a0_0x51ec,_0x5246e5=_0x7c0f5();while(!![]){try{const _0x22287a=-parseInt(_0x51cd94(0x1a9))/0x1*(-parseInt(_0x51cd94(0x145))/0x2)+-parseInt(_0x51cd94(0x10e))/0x3+-parseInt(_0x51cd94(0xaf))/0x4+-parseInt(_0x51cd94(0xb5))/0x5*(parseInt(_0x51cd94(0x131))/0x6)+parseInt(_0x51cd94(0xf8))/0x7*(-parseInt(_0x51cd94(0x1ad))/0x8)+parseInt(_0x51cd94(0x1ab))/0x9*(-parseInt(_0x51cd94(0x1a7))/0xa)+parseInt(_0x51cd94(0x143))/0xb;if(_0x22287a===_0x29b2b2)break;else _0x5246e5['push'](_0x5246e5['shift']());}catch(_0x517d93){_0x5246e5['push'](_0x5246e5['shift']());}}}(a0_0x1590,0xb30a1));function a0_0x51ec(_0x3e158f,_0x4deb0f){_0x3e158f=_0x3e158f-0x8c;const _0x159058=a0_0x1590();let _0x51ecdd=_0x159058[_0x3e158f];if(a0_0x51ec['snwPuF']===undefined){var _0x639cfc=function(_0x550d4c){const _0x2b1cc8='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x25a245='',_0x19528a='';for(let _0x469784=0x0,_0x1bc23b,_0x55e351,_0x35b828=0x0;_0x55e351=_0x550d4c['charAt'](_0x35b828++);~_0x55e351&&(_0x1bc23b=_0x469784%0x4?_0x1bc23b*0x40+_0x55e351:_0x55e351,_0x469784++%0x4)?_0x25a245+=String['fromCharCode'](0xff&_0x1bc23b>>(-0x2*_0x469784&0x6)):0x0){_0x55e351=_0x2b1cc8['indexOf'](_0x55e351);}for(let _0xbcb487=0x0,_0x1768d4=_0x25a245['length'];_0xbcb487<_0x1768d4;_0xbcb487++){_0x19528a+='%'+('00'+_0x25a245['charCodeAt'](_0xbcb487)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x19528a);};a0_0x51ec['Efayte']=_0x639cfc,a0_0x51ec['aDvgFB']={},a0_0x51ec['snwPuF']=!![];}const _0x5f1a46=_0x159058[0x0],_0x22ce00=_0x3e158f+_0x5f1a46,_0x1d87bc=a0_0x51ec['aDvgFB'][_0x22ce00];return!_0x1d87bc?(_0x51ecdd=a0_0x51ec['Efayte'](_0x51ecdd),a0_0x51ec['aDvgFB'][_0x22ce00]=_0x51ecdd):_0x51ecdd=_0x1d87bc,_0x51ecdd;}import{BaseTool}from'./baseTool.js';import a0_0x25a245 from'../utilities/tagParser.js';import a0_0x19528a from'../utilities/directoryAccessManager.js';import{spawn,exec}from'child_process';import a0_0x469784 from'path';import a0_0x1bc23b from'fs/promises';function a0_0x1590(){const _0x138899=['C2v0','CM0GlxjMic8','Cg93zxjZAgvSBcbfEhbHBMqTqxjJAgL2zq','uMvTB3zLluL0zw0Gjde','zNvUy3rPB24G','ksa+ia','y29UzMLYBwf0Aw9U','y2f0','n2LizeTcrW','yxn5BMm','q29TBwfUzcbUB3qGzM91BMq6ia','A2v5ChjLC3m','z2v0vgLTzq','Aw5KzxG','y3jLyxrLlwrPCMvJDg9YEq','CgXHDgzVCM1uExbL','y21K','zxjYB3i','vw5RBM93BIbHy3rPB24GDhLWztOG','yxjJAgL2zq','z2v0lxDVCMTPBMCTzgLYzwn0B3j5','z2v0rgvZy3jPChrPB24','DhjHBNnSyxrLq29TBwfUza','z3b0ltqTBwLUAq','C3rKB3v0qNvMzMvY','D2fPDgLUz19MB3jFAw5WDxq','quKGDhjHBNnSyxrPB24GzMfPBgvKlcbMywXSAw5NigjHy2SGDg8GC2LTCgXLihrYyw5ZBgf0Aw9U','quKGDhjHBNnSyxrPB24GCMv0DxjUzwqGC2fTzsbJB21Tyw5K','qMfJA2DYB3vUzcbJB21Tyw5KigTPBgXLza','Cg93zxjZAgvSBa','otyWntuYzvfhu0fz','DhjHBNnSyxrLq29TBwfUzfDPDgHbsq','y29WEsaKmsaKmG','ywLtzxj2AwnL','Bwf0y2HLzfrLEhq','C3rHDgu','q29TBwfUzcbJB21WyxrPyMLSAxr5igfUywX5C2LZ','Bwf4q29TBwfUzefNzu1PBNv0zxm','Aw5WDxq','BgvUz3rO','zM9Yic9M','y3vYBcaKmq','z2v0q29TBwfUzeHPC3rVCNK','CgvYBwLZC2LVBNm','AM9PBG','Bxm6ia','sw52B2TLlvjLC3rnzxrOB2q','C3rHCNrZv2L0Aa','zMLSzs1JB3b5','zMLSzq','CNvUlwnVBw1HBMq','D29YA2LUz0rPCMvJDg9YEq','r2v0lunOAwXKsxrLBq','AxndB21Tyw5Kq29TCgf0AwjSzq','D2LUmZi','zxHLy3v0zunVBw1HBMq','q29TBwfUzcb0CMfUC2XHDgLVBIbMywLSzwqSihvZAw5Nig9YAwDPBMfSignVBw1HBMq','CMvZB2X2zq','u2vSzwn0lvn0CMLUzW','r2vUzxjPyYbPBNb1DcbWCM9TChqGzgv0zwn0zwq','q29TBwfUzcbMywLSzwq6ia','C3LZDgvTAw5MBW','y3vZDg9TqxbPs2v5CW','CgfZC3DVCMq','BwvZC2fNzq','nJbbzfrMDfy','u2vSzwn0Aw9UihbYB21WDa','Bw9YzsaRBG','y29UDgLUDwu','zg93BMXVywq','r2v0lunVBNrLBNqGjde','rxHLy3v0Aw5NignVBw1HBMqGD2L0AcbZCgf3BJOG','cI0GvgfYz2v0ifrLCM1PBMfSoIa','z2v0ugfYyw1LDgvYu2nOzw1H','AxnZDwvZ','q29TBwfUzcbRAwXSzwqGC3vJy2vZC2z1BgX5','zgLY','y2HHBMDLrgLYzwn0B3j5','CNvUBMLUzW','r2vUzxjPyYbPBNb1DcbWCM9TChq','zgvIDwC','zgvZy3jPChrPB24','zwnOBYaLvvnfuK5btuuL','ndaYmJmZmJzbA3PAA0q','tMv3luL0zw0Glvr5CguGrMLSzq','nKLLqvPfuW','r2v0lvbYB2nLC3mGFcbtDg9WlvbYB2nLC3m','quKGy29TBwfUzcb0CMfUC2XHDgLVBIbJB21WBgv0zwq','qwXSia','zxHLy3v0zq','oIbJB21Tyw5KigLZihjLCxvPCMvKigzVCIbYDw4Ty29TBwfUza','y2fSBa','AxnbC3LUyW','D2HPBguG','tufyx0nptu1btKrFquDfx01jtLvurvm','Aw5MBW','A2LSBa','quKGy29TBwfUzcb0CMfUC2XHDgLVBIbMywLSzwq','q29TBwfUzcb0Aw1LzcbVDxqGywz0zxiG','zgvSic9Mic9X','Bwf4qMfJA2DYB3vUzenVBw1HBMrZugvYqwDLBNq','CgXHDgzVCM0','DMfSAwrHDgvdB21Tyw5Kt3DUzxjZAgLW','qMfZAcbZAgvSBcaOtgLUDxGVvw5PEc9TywnpuYK','D2fYBG','cGPsrvfvsvjftuvovfm6cJeUie1HA2uGDgHLignVBw1HBMqGD29YAYbJB3jYzwn0BhKGAw4G','r2v0luXVy2f0Aw9U','BxmPcI0Gyxn5BMm6ifDOzxrOzxiGDg8GCNvUignVBw1HBMqGyxn5BMnOCM9UB3vZBhKGkhrYDwuVzMfSC2uPcGPcqunlr1jpvu5eienptu1btKqGtufoquDftuvovcaOqwr2yw5JzwqPoGPgB3iGBg9UzY1YDw5UAw5NignVBw1HBMrZicHUCg0GAw5ZDgfSBcWGz2L0ig9WzxjHDgLVBNmSigj1AwXKCYKSihvZzsbIywnRz3jVDw5KignVBw1HBMqGDhjHy2TPBMC6cGOQkNn0yxj0qMfJA2DYB3vUzenVBw1HBMqOy29TBwfUzcWGD29YA2LUz0rPCIWGE2fNzw50swqSignVBNrLEhr9ksOQcI0Gu3rHCNrZignVBw1HBMqGAw4GyMfJA2DYB3vUzcb3AxrOihn0zgLUigTLChqGB3bLBGOTifjLDhvYBNmGy29TBwfUzeLKigzVCIb0CMfJA2LUzWOTie1HEca','y2XLyw51CefNzw50','q29UzMLYBwf0Aw9UihbYB21WDa','Dg9ju09tDhjPBMC','BMv0D29YAY10zxn0','D2LUzg93CY1JBwq','Dw5PEa','ihX8ia','zMLSzs12Awv3Aw5N','zxHPDenVzgu','y2XLyxjxB3jRAw5NrgLYzwn0B3j5','Dw5PEc1ZDhLSzs1WyxrOCW','z2v0q3vYCMvUDfDVCMTPBMDeAxjLy3rVCNK','y29TBwfUzeHPC3rVCNK','q3jLyxrLzcbKAxjLy3rVCNK6ia','zMLUzcaVyW','ChvZAa','qwDLBNqGy29TBwfUzhmGy2XLyw5Lzcb1Ca','q29UDgLUDwuGChjVBxb0','q2fUBM90ihnLBMqGAw5WDxqGDg8G','cI0Gq2f0zwDVCNK6ia','Bwf4qMfJA2DYB3vUzenVBw1HBMrZr2XVyMfS','qwnJzxnZigrLBMLLzdOG','q29TBwfUzcb0CMfUC2XHDgvKigzVCIbxAw5KB3DZiennra','r2v0lvDTAu9IAMvJDcaTq2XHC3mGv2LUmZjFugH5C2LJywXnzw1VCNK','C3vJy2vZCW','qwn0Aw9Uia','ignVBw1HBMrZigzVCIbHz2vUDca','y29TBwfUza','yw5HBhL6zunVBw1HBMrdB21WyxrPyMLSAxr5','z2v0v29YA2LUz0rPCMvJDg9YEq','Aw5JBhvKzxm','DhjHBNnSyxrLvg9qB3DLCLnOzwXS','ywrKvg9iAxn0B3j5','CM1KAxi','oGOkt1jjr0LoquWGq09ntufordOkygbGcG','u0HfteW','zM9YBwf0','D29YA2LUz0rPCMvJDg9YAwvZ','tufyx0jbq0ThuK9vtKrFq09ntuforfnFr0XpqKfm','BgfZDe91Dhb1DfrPBwu','ywX0zxjUyxrPDMvZ','DgfZA2TPBgWGl1bjrcaKmq','BwTKAxi','y29UDgvUDa','zMLSzs1JCMvHDgu','AxndB21Tyw5Kq29TCgf0AwjSzvDPDgHuzxjTAw5HBa','q29TBwfUzcbJB21WBgv0zwq6ia','twvUDsbZzwXLy3rPB24','uhjLC3mGzw50zxi','wwvZl05Vihf1zxn0Aw9U','Dw5RBM93BG','vxnLCM5HBwuGChjVBxb0','u0Lhvevstq','zw50CMLLCW','uhjVBxb0igrLDgvJDgvKigLUigjHy2TNCM91BMqGy29TBwfUzcbZDgrLCNi','sgL0igvUDgvY','yM9VBgvHBG','q2XLyw5Lzcb1Cca','Bwf4q29Uy3vYCMvUDe9WzxjHDgLVBNm','y2HHBMDLlwrPCMvJDg9YEq','ig9Mia','BwfW','zMLSDgvY','DMfSDwvZ','DgfZA2TPBgWGl2yGl2LT','Dg9tDhjPBMC','rM9YrwfJAc1pyMPLy3q','r2v0lunOAwXKsxrLBsaTuMvJDxjZzsb8ie1Lyxn1CMuTt2jQzwn0','ywXSB3DLzenVBw1HBMrZ','y2XLyw51Cfn0ywXLq29TBwfUzhm','C3rHy2S','C3rKB3v0','C3bLy2LMAwnjC3n1zxm','Cgf0DgvYBG','EwvZlw5V','mtb3z0HlvvO','Aw50zwDLCG','mZiZotK4ENPWDK1x','qMfJA2DYB3vUzcbJB21Tyw5Kihn0yxj0zwqGD2L0AcbjrdOG','mtiXmte0mtDdsNvPEKy','y29Kzq','ota3mtKYDuHkz09O','y29TBwfUzeLKq291BNrLCG','ChjVy2vZCW','r2v0lvbYB2nLC3m','Dw5PDMvYC2fS','ywn0Aw9UCW','z2v0u3vWCg9YDgvKqwn0Aw9UCW','q29TBwfUzcbWCM9JzxnZigLZig5VDcbYDw5UAw5N','zxHLy3v0Aw9UvgLTzq','A2LSBgvK','yMXVy2TLzenVBw1HBMrZ','rMfPBgvKihrVignYzwf0zsbKAxjLy3rVCNKG','zgvSzxrL','zxnJyxbLlxnLCxvLBMnLCW','q29TBwfUzcbLCNjVCIbJAhvUAZOG','ywDLBNrjza','CgLWzq','cMbGyaOkq09ntuforcbbtKfmwvnjuZOklsbdB21Tyw5Kifr5Cgu6ia','yNvPBgruCMfUC2XHDgLVBLbYB21WDa','y29TCgf0AwjSzq','tw92zs1jDgvT','BwvUDq','ufnnB2r1BgvqyxrO','BM93','CMvXDwLYzxnqCM9Qzwn0','CgXHDgzVCM1qCM92AwrLza','zgvMia','y29TCgXLDgvK','DgvZDa','DxnLCI1PBMzV','ChjVBxb0rgv0zwn0B3i','q29TBwfUzcbWCM9JzxnZig5VDcbMB3vUzcbVCIbHBhjLywr5igTPBgXLza','BgLZDefNzw50q29TBwfUzhm','DgfZA2XPC3q','C2H1DgrVD24','y29TBwfUzfr5Cgu','C2vUze1LC3nHz2u','y29WEq','tw92zs1jDgvTicqXicqY','zMfPBgvK','C3rYAw5N','uMvTB3zLluL0zw0','vxnPBMCGquKGDhjHBNnSyxrPB24','CMvWBgfJzq','zxHLy3v0zunVBw1HBMrxAxrOu3bHD24','zgLZAY1PBMzV','Bwf0y2G','C3vIC3rYAw5N','Dg9VBhnszwDPC3rYEq','BwvZC2fNzvbYB2nLC3nVCG','C2XPy2u','zgLYic9Z','AxnbCNjHEq','AxnbBgXVD2vKq29TBwfUza','y3vZDg9TvMfSAwrHDgvqyxjHBwv0zxjZ','rMfPBgvKihrVihbHCNnLihrLCM1PBMfSihbHCMfTzxrLCNm6ia','sw5WDxqGC2vUDcbZDwnJzxnZzNvSBhK','Cg93zxjZAgvSBcaTyW','rxHWyw5KlufYy2HPDMu','zgf0yq','Ahr0Cc1JBgLLBNq','AxneAxjLy3rVCNK','zw52','cJiUifbYzxnLCNzLihrOzsbVCMLNAw5HBcbPBNrLBNqGyw5Kigz1BMn0Aw9UywXPDhKkmY4GsgfUzgXLigzPBguGCgf0AhmSihf1B3rPBMCSigfUzcbZEw50yxGGy29YCMvJDgX5cJqUieLMignYzwf0Aw5NigzPBgvZlcbLBNn1CMuGChjVCgvYigvUy29KAw5NigfUzcbSAw5LigvUzgLUz3mkns4GqwrKCMvZCYb0AguGC3bLy2LMAwmGy29TCgf0AwjPBgL0EsbPC3n1zxmGAwrLBNrPzMLLzcbHyM92zqO2lIbszxr1CM4Gt05mwsb0AguGDhjHBNnSyxrLzcbJB21Tyw5KlcbUB3rOAw5NigvSC2ukcLrsqu5ttefuruqGq09ntufordO','q3vYCMvUDcb3B3jRAw5NigrPCMvJDg9YEtOG','zgv0zwn0sgfUzW','AwyG','zxHPDa','u0Lhs0Lmta','u3rVCc1qCM9JzxnZ','zwnOBYaIjdeIid4','y29TBwfUzenHDgvNB3j5','zgv0zwn0zwruzxjTAw5HBa','C29Tzq','C2vUzeLUChv0','C29YDa','zwnOBW','igfJDgLVBNmGy29TCgXLDgvKihn1y2nLC3nMDwXSEq','ntqYmdKXnK53DunREG','zwnOBYaN','y3DK','tufyx0jbq0ThuK9vtKrFq09ntuforfnFuevsx0fhru5u','DhLWzq','DxnLCM5HBwu','mZGWmZK1ruzZvxLp','Dg9mB3DLCKnHC2u','zgLYzwn0B3j5lwn1CNjLBNq','CMvHC29U','C2LUz2XLlxf1B3rLCY1WCM9IBgvTyxrPyW','BgLZDc1KAxjLy3rVCNK','ChjVBxb0rgv0zwn0zwq','ChjVy2vZCY1RAwXS','ChjVy2vZCY1SAxn0','zxH0CMfJDenVBNrLBNq','cI0Gu3vNz2vZDgvKiefSDgvYBMf0AxzLoIa','Aw5PDgLHBgL6zvrLCM1PBMfSrgv0zwn0Aw9U','q29TBwfUzcbHBhjLywr5ihrLCM1PBMf0zwq','y2f0zwDVCNK','zMLSzs1KzwXLDgu','C3rHCNruAw1L','A2LSBenVBw1HBMq','DgLTzw91Da','C3bSAxq','DhjPBq','y3jLyxrLrgLYzwn0B3j5','A2v5CW','zgv0zwn0uhjVBxb0','v2LUzg93CYbdB21Tyw5KifbYB21WDcaOy21KlMv4zsK','zMLSzs1TB3zL','z2v0','r2v0lunVBNrLBNq','rgLYzwn0B3j5ignOyw5NzsbIBg9JA2vKoIa','yMfZAa','zw5KvgLTzq','qxr0zw1WDgLUzYbbssb0CMfUC2XHDgLVBIbMB3iGy29TCgXLEcbJB21Tyw5K','vgvYBwLUywWGzgv0zwn0zwq','u2v0lufJBa','icyG','igL0zw1ZigLUia','C3rKzxjY','zgLYzwn0B3j5','q29TBwfUzcbZCgf3BIbLCNjVCJOG','Bg9Nz2vY','y29TBwfUzfrYywnRzxi','BwfPBIGP','lunVBw1HBMq','D2HVyw1P','C3rKzxjYqNvMzMvY','y3vYBa','CMvSyxrPDMu','DhLWzsaKmq','rMfPBgvKihrVignOyw5NzsbKAxjLy3rVCNKGDg8G','yxbPs2v5','oIb1BMTUB3DUigfJDgLVBIb0ExbLoIa','AxnbyNnVBhv0zq','q29TBwfUzcbLEgvJDxrLzcbZDwnJzxnZzNvSBhKGAw4G','cI0Gq29TCgf0AwjPBgL0EsbjC3n1zxm6ia','tMv3luL0zw0Glvr5CguGrgLYzwn0B3j5','Bg9N','B2jQzwn0','zgLYzwn0B3j5qwnJzxnZtwfUywDLCG','q29TChjLC3mTqxjJAgL2zq','q29TBwfUzcb0Aw1LzcbVDxqSigTPBgXPBMCGChjVy2vZCZOG'];a0_0x1590=function(){return _0x138899;};return a0_0x1590();}import{TOOL_STATUS,SYSTEM_DEFAULTS}from'../utilities/constants.js';class PromptDetector{constructor(){const _0x4b80f5=a0_0x51ec;this['promptPatterns']=[{'pattern':/\(y\/n\)/i,'type':_0x4b80f5(0x1a6),'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':_0x4b80f5(0x18d)},{'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':_0x4b80f5(0x134),'description':_0x4b80f5(0x16d)},{'pattern':/proceed\?/i,'type':'continue','description':'Proceed\x20prompt'},{'pattern':/press any key to continue/i,'type':_0x4b80f5(0xfb),'description':'Press\x20any\x20key'},{'pattern':/press enter to continue/i,'type':'keypress','description':_0x4b80f5(0x18c)},{'pattern':/hit enter to continue/i,'type':_0x4b80f5(0xfb),'description':_0x4b80f5(0x193)},{'pattern':/password:/i,'type':'password','description':'Password\x20prompt'},{'pattern':/enter password/i,'type':_0x4b80f5(0x12f),'description':'Password\x20prompt'},{'pattern':/passphrase:/i,'type':'password','description':'Passphrase\x20prompt'},{'pattern':/username:/i,'type':_0x4b80f5(0xb4),'description':'Username\x20prompt'},{'pattern':/enter username/i,'type':_0x4b80f5(0xb4),'description':_0x4b80f5(0x18f)},{'pattern':/enter\s+\w+:/i,'type':'input','description':_0x4b80f5(0x13f)},{'pattern':/please enter/i,'type':'input','description':_0x4b80f5(0x13f)},{'pattern':/input:/i,'type':_0x4b80f5(0x116),'description':_0x4b80f5(0x13f)},{'pattern':/are you sure\?/i,'type':_0x4b80f5(0xf6),'description':'Confirmation\x20prompt'},{'pattern':/do you want to/i,'type':_0x4b80f5(0xf6),'description':_0x4b80f5(0x15d)},{'pattern':/would you like to/i,'type':_0x4b80f5(0xf6),'description':_0x4b80f5(0x15d)},{'pattern':/select an option/i,'type':'selection','description':_0x4b80f5(0x132)},{'pattern':/choose/i,'type':'selection','description':'Selection\x20prompt'},{'pattern':/\d+\)\s+\w+/g,'type':_0x4b80f5(0x1c2),'description':_0x4b80f5(0x18b)}];}[a0_0x492ede(0xcb)](_0x55e351,_0x35b828='stdout'){const _0x59b01f=a0_0x492ede;if(!_0x55e351||_0x55e351['trim']()['length']===0x0)return null;const _0xbcb487=_0x55e351[_0x59b01f(0xc7)]('\x0a'),_0x1768d4=_0xbcb487['slice'](-0x5)[_0x59b01f(0x11c)]('\x0a');for(const _0x2846ed of this['promptPatterns']){const _0x4bdb3a=_0x1768d4['match'](_0x2846ed[_0x59b01f(0x1a5)]);if(_0x4bdb3a)return{'detected':!![],'type':_0x2846ed[_0x59b01f(0xb3)],'description':_0x2846ed['description'],'matchedText':_0x4bdb3a[0x0],'matchIndex':_0x4bdb3a[_0x59b01f(0xfd)],'source':_0x35b828,'fullContext':_0x1768d4,'timestamp':Date[_0x59b01f(0x1c4)]()};}const _0x462a7f=_0xbcb487[_0xbcb487[_0x59b01f(0x117)]-0x1]||'';if(_0x462a7f[_0x59b01f(0xc8)]()['length']>0x0){const _0x1c4c97=/:\s*$/['test'](_0x462a7f),_0x5388d0=/\?\s*$/['test'](_0x462a7f);if(_0x1c4c97||_0x5388d0){const _0x9c1798=/\b(enter|type|provide|specify|input)\b/i['test'](_0x462a7f);if(_0x9c1798)return{'detected':!![],'type':'generic','description':_0x59b01f(0x12b),'matchedText':_0x462a7f['trim'](),'source':_0x35b828,'fullContext':_0x1768d4,'timestamp':Date['now'](),'confidence':0.7};}}return null;}[a0_0x492ede(0xa2)](_0x3c0f72,_0x51b53a=0x7530){const _0x33f0be=a0_0x492ede,_0x3bde91=Date[_0x33f0be(0x1c4)](),_0x222830=_0x3bde91-_0x3c0f72;return{'isHanging':_0x222830>=_0x51b53a,'timeSinceLastOutput':_0x222830,'threshold':_0x51b53a,'likelyWaiting':_0x222830>=_0x51b53a/0x2};}}class TerminalTool extends BaseTool{constructor(_0x8f0fc3={},_0x23615f=null){const _0xd338bd=a0_0x492ede;super(_0x8f0fc3,_0x23615f),this[_0xd338bd(0x1c5)]=![],this[_0xd338bd(0x14c)]=![],this[_0xd338bd(0xc6)]=_0x8f0fc3['timeout']||0x1d4c0,this['maxConcurrentOperations']=_0x8f0fc3[_0xd338bd(0x196)]||0x3,this[_0xd338bd(0x181)]=new Map(),this['commandHistory']=[],this['allowedCommands']=_0x8f0fc3['allowedCommands']||null,this['blockedCommands']=_0x8f0fc3['blockedCommands']||[_0xd338bd(0xf1),_0xd338bd(0x180),_0xd338bd(0x153),_0xd338bd(0x1cf),'reboot','halt'],this['directoryAccessManager']=new a0_0x19528a(_0x8f0fc3,_0x23615f),this[_0xd338bd(0x1cb)]=new PromptDetector(),this[_0xd338bd(0xdc)]=new Map(),this[_0xd338bd(0x1ae)]=0x0,this['MAX_BACKGROUND_COMMANDS_PER_AGENT']=_0x8f0fc3[_0xd338bd(0x154)]||0x5,this['MAX_BACKGROUND_COMMANDS_GLOBAL']=_0x8f0fc3[_0xd338bd(0x170)]||0x14,this[_0xd338bd(0x14e)]=_0x8f0fc3[_0xd338bd(0x115)]||0x3c,this[_0xd338bd(0xa9)]=null,this['platformType']=null,this['initializeTerminalDetection']();}[a0_0x492ede(0x105)](){const _0x277770=a0_0x492ede;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['timeout']+_0x277770(0x15b)+this[_0x277770(0xb2)]+'\x20per\x20agent,\x20'+this[_0x277770(0x182)]+'\x20global\x0a-\x20Auto-detects\x20prompts\x20and\x20updates\x20state\x20to\x20\x27waiting_for_input\x27\x0a\x0a**getCommandStatus(commandId,\x20agentId)**\x0a-\x20Get\x20real-time\x20status:\x20running,\x20waiting_for_input,\x20completed,\x20failed\x0a-\x20Returns\x20stdout/stderr\x20buffers,\x20exit\x20code,\x20timestamps\x0a-\x20Shows\x20prompt\x20detection\x20info\x20if\x20interactive\x20prompt\x20detected\x0a\x0a**sendInput(commandId,\x20input,\x20agentId)**\x0a-\x20Send\x20input\x20to\x20command\x27s\x20stdin\x20(answers\x20prompts)\x0a-\x20Automatically\x20adds\x20newline\x20if\x20not\x20present\x0a-\x20Updates\x20state\x20from\x20\x27waiting_for_input\x27\x20to\x20\x27running\x27\x0a\x0a**killCommand(commandId,\x20agentId)**\x0a-\x20Terminate\x20background\x20command\x20(SIGTERM\x20→\x20SIGKILL)\x0a-\x20Safe\x20to\x20call\x20on\x20already-completed\x20commands\x0a\x0a**listAgentCommands(agentId)**\x0a-\x20List\x20all\x20commands\x20(running\x20and\x20completed)\x20for\x20agent\x0a-\x20Useful\x20for\x20monitoring\x20multiple\x20background\x20processes\x0a\x0aBACKGROUND\x20COMMAND\x20WORKFLOW:\x0a1.\x20Start:\x20const\x20{commandId}\x20=\x20await\x20terminal.startBackgroundCommand(\x27npm\x20install\x27,\x20dir,\x20{agentId})\x0a2.\x20Wait:\x20Use\x20agent-delay\x20tool\x20to\x20wait\x20while\x20command\x20runs\x0a3.\x20Check:\x20const\x20status\x20=\x20terminal.getCommandStatus(commandId,\x20agentId)\x0a4.\x20If\x20prompt\x20detected:\x20terminal.sendInput(commandId,\x20\x27y\x27,\x20agentId)\x0a5.\x20Verify:\x20Check\x20status.state\x20===\x20\x27completed\x27\x20&&\x20status.exitCode\x20===\x200\x0a\x0aEXAMPLES:\x0aBasic\x20command\x20execution:\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>npm\x20install</run-command>\x0a[/tool]\x0a\x0aExecute\x20curl\x20command:\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>curl\x20-s\x20https://api.github.com/zen</run-command>\x0a[/tool]\x0a\x0aChange\x20directory\x20and\x20run\x20command:\x0a[tool\x20id=\x22terminal\x22]\x0a<change-directory>../frontend</change-directory>\x0a<run-command>npm\x20run\x20build</run-command>\x0a[/tool]\x0a\x0aPackage\x20management:\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>pip\x20install\x20-r\x20requirements.txt</run-command>\x0a[/tool]\x0a\x0aGit\x20operations:\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>git\x20status</run-command>\x0a[/tool]\x0a\x0a[tool\x20id=\x22terminal\x22]\x0a<run-command>git\x20add\x20.</run-command>\x0a<run-command>git\x20commit\x20-m\x20\x22Update\x20files\x22</run-command>\x0a[/tool]\x0a\x0aDirectory\x20operations\x20(if\x20FileSystem\x20tool\x20unavailable):\x0a[tool\x20id=\x22terminal\x22]\x0a<create-directory>backend</create-directory>\x0a[/tool]\x0a\x0aSECURITY\x20NOTES:\x0a-\x20Dangerous\x20commands\x20are\x20blocked\x20for\x20safety\x0a-\x20Commands\x20execute\x20in\x20isolated\x20environment\x0a-\x20Output\x20is\x20captured\x20and\x20returned\x20safely\x0a-\x20Long-running\x20commands\x20may\x20time\x20out\x20-\x20use\x20agent-delay\x20tool\x20to\x20wait\x0a\x0aBEST\x20PRACTICES:\x0a-\x20Use\x20FileSystem\x20tool\x20for\x20file/directory\x20creation\x20and\x20management\x0a-\x20Use\x20Terminal\x20tool\x20for\x20command-line\x20utilities\x20(npm,\x20git,\x20curl,\x20grep,\x20etc.)\x0a-\x20After\x20starting\x20long-running\x20commands,\x20use\x20agent-delay\x20tool\x20to\x20pause\x20checking\x0a-\x20Always\x20check\x20command\x20output\x20to\x20verify\x20success\x0a\x0aCURRENT\x20DIRECTORY:\x0aThe\x20tool\x20maintains\x20a\x20current\x20working\x20directory\x20context\x20per\x20agent.\x0aUse\x20change-directory\x20to\x20navigate,\x20and\x20subsequent\x20commands\x20will\x20execute\x20from\x20that\x20location.\x0a\x20\x20\x20\x20';}['parseParameters'](_0x4f2040){const _0x3748d1=a0_0x492ede;try{const _0x5be3a7={},_0x1f4910=a0_0x25a245['extractContent'](_0x4f2040,_0x3748d1(0x122)),_0x1685e8=a0_0x25a245[_0x3748d1(0xbe)](_0x4f2040,_0x3748d1(0x197)),_0x5898ca=a0_0x25a245['extractContent'](_0x4f2040,_0x3748d1(0xba)),_0x1bae20=a0_0x25a245['extractContent'](_0x4f2040,_0x3748d1(0xfe)),_0x53adbc=a0_0x25a245['extractContent'](_0x4f2040,'get-working-directory'),_0x516195=a0_0x25a245['extractContent'](_0x4f2040,'timeout'),_0x1d8e0d=a0_0x25a245['extractContent'](_0x4f2040,'async'),_0x3068bd=[];return _0x1f4910[_0x3748d1(0x117)]>0x0&&_0x3068bd['push']({'type':'run-command','command':_0x1f4910[0x0][_0x3748d1(0xc8)]()}),_0x1685e8[_0x3748d1(0x117)]>0x0&&_0x3068bd[_0x3748d1(0x16b)]({'type':_0x3748d1(0x197),'directory':_0x1685e8[0x0][_0x3748d1(0xc8)]()}),_0x5898ca['length']>0x0&&_0x3068bd[_0x3748d1(0x16b)]({'type':_0x3748d1(0xba),'directory':_0x5898ca[0x0]['trim']()||'.'}),_0x1bae20['length']>0x0&&_0x3068bd['push']({'type':_0x3748d1(0xfe),'directory':_0x1bae20[0x0][_0x3748d1(0xc8)]()}),_0x53adbc['length']>0x0&&_0x3068bd['push']({'type':_0x3748d1(0x104)}),_0x5be3a7[_0x3748d1(0x1b2)]=_0x3068bd,_0x516195[_0x3748d1(0x117)]>0x0&&(_0x5be3a7['timeout']=parseInt(_0x516195[0x0],0xa)),_0x1d8e0d[_0x3748d1(0x117)]>0x0&&(_0x5be3a7[_0x3748d1(0xf9)]=_0x1d8e0d[0x0]['toLowerCase']()==='true'),_0x5be3a7['rawContent']=_0x4f2040[_0x3748d1(0xc8)](),_0x5be3a7;}catch(_0x24a6b3){throw new Error(_0x3748d1(0x98)+_0x24a6b3[_0x3748d1(0x130)]);}}['getRequiredParameters'](){const _0x281d3a=a0_0x492ede;return[_0x281d3a(0x1b2)];}[a0_0x492ede(0x97)](_0x5852e1){const _0xe8530e=a0_0x492ede,_0x2799e8=[];if(!_0x5852e1[_0xe8530e(0x1b2)]||!Array[_0xe8530e(0x95)](_0x5852e1['actions'])||_0x5852e1[_0xe8530e(0x1b2)][_0xe8530e(0x117)]===0x0)_0x2799e8['push']('At\x20least\x20one\x20action\x20is\x20required');else for(const [_0x5c2178,_0x52cb8e]of _0x5852e1[_0xe8530e(0x1b2)][_0xe8530e(0x191)]()){if(!_0x52cb8e[_0xe8530e(0xb3)]){_0x2799e8[_0xe8530e(0x16b)]('Action\x20'+(_0x5c2178+0x1)+':\x20type\x20is\x20required');continue;}switch(_0x52cb8e[_0xe8530e(0xb3)]){case _0xe8530e(0x122):if(!_0x52cb8e[_0xe8530e(0x177)]||!_0x52cb8e[_0xe8530e(0x177)][_0xe8530e(0xc8)]())_0x2799e8[_0xe8530e(0x16b)]('Action\x20'+(_0x5c2178+0x1)+_0xe8530e(0x14a));else{if(this['isBlockedCommand'](_0x52cb8e[_0xe8530e(0x177)]))_0x2799e8['push'](_0xe8530e(0x175)+(_0x5c2178+0x1)+':\x20command\x20is\x20blocked\x20for\x20security:\x20'+_0x52cb8e['command']);else this['allowedCommands']&&!this['isAllowedCommand'](_0x52cb8e['command'])&&_0x2799e8['push']('Action\x20'+(_0x5c2178+0x1)+':\x20command\x20is\x20not\x20in\x20allowed\x20list:\x20'+_0x52cb8e['command']);}break;case'change-directory':case _0xe8530e(0xba):case'create-directory':(!_0x52cb8e['directory']||!_0x52cb8e['directory']['trim']())&&_0x2799e8['push']('Action\x20'+(_0x5c2178+0x1)+':\x20directory\x20is\x20required\x20for\x20'+_0x52cb8e[_0xe8530e(0xb3)]);break;case _0xe8530e(0x104):break;default:_0x2799e8[_0xe8530e(0x16b)]('Action\x20'+(_0x5c2178+0x1)+_0xe8530e(0xe6)+_0x52cb8e[_0xe8530e(0xb3)]);}}return _0x5852e1['timeout']&&(_0x5852e1['timeout']<0x3e8||_0x5852e1['timeout']>this[_0xe8530e(0xc6)])&&_0x2799e8[_0xe8530e(0x16b)]('Timeout\x20must\x20be\x20between\x201000\x20and\x20'+this[_0xe8530e(0xc6)]+'\x20milliseconds'),{'valid':_0x2799e8['length']===0x0,'errors':_0x2799e8};}async[a0_0x492ede(0x149)](_0xc03327,_0x23bd00){const _0x25d26b=a0_0x492ede,{actions:_0x3de208,timeout:_0x1aa522,async:_0x58d000}=_0xc03327,{agentId:_0x2b8569,projectDir:_0x5431c8,directoryAccess:_0xf2c32b}=_0x23bd00,_0x56f8b0=_0xf2c32b||this[_0x25d26b(0xed)]['createDirectoryAccess']({'workingDirectory':_0x5431c8||process[_0x25d26b(0xb1)](),'writeEnabledDirectories':[_0x5431c8||process['cwd']()],'restrictToProject':!![]});_0xf2c32b&&_0xf2c32b[_0x25d26b(0x123)]?console['log']('Terminal\x20DEBUG:\x20Using\x20agent\x20configured\x20working\x20directory:',_0xf2c32b['workingDirectory']):console[_0x25d26b(0xeb)]('Terminal\x20DEBUG:\x20Using\x20fallback\x20working\x20directory:',_0x5431c8||process[_0x25d26b(0xb1)]());const _0x327860=_0x2b8569+'-'+(_0x5431c8||'default');let _0x24de77=this[_0x25d26b(0x181)][_0x25d26b(0xce)](_0x327860)||this['directoryAccessManager'][_0x25d26b(0x179)](_0x56f8b0);const _0x1d0646=[];for(const _0x52a516 of _0x3de208){try{let _0x410f32;switch(_0x52a516['type']){case _0x25d26b(0x122):_0x410f32=await this[_0x25d26b(0x127)](_0x52a516[_0x25d26b(0x177)],_0x24de77,{'timeout':_0x1aa522||this['timeout'],'async':_0x58d000||![],'agentId':_0x2b8569,'context':{'toolsRegistry':_0x23bd00['toolsRegistry'],'aiService':_0x23bd00['aiService'],'apiKey':_0x23bd00['apiKey'],'customApiKeys':_0x23bd00[_0x25d26b(0x12e)],'platformProvided':_0x23bd00[_0x25d26b(0x1c6)]}});break;case'change-directory':_0x410f32=await this[_0x25d26b(0x13d)](_0x52a516[_0x25d26b(0xd9)],_0x24de77,_0x56f8b0),_0x24de77=_0x410f32['newDirectory'],this[_0x25d26b(0x181)][_0x25d26b(0xf0)](_0x327860,_0x24de77);break;case _0x25d26b(0xba):_0x410f32=await this['listDirectory'](_0x52a516['directory']==='.'?_0x24de77:_0x52a516[_0x25d26b(0xd9)]);break;case _0x25d26b(0xfe):_0x410f32=await this['createDirectory'](_0x52a516[_0x25d26b(0xd9)],_0x24de77);break;case _0x25d26b(0x104):_0x410f32={'success':!![],'action':'get-working-directory','workingDirectory':_0x24de77,'message':_0x25d26b(0xa1)+_0x24de77};break;default:throw new Error(_0x25d26b(0x102)+_0x52a516[_0x25d26b(0xb3)]);}_0x1d0646[_0x25d26b(0x16b)](_0x410f32),this['addToHistory'](_0x52a516,_0x410f32,_0x2b8569);}catch(_0x179eb8){const _0x21dabb={'success':![],'action':_0x52a516['type'],'error':_0x179eb8[_0x25d26b(0x130)],'command':_0x52a516[_0x25d26b(0x177)]||_0x52a516['directory'],'workingDirectory':_0x24de77};_0x1d0646['push'](_0x21dabb),this['addToHistory'](_0x52a516,_0x21dabb,_0x2b8569);}}const _0x3d5ac4=_0x1d0646['every'](_0x377ab0=>_0x377ab0[_0x25d26b(0x174)]),_0x31b821=_0x1d0646[_0x25d26b(0x19a)](_0x4c5d27=>!_0x4c5d27['success']);return{'success':_0x3d5ac4,'actions':_0x1d0646,'workingDirectory':_0x24de77,'executedActions':_0x3de208[_0x25d26b(0x117)],'failedActions':_0x31b821['length'],'toolUsed':'terminal','message':_0x3d5ac4?_0x25d26b(0x148)+_0x3de208[_0x25d26b(0x117)]+_0x25d26b(0xae):_0x31b821[_0x25d26b(0x117)]+_0x25d26b(0x198)+_0x3de208['length']+'\x20actions\x20failed'};}async[a0_0x492ede(0x127)](_0x5cfcc4,_0x59c935,_0x368c20={}){const _0x42b764=a0_0x492ede,{timeout:timeout=this[_0x42b764(0xc6)],async:_0x1902a2=![],agentId:_0x4b2949,context:_0x49f266}=_0x368c20,_0x30eb42=_0x5cfcc4;let _0x59a34f;try{_0x59a34f=await this['translateCommand'](_0x5cfcc4,{'agentId':_0x4b2949,'toolsRegistry':_0x49f266?.['toolsRegistry'],'messageProcessor':_0x49f266?.['messageProcessor'],'aiService':_0x49f266?.['aiService'],'apiKey':_0x49f266?.[_0x42b764(0xe5)],'customApiKeys':_0x49f266?.['customApiKeys'],'platformProvided':_0x49f266?.['platformProvided']});}catch(_0x57cfe5){this['logger']?.[_0x42b764(0x158)](_0x42b764(0x128),{'originalCommand':_0x30eb42,'error':_0x57cfe5[_0x42b764(0x130)]}),_0x59a34f=_0x5cfcc4;}return new Promise((_0xe92773,_0x239257)=>{const _0x482668=_0x42b764,_0xe2c32c=Date[_0x482668(0x1c4)]();this[_0x482668(0xdb)]?.['info']('Executing\x20command:\x20'+_0x59a34f,{'originalCommand':_0x30eb42,'translatedCommand':_0x59a34f,'terminal':this[_0x482668(0xa9)],'workingDirectory':_0x59c935,'timeout':timeout,'agentId':_0x4b2949});const _0x996819=exec(_0x59a34f,{'cwd':_0x59c935,'timeout':timeout,'maxBuffer':0x400*0x400,'env':{...process[_0x482668(0x9f)]}},(_0x5240ff,_0x1c4c55,_0x326c10)=>{const _0x4e71b7=_0x482668,_0x446fb3=Date['now']()-_0xe2c32c;if(_0x5240ff){this['logger']?.[_0x4e71b7(0x101)](_0x4e71b7(0x12c)+_0x59a34f,{'originalCommand':_0x30eb42,'translatedCommand':_0x59a34f,'error':_0x5240ff[_0x4e71b7(0x130)],'workingDirectory':_0x59c935,'executionTime':_0x446fb3}),_0xe92773({'success':![],'action':'run-command','command':_0x30eb42,'translatedCommand':_0x59a34f!==_0x30eb42?_0x59a34f:undefined,'error':_0x5240ff[_0x4e71b7(0x130)],'stderr':_0x326c10[_0x4e71b7(0xc8)](),'stdout':_0x1c4c55[_0x4e71b7(0xc8)](),'exitCode':_0x5240ff[_0x4e71b7(0x1ac)],'executionTime':_0x446fb3,'workingDirectory':_0x59c935});return;}this['logger']?.['info'](_0x4e71b7(0x18a)+_0x59a34f,{'originalCommand':_0x30eb42,'translatedCommand':_0x59a34f,'executionTime':_0x446fb3,'stdoutLength':_0x1c4c55['length'],'stderrLength':_0x326c10['length']}),_0xe92773({'success':!![],'action':_0x4e71b7(0x122),'command':_0x30eb42,'translatedCommand':_0x59a34f!==_0x30eb42?_0x59a34f:undefined,'stdout':_0x1c4c55[_0x4e71b7(0xc8)](),'stderr':_0x326c10[_0x4e71b7(0xc8)](),'exitCode':0x0,'executionTime':_0x446fb3,'workingDirectory':_0x59c935,'message':_0x4e71b7(0xe8)+_0x446fb3+'ms'});});setTimeout(()=>{const _0x37edf3=_0x482668;!_0x996819[_0x37edf3(0x1b6)]&&(_0x996819['kill']('SIGTERM'),_0x239257(new Error(_0x37edf3(0x152)+timeout+_0x37edf3(0x11d)+_0x59a34f+'\x20(original:\x20'+_0x30eb42+')')));},timeout);});}async[a0_0x492ede(0x8d)](_0x19198,_0x282391,_0x34fac4={}){const _0x2ccde8=a0_0x492ede,{timeout:timeout=this[_0x2ccde8(0xc6)],agentId:_0x332f22,context:_0x4df968}=_0x34fac4,_0x22af8d=_0x19198;let _0x377249;try{_0x377249=await this[_0x2ccde8(0x106)](_0x19198,{'agentId':_0x332f22,'toolsRegistry':_0x4df968?.['toolsRegistry'],'messageProcessor':_0x4df968?.[_0x2ccde8(0x92)],'aiService':_0x4df968?.['aiService'],'apiKey':_0x4df968?.[_0x2ccde8(0xe5)],'customApiKeys':_0x4df968?.[_0x2ccde8(0x12e)],'platformProvided':_0x4df968?.[_0x2ccde8(0x1c6)]});}catch(_0x13e30){this['logger']?.['warn']('Command\x20translation\x20failed,\x20using\x20original\x20command',{'originalCommand':_0x22af8d,'error':_0x13e30[_0x2ccde8(0x130)]}),_0x377249=_0x19198;}return new Promise((_0x3c5458,_0x3cfef9)=>{const _0x29a488=_0x2ccde8,_0x43b4e6=Date['now']();this[_0x29a488(0xdb)]?.['info'](_0x29a488(0x137)+_0x377249,{'originalCommand':_0x22af8d,'translatedCommand':_0x377249,'terminal':this['detectedTerminal'],'workingDirectory':_0x282391,'timeout':timeout,'agentId':_0x332f22});let _0x5463e8;if(this['detectedTerminal']==='cmd'||this['detectedTerminal']==='powershell'){const _0xca1215=this['detectedTerminal']===_0x29a488(0x10d)?_0x29a488(0x10d):'cmd',_0x5117ea=this['detectedTerminal']==='powershell'?['-Command',_0x377249]:['/c',_0x377249];_0x5463e8=spawn(_0xca1215,_0x5117ea,{'cwd':_0x282391,'env':{...process['env']},'windowsHide':!![]});}else _0x5463e8=spawn('sh',['-c',_0x377249],{'cwd':_0x282391,'env':{...process[_0x29a488(0x9f)]}});let _0x376773='',_0x11e1a1='',_0x2dce91=![],_0x3b477f=null,_0x256a7d=Date['now'](),_0x5865f2=null;const _0x2de74e=setTimeout(()=>{const _0x50d1cd=_0x29a488;!_0x5463e8[_0x50d1cd(0x1b6)]&&_0x3b477f===null&&(_0x2dce91=!![],this[_0x50d1cd(0xdb)]?.['warn'](_0x50d1cd(0xef)+_0x377249,{'timeout':timeout,'agentId':_0x332f22}),_0x5463e8['kill'](_0x50d1cd(0x190)),setTimeout(()=>{const _0x407308=_0x50d1cd;!_0x5463e8[_0x407308(0x1b6)]&&_0x5463e8['kill'](_0x407308(0xa5));},0x1388));},timeout);_0x5463e8[_0x29a488(0x1a3)]['on'](_0x29a488(0x9c),_0x22e335=>{const _0x190b3b=_0x29a488,_0x4b4807=_0x22e335[_0x190b3b(0x19d)]();_0x376773+=_0x4b4807,_0x256a7d=Date['now'](),this[_0x190b3b(0xdb)]?.['debug']('Command\x20output\x20chunk:\x20'+_0x4b4807['substring'](0x0,0x64),{'agentId':_0x332f22,'command':_0x22af8d[_0x190b3b(0x90)](0x0,0x32)});if(!_0x5865f2){const _0x14d7fc=this[_0x190b3b(0x1cb)][_0x190b3b(0xcb)](_0x376773,'stdout');_0x14d7fc&&(_0x5865f2=_0x14d7fc,this['logger']?.['info']('Prompt\x20detected\x20in\x20stdout',{'type':_0x14d7fc[_0x190b3b(0xb3)],'description':_0x14d7fc['description'],'matchedText':_0x14d7fc['matchedText'],'agentId':_0x332f22,'command':_0x22af8d[_0x190b3b(0x90)](0x0,0x32)}));}}),_0x5463e8['stderr']['on']('data',_0x4aeab3=>{const _0x36fb41=_0x29a488,_0x4b2e6b=_0x4aeab3['toString']();_0x11e1a1+=_0x4b2e6b,_0x256a7d=Date[_0x36fb41(0x1c4)](),this['logger']?.[_0x36fb41(0x140)](_0x36fb41(0x1bb)+_0x4b2e6b[_0x36fb41(0x90)](0x0,0x64),{'agentId':_0x332f22,'command':_0x22af8d['substring'](0x0,0x32)});if(!_0x5865f2){const _0x15cf5b=this['promptDetector'][_0x36fb41(0xcb)](_0x11e1a1,_0x36fb41(0xd8));_0x15cf5b&&(_0x5865f2=_0x15cf5b,this[_0x36fb41(0xdb)]?.['info']('Prompt\x20detected\x20in\x20stderr',{'type':_0x15cf5b[_0x36fb41(0xb3)],'description':_0x15cf5b[_0x36fb41(0x141)],'matchedText':_0x15cf5b['matchedText'],'agentId':_0x332f22,'command':_0x22af8d['substring'](0x0,0x32)}));}}),_0x5463e8['on']('exit',(_0x3e3919,_0x297446)=>{const _0x581219=_0x29a488;clearTimeout(_0x2de74e),_0x3b477f=_0x3e3919;const _0x23a383=Date[_0x581219(0x1c4)]()-_0x43b4e6,_0x479f85=Date['now']()-_0x256a7d;this[_0x581219(0xdb)]?.['info']('Command\x20process\x20exited:\x20'+_0x377249,{'exitCode':_0x3e3919,'signal':_0x297446,'executionTime':_0x23a383,'timedOut':_0x2dce91,'stdoutLength':_0x376773['length'],'stderrLength':_0x11e1a1['length'],'promptDetected':!!_0x5865f2,'timeSinceLastOutput':_0x479f85});const _0x2a5f84={'action':'run-command','command':_0x22af8d,'translatedCommand':_0x377249!==_0x22af8d?_0x377249:undefined,'stdout':_0x376773[_0x581219(0xc8)](),'stderr':_0x11e1a1['trim'](),'exitCode':_0x3e3919,'executionTime':_0x23a383,'workingDirectory':_0x282391,'promptDetected':!!_0x5865f2,'promptInfo':_0x5865f2||undefined,'lastOutputTime':_0x256a7d,'timeSinceLastOutput':_0x479f85};if(_0x2dce91){_0x3c5458({..._0x2a5f84,'success':![],'error':'Command\x20timed\x20out\x20after\x20'+timeout+'ms','exitCode':_0x3e3919||-0x1,'timedOut':!![]});return;}if(_0x3e3919!==0x0){this[_0x581219(0xdb)]?.['error']('Command\x20failed\x20with\x20exit\x20code\x20'+_0x3e3919+':\x20'+_0x377249,{'originalCommand':_0x22af8d,'translatedCommand':_0x377249,'exitCode':_0x3e3919,'stderr':_0x11e1a1['substring'](0x0,0xc8),'executionTime':_0x23a383,'promptDetected':!!_0x5865f2}),_0x3c5458({..._0x2a5f84,'success':![],'error':'Command\x20exited\x20with\x20code\x20'+_0x3e3919});return;}this[_0x581219(0xdb)]?.['info']('Command\x20completed\x20successfully:\x20'+_0x377249,{'originalCommand':_0x22af8d,'executionTime':_0x23a383,'stdoutLength':_0x376773['length'],'stderrLength':_0x11e1a1['length'],'promptDetected':!!_0x5865f2}),_0x3c5458({..._0x2a5f84,'success':!![],'exitCode':0x0,'message':'Command\x20executed\x20successfully\x20in\x20'+_0x23a383+'ms'});}),_0x5463e8['on'](_0x29a488(0x101),_0x1de296=>{const _0x31d1f=_0x29a488;clearTimeout(_0x2de74e);const _0x3a1cb9=Date['now']()-_0x43b4e6,_0x4f5aed=Date['now']()-_0x256a7d;this['logger']?.[_0x31d1f(0x101)](_0x31d1f(0xda)+_0x377249,{'originalCommand':_0x22af8d,'error':_0x1de296[_0x31d1f(0x130)],'executionTime':_0x3a1cb9,'promptDetected':!!_0x5865f2}),_0x3c5458({'success':![],'action':_0x31d1f(0x122),'command':_0x22af8d,'translatedCommand':_0x377249!==_0x22af8d?_0x377249:undefined,'error':_0x1de296[_0x31d1f(0x130)],'stderr':_0x11e1a1['trim'](),'stdout':_0x376773[_0x31d1f(0xc8)](),'exitCode':-0x1,'executionTime':_0x3a1cb9,'workingDirectory':_0x282391,'promptDetected':!!_0x5865f2,'promptInfo':_0x5865f2||undefined,'lastOutputTime':_0x256a7d,'timeSinceLastOutput':_0x4f5aed});});});}async[a0_0x492ede(0x13d)](_0x5b5763,_0x1c1496,_0x25c5bd){const _0x30a977=a0_0x492ede;try{let _0x58761c;a0_0x469784['isAbsolute'](_0x5b5763)?_0x58761c=_0x5b5763:_0x58761c=a0_0x469784[_0x30a977(0x129)](_0x1c1496,_0x5b5763);const _0x4b5d9c=await a0_0x1bc23b['stat'](_0x58761c);if(!_0x4b5d9c[_0x30a977(0x9e)]())throw new Error('Not\x20a\x20directory:\x20'+_0x58761c);const _0x205c96=this[_0x30a977(0xed)]['validateReadAccess'](_0x58761c,_0x25c5bd);if(!_0x205c96['allowed']){this[_0x30a977(0xdb)]?.[_0x30a977(0x158)](_0x30a977(0xd0)+_0x205c96[_0x30a977(0xb8)],{'targetDirectory':_0x58761c,'reason':_0x205c96[_0x30a977(0xb8)],'category':_0x205c96['category']});throw new Error(_0x30a977(0x171)+_0x205c96[_0x30a977(0xb8)]);}return{'success':!![],'action':'change-directory','previousDirectory':_0x1c1496,'newDirectory':_0x58761c,'message':'Changed\x20directory\x20to\x20'+_0x58761c};}catch(_0x86bfbb){throw new Error(_0x30a977(0xe4)+_0x5b5763+':\x20'+_0x86bfbb[_0x30a977(0x130)]);}}async['listDirectory'](_0x5df34b){const _0x34e801=a0_0x492ede;try{const _0x352a7c=await a0_0x1bc23b['readdir'](_0x5df34b,{'withFileTypes':!![]}),_0x3498e3=_0x352a7c[_0x34e801(0x199)](_0x5ddc12=>({'name':_0x5ddc12['name'],'type':_0x5ddc12['isDirectory']()?_0x34e801(0xd9):_0x34e801(0x121),'isSymlink':_0x5ddc12['isSymbolicLink']()}));return{'success':!![],'action':'list-directory','directory':_0x5df34b,'contents':_0x3498e3,'totalItems':_0x3498e3['length'],'directories':_0x3498e3['filter'](_0x5374e8=>_0x5374e8['type']==='directory')['length'],'files':_0x3498e3[_0x34e801(0x19a)](_0x42a886=>_0x42a886[_0x34e801(0xb3)]==='file')[_0x34e801(0x117)],'message':'Listed\x20'+_0x3498e3[_0x34e801(0x117)]+_0x34e801(0xd7)+_0x5df34b};}catch(_0x37a78e){throw new Error('Failed\x20to\x20list\x20directory\x20'+_0x5df34b+':\x20'+_0x37a78e[_0x34e801(0x130)]);}}async[a0_0x492ede(0xc9)](_0x39e412,_0x2df872){const _0x404e01=a0_0x492ede;try{let _0x528533;return a0_0x469784[_0x404e01(0xe7)](_0x39e412)?_0x528533=_0x39e412:_0x528533=a0_0x469784['resolve'](_0x2df872,_0x39e412),await a0_0x1bc23b[_0x404e01(0x186)](_0x528533,{'recursive':!![]}),{'success':!![],'action':'create-directory','directory':_0x528533,'relativePath':a0_0x469784[_0x404e01(0xe2)](_0x2df872,_0x528533),'message':_0x404e01(0x169)+_0x528533};}catch(_0x5ce0a1){throw new Error(_0x404e01(0x1b8)+_0x39e412+':\x20'+_0x5ce0a1[_0x404e01(0x130)]);}}['isBlockedCommand'](_0x4f4400){const _0x2e2a2a=a0_0x492ede,_0x42c284=_0x4f4400['toLowerCase']()[_0x2e2a2a(0xc8)]();return this[_0x2e2a2a(0x1b7)]['some'](_0x31ffea=>{const _0x30d4cb=_0x31ffea['toLowerCase']();return _0x42c284===_0x30d4cb||_0x42c284['startsWith'](_0x30d4cb+'\x20');});}[a0_0x492ede(0x96)](_0x23e658){const _0x389326=a0_0x492ede;if(!this[_0x389326(0x1a0)])return!![];const _0x41991a=_0x23e658['toLowerCase']()['trim'](),_0x3df2f9=_0x41991a['split']('\x20')[0x0];return this['allowedCommands'][_0x389326(0xaa)](_0x36583b=>_0x36583b['toLowerCase']()===_0x3df2f9||_0x41991a['startsWith'](_0x36583b[_0x389326(0xb6)]()+'\x20'));}[a0_0x492ede(0x17c)](_0x32e3ef,_0x3d411c,_0xda1665){const _0x5a7b3c=a0_0x492ede,_0x1a09e0={'timestamp':new Date()['toISOString'](),'agentId':_0xda1665,'action':_0x32e3ef['type'],'command':_0x32e3ef[_0x5a7b3c(0x177)]||_0x32e3ef[_0x5a7b3c(0xd9)],'success':_0x3d411c['success'],'executionTime':_0x3d411c[_0x5a7b3c(0x1b5)]||0x0,'workingDirectory':_0x3d411c[_0x5a7b3c(0x123)]};this[_0x5a7b3c(0x168)][_0x5a7b3c(0x16b)](_0x1a09e0),this['commandHistory'][_0x5a7b3c(0x117)]>0x64&&(this['commandHistory']=this['commandHistory'][_0x5a7b3c(0x93)](-0x64));}[a0_0x492ede(0x1b3)](){const _0x143480=a0_0x492ede;return[_0x143480(0x122),'change-directory',_0x143480(0xba),'create-directory','get-working-directory'];}[a0_0x492ede(0x139)](){const _0x707474=a0_0x492ede;return{'type':_0x707474(0xec),'properties':{'actions':{'type':'array','minItems':0x1,'items':{'type':'object','properties':{'type':{'type':_0x707474(0x1d5),'enum':this[_0x707474(0x1b3)]()},'command':{'type':_0x707474(0x1d5)},'directory':{'type':_0x707474(0x1d5)}},'required':[_0x707474(0xb3)]}},'timeout':{'type':_0x707474(0x1a8),'minimum':0x3e8,'maximum':this[_0x707474(0xc6)]},'async':{'type':_0x707474(0x194)}},'required':[_0x707474(0x1b2)]};}[a0_0x492ede(0x11a)](_0x1ea066=null){const _0x185d98=a0_0x492ede;if(_0x1ea066)return this[_0x185d98(0x168)][_0x185d98(0x19a)](_0x1b95a5=>_0x1b95a5['agentId']===_0x1ea066);return[...this[_0x185d98(0x168)]];}[a0_0x492ede(0x165)](_0x4ef98f){const _0x43d0c8=a0_0x492ede;for(const [_0x555ecb]of this['workingDirectories']){_0x555ecb[_0x43d0c8(0x11f)](_0x4ef98f+'-')&&this[_0x43d0c8(0x181)][_0x43d0c8(0x1b9)](_0x555ecb);}}[a0_0x492ede(0x167)](_0xb8606a,_0x4ea0f5=null){const _0x3be198=a0_0x492ede,_0x1415d9=_0xb8606a+'-'+(_0x4ea0f5||'default');return this[_0x3be198(0x181)]['get'](_0x1415d9)||_0x4ea0f5||process['cwd']();}[a0_0x492ede(0xc0)](){const _0xd6135d=a0_0x492ede;this['platformType']=process['platform'];if(process['platform']===_0xd6135d(0x126)){if(process[_0xd6135d(0x9f)][_0xd6135d(0x1c3)])this[_0xd6135d(0xa9)]=_0xd6135d(0x10d);else process[_0xd6135d(0x9f)]['SHELL']&&process['env'][_0xd6135d(0x17f)][_0xd6135d(0x17a)](_0xd6135d(0xd1))?this[_0xd6135d(0xa9)]=_0xd6135d(0xd1):this['detectedTerminal']='cmd';}else process[_0xd6135d(0x155)]==='darwin'?this[_0xd6135d(0xa9)]='bash':this['detectedTerminal']='bash';this[_0xd6135d(0xdb)]?.[_0xd6135d(0x14f)](_0xd6135d(0xd4),{'platform':this[_0xd6135d(0xff)],'terminal':this['detectedTerminal'],'shell':process[_0xd6135d(0x9f)][_0xd6135d(0x17f)]});}async['translateCommand'](_0x44bde0,_0x21821e={}){const _0x1b5d7d=a0_0x492ede,_0xbe6d60=_0x44bde0['trim'](),_0x35776a=this[_0x1b5d7d(0x178)](_0xbe6d60);this[_0x1b5d7d(0xdb)]?.['info'](_0x1b5d7d(0x114),{'command':_0xbe6d60,'detectedTerminal':_0x35776a[_0x1b5d7d(0xa9)],'commandType':_0x35776a[_0x1b5d7d(0x1d0)],'commandCategory':_0x35776a[_0x1b5d7d(0xa8)],'compatible':_0x35776a[_0x1b5d7d(0x1c0)],'issues':_0x35776a[_0x1b5d7d(0x1a4)],'suggestedAction':_0x35776a['suggestedAction'],'confidence':_0x35776a['confidence']});if(_0x35776a[_0x1b5d7d(0x1c0)])return _0x44bde0;let _0x16089a=null;if(this['detectedTerminal']===_0x1b5d7d(0x100))_0x16089a=this['translateToWindowsCmd'](_0xbe6d60);else{if(this[_0x1b5d7d(0xa9)]===_0x1b5d7d(0x10d))_0x16089a=this[_0x1b5d7d(0x17b)](_0xbe6d60);else this[_0x1b5d7d(0xa9)]===_0x1b5d7d(0xd1)&&(_0x16089a=this['translateToBash'](_0xbe6d60));}if(_0x16089a&&this['isSimpleCommand'](_0xbe6d60))return this[_0x1b5d7d(0xdb)]?.[_0x1b5d7d(0x14f)]('Using\x20simple\x20translation',{'original':_0x44bde0,'translated':_0x16089a,'method':'simple'}),_0x16089a;if(_0x21821e[_0x1b5d7d(0x111)]||_0x21821e[_0x1b5d7d(0x91)]&&_0x21821e['agentId']){this[_0x1b5d7d(0xdb)]?.['info'](_0x1b5d7d(0xd3),{'command':_0x44bde0['substring'](0x0,0x64)+'...','hasAiService':!!_0x21821e['aiService'],'hasToolsRegistry':!!_0x21821e['toolsRegistry'],'agentId':_0x21821e['agentId']});try{const _0x363bad=await this[_0x1b5d7d(0x10f)](_0x44bde0,_0x21821e);if(_0x363bad&&_0x363bad[_0x1b5d7d(0xc8)]()!==_0x44bde0[_0x1b5d7d(0xc8)]())return this['logger']?.[_0x1b5d7d(0x14f)](_0x1b5d7d(0x1d7),{'original':_0x44bde0,'translated':_0x363bad,'method':'ai'}),_0x363bad;else this[_0x1b5d7d(0xdb)]?.[_0x1b5d7d(0x158)](_0x1b5d7d(0x10b),{'original':_0x44bde0,'translated':_0x363bad});}catch(_0x670631){this['logger']?.['warn'](_0x1b5d7d(0x10a),{'original':_0x44bde0,'error':_0x670631['message'],'stack':_0x670631[_0x1b5d7d(0x1a2)]});}}else this['logger']?.['warn']('AI\x20translation\x20not\x20available\x20-\x20missing\x20context',{'hasAiService':!!_0x21821e[_0x1b5d7d(0x111)],'hasToolsRegistry':!!_0x21821e['toolsRegistry'],'hasAgentId':!!_0x21821e[_0x1b5d7d(0x1bc)],'contextKeys':Object[_0x1b5d7d(0xca)](_0x21821e)});return _0x16089a||_0x44bde0;}['isSimpleCommand'](_0x50320f){const _0x39cda8=a0_0x492ede,_0x5bae0f=_0x50320f['toLowerCase']();if(_0x50320f[_0x39cda8(0x17a)]('\x5cn')||_0x50320f[_0x39cda8(0x17a)]('\x5cr')||_0x50320f[_0x39cda8(0x17a)]('\x5ct'))return![];if(_0x50320f['includes']('\x0a')||_0x50320f[_0x39cda8(0x17a)]('\x0d'))return![];if(_0x50320f[_0x39cda8(0x17a)]('#include')||_0x50320f['includes']('printf')||_0x50320f['includes'](_0x39cda8(0xdd)))return![];if(_0x50320f[_0x39cda8(0x17a)](_0x39cda8(0x1c7))||_0x50320f[_0x39cda8(0x17a)](_0x39cda8(0xf4))||_0x50320f['includes']('class\x20'))return![];if(_0x50320f[_0x39cda8(0x17a)]('echo\x20\x27')&&!_0x50320f['includes']('echo\x20\x22'))return![];const _0x4761b6=_0x50320f[_0x39cda8(0x8f)](/'([^']*)'/);if(_0x4761b6&&_0x4761b6[0x1][_0x39cda8(0x117)]>0x32)return![];if(this['detectedTerminal']==='cmd'&&_0x50320f['includes']('>')&&_0x50320f['includes']('/')&&!_0x50320f[_0x39cda8(0x17a)]('\x5c'))return![];if(_0x50320f['includes']('\x20&&\x20')||_0x50320f[_0x39cda8(0x17a)](_0x39cda8(0x162))||_0x50320f['includes'](';\x20'))return![];if(_0x50320f[_0x39cda8(0x17a)]('$(')||_0x50320f[_0x39cda8(0x17a)]('`')||_0x50320f[_0x39cda8(0x17a)]('{')||_0x50320f['includes']('['))return![];if(_0x5bae0f['includes']('for\x20')||_0x5bae0f['includes'](_0x39cda8(0x14d))||_0x5bae0f['includes'](_0x39cda8(0xa3)))return![];if(_0x5bae0f['includes']('export ')||_0x5bae0f['includes']('source\x20'))return![];if(_0x50320f['includes']('\x20|\x20')||_0x50320f[_0x39cda8(0x17a)]('\x20>\x20&'))return![];return!![];}async['translateCommandWithAI'](_0x3108f2,_0x21b223){const _0x4f46b4=a0_0x492ede;let _0x2e4dcf=_0x21b223['aiService'];if(!_0x2e4dcf&&_0x21b223[_0x4f46b4(0x91)]&&_0x21b223['agentId']){const _0x5aadbb=_0x21b223[_0x4f46b4(0x92)];_0x5aadbb&&_0x5aadbb['aiService']&&(_0x2e4dcf=_0x5aadbb[_0x4f46b4(0x111)]);}if(!_0x2e4dcf)throw new Error('AI\x20service\x20not\x20available\x20for\x20command\x20translation');const _0x27b269=this['buildTranslationPrompt'](_0x3108f2),_0x5153d4=_0x4f46b4(0x107);try{const _0x20e76f=await _0x2e4dcf[_0x4f46b4(0x1d1)](_0x5153d4,_0x27b269,{'agentId':_0x21b223[_0x4f46b4(0x1bc)],'temperature':0.1,'maxTokens':0xc8,'apiKey':_0x21b223[_0x4f46b4(0xe5)],'customApiKeys':_0x21b223['customApiKeys'],'platformProvided':_0x21b223['platformProvided']}),_0xc8047d=this['extractTranslatedCommand'](_0x20e76f[_0x4f46b4(0x187)]);return this['logger']?.[_0x4f46b4(0x140)](_0x4f46b4(0x147),{'original':_0x3108f2,'translated':_0xc8047d,'model':_0x5153d4,'terminal':this['detectedTerminal']}),_0xc8047d;}catch(_0x149f8b){this[_0x4f46b4(0xdb)]?.['error'](_0x4f46b4(0x151),{'command':_0x3108f2,'terminal':this['detectedTerminal'],'error':_0x149f8b[_0x4f46b4(0x130)]});throw _0x149f8b;}}[a0_0x492ede(0x1bf)](_0x105aa6){const _0x36d994=a0_0x492ede,_0x96c034={'cmd':_0x36d994(0xcc),'powershell':'Windows\x20PowerShell','bash':_0x36d994(0x157)},_0x29998e=_0x96c034[this['detectedTerminal']]||this[_0x36d994(0xa9)],_0x1c8658=this[_0x36d994(0x178)](_0x105aa6);let _0x3788fb='Translate\x20this\x20command\x20to\x20work\x20correctly\x20in\x20'+_0x29998e+_0x36d994(0x17e)+_0x105aa6+_0x36d994(0x1be)+_0x1c8658[_0x36d994(0x1d0)]+_0x36d994(0x16f)+_0x1c8658[_0x36d994(0xa8)]+_0x36d994(0x138)+_0x29998e+_0x36d994(0xe9)+(_0x1c8658['specificIssues'][_0x36d994(0x11c)](',\x20')||'None\x20detected');return _0x1c8658[_0x36d994(0x1d0)]==='unix'&&_0x1c8658[_0x36d994(0x184)]&&_0x1c8658['alternatives'][this['detectedTerminal']]&&(_0x3788fb+=_0x36d994(0xbf)+_0x1c8658['alternatives'][this[_0x36d994(0xa9)]]),_0x3788fb+=_0x36d994(0x159)+_0x29998e+_0x36d994(0xa0),_0x3788fb;}['extractTranslatedCommand'](_0x5520e5){const _0x8637ae=a0_0x492ede;let _0x3e38e7=_0x5520e5['replace'](/```[a-z]*\n?(.*?)\n?```/s,'$1');_0x3e38e7=_0x3e38e7['replace'](/^(TRANSLATED COMMAND:|Command:|Result:)\s*/i,'');const _0x19ef33=_0x3e38e7['trim']()['split']('\x0a');return _0x19ef33[_0x8637ae(0x117)]>0x1&&!_0x3e38e7['includes']('&&')&&!_0x3e38e7[_0x8637ae(0x17a)]('||')&&(_0x3e38e7=_0x19ef33[0x0]['trim']()),_0x3e38e7['trim']();}['analyzeCommandCompatibility'](_0x56c65f){const _0x458ac6=a0_0x492ede,_0x31ccda=this['classifyCommand'](_0x56c65f),_0x16a67a=this[_0x458ac6(0x189)](_0x31ccda,this['detectedTerminal']);return{'compatible':_0x16a67a,'detectedTerminal':this['detectedTerminal'],'commandType':_0x31ccda['type'],'commandCategory':_0x31ccda[_0x458ac6(0xc2)],'specificIssues':_0x31ccda[_0x458ac6(0x13a)],'suggestedAction':_0x16a67a?_0x458ac6(0x149):'translate','confidence':_0x31ccda['confidence']};}[a0_0x492ede(0x125)](_0x1cda23){const _0x1b0d7f=a0_0x492ede;return this[_0x1b0d7f(0x178)](_0x1cda23)[_0x1b0d7f(0x1c0)];}['classifyCommand'](_0x3e191e){const _0x39b07e=a0_0x492ede,_0x1c62bd=_0x3e191e['toLowerCase']()[_0x39b07e(0xc8)](),_0x135ec8=_0x1c62bd['split']('\x20')[0x0],_0x50b8b4=[];let _0x4a9982=0.9;const _0x53d1a5={'ls':{'category':'file-listing','alternatives':{'cmd':_0x39b07e(0x13c),'powershell':_0x39b07e(0x124)}},'cat':{'category':'file-viewing','alternatives':{'cmd':'type','powershell':_0x39b07e(0xcf)}},'grep':{'category':'text-search','alternatives':{'cmd':'findstr','powershell':_0x39b07e(0x12a)}},'find':{'category':'file-search','alternatives':{'cmd':_0x39b07e(0x94),'powershell':'Get-ChildItem\x20-Recurse'}},'head':{'category':'file-viewing','alternatives':{'cmd':'more','powershell':'Get-Content\x20-Head'}},'tail':{'category':'file-viewing','alternatives':{'cmd':_0x39b07e(0x133),'powershell':'Get-Content\x20-Tail'}},'wc':{'category':'text-analysis','alternatives':{'cmd':_0x39b07e(0x16a),'powershell':'Measure-Object'}},'cp':{'category':_0x39b07e(0x120),'alternatives':{'cmd':_0x39b07e(0x1d2),'powershell':'Copy-Item'}},'mv':{'category':_0x39b07e(0xcd),'alternatives':{'cmd':'move','powershell':'Move-Item'}},'rm':{'category':'file-delete','alternatives':{'cmd':'del','powershell':'Remove-Item'}},'mkdir':{'category':'directory-create','alternatives':{'cmd':_0x39b07e(0x186),'powershell':_0x39b07e(0xea)}},'rmdir':{'category':'directory-delete','alternatives':{'cmd':_0x39b07e(0x17d),'powershell':'Remove-Item'}},'touch':{'category':_0x39b07e(0x188),'alternatives':{'cmd':'type\x20nul\x20>','powershell':_0x39b07e(0x144)}},'chmod':{'category':_0x39b07e(0x11b),'alternatives':{'cmd':'icacls','powershell':'Set-Acl'}},'chown':{'category':'ownership','alternatives':{'cmd':'takeown','powershell':_0x39b07e(0xd5)}},'ps':{'category':_0x39b07e(0xbd),'alternatives':{'cmd':'tasklist','powershell':_0x39b07e(0x1b0)}},'kill':{'category':'process-kill','alternatives':{'cmd':'taskkill','powershell':'Stop-Process'}},'killall':{'category':_0x39b07e(0xbc),'alternatives':{'cmd':_0x39b07e(0x19c),'powershell':_0x39b07e(0x146)}},'top':{'category':'process-monitor','alternatives':{'cmd':_0x39b07e(0x1ce),'powershell':'Get-Process\x20|\x20Sort-Object\x20CPU'}},'wget':{'category':_0x39b07e(0x135),'alternatives':{'cmd':_0x39b07e(0xe1),'powershell':'Invoke-WebRequest'}},'curl':{'category':_0x39b07e(0x9d),'alternatives':{'cmd':_0x39b07e(0xe1),'powershell':_0x39b07e(0x11e)}},'ping':{'category':_0x39b07e(0x15f),'alternatives':{'cmd':'ping','powershell':'Test-NetConnection'}},'awk':{'category':'text-processing','alternatives':{'cmd':_0x39b07e(0x118),'powershell':_0x39b07e(0x19e)}},'sed':{'category':'text-edit','alternatives':{'cmd':_0x39b07e(0x9a),'powershell':'native'}},'sort':{'category':'text-sort','alternatives':{'cmd':_0x39b07e(0xac),'powershell':'Sort-Object'}},'uniq':{'category':'text-dedupe','alternatives':{'cmd':'sort\x20/unique','powershell':'Sort-Object\x20-Unique'}},'pwd':{'category':_0x39b07e(0xb7),'alternatives':{'cmd':'cd','powershell':_0x39b07e(0x15a)}},'whoami':{'category':_0x39b07e(0x1ca),'alternatives':{'cmd':_0x39b07e(0x142),'powershell':_0x39b07e(0xdf)}},'env':{'category':'environment','alternatives':{'cmd':_0x39b07e(0xf0),'powershell':'Get-ChildItem\x20Env:'}},'export':{'category':'environment','alternatives':{'cmd':'set','powershell':'$env:'}},'source':{'category':'script-execute','alternatives':{'cmd':_0x39b07e(0x14b),'powershell':'.\x20'}},'tar':{'category':'archive','alternatives':{'cmd':'7z','powershell':_0x39b07e(0xee)}},'zip':{'category':_0x39b07e(0x103),'alternatives':{'cmd':'powershell\x20Compress-Archive','powershell':_0x39b07e(0xee)}},'unzip':{'category':_0x39b07e(0x103),'alternatives':{'cmd':_0x39b07e(0xf2),'powershell':_0x39b07e(0x9b)}},'df':{'category':_0x39b07e(0x8e),'alternatives':{'cmd':'fsutil\x20volume\x20diskfree','powershell':'Get-WmiObject\x20-Class\x20Win32_LogicalDisk'}},'du':{'category':'disk-usage','alternatives':{'cmd':_0x39b07e(0x94),'powershell':_0x39b07e(0x19f)}},'free':{'category':'memory-info','alternatives':{'cmd':'systeminfo','powershell':_0x39b07e(0x173)}},'uname':{'category':'system-info','alternatives':{'cmd':_0x39b07e(0x12d),'powershell':'Get-ComputerInfo'}}},_0xf720c6={'dir':{'category':'file-listing','alternatives':{'unix':'ls','powershell':'Get-ChildItem'}},'type':{'category':_0x39b07e(0x163),'alternatives':{'unix':_0x39b07e(0xf7),'powershell':_0x39b07e(0xcf)}},'copy':{'category':_0x39b07e(0x120),'alternatives':{'unix':'cp','powershell':'Copy-Item'}},'move':{'category':'file-move','alternatives':{'unix':'mv','powershell':_0x39b07e(0x1c1)}},'del':{'category':'file-delete','alternatives':{'unix':'rm','powershell':_0x39b07e(0x1d6)}},'tasklist':{'category':'process-list','alternatives':{'unix':'ps','powershell':_0x39b07e(0x1b0)}},'taskkill':{'category':'process-kill','alternatives':{'unix':'kill','powershell':_0x39b07e(0xa6)}},'findstr':{'category':'text-search','alternatives':{'unix':'grep','powershell':'Select-String'}}},_0x1a7782={'get-childitem':{'category':'file-listing','alternatives':{'unix':'ls','cmd':'dir'}},'get-content':{'category':'file-viewing','alternatives':{'unix':'cat','cmd':_0x39b07e(0xb3)}},'copy-item':{'category':'file-copy','alternatives':{'unix':'cp','cmd':'copy'}},'move-item':{'category':_0x39b07e(0xcd),'alternatives':{'unix':'mv','cmd':'move'}},'remove-item':{'category':_0x39b07e(0xc3),'alternatives':{'unix':'rm','cmd':'del'}},'get-process':{'category':_0x39b07e(0xbd),'alternatives':{'unix':'ps','cmd':_0x39b07e(0x1ce)}},'stop-process':{'category':'process-kill','alternatives':{'unix':_0x39b07e(0x150),'cmd':'taskkill'}}};let _0x1f2b2d='unknown',_0x43c665=_0x39b07e(0x18e),_0x10f34a={};if(_0x53d1a5[_0x135ec8])_0x1f2b2d='unix',_0x43c665=_0x53d1a5[_0x135ec8]['category'],_0x10f34a=_0x53d1a5[_0x135ec8]['alternatives'];else{if(_0xf720c6[_0x135ec8])_0x1f2b2d=_0x39b07e(0x160),_0x43c665=_0xf720c6[_0x135ec8][_0x39b07e(0xc2)],_0x10f34a=_0xf720c6[_0x135ec8]['alternatives'];else{if(_0x1a7782[_0x135ec8])_0x1f2b2d='powershell',_0x43c665=_0x1a7782[_0x135ec8][_0x39b07e(0xc2)],_0x10f34a=_0x1a7782[_0x135ec8][_0x39b07e(0x184)];else{const _0x26a420=[_0x39b07e(0xad),'cd','exit','help'];_0x26a420[_0x39b07e(0x17a)](_0x135ec8)?(_0x1f2b2d=_0x39b07e(0x1b1),_0x43c665='builtin'):(_0x1f2b2d=_0x39b07e(0x18e),_0x4a9982=0.3);}}}return _0x3e191e[_0x39b07e(0x17a)]('\x27')&&!_0x3e191e['includes']('\x22')&&_0x50b8b4[_0x39b07e(0x16b)]('single-quotes-problematic'),_0x3e191e['includes']('/')&&!_0x3e191e['includes']('\x5c')&&!_0x3e191e[_0x39b07e(0x17a)]('http')&&_0x3e191e[_0x39b07e(0x17a)]('>')&&_0x50b8b4[_0x39b07e(0x16b)]('unix-style-paths'),(_0x3e191e['includes']('\x5cn')||_0x3e191e['includes']('\x5ct'))&&_0x50b8b4[_0x39b07e(0x16b)](_0x39b07e(0x1ba)),(_0x3e191e['includes']('\x20&&\x20')||_0x3e191e['includes']('\x20||\x20')||_0x3e191e['includes'](';'))&&_0x50b8b4['push']('command-chaining'),{'type':_0x1f2b2d,'category':_0x43c665,'alternatives':_0x10f34a,'issues':_0x50b8b4,'confidence':_0x4a9982,'firstWord':_0x135ec8,'fullCommand':_0x3e191e};}[a0_0x492ede(0x189)](_0xcc71b4,_0x15297a){const _0x2f1d76=a0_0x492ede;switch(_0x15297a){case _0x2f1d76(0x100):if(_0xcc71b4[_0x2f1d76(0xb3)]===_0x2f1d76(0x161))return![];if(_0xcc71b4[_0x2f1d76(0x13a)][_0x2f1d76(0x17a)](_0x2f1d76(0xb9)))return![];if(_0xcc71b4['issues']['includes'](_0x2f1d76(0x166)))return![];return _0xcc71b4['type']==='windows-cmd'||_0xcc71b4['type']==='universal';case _0x2f1d76(0x10d):if(_0xcc71b4[_0x2f1d76(0xb3)]==='unix'&&!_0xcc71b4['alternatives'][_0x2f1d76(0x10d)])return![];return!![];case _0x2f1d76(0xd1):if(_0xcc71b4['type']==='windows-cmd')return![];return _0xcc71b4[_0x2f1d76(0xb3)]===_0x2f1d76(0x161)||_0xcc71b4[_0x2f1d76(0xb3)]==='universal';default:return![];}}['translateToWindowsCmd'](_0x188fc8){const _0x2743a4=a0_0x492ede;let _0x57d5d9=_0x188fc8;const _0x577bcc=new Map([[/^ls\s*$/,_0x2743a4(0x13c)],[/^ls\s+-la?$/,'dir'],[/^ls\s+-l$/,_0x2743a4(0x13c)],[/^ls\s+-a$/,'dir\x20/a'],[/^cat\s+(.+)$/,_0x2743a4(0xe3)],[/^cp\s+(.+)\s+(.+)$/,_0x2743a4(0x110)],[/^mv\s+(.+)\s+(.+)$/,'move\x20$1\x20$2'],[/^rm\s+(.+)$/,'del\x20$1'],[/^mkdir\s+(.+)$/,'mkdir\x20$1'],[/^rmdir\s+(.+)$/,'rmdir\x20$1'],[/^ps\s*$/,_0x2743a4(0x1ce)],[/^kill\s+(.+)$/,_0x2743a4(0x185)],[/^pwd\s*$/,'cd'],[/^whoami\s*$/,'echo\x20%USERNAME%'],[/^ping\s+(.+)$/,'ping\x20$1'],[/^wget\s+(.+)$/,'curl\x20-O\x20$1'],[/^curl\s+(.+)$/,_0x2743a4(0x119)]]);for(const [_0xfc1ec,_0x3c87b1]of _0x577bcc){if(_0xfc1ec[_0x2743a4(0x1c9)](_0x57d5d9)){_0x57d5d9=_0x57d5d9['replace'](_0xfc1ec,_0x3c87b1);break;}}_0x57d5d9=_0x57d5d9[_0x2743a4(0x8c)](/echo\s+'([^']+)'\s*>/g,_0x2743a4(0xa7)),_0x57d5d9=_0x57d5d9[_0x2743a4(0x8c)](/echo\s+'([^']+)'$/g,'echo\x20\x22$1\x22');if(_0x57d5d9[_0x2743a4(0x17a)](_0x2743a4(0xb0))&&_0x57d5d9['includes']('\x5cn')){const _0x11819c=_0x57d5d9[_0x2743a4(0x8f)](/echo\s+'(.+?)'\s*>\s*(.+)$/);if(_0x11819c){const _0x4b14a3=_0x11819c[0x1][_0x2743a4(0x8c)](/\\n/g,'\x0a'),_0x4e922c=_0x11819c[0x2],_0x7d2b2b=_0x4b14a3[_0x2743a4(0xc7)]('\x0a');_0x57d5d9='('+_0x7d2b2b[_0x2743a4(0x199)](_0x3e3ba1=>'echo\x20'+_0x3e3ba1)[_0x2743a4(0x11c)](_0x2743a4(0xd6))+_0x2743a4(0xf5)+_0x4e922c;}}return this[_0x2743a4(0xdb)]?.['info'](_0x2743a4(0x172),{'original':_0x188fc8,'translated':_0x57d5d9}),_0x57d5d9;}['translateToPowerShell'](_0x2e6198){const _0x8066c6=a0_0x492ede;let _0x28fda8=_0x2e6198;const _0x30af71=new Map([[/^ls\s*$/,_0x8066c6(0x124)],[/^ls\s+-la?$/,'Get-ChildItem\x20-Force'],[/^cat\s+(.+)$/,_0x8066c6(0x136)],[/^cp\s+(.+)\s+(.+)$/,'Copy-Item\x20$1\x20$2'],[/^mv\s+(.+)\s+(.+)$/,_0x8066c6(0x1d3)],[/^rm\s+(.+)$/,_0x8066c6(0xf3)],[/^pwd\s*$/,'Get-Location'],[/^ps\s*$/,_0x8066c6(0x1b0)]]);for(const [_0x11747e,_0x22e33a]of _0x30af71){if(_0x11747e['test'](_0x28fda8)){_0x28fda8=_0x28fda8['replace'](_0x11747e,_0x22e33a);break;}}return this['logger']?.['info']('Command\x20translated\x20for\x20PowerShell',{'original':_0x2e6198,'translated':_0x28fda8}),_0x28fda8;}['translateToBash'](_0x18462d){const _0xf8f485=a0_0x492ede;let _0xee44cf=_0x18462d;const _0x563e5c=new Map([[/^dir\s*$/,'ls'],[/^dir\s+\/a$/,'ls\x20-a'],[/^type\s+(.+)$/,'cat\x20$1'],[/^copy\s+(.+)\s+(.+)$/,'cp\x20$1\x20$2'],[/^move\s+(.+)\s+(.+)$/,'mv\x20$1\x20$2'],[/^del\s+(.+)$/,'rm\x20$1'],[/^tasklist\s*$/,'ps'],[/^cd\s*$/,'pwd']]);for(const [_0x14f077,_0x4a688d]of _0x563e5c){if(_0x14f077['test'](_0xee44cf)){_0xee44cf=_0xee44cf[_0xf8f485(0x8c)](_0x14f077,_0x4a688d);break;}}return _0xee44cf;}async['cleanup'](_0x3b2b5f){}async['startBackgroundCommand'](_0x474d2f,_0x25a7d1,_0x5a23bd={}){const _0x5883b5=a0_0x492ede,{agentId:_0x418857,context:_0x115cda}=_0x5a23bd;if(!_0x418857)throw new Error('agentId\x20is\x20required\x20for\x20background\x20commands');const _0x2d472=this['getAgentCommands'](_0x418857),_0xfd06a2=_0x2d472['filter'](_0x1a94db=>_0x1a94db[_0x5883b5(0x113)]===_0x5883b5(0x13e)||_0x1a94db['state']==='waiting_for_input');if(_0xfd06a2['length']>=this[_0x5883b5(0xb2)])throw new Error('Maximum\x20background\x20commands\x20per\x20agent\x20exceeded\x20('+this['MAX_BACKGROUND_COMMANDS_PER_AGENT']+')');const _0xec3889=Array['from'](this[_0x5883b5(0xdc)][_0x5883b5(0x19b)]()),_0x50ac15=_0xec3889['filter'](_0x13c28e=>_0x13c28e['state']===_0x5883b5(0x13e)||_0x13c28e['state']===_0x5883b5(0x109));if(_0x50ac15['length']>=this[_0x5883b5(0x182)])throw new Error('Maximum\x20global\x20background\x20commands\x20exceeded\x20('+this[_0x5883b5(0x182)]+')');const _0x366edb=_0x418857+'-cmd-'+Date[_0x5883b5(0x1c4)]()+'-'+ ++this[_0x5883b5(0x1ae)],_0x3d160b=_0x474d2f;let _0x454d3d;try{_0x454d3d=await this[_0x5883b5(0x106)](_0x474d2f,{'agentId':_0x418857,'toolsRegistry':_0x115cda?.['toolsRegistry'],'messageProcessor':_0x115cda?.['messageProcessor'],'aiService':_0x115cda?.['aiService'],'apiKey':_0x115cda?.[_0x5883b5(0xe5)],'customApiKeys':_0x115cda?.[_0x5883b5(0x12e)],'platformProvided':_0x115cda?.[_0x5883b5(0x1c6)]});}catch(_0x5e756b){this[_0x5883b5(0xdb)]?.[_0x5883b5(0x158)](_0x5883b5(0x128),{'originalCommand':_0x3d160b,'error':_0x5e756b[_0x5883b5(0x130)]}),_0x454d3d=_0x474d2f;}this['logger']?.['info']('Starting\x20background\x20command:\x20'+_0x454d3d,{'commandId':_0x366edb,'agentId':_0x418857,'originalCommand':_0x3d160b,'workingDirectory':_0x25a7d1});let _0x1ddee7;if(this['detectedTerminal']==='cmd'||this['detectedTerminal']==='powershell'){const _0x51dc00=this[_0x5883b5(0xa9)]===_0x5883b5(0x10d)?_0x5883b5(0x10d):'cmd',_0x540adb=this[_0x5883b5(0xa9)]===_0x5883b5(0x10d)?[_0x5883b5(0xde),_0x454d3d]:['/c',_0x454d3d];_0x1ddee7=spawn(_0x51dc00,_0x540adb,{'cwd':_0x25a7d1,'env':{...process['env']},'windowsHide':!![],'stdio':[_0x5883b5(0x1bd),_0x5883b5(0x1bd),'pipe']});}else _0x1ddee7=spawn('sh',['-c',_0x454d3d],{'cwd':_0x25a7d1,'env':{...process[_0x5883b5(0x9f)]},'stdio':['pipe',_0x5883b5(0x1bd),'pipe']});const _0x3e0d38={'commandId':_0x366edb,'agentId':_0x418857,'pid':_0x1ddee7['pid'],'command':_0x3d160b,'translatedCommand':_0x454d3d,'workingDirectory':_0x25a7d1,'startTime':new Date()['toISOString'](),'state':_0x5883b5(0x13e),'exitCode':null,'stdoutBuffer':'','stderrBuffer':'','lastOutputTime':Date[_0x5883b5(0x1c4)](),'promptDetected':null,'process':_0x1ddee7};return this['commandTracker']['set'](_0x366edb,_0x3e0d38),_0x1ddee7[_0x5883b5(0x1a3)]['on'](_0x5883b5(0x9c),_0x47aac1=>{const _0x5b405a=_0x5883b5,_0x360942=_0x47aac1['toString']();_0x3e0d38[_0x5b405a(0x108)]+=_0x360942,_0x3e0d38[_0x5b405a(0x183)]=Date[_0x5b405a(0x1c4)]();if(!_0x3e0d38['promptDetected']){const _0x579f83=this[_0x5b405a(0x1cb)][_0x5b405a(0xcb)](_0x3e0d38[_0x5b405a(0x108)],'stdout');_0x579f83&&(_0x3e0d38['promptDetected']=_0x579f83,_0x3e0d38['state']='waiting_for_input',this[_0x5b405a(0xdb)]?.['info']('Prompt\x20detected\x20in\x20background\x20command',{'commandId':_0x366edb,'agentId':_0x418857,'type':_0x579f83[_0x5b405a(0xb3)],'matchedText':_0x579f83[_0x5b405a(0x112)]}));}}),_0x1ddee7[_0x5883b5(0xd8)]['on'](_0x5883b5(0x9c),_0x370f0c=>{const _0x1c66cd=_0x5883b5,_0x3cadb2=_0x370f0c['toString']();_0x3e0d38['stderrBuffer']+=_0x3cadb2,_0x3e0d38[_0x1c66cd(0x183)]=Date['now']();if(!_0x3e0d38['promptDetected']){const _0x1b8451=this['promptDetector'][_0x1c66cd(0xcb)](_0x3e0d38[_0x1c66cd(0xe0)],_0x1c66cd(0xd8));_0x1b8451&&(_0x3e0d38['promptDetected']=_0x1b8451,_0x3e0d38['state']=_0x1c66cd(0x109),this[_0x1c66cd(0xdb)]?.[_0x1c66cd(0x14f)](_0x1c66cd(0x192),{'commandId':_0x366edb,'agentId':_0x418857,'type':_0x1b8451['type'],'matchedText':_0x1b8451[_0x1c66cd(0x112)]}));}}),_0x1ddee7['on'](_0x5883b5(0xa4),(_0x3188ee,_0x3ed2a8)=>{const _0x5d0f69=_0x5883b5;_0x3e0d38[_0x5d0f69(0x164)]=_0x3188ee,_0x3e0d38['state']=_0x3188ee===0x0?'completed':'failed',_0x3e0d38[_0x5d0f69(0xd2)]=new Date()[_0x5d0f69(0x15e)](),this[_0x5d0f69(0xdb)]?.[_0x5d0f69(0x14f)]('Background\x20command\x20exited',{'commandId':_0x366edb,'agentId':_0x418857,'exitCode':_0x3188ee,'signal':_0x3ed2a8,'state':_0x3e0d38[_0x5d0f69(0x113)]});}),_0x1ddee7['on'](_0x5883b5(0x101),_0xb0a0e8=>{const _0x542c0b=_0x5883b5;_0x3e0d38[_0x542c0b(0x113)]='failed',_0x3e0d38[_0x542c0b(0x101)]=_0xb0a0e8['message'],_0x3e0d38[_0x542c0b(0xd2)]=new Date()[_0x542c0b(0x15e)](),this[_0x542c0b(0xdb)]?.['error']('Background\x20command\x20error',{'commandId':_0x366edb,'agentId':_0x418857,'error':_0xb0a0e8[_0x542c0b(0x130)]});}),{'success':!![],'commandId':_0x366edb,'pid':_0x1ddee7['pid'],'command':_0x3d160b,'translatedCommand':_0x454d3d,'workingDirectory':_0x25a7d1,'message':_0x5883b5(0x1aa)+_0x366edb};}[a0_0x492ede(0xab)](_0x300160,_0x8ec8b2,_0x28f294){const _0x346db2=a0_0x492ede,_0x1ece3a=this[_0x346db2(0x156)](_0x300160,_0x28f294);if(_0x1ece3a['state']===_0x346db2(0x1c8)||_0x1ece3a['state']==='failed')throw new Error(_0x346db2(0x16e)+_0x1ece3a['state']+'\x20command');if(!_0x1ece3a['process']||_0x1ece3a[_0x346db2(0x1af)]['killed'])throw new Error(_0x346db2(0x1b4));const _0x2e10bf=_0x8ec8b2['endsWith']('\x0a')?_0x8ec8b2:_0x8ec8b2+'\x0a';return _0x1ece3a[_0x346db2(0x1af)]['stdin']['write'](_0x2e10bf),this['logger']?.['info']('Input\x20sent\x20to\x20background\x20command',{'commandId':_0x300160,'agentId':_0x28f294,'inputLength':_0x8ec8b2[_0x346db2(0x117)]}),_0x1ece3a['state']==='waiting_for_input'&&(_0x1ece3a['state']='running',_0x1ece3a['promptDetected']=null),{'success':!![],'commandId':_0x300160,'message':_0x346db2(0x99)};}['getCommandStatus'](_0xd6218c,_0x2cc875){const _0x4df033=a0_0x492ede,_0x2f6392=this[_0x4df033(0x156)](_0xd6218c,_0x2cc875),_0x253bc6=Date[_0x4df033(0x1c4)]()-_0x2f6392['lastOutputTime'];return{'success':!![],'commandId':_0xd6218c,'pid':_0x2f6392['pid'],'command':_0x2f6392[_0x4df033(0x177)],'state':_0x2f6392[_0x4df033(0x113)],'exitCode':_0x2f6392['exitCode'],'startTime':_0x2f6392['startTime'],'endTime':_0x2f6392['endTime'],'workingDirectory':_0x2f6392[_0x4df033(0x123)],'stdout':_0x2f6392[_0x4df033(0x108)],'stderr':_0x2f6392[_0x4df033(0xe0)],'stdoutLength':_0x2f6392['stdoutBuffer'][_0x4df033(0x117)],'stderrLength':_0x2f6392[_0x4df033(0xe0)][_0x4df033(0x117)],'lastOutputTime':_0x2f6392['lastOutputTime'],'timeSinceLastOutput':_0x253bc6,'promptDetected':!!_0x2f6392[_0x4df033(0xbb)],'promptInfo':_0x2f6392['promptDetected']||undefined};}[a0_0x492ede(0xc5)](_0x585b07,_0x220e75){const _0x27b20f=a0_0x492ede,_0x3d401e=this['validateCommandOwnership'](_0x585b07,_0x220e75);if(_0x3d401e['state']==='completed'||_0x3d401e['state']===_0x27b20f(0x1d4))return{'success':!![],'commandId':_0x585b07,'message':_0x27b20f(0xc1),'state':_0x3d401e[_0x27b20f(0x113)]};if(_0x3d401e['process']&&!_0x3d401e['process'][_0x27b20f(0x1b6)])return _0x3d401e[_0x27b20f(0x1af)][_0x27b20f(0x150)]('SIGTERM'),setTimeout(()=>{const _0x6549fe=_0x27b20f;_0x3d401e['process']&&!_0x3d401e[_0x6549fe(0x1af)][_0x6549fe(0x1b6)]&&_0x3d401e[_0x6549fe(0x1af)]['kill'](_0x6549fe(0xa5));},0x1388),this[_0x27b20f(0xdb)]?.['info'](_0x27b20f(0x10c),{'commandId':_0x585b07,'agentId':_0x220e75}),{'success':!![],'commandId':_0x585b07,'message':_0x27b20f(0x13b)};return{'success':![],'commandId':_0x585b07,'error':_0x27b20f(0x1cc)};}[a0_0x492ede(0x1cd)](_0x14b681){const _0x4de011=a0_0x492ede,_0x331f6f=this['getAgentCommands'](_0x14b681);return _0x331f6f['map'](_0x5e8bbd=>({'commandId':_0x5e8bbd['commandId'],'command':_0x5e8bbd['command'],'state':_0x5e8bbd['state'],'pid':_0x5e8bbd['pid'],'exitCode':_0x5e8bbd[_0x4de011(0x164)],'startTime':_0x5e8bbd[_0x4de011(0xc4)],'endTime':_0x5e8bbd['endTime'],'promptDetected':!!_0x5e8bbd[_0x4de011(0xbb)],'timeSinceLastOutput':Date[_0x4de011(0x1c4)]()-_0x5e8bbd[_0x4de011(0x183)]}));}['getAgentCommands'](_0x2c41f1){const _0xee0bc9=a0_0x492ede;return Array['from'](this['commandTracker'][_0xee0bc9(0x19b)]())[_0xee0bc9(0x19a)](_0x41810a=>_0x41810a[_0xee0bc9(0x1bc)]===_0x2c41f1);}[a0_0x492ede(0x156)](_0x30b5fe,_0x49b0b6){const _0x153d7a=a0_0x492ede,_0x2be09e=this[_0x153d7a(0xdc)][_0x153d7a(0xce)](_0x30b5fe);if(!_0x2be09e)throw new Error(_0x153d7a(0xfa)+_0x30b5fe);if(_0x2be09e[_0x153d7a(0x1bc)]!==_0x49b0b6)throw new Error('Access\x20denied:\x20Command\x20belongs\x20to\x20agent\x20'+_0x2be09e[_0x153d7a(0x1bc)]);return _0x2be09e;}async[a0_0x492ede(0x15c)](_0x27f9e4){const _0x567b46=a0_0x492ede,_0x22208c=this['getAgentCommands'](_0x27f9e4);let _0x49a15b=0x0,_0x44c616=0x0;for(const _0x41ee95 of _0x22208c){_0x41ee95['process']&&!_0x41ee95['process']['killed']&&(_0x41ee95[_0x567b46(0x1af)][_0x567b46(0x150)](_0x567b46(0x190)),_0x49a15b++,setTimeout(()=>{const _0x4d543c=_0x567b46;_0x41ee95[_0x4d543c(0x1af)]&&!_0x41ee95['process'][_0x4d543c(0x1b6)]&&_0x41ee95['process'][_0x4d543c(0x150)]('SIGKILL');},0xbb8)),this[_0x567b46(0xdc)]['delete'](_0x41ee95['commandId']),_0x44c616++;}return this[_0x567b46(0xdb)]?.[_0x567b46(0x14f)](_0x567b46(0x16c),{'agentId':_0x27f9e4,'killedCount':_0x49a15b,'removedCount':_0x44c616}),{'success':!![],'agentId':_0x27f9e4,'killedCount':_0x49a15b,'removedCount':_0x44c616,'message':_0x567b46(0x195)+_0x44c616+_0x567b46(0x176)+_0x27f9e4};}[a0_0x492ede(0x1a1)](){const _0x6aee08=a0_0x492ede,_0x3c60fc=Date['now']();let _0x1237b7=0x0;for(const [_0x4da572,_0x37b5a4]of this['commandTracker']['entries']()){if(_0x37b5a4['state']!=='completed'&&_0x37b5a4['state']!==_0x6aee08(0x1d4))continue;const _0x188bdd=new Date(_0x37b5a4['startTime'])[_0x6aee08(0xfc)](),_0xf96f4a=(_0x3c60fc-_0x188bdd)/0x3e8/0x3c;_0xf96f4a>this['MAX_COMMAND_AGE_MINUTES']&&(this['commandTracker']['delete'](_0x4da572),_0x1237b7++);}return _0x1237b7>0x0&&this[_0x6aee08(0xdb)]?.[_0x6aee08(0x14f)]('Stale\x20commands\x20cleaned\x20up',{'removedCount':_0x1237b7,'ageThresholdMinutes':this['MAX_COMMAND_AGE_MINUTES']}),{'success':!![],'removedCount':_0x1237b7,'message':_0x6aee08(0x195)+_0x1237b7+'\x20stale\x20commands'};}}export default TerminalTool;
|