UNPKG

washm

Version:

WASM shell: Bash inside WASM

102 lines (90 loc) 3.27 kB
#!/usr/bin/env -S node --no-warnings // Suppress only the WASI ExperimentalWarning (keeps other warnings intact). // This is intentionally minimal: wrap `process.emitWarning` and drop ExperimentalWarning messages that mention 'WASI'. const _originalEmitWarning = process.emitWarning; process.emitWarning = function(warning, ...args) { try { const name = (typeof args[0] === 'string' ? args[0] : (warning && warning.name)) || ''; const message = typeof warning === 'string' ? warning : (warning && warning.message) || ''; if ((name === 'ExperimentalWarning' || /ExperimentalWarning/.test(name)) && /WASI/.test(message)) return; } catch (e) { /* fall through to default behavior */ } return _originalEmitWarning.call(process, warning, ...args); }; const fs = require('fs'); const { WASI } = require('wasi'); const argv = process.argv; async function main() { const wasmPath = __dirname + '/washm.wasm'; const wasmBuffer = fs.readFileSync(wasmPath); const wasi = new WASI({ args: ['washm.js', ...argv.slice(2)], env: process.env, preopens: (function() { const preopens = { '/': '/' }; if (process.platform !== 'win32') return preopens; const pathModule = require('path'); const os = require('os'); const cwdRoot = pathModule.parse(process.cwd()).root; const homeRoot = pathModule.parse(os.homedir()).root; [cwdRoot, homeRoot].filter(Boolean).forEach(r => { const rootPath = r.endsWith('\\') ? r : r + '\\'; const letter = rootPath[0].toUpperCase(); preopens[`/${letter}:/`] = rootPath; }); return preopens; })(), version: 'preview1' }); const wasiSnapshot = {}; for (const key of Object.keys(wasi.wasiImport)) { wasiSnapshot[key] = function () { return wasiSnapshot[key].actual.apply(this, arguments); }; wasiSnapshot[key].actual = wasi.wasiImport[key]; } let collectEvalJS = ""; let instance; const importObj = { wasi_snapshot_preview1: wasiSnapshot }; // Special handling for bootstrap FD 20251219 const origFdWrite = wasiSnapshot.fd_write.actual; wasiSnapshot.fd_write.actual = (fd, iovs, iovsLen, nwritten) => { if (fd === 20251219) { const memory = new Uint8Array(instance.exports.memory.buffer); const view = new DataView(memory.buffer); let total = 0; for (let i = 0; i < iovsLen; i++) { const ptr = view.getUint32(iovs + i * 8, true); const len = view.getUint32(iovs + i * 8 + 4, true); const chunk = memory.slice(ptr, ptr + len); collectEvalJS += new TextDecoder().decode(chunk); total += len; } view.setUint32(nwritten, total, true); return 0; } return origFdWrite(fd, iovs, iovsLen, nwritten); }; const origFdClose = wasiSnapshot.fd_close.actual; wasiSnapshot.fd_close.actual = (fd) => { if (fd === 20251219) { const js = collectEvalJS; collectEvalJS = ''; eval(js); return 0; } return origFdClose(fd); }; const result = await WebAssembly.instantiate(wasmBuffer, importObj); instance = result.instance; globalThis.__washm_bootstrap = { wasi, importObj, wasiSnapshot, instance, require, }; wasi.start(instance); } main();