()
| 98 | } |
| 99 | |
| 100 | async function main() { |
| 101 | const args = process.argv.slice(2); |
| 102 | const options = parseArgs(args); |
| 103 | |
| 104 | // Print startup info to stderr so it doesn't interfere with VM output |
| 105 | process.stderr.write('AgentVM Terminal\n'); |
| 106 | process.stderr.write('================\n'); |
| 107 | process.stderr.write(`Network: ${options.network ? 'enabled' : 'disabled'}\n`); |
| 108 | |
| 109 | if (Object.keys(options.mounts).length > 0) { |
| 110 | process.stderr.write('Mounts:\n'); |
| 111 | for (const [vmPath, hostPath] of Object.entries(options.mounts)) { |
| 112 | process.stderr.write(` ${hostPath} -> ${vmPath}\n`); |
| 113 | } |
| 114 | } |
| 115 | process.stderr.write('\n'); |
| 116 | |
| 117 | const vm = new AgentVM({ |
| 118 | network: options.network, |
| 119 | mounts: options.mounts, |
| 120 | debug: options.debug, |
| 121 | interactive: true, // Use interactive/raw mode |
| 122 | }); |
| 123 | |
| 124 | // Connect VM stdout/stderr directly to process stdout/stderr |
| 125 | vm.onStdout = (data) => { |
| 126 | process.stdout.write(data); |
| 127 | }; |
| 128 | |
| 129 | vm.onStderr = (data) => { |
| 130 | process.stderr.write(data); |
| 131 | }; |
| 132 | |
| 133 | // Handle VM exit (e.g., user types 'exit' in shell) |
| 134 | vm.onExit = async () => { |
| 135 | if (process.stdin.isTTY) { |
| 136 | process.stdin.setRawMode(false); |
| 137 | } |
| 138 | process.exit(0); |
| 139 | }; |
| 140 | |
| 141 | process.stderr.write('Booting VM...\n'); |
| 142 | |
| 143 | try { |
| 144 | await vm.start(); |
| 145 | } catch (err) { |
| 146 | process.stderr.write(`Failed to start VM: ${err.message}\n`); |
| 147 | process.exit(1); |
| 148 | } |
| 149 | |
| 150 | process.stderr.write('VM Ready. Press Ctrl+D to exit.\n\n'); |
| 151 | |
| 152 | // Put stdin in raw mode for true terminal experience |
| 153 | if (process.stdin.isTTY) { |
| 154 | process.stdin.setRawMode(true); |
| 155 | } |
| 156 | process.stdin.resume(); |
| 157 |
no test coverage detected