import test from 'brittle' import fs from 'fs' import os from 'os' import path from 'path' import { bareOsQvacModelsGuestPath, bareOsQvacModelsHostPath, bareOsQvacModelsStripHashPrefix, bareOsQvacHostGgufMatchesSize, bareOsQvacPrepareHostCacheConfig, bareOsQvacIsHostJsonConfigPath, bareOsQvacTryReadHostJsonConfig, bareOsQvacMaterializeGgufToHost, bareOsQvacMirrorHostGgufToHdms, bareOsQvacListHdmsGgufs, bareOsQvacFindHdmsGguf, BARE_OS_QVAC_MODELS_GUEST_ROOT } from './lib/services/bare-os-qvac-models-store.mjs' test('guest/host path + hash prefix mapping', async (t) => { t.is( bareOsQvacModelsGuestPath('5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf'), BARE_OS_QVAC_MODELS_GUEST_ROOT + '/5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf' ) t.is( bareOsQvacModelsStripHashPrefix('5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf'), 'Qwen3-0.6B-Q4_0.gguf' ) t.is( bareOsQvacModelsStripHashPrefix('Qwen3-0.6B-Q4_0.gguf'), 'Qwen3-0.6B-Q4_0.gguf' ) const host = bareOsQvacModelsHostPath('a.gguf', '/tmp/qvac-cache') t.is(host, path.join('/tmp/qvac-cache', 'a.gguf')) }) test('skip materialize when host size matches', async (t) => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-qvac-models-')) const hostPath = path.join(dir, 'model.gguf') const payload = Buffer.from('GGUF-fake-payload-0123456789') fs.writeFileSync(hostPath, payload) t.ok(bareOsQvacHostGgufMatchesSize(hostPath, payload.byteLength)) t.absent(bareOsQvacHostGgufMatchesSize(hostPath, payload.byteLength + 1)) /** @type {Record} */ const files = { [BARE_OS_QVAC_MODELS_GUEST_ROOT + '/model.gguf']: payload } const vfs = { async stat(p) { const b = files[p] if (!b) throw new Error('ENOENT') return { size: b.byteLength } }, async readFile(p) { const b = files[p] if (!b) throw new Error('ENOENT') return b }, async writeFile() { throw new Error('should not write') }, async readdir() { return ['model.gguf'] } } const r = await bareOsQvacMaterializeGgufToHost({ vfs, guestPath: BARE_OS_QVAC_MODELS_GUEST_ROOT + '/model.gguf', hostPath, guestSize: payload.byteLength }) t.ok(r.ok) t.ok(r.skipped) t.is(r.reason, 'size_match') fs.rmSync(dir, { recursive: true, force: true }) }) test('materialize + mirror round-trip via fake vfs', async (t) => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-qvac-models-')) const hostPath = path.join(dir, 'hash_demo.gguf') const payload = Buffer.from('GGUF-roundtrip-bytes') /** @type {Record} */ const files = { [BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf']: payload } const vfs = { async stat(p) { const b = files[p] if (!b) throw new Error('ENOENT') return { size: b.byteLength } }, async readFile(p) { const b = files[p] if (!b) throw new Error('ENOENT') return b }, async writeFile(p, buf) { files[p] = Buffer.from(buf) }, async readdir() { return Object.keys(files).map((p) => path.basename(p)) } } const mat = await bareOsQvacMaterializeGgufToHost({ vfs, guestPath: BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf', hostPath }) t.ok(mat.ok) t.absent(mat.skipped) t.is(fs.readFileSync(hostPath).equals(payload), true) // Change host and mirror back const next = Buffer.from('GGUF-roundtrip-bytes-UPDATED') fs.writeFileSync(hostPath, next) const mir = await bareOsQvacMirrorHostGgufToHdms({ vfs, hostPath, guestName: 'hash_demo.gguf' }) t.ok(mir.ok) t.absent(mir.skipped) t.ok( files[BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf'].equals(next) ) const names = await bareOsQvacListHdmsGgufs(vfs) t.ok(names.includes('hash_demo.gguf')) const found = await bareOsQvacFindHdmsGguf(vfs, 'hash_demo.gguf') t.is(found, BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf') fs.rmSync(dir, { recursive: true, force: true }) }) test('prepareHostCacheConfig writes absolute cacheDirectory', async (t) => { const prev = process.env.BARE_OS_HOST_DATA const prevCfg = process.env.QVAC_CONFIG_PATH const prevRequire = globalThis.require const root = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-host-data-')) process.env.BARE_OS_HOST_DATA = root try { delete globalThis.require const cacheDir = path.join(root, 'qvac', 'models') const prepared = bareOsQvacPrepareHostCacheConfig({ cacheDir }) t.is(prepared.cacheDir, cacheDir) t.ok(fs.existsSync(prepared.configPath)) const body = JSON.parse(fs.readFileSync(prepared.configPath, 'utf8')) t.is(body.cacheDirectory, cacheDir) t.is(body.loggerLevel, 'error') t.is(body.loggerConsoleOutput, true) t.is(process.env.QVAC_CONFIG_PATH, prepared.configPath) t.is(typeof globalThis.require, 'function') const viaRequire = globalThis.require(prepared.configPath) t.is(viaRequire.cacheDirectory, cacheDir) } finally { if (prevRequire === undefined) delete globalThis.require else globalThis.require = prevRequire if (prev === undefined) delete process.env.BARE_OS_HOST_DATA else process.env.BARE_OS_HOST_DATA = prev if (prevCfg === undefined) delete process.env.QVAC_CONFIG_PATH else process.env.QVAC_CONFIG_PATH = prevCfg fs.rmSync(root, { recursive: true, force: true }) } }) test('config require shim wraps existing Bare require for host JSON', async (t) => { const prev = process.env.BARE_OS_HOST_DATA const prevCfg = process.env.QVAC_CONFIG_PATH const prevRequire = globalThis.require const root = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-host-data-')) process.env.BARE_OS_HOST_DATA = root /** @type {string[]} */ const delegated = [] function existingRequire(id) { delegated.push(String(id)) if (id === 'events') return { EventEmitter: function EventEmitter() {} } const err = new Error( "MODULE_NOT_FOUND: Cannot find module '" + id + "' imported from 'bare:/app.bundle/packages/bare-os-booter/lib/ctx/bare-os-ctx-bare.js'" ) err.code = 'MODULE_NOT_FOUND' throw err } existingRequire.addon = function addon() { return {} } existingRequire.resolve = function resolve() { return 'ok' } try { globalThis.require = existingRequire const cacheDir = path.join(root, 'qvac', 'models') const prepared = bareOsQvacPrepareHostCacheConfig({ cacheDir }) t.ok(globalThis.require.__bareOsQvacConfigRequire) t.is(typeof globalThis.require.addon, 'function') t.is(globalThis.require.resolve(), 'ok') const viaRequire = globalThis.require(prepared.configPath) t.is(viaRequire.cacheDirectory, cacheDir) t.ok(!delegated.includes(prepared.configPath)) const ev = globalThis.require('events') t.is(typeof ev.EventEmitter, 'function') t.ok(delegated.includes('events')) } finally { if (prevRequire === undefined) delete globalThis.require else globalThis.require = prevRequire if (prev === undefined) delete process.env.BARE_OS_HOST_DATA else process.env.BARE_OS_HOST_DATA = prev if (prevCfg === undefined) delete process.env.QVAC_CONFIG_PATH else process.env.QVAC_CONFIG_PATH = prevCfg fs.rmSync(root, { recursive: true, force: true }) } }) test('host JSON config path accepts POSIX and Windows, rejects URLs', async (t) => { t.ok(bareOsQvacIsHostJsonConfigPath('/home/raven/.bare-os/qvac/qvac.config.json')) t.ok(bareOsQvacIsHostJsonConfigPath('C:\\Users\\raven\\.bare-os\\qvac\\qvac.config.json')) t.ok(bareOsQvacIsHostJsonConfigPath('C:/Users/raven/.bare-os/qvac/qvac.config.json')) t.absent(bareOsQvacIsHostJsonConfigPath('bare:/home/raven/.bare-os/qvac/qvac.config.json')) t.absent(bareOsQvacIsHostJsonConfigPath('file:///home/raven/.bare-os/qvac/qvac.config.json')) t.absent(bareOsQvacIsHostJsonConfigPath('qvac.config.js')) t.absent(bareOsQvacIsHostJsonConfigPath('relative/qvac.config.json')) const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-qvac-cfg-')) const cfg = path.join(dir, 'qvac.config.json') fs.writeFileSync(cfg, JSON.stringify({ cacheDirectory: '/tmp/models' })) t.is(bareOsQvacTryReadHostJsonConfig(cfg).cacheDirectory, '/tmp/models') t.is(bareOsQvacTryReadHostJsonConfig('bare:' + cfg), undefined) fs.rmSync(dir, { recursive: true, force: true }) })