shoud-cli 1.0.8 → 1.0.11
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/bin/shoud.js +10 -6
- package/package.json +1 -1
- package/src/tools/index.js +56 -0
package/bin/shoud.js
CHANGED
|
@@ -15,7 +15,7 @@ const BANNER_ART = [
|
|
|
15
15
|
" ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ "
|
|
16
16
|
];
|
|
17
17
|
|
|
18
|
-
// ─── Static Banner (
|
|
18
|
+
// ─── Static Banner (prints at the start of commands) ──────
|
|
19
19
|
function printStaticBanner() {
|
|
20
20
|
const color = chalk.hex('#B5F96C');
|
|
21
21
|
console.log(color(BANNER_ART.join('\n')));
|
|
@@ -95,7 +95,7 @@ async function main() {
|
|
|
95
95
|
args[0] === 'help' || args[0] === '--help' || args[0] === '-h' ||
|
|
96
96
|
args[0] === '--version' || args[0] === '-v') {
|
|
97
97
|
if (args[0] === '--version' || args[0] === '-v') {
|
|
98
|
-
program.version('1.0.
|
|
98
|
+
program.version('1.0.9');
|
|
99
99
|
program.parse(process.argv);
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
@@ -105,13 +105,16 @@ async function main() {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
program
|
|
108
|
-
.version('1.0.
|
|
108
|
+
.version('1.0.9')
|
|
109
109
|
.description('SHOUD Terminal Agent');
|
|
110
110
|
|
|
111
111
|
program
|
|
112
112
|
.command('login')
|
|
113
113
|
.description('Authenticate this device with your SHOUD account')
|
|
114
|
-
.action(
|
|
114
|
+
.action(() => {
|
|
115
|
+
// Optionally show banner before login? We'll keep it clean.
|
|
116
|
+
login();
|
|
117
|
+
});
|
|
115
118
|
|
|
116
119
|
// Placeholder for status
|
|
117
120
|
program
|
|
@@ -129,9 +132,10 @@ async function main() {
|
|
|
129
132
|
return;
|
|
130
133
|
}
|
|
131
134
|
const taskPrompt = promptArr.join(' ');
|
|
132
|
-
|
|
133
|
-
// ✅ After task completes, show the static banner
|
|
135
|
+
// ✅ Show the static banner at the start
|
|
134
136
|
printStaticBanner();
|
|
137
|
+
await executeTask(taskPrompt);
|
|
138
|
+
// No banner at the end (removed)
|
|
135
139
|
});
|
|
136
140
|
|
|
137
141
|
program.parse(process.argv);
|
package/package.json
CHANGED
package/src/tools/index.js
CHANGED
|
@@ -112,4 +112,60 @@ function executeTool(toolName, input) {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Read an image/video file and return a data URL for Gemini.
|
|
117
|
+
*/
|
|
118
|
+
function readImage(filePath) {
|
|
119
|
+
const safePath = sanitizePath(filePath);
|
|
120
|
+
try {
|
|
121
|
+
const stats = fs.statSync(safePath);
|
|
122
|
+
if (!stats.isFile()) throw new Error('Path is not a file.');
|
|
123
|
+
const buffer = fs.readFileSync(safePath);
|
|
124
|
+
const base64 = buffer.toString('base64');
|
|
125
|
+
const mimeType = getMimeType(safePath); // you need to define this helper
|
|
126
|
+
return `data:${mimeType};base64,${base64}`;
|
|
127
|
+
} catch (err) {
|
|
128
|
+
throw new Error(`Failed to read image: ${err.message}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Helper: determine MIME type from file extension
|
|
133
|
+
function getMimeType(filePath) {
|
|
134
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
135
|
+
const map = {
|
|
136
|
+
'.jpg': 'image/jpeg',
|
|
137
|
+
'.jpeg': 'image/jpeg',
|
|
138
|
+
'.png': 'image/png',
|
|
139
|
+
'.gif': 'image/gif',
|
|
140
|
+
'.webp': 'image/webp',
|
|
141
|
+
'.mp4': 'video/mp4',
|
|
142
|
+
'.mov': 'video/quicktime',
|
|
143
|
+
'.avi': 'video/x-msvideo',
|
|
144
|
+
'.webm': 'video/webm',
|
|
145
|
+
'.mkv': 'video/x-matroska',
|
|
146
|
+
'.pdf': 'application/pdf',
|
|
147
|
+
};
|
|
148
|
+
return map[ext] || 'application/octet-stream';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// In executeTool, add:
|
|
152
|
+
function executeTool(toolName, input) {
|
|
153
|
+
try {
|
|
154
|
+
switch (toolName) {
|
|
155
|
+
case 'execute_shell':
|
|
156
|
+
return executeShell(input.command);
|
|
157
|
+
case 'read_file':
|
|
158
|
+
return readFile(input.path);
|
|
159
|
+
case 'write_file':
|
|
160
|
+
return writeFile(input.path, input.content);
|
|
161
|
+
case 'read_image': // new
|
|
162
|
+
return readImage(input.path);
|
|
163
|
+
default:
|
|
164
|
+
throw new Error(`Tool "${toolName}" is not supported.`);
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return `Tool execution failed: ${error.message}`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
115
171
|
module.exports = { executeTool };
|