shoud-cli 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/tools/index.js +22 -27
package/package.json
CHANGED
package/src/tools/index.js
CHANGED
|
@@ -3,23 +3,16 @@ const fs = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
|
|
6
|
-
// Maximum output size (1 MB)
|
|
7
6
|
const MAX_OUTPUT_SIZE = 1024 * 1024;
|
|
8
|
-
|
|
9
|
-
// Get the project root (current working directory where CLI was started)
|
|
10
7
|
const PROJECT_ROOT = process.cwd();
|
|
11
8
|
|
|
12
|
-
// Determine the appropriate shell
|
|
13
9
|
function getShell() {
|
|
14
10
|
if (os.platform() === 'win32') {
|
|
15
|
-
return 'powershell.exe';
|
|
11
|
+
return 'powershell.exe';
|
|
16
12
|
}
|
|
17
|
-
return '/bin/bash';
|
|
13
|
+
return '/bin/bash';
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
/**
|
|
21
|
-
* Sanitize a file path to ensure it stays within the project root.
|
|
22
|
-
*/
|
|
23
16
|
function sanitizePath(inputPath) {
|
|
24
17
|
const resolved = path.resolve(PROJECT_ROOT, inputPath);
|
|
25
18
|
if (!resolved.startsWith(PROJECT_ROOT)) {
|
|
@@ -29,43 +22,53 @@ function sanitizePath(inputPath) {
|
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
/**
|
|
32
|
-
* Execute a shell command
|
|
33
|
-
*
|
|
25
|
+
* Execute a shell command and return plain text output.
|
|
26
|
+
* On Windows, we use PowerShell with `Out-String` to get text.
|
|
34
27
|
*/
|
|
35
28
|
function executeShell(commandString) {
|
|
36
29
|
if (!commandString || commandString.trim().length === 0) {
|
|
37
30
|
throw new Error('Empty command.');
|
|
38
31
|
}
|
|
39
32
|
|
|
33
|
+
let finalCommand = commandString;
|
|
34
|
+
if (os.platform() === 'win32') {
|
|
35
|
+
// ✅ Force PowerShell to output plain text
|
|
36
|
+
// Escape double quotes in the command
|
|
37
|
+
const escaped = commandString.replace(/"/g, '`"');
|
|
38
|
+
// Wrap in a PowerShell script block and pipe to Out-String
|
|
39
|
+
finalCommand = `& { ${escaped} } | Out-String -Width 4096`;
|
|
40
|
+
}
|
|
41
|
+
|
|
40
42
|
try {
|
|
41
|
-
const output = execSync(
|
|
43
|
+
const output = execSync(finalCommand, {
|
|
42
44
|
cwd: PROJECT_ROOT,
|
|
43
45
|
encoding: 'utf-8',
|
|
44
46
|
shell: getShell(),
|
|
45
|
-
timeout: 30000,
|
|
47
|
+
timeout: 30000,
|
|
46
48
|
maxBuffer: MAX_OUTPUT_SIZE,
|
|
47
49
|
stdio: 'pipe',
|
|
48
50
|
});
|
|
49
|
-
|
|
51
|
+
const trimmed = output.trim();
|
|
52
|
+
return trimmed || 'Command executed successfully with no output.';
|
|
50
53
|
} catch (err) {
|
|
51
|
-
// If command fails, return the error message
|
|
54
|
+
// If the command fails, return the error message
|
|
52
55
|
if (err.stderr) {
|
|
53
56
|
return `Error: ${err.stderr.trim()}`;
|
|
54
57
|
}
|
|
58
|
+
if (err.stdout) {
|
|
59
|
+
// Some commands output to stdout even on failure (e.g., `dir`)
|
|
60
|
+
return err.stdout.trim();
|
|
61
|
+
}
|
|
55
62
|
throw new Error(`Command execution failed: ${err.message}`);
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
/**
|
|
60
|
-
* Read a file securely, ensuring it's within the project root.
|
|
61
|
-
*/
|
|
62
66
|
function readFile(filePath) {
|
|
63
67
|
const safePath = sanitizePath(filePath);
|
|
64
68
|
try {
|
|
65
69
|
const stats = fs.statSync(safePath);
|
|
66
70
|
if (!stats.isFile()) throw new Error('Path is not a file.');
|
|
67
71
|
if (stats.size > MAX_OUTPUT_SIZE) {
|
|
68
|
-
// Read only first 1 MB
|
|
69
72
|
const buffer = Buffer.alloc(MAX_OUTPUT_SIZE);
|
|
70
73
|
const fd = fs.openSync(safePath, 'r');
|
|
71
74
|
fs.readSync(fd, buffer, 0, MAX_OUTPUT_SIZE, 0);
|
|
@@ -78,9 +81,6 @@ function readFile(filePath) {
|
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
/**
|
|
82
|
-
* Write content to a file securely, ensuring it's within the project root.
|
|
83
|
-
*/
|
|
84
84
|
function writeFile(filePath, content) {
|
|
85
85
|
const safePath = sanitizePath(filePath);
|
|
86
86
|
try {
|
|
@@ -95,10 +95,6 @@ function writeFile(filePath, content) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
/**
|
|
99
|
-
* Main tool dispatcher.
|
|
100
|
-
* Returns the result as a string (to be sent back to the AI).
|
|
101
|
-
*/
|
|
102
98
|
function executeTool(toolName, input) {
|
|
103
99
|
try {
|
|
104
100
|
switch (toolName) {
|
|
@@ -112,7 +108,6 @@ function executeTool(toolName, input) {
|
|
|
112
108
|
throw new Error(`Tool "${toolName}" is not supported.`);
|
|
113
109
|
}
|
|
114
110
|
} catch (error) {
|
|
115
|
-
// Return a generic error message to the AI (don't leak internal details)
|
|
116
111
|
return `Tool execution failed: ${error.message}`;
|
|
117
112
|
}
|
|
118
113
|
}
|