aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-29 12:13:33 +0100
committerAgando <roduccomm@gmail.com>2026-10-29 12:13:33 +0100
commit43d067396b5a620441b9a299c45e7b0b129ccd15 (patch)
treea0a03230969a56ce210dc9df2d8457cc866c3a3e
parent1d78155c38fcbc9c76bad7c522e9d9f1060bc4b9 (diff)
fix(newos4): js console handles promise rejections + Node-builtin hint (v4.6.128)
evalJS() evaluated the expression bare and printed JSON.stringify(result), so a rejected thenable (e.g. `js import('fs')`) became `{}` on screen while the rejection escaped to window.onunhandledrejection and was auto-filed as a runtime bug report (RPT-20261028-172211-9c7f2adb, cluster 480x). evalJSFile() already had .then/.catch — the asymmetry was the defect. - modules/ext/console.js: thenable branch in evalJS() awaits and catches; new _printError() is the single error sink for all four catch paths and appends a hint when a bare specifier fails to resolve ("'fs' is a Node built-in; the browser has no Node — use the VFS (ls/cat/run, terminal.fs) instead"). - help.html: js / js-run rows say "browser only — no Node built-ins". - module-loader.js + main.html: v4.6.128. Verification (/tmp/test-console-fs.js, 11 asserts, new Function harness over the module): GREEN 11/11 — rejection prints one red error + hint, no unhandledRejection; resolved thenable prints its value; sync value/throw unchanged; js-run file + missing file OK. RED 4/11 against .bkp-console-20261029_121243/console.js — A1/A2/A3 print `{}`, A4/G2 leak "Failed to resolve module specifier 'fs'". node --check modules/ext/console.js → OK. console.js is loaded separately via extKeys (not in critical-ext-bundle.js), so no bundle rebuild — proven by `grep -c JSConsoleModule modules/ext/critical-ext-bundle.js` = 0. Consumes STEER-20261028-195043-8084. Plan: .hermes/plans/2026-10-29_063000-newos4-js-console-fs-specifier.md
-rw-r--r--help.html4
-rw-r--r--main.html6
-rw-r--r--modules/core/module-loader.js2
-rw-r--r--modules/ext/console.js35
4 files changed, 37 insertions, 10 deletions
diff --git a/help.html b/help.html
index b812fcd..185a9da 100644
--- a/help.html
+++ b/help.html
@@ -1007,8 +1007,8 @@ ollamaconnect</pre>
<tr><td><code>listmods</code></td><td>List all loaded modules</td></tr>
<tr><td><code>load-local</code></td><td>Load module from VFS or URL</td></tr>
<tr><td><code>loadlocal</code></td><td>Alias for load-local</td></tr>
- <tr><td><code>js &lt;expr&gt;</code></td><td>Evaluate JavaScript in page context</td></tr>
- <tr><td><code>js-run &lt;path&gt;</code></td><td>Load and execute a JS file from VFS</td></tr>
+ <tr><td><code>js &lt;expr&gt;</code></td><td>Evaluate JavaScript in page context (browser only — no Node built-ins such as <code>fs</code>)</td></tr>
+ <tr><td><code>js-run &lt;path&gt;</code></td><td>Load and execute a JS file from VFS (browser only — no Node built-ins)</td></tr>
<tr><td><code>startup-modules</code></td><td>Configure boot modules</td></tr>
<tr><td><code>module-load &lt;name&gt;</code></td><td>Load a module by name</td></tr>
<tr><td><code>module-unload &lt;name&gt;</code></td><td>Unload a module</td></tr>
diff --git a/main.html b/main.html
index c386cc2..60ab3f0 100644
--- a/main.html
+++ b/main.html
@@ -1349,13 +1349,13 @@
</script>
<!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix -->
-<script src="modules/core/core-bundle.js?v=v4.6.119"></script>
+<script src="modules/core/core-bundle.js?v=v4.6.128"></script>
<!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules -->
-<script src="modules/core/module-loader.js?v=v4.6.119"></script>
+<script src="modules/core/module-loader.js?v=v4.6.128"></script>
<!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work -->
-<script src="modules/ext/critical-ext-bundle.js?v=v4.6.119"></script>
+<script src="modules/ext/critical-ext-bundle.js?v=v4.6.128"></script>
<script>
// ═══ ONE TRUE VERSION SOURCE ═══
diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js
index 18938f7..1d79b3a 100644
--- a/modules/core/module-loader.js
+++ b/modules/core/module-loader.js
@@ -4,7 +4,7 @@
// Core module bundle loaded synchronously in main.html.
// This loader only handles version cache-busting, splash, terminal init, and optional ext modules.
- const LATEST_VER = 'v4.6.119';
+ const LATEST_VER = 'v4.6.128';
const CACHE = '?v=' + LATEST_VER;
// Exposed so ext modules can register their own URL with the same cache-busting version
// instead of an unversioned path the browser may already have cached (shell.js did).
diff --git a/modules/ext/console.js b/modules/ext/console.js
index 5d3007a..60f75a7 100644
--- a/modules/ext/console.js
+++ b/modules/ext/console.js
@@ -30,13 +30,28 @@ class JSConsoleModule {
evalJS(args) {
if (!args[0]) return this.terminal.print('Usage: js <expression>', 'warning');
const expr = args.join(' ');
- // v4.5.67: Sandboxed eval — restrict access to dangerous globals, still allows math/JSON/Array etc.
+ // v4.6.128: Sandboxed eval — restrict access to dangerous globals, still allows math/JSON/Array etc.
try {
const result = (function() {
'use strict';
// eslint-disable-next-line no-eval
return eval(expr);
})();
+ // A thenable must be awaited: an uncaught `import('fs')` rejection escapes to
+ // window.onunhandledrejection and is auto-filed as a runtime bug report.
+ if (result && typeof result.then === 'function') {
+ result.then(val => {
+ const output = val === undefined ? 'undefined' :
+ typeof val === 'string' ? val :
+ val === null ? 'null' :
+ typeof val === 'object' ? JSON.stringify(val, null, 2) :
+ String(val);
+ this.terminal.print(output, 'success');
+ }).catch(e => {
+ this._printError(e);
+ });
+ return;
+ }
const output = result === undefined ? 'undefined' :
typeof result === 'string' ? result :
result === null ? 'null' :
@@ -44,7 +59,19 @@ class JSConsoleModule {
String(result);
this.terminal.print(output, 'success');
} catch (e) {
- this.terminal.print(`Error: ${e.message}`, 'error');
+ this._printError(e);
+ }
+ }
+
+ // Single error sink: prints `Error: <msg>`, plus a Node-builtin hint when the browser
+ // could not resolve a bare specifier (v4.6.128).
+ _printError(e) {
+ const msg = (e && e.message) ? e.message : String(e);
+ this.terminal.print(`Error: ${msg}`, 'error');
+ const m = /(?:Failed to resolve module specifier|Cannot find module) '([^']+)'/.exec(msg);
+ if (m) {
+ this.terminal.print(`'${m[1]}' is a Node built-in; the browser has no Node — ` +
+ `use the VFS (ls/cat/run, terminal.fs) instead`, 'warning');
}
}
@@ -73,7 +100,7 @@ class JSConsoleModule {
String(val);
this.terminal.print(output, 'success');
}).catch(e => {
- this.terminal.print(`Error: ${e.message}`, 'error');
+ this._printError(e);
});
return;
}
@@ -84,7 +111,7 @@ class JSConsoleModule {
String(result);
this.terminal.print(output, 'success');
} catch (e) {
- this.terminal.print(`Error: ${e.message}`, 'error');
+ this._printError(e);
}
}