#!/usr/bin/env node // menu.js — npu-forge front door (start.bat runs this). 'use strict'; const readline = require('readline'); const path = require('path'); const { spawnSync, spawn } = require('child_process'); const FORGE = path.join(__dirname, '..'); const ENV = { ...process.env, PYTHONIOENCODING: 'utf-8' }; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const pending = [], waiting = []; let closed = false; rl.on('line', l => { const w = waiting.shift(); if (w) w(l); else pending.push(l); }); rl.on('close', () => { closed = true; while (waiting.length) waiting.shift()(null); }); const ask = q => { process.stdout.write(q); return new Promise(r => { const b = pending.shift(); if (b !== undefined) { console.log(b); r(b); } else if (closed) r(null); else waiting.push(r); }); }; function forge(args) { rl.pause(); spawnSync('node', [path.join(FORGE, 'forge.js'), ...args], { stdio: 'inherit', env: ENV, shell: true }); rl.resume(); } (async () => { while (true) { console.log('\n=============================================='); console.log(' NPU-FORGE — your models, on your NPU'); console.log('=============================================='); console.log(' 1. doctor — NPU / driver / registry health'); console.log(' 2. list — models + your forge customs'); console.log(' 3. register — activate customs (UAC, one click)'); console.log(' 4. serve — start an NPU server'); console.log(' t. tune — how to fine-tune your own (guide)'); console.log(' q. quit'); const pick = ((await ask('\nPick: ')) || '').trim().toLowerCase(); if (pick === null || pick === 'q' || pick === '') break; if (pick === '1') forge(['doctor']); else if (pick === '2') forge(['list']); else if (pick === '3') { spawn('cmd', ['/c', 'start', '', path.join(FORGE, 'register-admin.bat')], { detached: true }); console.log('(UAC window launched — click Yes; results land in register-cmd-log.txt)'); } else if (pick.startsWith('4')) { const tag = pick.split(/\s+/)[1] || (await ask('model tag (e.g. llama3.2:1b): ')) || ''; if (tag.trim()) { console.log('(Ctrl+C stops the server and returns here)'); forge(['serve', tag.trim()]); } } else if (pick === 't') { console.log('\nFine-tune your own voice onto the NPU (needs a free modal.com account):'); console.log(' 1. Make chats.jsonl — one line per exchange:'); console.log(' {"messages":[{"role":"user","content":"..."},{"role":"assistant","content":"..."}]}'); console.log(' 2. node forge.js tune chats.jsonl --name myvoice'); console.log(' 3. node forge.js register (one UAC click)'); console.log(' 4. flm run myvoice-forge:1b — your voice, on your NPU.'); console.log(' (~3 minutes and ~$0.10 of cloud time for a 1B; see README.md)'); } } rl.close(); })();