()
| 65 | let instance = null; |
| 66 | |
| 67 | async function start() { |
| 68 | const wasmBuffer = fs.readFileSync(wasmPath); |
| 69 | |
| 70 | // Build WASI args based on options |
| 71 | // The emulator supports -net socket for networking via WASI sockets |
| 72 | const wasiArgs = ['agentvm']; |
| 73 | if (network) { |
| 74 | wasiArgs.push('-net', 'socket'); |
| 75 | if (mac) { |
| 76 | wasiArgs.push('-mac', mac); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | // parentPort.postMessage({ type: 'debug', msg: `WASI args: ${wasiArgs.join(' ')}` }); |
| 81 | |
| 82 | // Store preopens for our custom path_open implementation |
| 83 | const preopenPaths = mounts || {}; |
| 84 | // Map wasi fd to host path (fd 3 onwards) |
| 85 | const fdToHostPath = new Map(); |
| 86 | let preopen_fd = 3; |
| 87 | for (const [wasiPath, hostPath] of Object.entries(preopenPaths)) { |
| 88 | fdToHostPath.set(preopen_fd, { wasiPath, hostPath: require('path').resolve(hostPath) }); |
| 89 | preopen_fd++; |
| 90 | } |
| 91 | |
| 92 | const wasi = new WASI({ |
| 93 | version: 'preview1', |
| 94 | args: wasiArgs, |
| 95 | env: { 'TERM': 'xterm-256color', 'LISTEN_FDS': '1' }, |
| 96 | preopens: preopenPaths |
| 97 | }); |
| 98 | |
| 99 | const wasiImport = wasi.wasiImport; |
| 100 | |
| 101 | // Track next available fd for our fake duplicates and custom file handles |
| 102 | let nextFakeFd = 100; // Start high to avoid conflicts |
| 103 | const fakeFdMap = new Map(); // fake fd -> original fd (for directory duplicates) |
| 104 | const customFdHandles = new Map(); // fd -> {type: 'file', handle: fs.FileHandle, hostPath: string} |
| 105 | |
| 106 | // Fix for path_open: Node.js WASI has multiple bugs with preopened directories |
| 107 | // We implement our own file opening for preopened directory contents |
| 108 | const origPathOpen = wasiImport.path_open; |
| 109 | wasiImport.path_open = (fd, dirflags, path_ptr, path_len, oflags, fs_rights_base, fs_rights_inheriting, fdflags, opened_fd_ptr) => { |
| 110 | // Get the path string |
| 111 | let pathStr = ''; |
| 112 | if (instance) { |
| 113 | const mem = new Uint8Array(instance.exports.memory.buffer); |
| 114 | const pathBytes = mem.slice(path_ptr, path_ptr + path_len); |
| 115 | pathStr = new TextDecoder().decode(pathBytes); |
| 116 | } |
| 117 | |
| 118 | // Resolve fake fd to real fd for the base directory |
| 119 | let actualFd = fakeFdMap.has(fd) ? fakeFdMap.get(fd) : fd; |
| 120 | |
| 121 | // Check if this is a preopened directory OR one of our custom directory handles |
| 122 | let preopenInfo = fdToHostPath.get(actualFd); |
| 123 | |
| 124 | // Also check if fd is one of our custom directory handles |
no test coverage detected