| import { resolve } from 'node:path'; |
| import { readFileSync } from 'node:fs'; |
| import { createHash } from 'node:crypto'; |
|
|
| |
| |
| export function piBrowser() { |
| const sourceRoot = resolve('vendor/pi-coding-agent'); |
| const provenance = JSON.parse(readFileSync(resolve(sourceRoot, 'provenance.json'), 'utf8')); |
| for (const [file, expected] of Object.entries(provenance.files)) { |
| const actual = createHash('sha256').update(readFileSync(resolve(sourceRoot, file))).digest('hex'); |
| if (actual !== expected) throw Error(`Vendored Pi component differs from its upstream checksum: ${file}`); |
| } |
| const host = resolve('src/pi/browser-host.mjs'); |
| return { |
| name: 'pi-browser-host', enforce: 'pre', |
| resolveId(source, importer = '') { |
| if (source === '@earendil-works/pi-tui') return resolve('src/pi/entry.mjs'); |
| if (importer.includes('/@earendil-works/pi-tui/')) { |
| if (source.endsWith('/terminal-image.js')) return resolve('src/pi/capabilities.mjs'); |
| if (source === 'node:perf_hooks') return host; |
| } |
| if (importer.includes('/vendor/pi-coding-agent/') && source === '../theme/theme.js') return resolve('src/pi/theme.mjs'); |
| }, |
| transform(code, id) { |
| if (!id.includes('/@earendil-works/pi-tui/') || !id.split('?')[0].endsWith('.js')) return; |
| |
| |
| let adapted = code.replace(/\.unref\(\)/g, '.unref?.()'); |
| if (/\b(?:process|Buffer)\./.test(code)) adapted = `import { browserProcess as process, Buffer } from ${JSON.stringify(host)};\n${adapted}`; |
| if (adapted !== code) return { code: adapted, map: null }; |
| }, |
| }; |
| } |
|
|