aboutsummaryrefslogtreecommitdiff
path: root/modules/core/sandbox-worker.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-06 06:00:27 +0200
committerAgando <roduccomm@gmail.com>2026-06-06 06:00:27 +0200
commitccc7d9956559d2195e20345e7a794662b52cd403 (patch)
tree757354fbfec5c75b4577b2cb620d5ab1582e19b1 /modules/core/sandbox-worker.js
parentb538577cd0a4292e4cd4ca1c9f9829fc7e133caa (diff)
auto: 2026-06-06_06:00 changes
Diffstat (limited to 'modules/core/sandbox-worker.js')
-rw-r--r--modules/core/sandbox-worker.js119
1 files changed, 61 insertions, 58 deletions
diff --git a/modules/core/sandbox-worker.js b/modules/core/sandbox-worker.js
index 5841582..696c510 100644
--- a/modules/core/sandbox-worker.js
+++ b/modules/core/sandbox-worker.js
@@ -5,11 +5,16 @@
let _vfs = null;
let _apiProxyOrigin = null;
-self.onmessage = async (e) => {
- const { taskId, task, capabilities, vfsSnapshot, allowedCommands, apiProxy } = e.data;
- _apiProxyOrigin = apiProxy ? new URL(apiProxy).origin : null;
+// Signal ready immediately
+self.postMessage({ type: 'ready' });
- const startTime = performance.now();
+self.addEventListener('message', async (e) => {
+ const { taskId, task, capabilities, vfsSnapshot, allowedCommands, apiProxy } = e.data || {};
+
+ // Must have a taskId to respond to
+ if (!taskId) return;
+
+ const startTime = self.performance.now();
let toolCalls = 0;
let result = '';
let error = null;
@@ -17,18 +22,13 @@ self.onmessage = async (e) => {
try {
// Rebuild VFS from snapshot
_vfs = vfsSnapshot ? JSON.parse(vfsSnapshot) : { root: { type: 'dir', content: {} }, currentPath: [] };
-
- // Log start
- console.log(`[Sandbox ${taskId}] Starting task: "${task.substring(0, 60)}"`);
+ _apiProxyOrigin = apiProxy ? new URL(apiProxy).origin : null;
// Parse the task for tool use
- const toolResults = {};
+ const parts = (task || '').trim().split(/\s+/);
+ const cmd = parts.length > 0 ? parts[0].toLowerCase() : '';
const commandWhitelist = allowedCommands || ['ls', 'cat', 'echo', 'find', 'grep', 'help', 'status'];
- // Execute basic commands
- const parts = task.trim().split(/\s+/);
- const cmd = parts[0].toLowerCase();
-
if (cmd === 'ls' || cmd === 'list') {
result = sandbox_ls(parts[1] || '/');
toolCalls++;
@@ -50,117 +50,115 @@ self.onmessage = async (e) => {
} else if (cmd === 'status') {
result = sandbox_status();
toolCalls++;
- } else if (capabilities.includes('run_command') && commandWhitelist.includes(cmd)) {
+ } else if (capabilities && capabilities.includes('run_command') && commandWhitelist.includes(cmd)) {
result = sandbox_run(cmd, parts.slice(1));
toolCalls++;
} else {
// If the task is descriptive (not a command), run smart handling
- if (capabilities.includes('list_files') || capabilities.includes('read_file')) {
- // Smart mode: interpret task
- const lower = task.toLowerCase();
+ if (capabilities && (capabilities.includes('list_files') || capabilities.includes('read_file'))) {
+ const lower = (task || '').toLowerCase();
if (lower.includes('list') || lower.includes('file')) {
const dir = parts.find(p => p.startsWith('/') || p.startsWith('.')) || '/';
result = sandbox_ls(dir);
} else if (lower.includes('find') || lower.includes('search')) {
- const q = task.replace(/find|search/i, '').trim();
+ const q = (task || '').replace(/find|search/i, '').trim();
result = sandbox_find(q || '');
} else if (lower.includes('count') || lower.includes('how many')) {
result = sandbox_ls('/');
const count = (result.match(/\[file\]|\[dir\]/g) || []).length;
- result = `Found ${count} items in total.\\n${result}`;
+ result = 'Found ' + count + ' items in total.\n' + result;
} else if (lower.includes('status') || lower.includes('health')) {
result = sandbox_status();
} else {
- result = `Task interpreted: "${task}"\\nCapabilities: ${capabilities.join(', ')}\\nTip: Be more specific (e.g. "list files in /")`;
+ result = 'Task interpreted: "' + (task || '') + '"\nCapabilities: ' + (capabilities || []).join(', ') + '\nTip: Be more specific (e.g. "list files in /")';
}
toolCalls++;
} else {
- result = `Task: "${task}"\\nNo matching capability for command "${cmd}"`;
+ result = 'Task: "' + (task || '') + '"\nNo matching capability for command "' + cmd + '"';
}
}
} catch (e) {
- error = e.message;
- console.error(`[Sandbox ${taskId}] Error:`, e);
+ error = e.message || String(e);
}
- const duration = ((performance.now() - startTime) / 1000).toFixed(2);
+ const duration = ((self.performance.now() - startTime) / 1000).toFixed(2);
self.postMessage({
- taskId,
- result,
- error,
- toolCalls,
+ taskId: taskId,
+ result: result,
+ error: error,
+ toolCalls: toolCalls,
duration: parseFloat(duration),
vfsSnapshot: JSON.stringify(_vfs)
});
-};
+});
// ─── Sandboxed VFS Operations ───
function sandbox_ls(path) {
path = path || '/';
const entries = _vfs_get_entries(path);
- if (!entries) return `ls: ${path}: No such directory`;
- const lines = entries.map(e => {
+ if (!entries) return 'ls: ' + path + ': No such directory';
+ const lines = entries.map(function(e) {
const icon = e.type === 'dir' ? '[dir]' : '[file]';
- const size = e.size !== undefined ? ` (${e.size}B)` : '';
- return `${icon} ${e.name}${size}`;
+ const size = e.size !== undefined ? ' (' + e.size + 'B)' : '';
+ return icon + ' ' + e.name + size;
});
- return lines.join('\\n') || '(empty)';
+ return lines.join('\n') || '(empty)';
}
function sandbox_cat(path) {
const content = _vfs_get_content(path);
- if (content === null) return `cat: ${path}: No such file`;
- if (typeof content === 'object') return `cat: ${path}: Is a directory`;
- if (content.length > 8000) return content.substring(0, 8000) + '\\n... (truncated at 8KB)';
+ if (content === null) return 'cat: ' + path + ': No such file';
+ if (typeof content === 'object') return 'cat: ' + path + ': Is a directory';
+ if (content.length > 8000) return content.substring(0, 8000) + '\n... (truncated at 8KB)';
return content;
}
function sandbox_find(query) {
const results = [];
const q = query ? query.toLowerCase() : '';
- _vfs_walk('/', (path, node) => {
+ _vfs_walk('/', function(path, node) {
if (node.type === 'file') {
if (!q || path.toLowerCase().includes(q)) {
results.push(path);
}
}
});
- if (results.length === 0) return `No files found${query ? ` matching "${query}"` : ''}`;
- return results.join('\\n');
+ if (results.length === 0) return 'No files found' + (query ? ' matching "' + query + '"' : '');
+ return results.join('\n');
}
function sandbox_grep(query) {
if (!query) return 'grep: missing pattern';
const q = query.toLowerCase();
const results = [];
- _vfs_walk('/', (path, node) => {
+ _vfs_walk('/', function(path, node) {
if (node.type === 'file' && typeof node.content === 'string') {
- const lines = node.content.split('\\n');
+ const lines = node.content.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].toLowerCase().includes(q)) {
- results.push(`${path}:${i + 1}: ${lines[i].trim().substring(0, 100)}`);
+ results.push(path + ':' + (i + 1) + ': ' + lines[i].trim().substring(0, 100));
}
}
}
});
- if (results.length === 0) return `grep: no matches for "${query}"`;
- return results.slice(0, 50).join('\\n') + (results.length > 50 ? `\\n... (+${results.length - 50} more)` : '');
+ if (results.length === 0) return 'grep: no matches for "' + query + '"';
+ return results.slice(0, 50).join('\n') + (results.length > 50 ? '\n... (+' + (results.length - 50) + ' more)' : '');
}
function sandbox_status() {
let fileCount = 0, dirCount = 0;
- _vfs_walk('/', (path, node) => {
+ _vfs_walk('/', function(path, node) {
if (node.type === 'file') fileCount++;
else dirCount++;
});
const vfsSize = JSON.stringify(_vfs).length;
- return `Sandbox VFS Status:\\n Files: ${fileCount}\\n Directories: ${dirCount}\\n VFS Size: ${(vfsSize / 1024).toFixed(1)}KB`;
+ return 'Sandbox VFS Status:\n Files: ' + fileCount + '\n Directories: ' + dirCount + '\n VFS Size: ' + (vfsSize / 1024).toFixed(1) + 'KB';
}
function sandbox_run(cmd, args) {
- return `[sandbox] ${cmd} ${args.join(' ')}\\n(Command execution limited in sandbox mode)`;
+ return '[sandbox] ' + cmd + ' ' + args.join(' ') + '\n(Command execution limited in sandbox mode)';
}
// ─── VFS Helpers ───
@@ -168,11 +166,15 @@ function sandbox_run(cmd, args) {
function _vfs_get_entries(path) {
const dir = _vfs_resolve(path);
if (!dir || dir.type !== 'dir') return null;
- return Object.entries(dir.content || {}).map(([name, node]) => ({
- name,
- type: node.type || 'file',
- size: typeof node.content === 'string' ? node.content.length : undefined
- })).sort((a, b) => a.name.localeCompare(b.name));
+ return Object.entries(dir.content || {}).map(function(entry) {
+ const name = entry[0];
+ const node = entry[1];
+ return {
+ name: name,
+ type: node.type || 'file',
+ size: typeof node.content === 'string' ? node.content.length : undefined
+ };
+ }).sort(function(a, b) { return a.name.localeCompare(b.name); });
}
function _vfs_get_content(path) {
@@ -184,11 +186,11 @@ function _vfs_get_content(path) {
function _vfs_resolve(path) {
if (!_vfs || !_vfs.root) return null;
if (path === '/' || path === '') return _vfs.root;
- const parts = path.split('/').filter(p => p);
+ const parts = path.split('/').filter(function(p) { return p; });
let current = _vfs.root;
- for (const part of parts) {
- if (!current.content || !current.content[part]) return null;
- current = current.content[part];
+ for (let i = 0; i < parts.length; i++) {
+ if (!current.content || !current.content[parts[i]]) return null;
+ current = current.content[parts[i]];
}
return current;
}
@@ -198,8 +200,9 @@ function _vfs_walk(path, cb) {
if (!node) return;
cb(path, node);
if (node.type === 'dir' && node.content) {
- for (const [name, child] of Object.entries(node.content)) {
- _vfs_walk(path === '/' ? '/' + name : path + '/' + name, cb);
+ const names = Object.keys(node.content);
+ for (let i = 0; i < names.length; i++) {
+ _vfs_walk(path === '/' ? '/' + names[i] : path + '/' + names[i], cb);
}
}
} \ No newline at end of file