@@ -5,12 +5,15 @@ import {
55 chmodSync ,
66 existsSync ,
77 mkdirSync ,
8+ mkdtempSync ,
89 readdirSync ,
910 readFileSync ,
11+ rmSync ,
1012 writeFileSync ,
1113} from 'fs'
1214import { dirname , join } from 'path'
1315import { fileURLToPath } from 'url'
16+ import { tmpdir } from 'os'
1417
1518type TargetInfo = {
1619 bunTarget : string
@@ -28,6 +31,7 @@ const OVERRIDE_ARCH = process.env.OVERRIDE_ARCH ?? undefined
2831const __filename = fileURLToPath ( import . meta. url )
2932const __dirname = dirname ( __filename )
3033const cliRoot = join ( __dirname , '..' )
34+ const repoRoot = dirname ( cliRoot )
3135
3236function log ( message : string ) {
3337 if ( VERBOSE ) {
@@ -128,6 +132,7 @@ async function main() {
128132 runCommand ( 'bun' , [ 'run' , 'build:sdk' ] , { cwd : cliRoot } )
129133
130134 patchOpenTuiAssetPaths ( )
135+ await ensureOpenTuiNativeBundle ( targetInfo )
131136
132137 const outputFilename =
133138 targetInfo . platform === 'win32' ? `${ binaryName } .exe` : binaryName
@@ -210,3 +215,103 @@ function patchOpenTuiAssetPaths() {
210215 writeFileSync ( indexPath , patched )
211216 logAlways ( 'Patched OpenTUI core tree-sitter asset paths' )
212217}
218+
219+ async function ensureOpenTuiNativeBundle ( targetInfo : TargetInfo ) {
220+ const packageName = `@opentui/core-${ targetInfo . platform } -${ targetInfo . arch } `
221+ const packageFolder = `core-${ targetInfo . platform } -${ targetInfo . arch } `
222+ const installTargets = [
223+ {
224+ label : 'workspace root' ,
225+ packagesDir : join ( repoRoot , 'node_modules' , '@opentui' ) ,
226+ packageDir : join ( repoRoot , 'node_modules' , '@opentui' , packageFolder ) ,
227+ } ,
228+ {
229+ label : 'CLI workspace' ,
230+ packagesDir : join ( cliRoot , 'node_modules' , '@opentui' ) ,
231+ packageDir : join ( cliRoot , 'node_modules' , '@opentui' , packageFolder ) ,
232+ } ,
233+ ]
234+
235+ const missingTargets = installTargets . filter ( ( { packageDir } ) => ! existsSync ( packageDir ) )
236+ if ( missingTargets . length === 0 ) {
237+ log ( `OpenTUI native bundle already present for ${ targetInfo . platform } -${ targetInfo . arch } ` )
238+ return
239+ }
240+
241+ const corePackagePath =
242+ installTargets
243+ . map ( ( { packagesDir } ) => join ( packagesDir , 'core' , 'package.json' ) )
244+ . find ( ( candidate ) => existsSync ( candidate ) ) ?? null
245+
246+ if ( ! corePackagePath ) {
247+ log ( 'OpenTUI core package metadata missing; skipping native bundle fetch' )
248+ return
249+ }
250+ const corePackageJson = JSON . parse ( readFileSync ( corePackagePath , 'utf8' ) ) as {
251+ optionalDependencies ?: Record < string , string >
252+ }
253+ const version = corePackageJson . optionalDependencies ?. [ packageName ]
254+ if ( ! version ) {
255+ log ( `No optional dependency declared for ${ packageName } ; skipping native bundle fetch` )
256+ return
257+ }
258+
259+ const registryBase =
260+ process . env . CODEBUFF_NPM_REGISTRY ??
261+ process . env . NPM_REGISTRY_URL ??
262+ 'https://registry.npmjs.org'
263+ const metadataUrl = `${ registryBase . replace ( / \/ $ / , '' ) } /${ encodeURIComponent ( packageName ) } `
264+ log ( `Fetching OpenTUI native bundle metadata from ${ metadataUrl } ` )
265+
266+ const metadataResponse = await fetch ( metadataUrl )
267+ if ( ! metadataResponse . ok ) {
268+ throw new Error (
269+ `Failed to fetch metadata for ${ packageName } : ${ metadataResponse . status } ${ metadataResponse . statusText } ` ,
270+ )
271+ }
272+
273+ const metadata = ( await metadataResponse . json ( ) ) as {
274+ versions ?: Record <
275+ string ,
276+ {
277+ dist ?: {
278+ tarball ?: string
279+ }
280+ }
281+ >
282+ }
283+ const tarballUrl = metadata . versions ?. [ version ] ?. dist ?. tarball
284+ if ( ! tarballUrl ) {
285+ throw new Error ( `Tarball URL missing for ${ packageName } @${ version } ` )
286+ }
287+
288+ log ( `Downloading OpenTUI native bundle from ${ tarballUrl } ` )
289+ const tarballResponse = await fetch ( tarballUrl )
290+ if ( ! tarballResponse . ok ) {
291+ throw new Error (
292+ `Failed to download ${ packageName } @${ version } : ${ tarballResponse . status } ${ tarballResponse . statusText } ` ,
293+ )
294+ }
295+
296+ const tempDir = mkdtempSync ( join ( tmpdir ( ) , 'opentui-' ) )
297+ try {
298+ const tarballPath = join (
299+ tempDir ,
300+ `${ packageName . split ( '/' ) . pop ( ) ?? 'package' } -${ version } .tgz` ,
301+ )
302+ await Bun . write ( tarballPath , await tarballResponse . arrayBuffer ( ) )
303+
304+ for ( const target of missingTargets ) {
305+ mkdirSync ( target . packagesDir , { recursive : true } )
306+ mkdirSync ( target . packageDir , { recursive : true } )
307+
308+ runCommand ( 'tar' , [ '-xzf' , tarballPath , '--strip-components=1' , '-C' , target . packageDir ] )
309+ log (
310+ `Installed OpenTUI native bundle for ${ targetInfo . platform } -${ targetInfo . arch } in ${ target . label } ` ,
311+ )
312+ }
313+ logAlways ( `Fetched OpenTUI native bundle for ${ targetInfo . platform } -${ targetInfo . arch } ` )
314+ } finally {
315+ rmSync ( tempDir , { recursive : true , force : true } )
316+ }
317+ }
0 commit comments