aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-sandbox.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/module-sandbox.js
parentb538577cd0a4292e4cd4ca1c9f9829fc7e133caa (diff)
auto: 2026-06-06_06:00 changes
Diffstat (limited to 'modules/core/module-sandbox.js')
-rw-r--r--modules/core/module-sandbox.js62
1 files changed, 51 insertions, 11 deletions
diff --git a/modules/core/module-sandbox.js b/modules/core/module-sandbox.js
index dc8dc76..67b8357 100644
--- a/modules/core/module-sandbox.js
+++ b/modules/core/module-sandbox.js
@@ -33,7 +33,7 @@ class SandboxModule {
init(terminal) {
this.terminal = terminal;
- this.workerUrl = '/spaces/newos4/modules/core/sandbox-worker.js';
+ this.workerUrl = '/spaces/newos4/modules/core/sandbox-worker.js?v=2026-06-05-v4.4.0';
// Detect Worker availability
if (typeof Worker === 'undefined') {
@@ -41,6 +41,19 @@ class SandboxModule {
this.terminal.print('⚠️ WebWorkers not available — sandbox using inline fallback', 'warning');
} else {
this._initPool();
+ // Deferred check: workers may fail asynchronously (headless browsers)
+ // If no worker proves alive within 1.5s, switch to inline fallback
+ this._workerCheckTimer = setTimeout(() => {
+ if (!this._fallbackMode && this.workers.length > 0) {
+ const alive = this.workers.some(w => !w._failed && this._workerReady[w._sandboxId]);
+ if (!alive) {
+ this._fallbackMode = true;
+ this.workers.forEach(w => w.terminate());
+ this.workers = [];
+ this.terminal.print('⚠️ WebWorkers unavailable — switching to inline fallback', 'warning');
+ }
+ }
+ }, 1500);
}
this.terminal.print('🧪 Sandbox module loaded', 'info');
@@ -49,44 +62,65 @@ class SandboxModule {
_initPool() {
// Start with MIN_WORKERS, grow on demand up to MAX_WORKERS
for (let i = 0; i < this.MIN_WORKERS; i++) {
- this._spawnWorker();
+ const w = this._spawnWorker();
+ if (!w) break; // first failure kills the pool
}
}
_spawnWorker() {
if (this.workers.length >= this.MAX_WORKERS) return null;
+ if (this._fallbackMode) return null;
try {
const worker = new Worker(this.workerUrl);
const id = `w${this.workers.length + 1}`;
worker._sandboxId = id;
worker._busy = false;
+ worker._failed = false;
- worker.onmessage = (e) => this._handleResult(e.data, id);
+ // Detect immediate worker failure (headless browsers, restricted contexts)
+ const failTimer = setTimeout(() => {
+ if (!worker._failed) {
+ // Worker survived 2 seconds - likely functional
+ }
+ }, 2000);
+
+ worker.onmessage = (e) => {
+ clearTimeout(failTimer);
+ if (e.data && e.data.type === 'ready') {
+ this._workerReady[id] = true;
+ } else {
+ this._handleResult(e.data, id);
+ }
+ };
worker.onerror = (e) => {
- console.error(`[Sandbox] Worker ${id} error:`, e.message);
- this._totalErrors++;
- this._replaceWorker(id);
+ clearTimeout(failTimer);
+ worker._failed = true;
+ worker.terminate();
+ console.warn(`[Sandbox] Worker ${id} failed (headless env) — switching to inline`);
+ this._fallbackMode = true;
+ this.workers.forEach(w => w.terminate());
+ this.workers = [];
+ this.terminal.print('⚠️ WebWorkers unavailable in this environment — using inline fallback', 'warning');
};
this.workers.push(worker);
- this._workerReady[id] = true;
return worker;
} catch (e) {
- console.error('[Sandbox] Failed to spawn worker:', e);
+ console.warn('[Sandbox] Failed to spawn worker:', e);
this._fallbackMode = true;
return null;
}
}
_replaceWorker(id) {
+ // In headless environments, workers don't work — don't retry
+ if (this._fallbackMode) return;
const idx = this.workers.findIndex(w => w._sandboxId === id);
if (idx !== -1) {
this.workers[idx].terminate();
this.workers.splice(idx, 1);
delete this._workerReady[id];
}
- // Re-spawn after a delay
- setTimeout(() => this._spawnWorker(), 1000);
}
_getIdleWorker() {
@@ -104,7 +138,13 @@ class SandboxModule {
async runInSandbox(task, capabilities) {
if (!task) return this.terminal.print('Usage: sandbox-run <task>', 'error');
- if (this._fallbackMode) {
+ // Check if any worker is actually alive and ready
+ const hasAliveWorker = this.workers.some(w =>
+ !w._failed && this._workerReady[w._sandboxId]
+ );
+ const useInline = this._fallbackMode || this.workers.length === 0 || !hasAliveWorker;
+
+ if (useInline) {
return this._runInline(task, capabilities);
}