erosolar-cli 2.1.237 → 2.1.239
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 +9 -0
- package/dist/contracts/tools.schema.json +3 -1
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +5 -1
- package/dist/core/agent.js.map +1 -1
- package/dist/core/agentOrchestrator.d.ts +4 -0
- package/dist/core/agentOrchestrator.d.ts.map +1 -1
- package/dist/core/agentOrchestrator.js +58 -6
- package/dist/core/agentOrchestrator.js.map +1 -1
- package/dist/core/autoExecutionOrchestrator.d.ts +172 -0
- package/dist/core/autoExecutionOrchestrator.d.ts.map +1 -0
- package/dist/core/autoExecutionOrchestrator.js +591 -0
- package/dist/core/autoExecutionOrchestrator.js.map +1 -0
- package/dist/core/contextManager.d.ts.map +1 -1
- package/dist/core/contextManager.js.map +1 -1
- package/dist/core/dualAgentOrchestrator.d.ts +34 -0
- package/dist/core/dualAgentOrchestrator.d.ts.map +1 -0
- package/dist/core/dualAgentOrchestrator.js +94 -0
- package/dist/core/dualAgentOrchestrator.js.map +1 -0
- package/dist/core/errors/safetyValidator.d.ts +25 -12
- package/dist/core/errors/safetyValidator.d.ts.map +1 -1
- package/dist/core/errors/safetyValidator.js +165 -17
- package/dist/core/errors/safetyValidator.js.map +1 -1
- package/dist/core/governmentProcedures.d.ts +118 -0
- package/dist/core/governmentProcedures.d.ts.map +1 -0
- package/dist/core/governmentProcedures.js +912 -0
- package/dist/core/governmentProcedures.js.map +1 -0
- package/dist/core/infrastructureTemplates.d.ts +123 -0
- package/dist/core/infrastructureTemplates.d.ts.map +1 -0
- package/dist/core/infrastructureTemplates.js +1326 -0
- package/dist/core/infrastructureTemplates.js.map +1 -0
- package/dist/core/orchestration.d.ts +534 -0
- package/dist/core/orchestration.d.ts.map +1 -0
- package/dist/core/orchestration.js +2009 -0
- package/dist/core/orchestration.js.map +1 -0
- package/dist/core/persistentObjectiveStore.d.ts +292 -0
- package/dist/core/persistentObjectiveStore.d.ts.map +1 -0
- package/dist/core/persistentObjectiveStore.js +613 -0
- package/dist/core/persistentObjectiveStore.js.map +1 -0
- package/dist/core/preferences.js +1 -1
- package/dist/core/preferences.js.map +1 -1
- package/dist/core/reliabilityPrompt.d.ts.map +1 -1
- package/dist/core/reliabilityPrompt.js +3 -0
- package/dist/core/reliabilityPrompt.js.map +1 -1
- package/dist/core/securityDeliverableGenerator.d.ts +292 -0
- package/dist/core/securityDeliverableGenerator.d.ts.map +1 -0
- package/dist/core/securityDeliverableGenerator.js +1590 -0
- package/dist/core/securityDeliverableGenerator.js.map +1 -0
- package/dist/core/taskCompletionDetector.d.ts.map +1 -1
- package/dist/core/taskCompletionDetector.js +4 -1
- package/dist/core/taskCompletionDetector.js.map +1 -1
- package/dist/shell/autoExecutor.d.ts.map +1 -1
- package/dist/shell/autoExecutor.js +32 -3
- package/dist/shell/autoExecutor.js.map +1 -1
- package/dist/shell/interactiveShell.d.ts +9 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +282 -190
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/tools/bashTools.d.ts +3 -5
- package/dist/tools/bashTools.d.ts.map +1 -1
- package/dist/tools/bashTools.js +259 -161
- package/dist/tools/bashTools.js.map +1 -1
- package/dist/tools/tao/index.d.ts +4 -4
- package/dist/tools/tao/index.d.ts.map +1 -1
- package/dist/tools/tao/index.js +15 -5
- package/dist/tools/tao/index.js.map +1 -1
- package/dist/tools/tao/rl.d.ts +164 -0
- package/dist/tools/tao/rl.d.ts.map +1 -0
- package/dist/tools/tao/rl.js +2998 -0
- package/dist/tools/tao/rl.js.map +1 -0
- package/dist/tools/taoTools.d.ts +2 -2
- package/dist/tools/taoTools.d.ts.map +1 -1
- package/dist/tools/taoTools.js +103 -20
- package/dist/tools/taoTools.js.map +1 -1
- package/dist/ui/PromptController.d.ts +3 -0
- package/dist/ui/PromptController.d.ts.map +1 -1
- package/dist/ui/PromptController.js +3 -0
- package/dist/ui/PromptController.js.map +1 -1
- package/dist/ui/UnifiedUIRenderer.d.ts +4 -0
- package/dist/ui/UnifiedUIRenderer.d.ts.map +1 -1
- package/dist/ui/UnifiedUIRenderer.js +37 -6
- package/dist/ui/UnifiedUIRenderer.js.map +1 -1
- package/dist/ui/display.d.ts +9 -1
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +66 -9
- package/dist/ui/display.js.map +1 -1
- package/dist/ui/shortcutsHelp.d.ts.map +1 -1
- package/dist/ui/shortcutsHelp.js +1 -0
- package/dist/ui/shortcutsHelp.js.map +1 -1
- package/package.json +3 -2
- package/dist/capabilities/askUserCapability.d.ts +0 -14
- package/dist/capabilities/askUserCapability.d.ts.map +0 -1
- package/dist/capabilities/askUserCapability.js +0 -134
- package/dist/capabilities/askUserCapability.js.map +0 -1
- package/dist/capabilities/codeGenerationCapability.d.ts +0 -13
- package/dist/capabilities/codeGenerationCapability.d.ts.map +0 -1
- package/dist/capabilities/codeGenerationCapability.js +0 -25
- package/dist/capabilities/codeGenerationCapability.js.map +0 -1
- package/dist/capabilities/performanceMonitoringCapability.d.ts +0 -108
- package/dist/capabilities/performanceMonitoringCapability.d.ts.map +0 -1
- package/dist/capabilities/performanceMonitoringCapability.js +0 -176
- package/dist/capabilities/performanceMonitoringCapability.js.map +0 -1
- package/dist/capabilities/todoCapability.d.ts +0 -19
- package/dist/capabilities/todoCapability.d.ts.map +0 -1
- package/dist/capabilities/todoCapability.js +0 -170
- package/dist/capabilities/todoCapability.js.map +0 -1
- package/dist/core/baseToolFactory.d.ts +0 -187
- package/dist/core/baseToolFactory.d.ts.map +0 -1
- package/dist/core/baseToolFactory.js +0 -352
- package/dist/core/baseToolFactory.js.map +0 -1
- package/dist/core/intelligentSummarizer.d.ts +0 -79
- package/dist/core/intelligentSummarizer.d.ts.map +0 -1
- package/dist/core/intelligentSummarizer.js +0 -273
- package/dist/core/intelligentSummarizer.js.map +0 -1
- package/dist/core/memorySystem.d.ts +0 -67
- package/dist/core/memorySystem.d.ts.map +0 -1
- package/dist/core/memorySystem.js +0 -334
- package/dist/core/memorySystem.js.map +0 -1
- package/dist/core/outputStyles.d.ts +0 -48
- package/dist/core/outputStyles.d.ts.map +0 -1
- package/dist/core/outputStyles.js +0 -270
- package/dist/core/outputStyles.js.map +0 -1
- package/dist/core/toolPatternAnalyzer.d.ts +0 -87
- package/dist/core/toolPatternAnalyzer.d.ts.map +0 -1
- package/dist/core/toolPatternAnalyzer.js +0 -272
- package/dist/core/toolPatternAnalyzer.js.map +0 -1
- package/dist/tools/backgroundBashTools.d.ts +0 -21
- package/dist/tools/backgroundBashTools.d.ts.map +0 -1
- package/dist/tools/backgroundBashTools.js +0 -215
- package/dist/tools/backgroundBashTools.js.map +0 -1
- package/dist/tools/code-quality-dashboard.d.ts +0 -57
- package/dist/tools/code-quality-dashboard.d.ts.map +0 -1
- package/dist/tools/code-quality-dashboard.js +0 -218
- package/dist/tools/code-quality-dashboard.js.map +0 -1
- package/dist/tools/tao/rlEngine.d.ts +0 -40
- package/dist/tools/tao/rlEngine.d.ts.map +0 -1
- package/dist/tools/tao/rlEngine.js +0 -237
- package/dist/tools/tao/rlEngine.js.map +0 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { ToolDefinition } from '../core/toolRuntime.js';
|
|
2
|
-
export declare function
|
|
3
|
-
interface SandboxEnvOptions {
|
|
2
|
+
export declare function buildSandboxEnv(workingDir: string, options?: {
|
|
4
3
|
preserveHome?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare function
|
|
7
|
-
export {};
|
|
4
|
+
}): Promise<NodeJS.ProcessEnv>;
|
|
5
|
+
export declare function createBashTools(workingDir: string): ToolDefinition[];
|
|
8
6
|
//# sourceMappingURL=bashTools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashTools.d.ts","sourceRoot":"","sources":["../../src/tools/bashTools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"bashTools.d.ts","sourceRoot":"","sources":["../../src/tools/bashTools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AA8R7D,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACnC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAqB5B;AAMD,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,CAoOpE"}
|
package/dist/tools/bashTools.js
CHANGED
|
@@ -2,16 +2,105 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { mkdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { reportToolProgress } from '../core/toolRuntime.js';
|
|
5
|
-
import { createBackgroundBashTools, startBackgroundShell } from './backgroundBashTools.js';
|
|
6
5
|
import { validateBashCommand, SmartFixer } from '../core/errors/safetyValidator.js';
|
|
7
6
|
import { toStructuredError } from '../core/errors/errorTypes.js';
|
|
8
7
|
import { analyzeBashFlow } from '../core/bashCommandGuidance.js';
|
|
8
|
+
import { buildError } from '../core/errors.js';
|
|
9
9
|
import { verifiedSuccess, verifiedFailure, analyzeOutput, OutputPatterns, createCommandCheck, } from '../core/resultVerification.js';
|
|
10
10
|
import { createErrorFixer } from '../core/aiErrorFixer.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Background Shell Manager (consolidated from backgroundBashTools.ts)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
class BackgroundShell {
|
|
15
|
+
id;
|
|
16
|
+
command;
|
|
17
|
+
workingDir;
|
|
18
|
+
process;
|
|
19
|
+
outputBuffer = [];
|
|
20
|
+
errorBuffer = [];
|
|
21
|
+
lastReadPosition = 0;
|
|
22
|
+
isRunning = false;
|
|
23
|
+
exitCode;
|
|
24
|
+
constructor(id, command, workingDir) {
|
|
25
|
+
this.id = id;
|
|
26
|
+
this.command = command;
|
|
27
|
+
this.workingDir = workingDir;
|
|
28
|
+
}
|
|
29
|
+
start() {
|
|
30
|
+
this.process = spawn('bash', ['-c', this.command], {
|
|
31
|
+
cwd: this.workingDir,
|
|
32
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
33
|
+
});
|
|
34
|
+
this.isRunning = true;
|
|
35
|
+
this.process.stdout?.on('data', (data) => {
|
|
36
|
+
this.outputBuffer.push(data.toString());
|
|
37
|
+
});
|
|
38
|
+
this.process.stderr?.on('data', (data) => {
|
|
39
|
+
this.errorBuffer.push(data.toString());
|
|
40
|
+
});
|
|
41
|
+
this.process.on('exit', (code) => {
|
|
42
|
+
this.exitCode = code ?? 0;
|
|
43
|
+
this.isRunning = false;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
getNewOutput(filter) {
|
|
47
|
+
const allOutput = this.outputBuffer.join('');
|
|
48
|
+
const newOutput = allOutput.substring(this.lastReadPosition);
|
|
49
|
+
this.lastReadPosition = allOutput.length;
|
|
50
|
+
const allError = this.errorBuffer.join('');
|
|
51
|
+
let stdout = newOutput;
|
|
52
|
+
if (filter) {
|
|
53
|
+
const lines = newOutput.split('\n');
|
|
54
|
+
stdout = lines.filter(line => filter.test(line)).join('\n');
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
stdout,
|
|
58
|
+
stderr: allError,
|
|
59
|
+
status: this.isRunning ? 'running' : `exited with code ${this.exitCode}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
kill() {
|
|
63
|
+
if (this.process) {
|
|
64
|
+
this.process.kill('SIGTERM');
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
if (this.process && !this.process.killed) {
|
|
67
|
+
this.process.kill('SIGKILL');
|
|
68
|
+
}
|
|
69
|
+
}, 5000);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class BackgroundShellManager {
|
|
74
|
+
shells = new Map();
|
|
75
|
+
nextId = 1;
|
|
76
|
+
createShell(command, workingDir) {
|
|
77
|
+
const shellId = `shell_${this.nextId++}`;
|
|
78
|
+
const shell = new BackgroundShell(shellId, command, workingDir);
|
|
79
|
+
this.shells.set(shellId, shell);
|
|
80
|
+
shell.start();
|
|
81
|
+
return shellId;
|
|
82
|
+
}
|
|
83
|
+
getShell(shellId) {
|
|
84
|
+
return this.shells.get(shellId);
|
|
85
|
+
}
|
|
86
|
+
killShell(shellId) {
|
|
87
|
+
const shell = this.shells.get(shellId);
|
|
88
|
+
if (shell) {
|
|
89
|
+
shell.kill();
|
|
90
|
+
this.shells.delete(shellId);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
listShells() {
|
|
96
|
+
return Array.from(this.shells.keys());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Global shell manager instance
|
|
100
|
+
const shellManager = new BackgroundShellManager();
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Streaming Execution
|
|
103
|
+
// ============================================================================
|
|
15
104
|
async function execWithStreaming(command, options) {
|
|
16
105
|
return new Promise((resolve, reject) => {
|
|
17
106
|
const stdout = [];
|
|
@@ -30,8 +119,7 @@ async function execWithStreaming(command, options) {
|
|
|
30
119
|
}, options.timeout);
|
|
31
120
|
const processLine = (line, isStderr) => {
|
|
32
121
|
lineCount++;
|
|
33
|
-
|
|
34
|
-
const trimmedLine = line.slice(0, 80); // Truncate long lines for display
|
|
122
|
+
const trimmedLine = line.slice(0, 80);
|
|
35
123
|
reportToolProgress({
|
|
36
124
|
current: lineCount,
|
|
37
125
|
message: isStderr ? `stderr: ${trimmedLine}` : trimmedLine,
|
|
@@ -42,9 +130,8 @@ async function execWithStreaming(command, options) {
|
|
|
42
130
|
const text = data.toString();
|
|
43
131
|
stdout.push(text);
|
|
44
132
|
stdoutBuffer += text;
|
|
45
|
-
// Process complete lines
|
|
46
133
|
const lines = stdoutBuffer.split('\n');
|
|
47
|
-
stdoutBuffer = lines.pop() || '';
|
|
134
|
+
stdoutBuffer = lines.pop() || '';
|
|
48
135
|
for (const line of lines) {
|
|
49
136
|
if (line.trim())
|
|
50
137
|
processLine(line, false);
|
|
@@ -55,7 +142,6 @@ async function execWithStreaming(command, options) {
|
|
|
55
142
|
const text = data.toString();
|
|
56
143
|
stderr.push(text);
|
|
57
144
|
stderrBuffer += text;
|
|
58
|
-
// Process complete lines
|
|
59
145
|
const lines = stderrBuffer.split('\n');
|
|
60
146
|
stderrBuffer = lines.pop() || '';
|
|
61
147
|
for (const line of lines) {
|
|
@@ -65,7 +151,6 @@ async function execWithStreaming(command, options) {
|
|
|
65
151
|
});
|
|
66
152
|
child.on('close', (code) => {
|
|
67
153
|
clearTimeout(timeoutId);
|
|
68
|
-
// Process any remaining buffered content
|
|
69
154
|
if (stdoutBuffer.trim())
|
|
70
155
|
processLine(stdoutBuffer, false);
|
|
71
156
|
if (stderrBuffer.trim())
|
|
@@ -74,11 +159,7 @@ async function execWithStreaming(command, options) {
|
|
|
74
159
|
reject({ killed: true, stdout: stdout.join(''), stderr: stderr.join(''), code });
|
|
75
160
|
}
|
|
76
161
|
else {
|
|
77
|
-
resolve({
|
|
78
|
-
stdout: stdout.join(''),
|
|
79
|
-
stderr: stderr.join(''),
|
|
80
|
-
exitCode: code ?? 0,
|
|
81
|
-
});
|
|
162
|
+
resolve({ stdout: stdout.join(''), stderr: stderr.join(''), exitCode: code ?? 0 });
|
|
82
163
|
}
|
|
83
164
|
});
|
|
84
165
|
child.on('error', (error) => {
|
|
@@ -87,11 +168,13 @@ async function execWithStreaming(command, options) {
|
|
|
87
168
|
});
|
|
88
169
|
});
|
|
89
170
|
}
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Utility Functions
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Keep the shell responsive while long commands run
|
|
90
175
|
function findGuiLauncher(_command) {
|
|
91
|
-
// Kinetic capabilities enabled - GUI blocking disabled
|
|
92
176
|
return null;
|
|
93
177
|
}
|
|
94
|
-
// Shared error fixer instance (lazy initialized per working dir)
|
|
95
178
|
const errorFixerCache = new Map();
|
|
96
179
|
function getErrorFixer(workingDir) {
|
|
97
180
|
let fixer = errorFixerCache.get(workingDir);
|
|
@@ -101,18 +184,8 @@ function getErrorFixer(workingDir) {
|
|
|
101
184
|
}
|
|
102
185
|
return fixer;
|
|
103
186
|
}
|
|
104
|
-
const sandboxCache = new Map();
|
|
105
187
|
/**
|
|
106
|
-
* Smart timeout detection
|
|
107
|
-
* Returns appropriate timeout based on command type.
|
|
108
|
-
* - python/torch training & fine-tuning: 10 minutes
|
|
109
|
-
* - npm install/ci: 5 minutes
|
|
110
|
-
* - npm build/test: 5 minutes
|
|
111
|
-
* - npx create-*: 5 minutes
|
|
112
|
-
* - pytest/python -m pytest: 5 minutes
|
|
113
|
-
* - docker build/pull: 10 minutes
|
|
114
|
-
* - git clone: 3 minutes
|
|
115
|
-
* - Default: 30 seconds
|
|
188
|
+
* Smart timeout detection based on command type
|
|
116
189
|
*/
|
|
117
190
|
function getSmartTimeout(command) {
|
|
118
191
|
const cmd = command.toLowerCase().trim();
|
|
@@ -120,96 +193,111 @@ function getSmartTimeout(command) {
|
|
|
120
193
|
if (/\b(python|python3)\b/.test(cmd) && /\b(train|fine[-\s]?tune|finetune)\b/.test(cmd)) {
|
|
121
194
|
return 600000;
|
|
122
195
|
}
|
|
123
|
-
|
|
124
|
-
if (/\b(torchrun|accelerate\s+launch)\b/.test(cmd)) {
|
|
196
|
+
if (/\b(torchrun|accelerate\s+launch)\b/.test(cmd))
|
|
125
197
|
return 600000;
|
|
126
|
-
}
|
|
127
198
|
// Python/pytest test runners (5 minutes)
|
|
128
|
-
if (/\b(pytest|python\s+-m\s+pytest)\b/.test(cmd))
|
|
199
|
+
if (/\b(pytest|python\s+-m\s+pytest)\b/.test(cmd))
|
|
129
200
|
return 300000;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (/\b(npm|yarn|pnpm)\s+(install|ci|i|add|update|upgrade)\b/.test(cmd)) {
|
|
201
|
+
// NPM/Yarn/PNPM operations (5 minutes)
|
|
202
|
+
if (/\b(npm|yarn|pnpm)\s+(install|ci|i|add|update|upgrade)\b/.test(cmd))
|
|
133
203
|
return 300000;
|
|
134
|
-
|
|
135
|
-
// NPM/Yarn build and test operations (5 minutes)
|
|
136
|
-
if (/\b(npm|yarn|pnpm)\s+(run\s+)?(build|test|lint|start|dev)\b/.test(cmd)) {
|
|
204
|
+
if (/\b(npm|yarn|pnpm)\s+(run\s+)?(build|test|lint|start|dev)\b/.test(cmd))
|
|
137
205
|
return 300000;
|
|
138
|
-
|
|
139
|
-
// NPX create commands (5 minutes)
|
|
140
|
-
if (/\bnpx\s+(create-|degit|giget)\b/.test(cmd)) {
|
|
206
|
+
if (/\bnpx\s+(create-|degit|giget)\b/.test(cmd))
|
|
141
207
|
return 300000;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (/\b(prisma|npx prisma)\s+(generate|migrate|db push|db pull)\b/.test(cmd)) {
|
|
208
|
+
// Prisma (3 minutes)
|
|
209
|
+
if (/\b(prisma|npx prisma)\s+(generate|migrate|db push|db pull)\b/.test(cmd))
|
|
145
210
|
return 180000;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (/\bdocker\s+(build|pull|push|compose)\b/.test(cmd)) {
|
|
211
|
+
// Docker (10 minutes)
|
|
212
|
+
if (/\bdocker\s+(build|pull|push|compose)\b/.test(cmd))
|
|
149
213
|
return 600000;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (/\bgit\s+clone\b/.test(cmd)) {
|
|
214
|
+
// Git clone / pip install (3 minutes)
|
|
215
|
+
if (/\bgit\s+clone\b/.test(cmd))
|
|
153
216
|
return 180000;
|
|
154
|
-
|
|
155
|
-
// Pip install (3 minutes)
|
|
156
|
-
if (/\bpip\s+install\b/.test(cmd)) {
|
|
217
|
+
if (/\bpip\s+install\b/.test(cmd))
|
|
157
218
|
return 180000;
|
|
219
|
+
return 30000; // Default
|
|
220
|
+
}
|
|
221
|
+
const sandboxCache = new Map();
|
|
222
|
+
async function ensureSandboxPaths(workingDir) {
|
|
223
|
+
let pending = sandboxCache.get(workingDir);
|
|
224
|
+
if (!pending) {
|
|
225
|
+
pending = createSandboxPaths(workingDir);
|
|
226
|
+
sandboxCache.set(workingDir, pending);
|
|
158
227
|
}
|
|
159
|
-
|
|
160
|
-
return 30000;
|
|
228
|
+
return pending;
|
|
161
229
|
}
|
|
230
|
+
async function createSandboxPaths(workingDir) {
|
|
231
|
+
const root = join(workingDir, '.erosolar', 'shell-sandbox');
|
|
232
|
+
const home = join(root, 'home');
|
|
233
|
+
const cache = join(root, 'cache');
|
|
234
|
+
const config = join(root, 'config');
|
|
235
|
+
const data = join(root, 'data');
|
|
236
|
+
const tmp = join(root, 'tmp');
|
|
237
|
+
await Promise.all([home, cache, config, data, tmp].map((dir) => mkdir(dir, { recursive: true })));
|
|
238
|
+
return { root, home, cache, config, data, tmp };
|
|
239
|
+
}
|
|
240
|
+
export async function buildSandboxEnv(workingDir, options) {
|
|
241
|
+
const envPreference = process.env['EROSOLAR_PRESERVE_HOME'];
|
|
242
|
+
const preserveHome = envPreference === '1' ? true : envPreference === '0' ? false : Boolean(options?.preserveHome);
|
|
243
|
+
const paths = await ensureSandboxPaths(workingDir);
|
|
244
|
+
const env = {
|
|
245
|
+
...process.env,
|
|
246
|
+
EROSOLAR_SANDBOX_ROOT: paths.root,
|
|
247
|
+
EROSOLAR_SANDBOX_HOME: paths.home,
|
|
248
|
+
EROSOLAR_SANDBOX_TMP: paths.tmp,
|
|
249
|
+
};
|
|
250
|
+
if (!preserveHome)
|
|
251
|
+
env['HOME'] = paths.home;
|
|
252
|
+
env['XDG_CACHE_HOME'] = paths.cache;
|
|
253
|
+
env['XDG_CONFIG_HOME'] = paths.config;
|
|
254
|
+
env['XDG_DATA_HOME'] = paths.data;
|
|
255
|
+
env['TMPDIR'] = paths.tmp;
|
|
256
|
+
env['TMP'] = paths.tmp;
|
|
257
|
+
env['TEMP'] = paths.tmp;
|
|
258
|
+
return env;
|
|
259
|
+
}
|
|
260
|
+
// ============================================================================
|
|
261
|
+
// Main Tool Factory
|
|
262
|
+
// ============================================================================
|
|
162
263
|
export function createBashTools(workingDir) {
|
|
163
|
-
const backgroundTools = createBackgroundBashTools(workingDir);
|
|
164
264
|
return [
|
|
265
|
+
// Main bash execution tool
|
|
165
266
|
{
|
|
166
267
|
name: 'execute_bash',
|
|
167
|
-
description: 'Execute a bash command
|
|
268
|
+
description: 'Execute a bash command. Commands auto-timeout based on type. Use run_in_background: true for servers/watchers.',
|
|
168
269
|
parameters: {
|
|
169
270
|
type: 'object',
|
|
170
271
|
properties: {
|
|
171
|
-
command: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
},
|
|
175
|
-
timeout: {
|
|
176
|
-
type: 'number',
|
|
177
|
-
description: 'Timeout in milliseconds. Default is smart: 30s for most commands, 5min for npm/docker, 3min for git clone. Not used when run_in_background is true.',
|
|
178
|
-
},
|
|
179
|
-
run_in_background: {
|
|
180
|
-
type: 'boolean',
|
|
181
|
-
description: 'Set to true to run this command in the background (for servers, watchers, long-running processes). Returns a shell ID that can be used with BashOutput to monitor output.',
|
|
182
|
-
},
|
|
272
|
+
command: { type: 'string', description: 'The bash command to execute' },
|
|
273
|
+
timeout: { type: 'number', description: 'Timeout in milliseconds (smart defaults apply)' },
|
|
274
|
+
run_in_background: { type: 'boolean', description: 'Run in background for long-running processes' },
|
|
183
275
|
},
|
|
184
276
|
required: ['command'],
|
|
185
277
|
},
|
|
186
278
|
handler: async (args) => {
|
|
187
279
|
const command = args['command'];
|
|
188
280
|
const runInBackground = args['run_in_background'] === true;
|
|
189
|
-
// Smart timeout: auto-extend for known long-running commands
|
|
190
281
|
const userTimeout = args['timeout'];
|
|
191
282
|
const timeout = userTimeout ?? getSmartTimeout(command);
|
|
192
|
-
//
|
|
283
|
+
// Flow guidance
|
|
193
284
|
const flowWarnings = analyzeBashFlow(command);
|
|
194
285
|
for (const warning of flowWarnings) {
|
|
195
286
|
const suffix = warning.suggestion ? ` — ${warning.suggestion}` : '';
|
|
196
287
|
console.warn(`[Bash Flow] ${warning.message}${suffix}`);
|
|
197
288
|
}
|
|
198
|
-
//
|
|
289
|
+
// Safety validation
|
|
199
290
|
const validation = validateBashCommand(command);
|
|
200
291
|
if (!validation.valid) {
|
|
201
292
|
const structuredError = validation.error ? toStructuredError(validation.error) : null;
|
|
202
293
|
if (structuredError) {
|
|
203
|
-
// Return formatted error with suggestions
|
|
204
294
|
let errorMsg = structuredError.toDisplayString();
|
|
205
|
-
// Add auto-fix suggestion if available
|
|
206
295
|
if (validation.autoFix?.available) {
|
|
207
296
|
const { fixed, changes } = SmartFixer.fixDangerousCommand(command);
|
|
208
297
|
if (changes.length > 0) {
|
|
209
298
|
errorMsg += '\n\nAuto-fix available:';
|
|
210
|
-
for (const change of changes)
|
|
299
|
+
for (const change of changes)
|
|
211
300
|
errorMsg += `\n - ${change}`;
|
|
212
|
-
}
|
|
213
301
|
errorMsg += `\n\nFixed command: ${fixed}`;
|
|
214
302
|
}
|
|
215
303
|
}
|
|
@@ -217,67 +305,50 @@ export function createBashTools(workingDir) {
|
|
|
217
305
|
}
|
|
218
306
|
return 'Error: Command validation failed';
|
|
219
307
|
}
|
|
220
|
-
// Log warnings if any
|
|
221
308
|
if (validation.warnings.length > 0) {
|
|
222
309
|
for (const warning of validation.warnings) {
|
|
223
310
|
console.warn(`[Bash Safety] ${warning}`);
|
|
224
311
|
}
|
|
225
312
|
}
|
|
226
|
-
//
|
|
313
|
+
// GUI blocking check (disabled for red team ops)
|
|
227
314
|
const guiBlocked = findGuiLauncher(command);
|
|
228
315
|
if (guiBlocked) {
|
|
229
|
-
return `Blocked
|
|
316
|
+
return `Blocked: ${guiBlocked}`;
|
|
230
317
|
}
|
|
231
|
-
//
|
|
318
|
+
// Background execution
|
|
232
319
|
if (runInBackground) {
|
|
233
|
-
const shellId =
|
|
234
|
-
return `Background shell started: ${shellId}\n\nUse BashOutput with bash_id="${shellId}" to monitor
|
|
320
|
+
const shellId = shellManager.createShell(command, workingDir);
|
|
321
|
+
return `Background shell started: ${shellId}\n\nUse BashOutput with bash_id="${shellId}" to monitor.\nUse KillShell with shell_id="${shellId}" to terminate.`;
|
|
235
322
|
}
|
|
236
|
-
//
|
|
323
|
+
// Foreground execution
|
|
237
324
|
const startTime = Date.now();
|
|
238
325
|
try {
|
|
239
326
|
const env = await buildSandboxEnv(workingDir);
|
|
240
|
-
const { stdout, stderr, exitCode } = await execWithStreaming(command, {
|
|
241
|
-
cwd: workingDir,
|
|
242
|
-
timeout,
|
|
243
|
-
env,
|
|
244
|
-
});
|
|
327
|
+
const { stdout, stderr, exitCode } = await execWithStreaming(command, { cwd: workingDir, timeout, env });
|
|
245
328
|
const durationMs = Date.now() - startTime;
|
|
246
329
|
const combinedOutput = [stdout, stderr].filter(Boolean).join('\n');
|
|
247
|
-
// Select appropriate patterns based on command type
|
|
248
330
|
const commandLower = command.toLowerCase().trim();
|
|
249
331
|
let patterns = OutputPatterns.command;
|
|
250
|
-
if (commandLower.startsWith('git ') || commandLower === 'git')
|
|
332
|
+
if (commandLower.startsWith('git ') || commandLower === 'git')
|
|
251
333
|
patterns = OutputPatterns.git;
|
|
252
|
-
|
|
253
|
-
else if (commandLower.startsWith('npm ') || commandLower.startsWith('npx ')) {
|
|
334
|
+
else if (commandLower.startsWith('npm ') || commandLower.startsWith('npx '))
|
|
254
335
|
patterns = OutputPatterns.npm;
|
|
255
|
-
}
|
|
256
|
-
// Analyze the output to determine actual success
|
|
257
336
|
const analysis = analyzeOutput(combinedOutput, patterns, exitCode);
|
|
258
337
|
const commandCheck = createCommandCheck('Command execution', exitCode, combinedOutput);
|
|
259
|
-
// Non-zero exit code = failure
|
|
260
338
|
if (exitCode !== 0) {
|
|
261
|
-
// AI Error Analysis - automatically analyze failures
|
|
262
339
|
const errorFixer = getErrorFixer(workingDir);
|
|
263
340
|
const aiErrors = errorFixer.analyzeOutput(combinedOutput, command);
|
|
264
341
|
const aiGuidance = aiErrors.length > 0 ? errorFixer.formatForAI(aiErrors) : '';
|
|
265
|
-
const suggestions = ['Review the error message', 'Fix the issue and retry
|
|
342
|
+
const suggestions = ['Review the error message', 'Fix the issue and retry'];
|
|
266
343
|
const firstError = aiErrors[0];
|
|
267
|
-
if (firstError
|
|
268
|
-
|
|
269
|
-
if (bestFix) {
|
|
270
|
-
suggestions.unshift(`AI Suggestion: ${bestFix.description}`);
|
|
271
|
-
}
|
|
344
|
+
if (firstError?.suggestedFixes[0]) {
|
|
345
|
+
suggestions.unshift(`AI Suggestion: ${firstError.suggestedFixes[0].description}`);
|
|
272
346
|
}
|
|
273
347
|
return verifiedFailure(`Command failed with exit code ${exitCode}`, `Command: ${command}\n\nOutput:\n${combinedOutput || '(none)'}${aiGuidance}`, suggestions, [commandCheck], durationMs);
|
|
274
348
|
}
|
|
275
|
-
// Check for explicit failure patterns in output despite exit code 0
|
|
276
|
-
// Some commands exit 0 but print errors (e.g., "error:" in output)
|
|
277
349
|
if (analysis.isFailure) {
|
|
278
|
-
return verifiedFailure(`Command completed with exit code 0 but output indicates failure`, `Command: ${command}\n\nOutput:\n${combinedOutput || '(no output)'}`, ['Review the error message in the output', 'Fix the underlying issue and retry'], [commandCheck, { check: 'Output analysis', passed: false, details: `Failure pattern
|
|
350
|
+
return verifiedFailure(`Command completed with exit code 0 but output indicates failure`, `Command: ${command}\n\nOutput:\n${combinedOutput || '(no output)'}`, ['Review the error message in the output', 'Fix the underlying issue and retry'], [commandCheck, { check: 'Output analysis', passed: false, details: `Failure pattern: ${analysis.matchedPattern}` }], durationMs);
|
|
279
351
|
}
|
|
280
|
-
// Exit code 0 + no failure patterns = success
|
|
281
352
|
return verifiedSuccess(combinedOutput.trim() ? `Command executed successfully` : `Command executed successfully (no output)`, `Command: ${command}${combinedOutput.trim() ? `\n\nOutput:\n${combinedOutput}` : ''}`, [commandCheck, ...(analysis.isSuccess ? [{ check: 'Output analysis', passed: true, details: `Success pattern matched` }] : [])], durationMs);
|
|
282
353
|
}
|
|
283
354
|
catch (error) {
|
|
@@ -286,70 +357,97 @@ export function createBashTools(workingDir) {
|
|
|
286
357
|
const exitCode = execError.code ?? 1;
|
|
287
358
|
const combinedError = [execError.stdout, execError.stderr, execError.message].filter(Boolean).join('\n');
|
|
288
359
|
if (execError.killed) {
|
|
289
|
-
return verifiedFailure(`Command timed out after ${timeout}ms`, `Command: ${command}\n\
|
|
360
|
+
return verifiedFailure(`Command timed out after ${timeout}ms`, `Command: ${command}\n\nPartial output:\n${combinedError || '(none)'}`, ['Increase timeout if command legitimately needs more time', 'Check if command is hanging'], [{ check: 'Timeout', passed: false, details: `Exceeded ${timeout}ms` }], durationMs);
|
|
290
361
|
}
|
|
291
|
-
// AI Error Analysis - automatically analyze failures
|
|
292
362
|
const errorFixer = getErrorFixer(workingDir);
|
|
293
363
|
const aiErrors = errorFixer.analyzeOutput(combinedError, command);
|
|
294
364
|
const aiGuidance = aiErrors.length > 0 ? errorFixer.formatForAI(aiErrors) : '';
|
|
295
|
-
|
|
296
|
-
const suggestions = ['Review the error message', 'Fix the issue and retry the command'];
|
|
365
|
+
const suggestions = ['Review the error message', 'Fix the issue and retry'];
|
|
297
366
|
const firstError = aiErrors[0];
|
|
298
|
-
if (firstError
|
|
299
|
-
|
|
300
|
-
if (bestFix) {
|
|
301
|
-
suggestions.unshift(`AI Suggestion: ${bestFix.description}`);
|
|
302
|
-
}
|
|
367
|
+
if (firstError?.suggestedFixes[0]) {
|
|
368
|
+
suggestions.unshift(`AI Suggestion: ${firstError.suggestedFixes[0].description}`);
|
|
303
369
|
}
|
|
304
370
|
return verifiedFailure(`Command failed with exit code ${exitCode}`, `Command: ${command}\n\nError output:\n${combinedError || '(none)'}${aiGuidance}`, suggestions, [createCommandCheck('Command execution', exitCode, combinedError)], durationMs);
|
|
305
371
|
}
|
|
306
372
|
},
|
|
307
373
|
},
|
|
308
|
-
|
|
374
|
+
// Background shell output retrieval
|
|
375
|
+
{
|
|
376
|
+
name: 'BashOutput',
|
|
377
|
+
description: 'Retrieve output from a running or completed background bash shell.',
|
|
378
|
+
parameters: {
|
|
379
|
+
type: 'object',
|
|
380
|
+
properties: {
|
|
381
|
+
bash_id: { type: 'string', description: 'The ID of the background shell' },
|
|
382
|
+
filter: { type: 'string', description: 'Optional regex to filter output lines' },
|
|
383
|
+
},
|
|
384
|
+
required: ['bash_id'],
|
|
385
|
+
additionalProperties: false,
|
|
386
|
+
},
|
|
387
|
+
handler: async (args) => {
|
|
388
|
+
const bashId = args['bash_id'];
|
|
389
|
+
const filterStr = args['filter'];
|
|
390
|
+
if (typeof bashId !== 'string' || !bashId.trim()) {
|
|
391
|
+
return 'Error: bash_id must be a non-empty string.';
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
const shell = shellManager.getShell(bashId);
|
|
395
|
+
if (!shell) {
|
|
396
|
+
const available = shellManager.listShells();
|
|
397
|
+
return `Error: Shell "${bashId}" not found.\n\nAvailable: ${available.length > 0 ? available.join(', ') : 'none'}`;
|
|
398
|
+
}
|
|
399
|
+
const filter = filterStr && typeof filterStr === 'string' ? new RegExp(filterStr) : undefined;
|
|
400
|
+
const { stdout, stderr, status } = shell.getNewOutput(filter);
|
|
401
|
+
const parts = [`Shell: ${bashId}`, `Status: ${status}`];
|
|
402
|
+
if (stdout) {
|
|
403
|
+
parts.push('\n=== New Output ===');
|
|
404
|
+
parts.push(stdout);
|
|
405
|
+
}
|
|
406
|
+
if (stderr) {
|
|
407
|
+
parts.push('\n=== Errors ===');
|
|
408
|
+
parts.push(stderr);
|
|
409
|
+
}
|
|
410
|
+
if (!stdout && !stderr)
|
|
411
|
+
parts.push('\n(No new output)');
|
|
412
|
+
return parts.join('\n');
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
return buildError('retrieving shell output', error, { bash_id: bashId });
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
// Kill background shell
|
|
420
|
+
{
|
|
421
|
+
name: 'KillShell',
|
|
422
|
+
description: 'Kill a running background bash shell by its ID.',
|
|
423
|
+
parameters: {
|
|
424
|
+
type: 'object',
|
|
425
|
+
properties: {
|
|
426
|
+
shell_id: { type: 'string', description: 'The ID of the background shell to kill' },
|
|
427
|
+
},
|
|
428
|
+
required: ['shell_id'],
|
|
429
|
+
additionalProperties: false,
|
|
430
|
+
},
|
|
431
|
+
handler: async (args) => {
|
|
432
|
+
const shellId = args['shell_id'];
|
|
433
|
+
if (typeof shellId !== 'string' || !shellId.trim()) {
|
|
434
|
+
return 'Error: shell_id must be a non-empty string.';
|
|
435
|
+
}
|
|
436
|
+
try {
|
|
437
|
+
const success = shellManager.killShell(shellId);
|
|
438
|
+
if (success) {
|
|
439
|
+
return `Shell "${shellId}" has been terminated.`;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
const available = shellManager.listShells();
|
|
443
|
+
return `Error: Shell "${shellId}" not found.\n\nAvailable: ${available.length > 0 ? available.join(', ') : 'none'}`;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
return buildError('killing shell', error, { shell_id: shellId });
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
},
|
|
309
451
|
];
|
|
310
452
|
}
|
|
311
|
-
export async function buildSandboxEnv(workingDir, options) {
|
|
312
|
-
const envPreference = process.env['EROSOLAR_PRESERVE_HOME'];
|
|
313
|
-
const preserveHome = envPreference === '1'
|
|
314
|
-
? true
|
|
315
|
-
: envPreference === '0'
|
|
316
|
-
? false
|
|
317
|
-
: Boolean(options?.preserveHome);
|
|
318
|
-
const paths = await ensureSandboxPaths(workingDir);
|
|
319
|
-
const env = {
|
|
320
|
-
...process.env,
|
|
321
|
-
EROSOLAR_SANDBOX_ROOT: paths.root,
|
|
322
|
-
EROSOLAR_SANDBOX_HOME: paths.home,
|
|
323
|
-
EROSOLAR_SANDBOX_TMP: paths.tmp,
|
|
324
|
-
};
|
|
325
|
-
if (!preserveHome) {
|
|
326
|
-
env['HOME'] = paths.home;
|
|
327
|
-
}
|
|
328
|
-
env['XDG_CACHE_HOME'] = paths.cache;
|
|
329
|
-
env['XDG_CONFIG_HOME'] = paths.config;
|
|
330
|
-
env['XDG_DATA_HOME'] = paths.data;
|
|
331
|
-
env['TMPDIR'] = paths.tmp;
|
|
332
|
-
env['TMP'] = paths.tmp;
|
|
333
|
-
env['TEMP'] = paths.tmp;
|
|
334
|
-
return env;
|
|
335
|
-
}
|
|
336
|
-
async function ensureSandboxPaths(workingDir) {
|
|
337
|
-
const key = workingDir;
|
|
338
|
-
let pending = sandboxCache.get(key);
|
|
339
|
-
if (!pending) {
|
|
340
|
-
pending = createSandboxPaths(workingDir);
|
|
341
|
-
sandboxCache.set(key, pending);
|
|
342
|
-
}
|
|
343
|
-
return pending;
|
|
344
|
-
}
|
|
345
|
-
async function createSandboxPaths(workingDir) {
|
|
346
|
-
const root = join(workingDir, '.erosolar', 'shell-sandbox');
|
|
347
|
-
const home = join(root, 'home');
|
|
348
|
-
const cache = join(root, 'cache');
|
|
349
|
-
const config = join(root, 'config');
|
|
350
|
-
const data = join(root, 'data');
|
|
351
|
-
const tmp = join(root, 'tmp');
|
|
352
|
-
await Promise.all([home, cache, config, data, tmp].map((dir) => mkdir(dir, { recursive: true })));
|
|
353
|
-
return { root, home, cache, config, data, tmp };
|
|
354
|
-
}
|
|
355
453
|
//# sourceMappingURL=bashTools.js.map
|