1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
class JSConsoleModule {
constructor() {
this.commands = {};
this.commandsMeta = { 'js': { argType: 'file' }, 'js-run': { argType: 'file' } };
this.terminal = null;
}
getHelpInfo() {
return {
'js': 'js <expression> — Evaluate JavaScript in page context',
'js-run': 'js-run <path> — Load and execute a JS file from VFS',
'node': 'node <path> — Alias for js-run (executes a JS file from VFS)'
};
}
registerCommands() {
this.commands['js'] = (args) => this.evalJS(args);
this.commands['js-run'] = (args) => this.evalJSFile(args);
this.commands['node'] = (args) => {
// Bridge: AI hallucinates `node script.js` — map to js-run
if (!args[0]) return this.terminal.print('Usage: node <script.js> (alias for js-run)', 'warning');
// Handle `node -e "expr"` — inline eval like Node.js
if (args[0] === '-e') {
return this.evalJS(args.slice(1));
}
return this.evalJSFile(args);
};
}
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.
try {
const result = (function() {
'use strict';
// eslint-disable-next-line no-eval
return eval(expr);
})();
const output = result === undefined ? 'undefined' :
typeof result === 'string' ? result :
result === null ? 'null' :
typeof result === 'object' ? JSON.stringify(result, null, 2) :
String(result);
this.terminal.print(output, 'success');
} catch (e) {
this.terminal.print(`Error: ${e.message}`, 'error');
}
}
evalJSFile(args) {
if (!args[0]) return this.terminal.print('Usage: js-run <path>', 'warning');
const path = args.join(' ');
try {
const content = this.terminal.fs.readFile(path);
if (content === null || content === undefined || content === false) {
return this.terminal.print(`js-run: ${path}: No such file`, 'error');
}
// v4.5.67: Wrap in sandboxed async IIFE
const wrapped = `(async () => {\n${content}\n})()`;
const result = (function() {
'use strict';
// eslint-disable-next-line no-eval
return eval(wrapped);
})();
// If it returns a promise, wait for it via .then
if (result && typeof result.then === 'function') {
result.then(val => {
const output = val === undefined ? '✓ Script executed' :
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.terminal.print(`Error: ${e.message}`, 'error');
});
return;
}
const output = result === undefined ? '✓ Script executed' :
typeof result === 'string' ? result :
result === null ? 'null' :
typeof result === 'object' ? JSON.stringify(result, null, 2) :
String(result);
this.terminal.print(output, 'success');
} catch (e) {
this.terminal.print(`Error: ${e.message}`, 'error');
}
}
seed() {}
init() {}
}
if (typeof window !== 'undefined') window.JSConsoleModule = JSConsoleModule;
|