From 18cf4243fa94ed9fdc332e94a635f74ef15672eb Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 19 Feb 2026 13:33:58 -0800 Subject: [PATCH 1/2] Build CLI binaries on-demand when requested via /dist/:file endpoint --- src/server/index.tsx | 49 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/server/index.tsx b/src/server/index.tsx index f8f40a2..8b7dfba 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -59,9 +59,49 @@ app.all('/api/tools/:tool/:path{.+}', async c => { }) }) +const CLI_ENTRY = import.meta.dir + '/../cli/index.ts' const DIST_DIR = import.meta.dir + '/../../dist' const INSTALL_SCRIPT = await Bun.file(import.meta.dir + '/install.sh').text() +interface BuildTarget { + arch: string + name: string + os: string +} + +const BUILD_TARGETS: BuildTarget[] = [ + { os: 'darwin', arch: 'arm64', name: 'toes-macos-arm64' }, + { os: 'darwin', arch: 'x64', name: 'toes-macos-x64' }, + { os: 'linux', arch: 'arm64', name: 'toes-linux-arm64' }, + { os: 'linux', arch: 'x64', name: 'toes-linux-x64' }, +] + +const buildInFlight = new Map>() + +async function buildBinary(target: BuildTarget): Promise { + const existing = buildInFlight.get(target.name) + if (existing) return existing + + const promise = (async () => { + const { existsSync, mkdirSync } = await import('fs') + if (!existsSync(DIST_DIR)) mkdirSync(DIST_DIR, { recursive: true }) + + const proc = Bun.spawn([ + 'bun', 'build', CLI_ENTRY, '--compile', + '--target', `bun-${target.os}-${target.arch}`, + '--minify', '--sourcemap=external', + '--outfile', `${DIST_DIR}/${target.name}`, + ], { stdout: 'inherit', stderr: 'inherit' }) + + const exitCode = await proc.exited + return exitCode === 0 + })() + + buildInFlight.set(target.name, promise) + promise.finally(() => buildInFlight.delete(target.name)) + return promise +} + // Install script: curl -fsSL http://toes.local/install | bash app.get('/install', c => { if (!TOES_URL) return c.text('TOES_URL is not configured', 500) @@ -69,7 +109,7 @@ app.get('/install', c => { return c.text(script, 200, { 'content-type': 'text/plain' }) }) -// Serve built CLI binaries from dist/ +// Serve built CLI binaries from dist/, building on-demand if needed app.get('/dist/:file', async c => { const file = c.req.param('file') if (!file || file.includes('/') || file.includes('..')) { @@ -77,9 +117,12 @@ app.get('/dist/:file', async c => { } const bunFile = Bun.file(`${DIST_DIR}/${file}`) if (!(await bunFile.exists())) { - return c.text(`Binary "${file}" not found — run cli:build:all on the server`, 404) + const target = BUILD_TARGETS.find(t => t.name === file) + if (!target) return c.text('Not found', 404) + const ok = await buildBinary(target) + if (!ok) return c.text(`Failed to build "${file}"`, 500) } - return new Response(bunFile, { + return new Response(Bun.file(`${DIST_DIR}/${file}`), { headers: { 'content-type': 'application/octet-stream' }, }) }) From aaf466081641417963a3241f42bf5525193e8281 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 19 Feb 2026 19:16:12 -0800 Subject: [PATCH 2/2] Delegate build logic to external script, simplify build target representation --- src/server/index.tsx | 48 ++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/server/index.tsx b/src/server/index.tsx index 8b7dfba..ce5bbcb 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -59,46 +59,33 @@ app.all('/api/tools/:tool/:path{.+}', async c => { }) }) -const CLI_ENTRY = import.meta.dir + '/../cli/index.ts' +const BUILD_SCRIPT = import.meta.dir + '/../../scripts/build.ts' const DIST_DIR = import.meta.dir + '/../../dist' const INSTALL_SCRIPT = await Bun.file(import.meta.dir + '/install.sh').text() -interface BuildTarget { - arch: string - name: string - os: string -} - -const BUILD_TARGETS: BuildTarget[] = [ - { os: 'darwin', arch: 'arm64', name: 'toes-macos-arm64' }, - { os: 'darwin', arch: 'x64', name: 'toes-macos-x64' }, - { os: 'linux', arch: 'arm64', name: 'toes-linux-arm64' }, - { os: 'linux', arch: 'x64', name: 'toes-linux-x64' }, +const BUILD_TARGETS = [ + 'toes-macos-arm64', + 'toes-macos-x64', + 'toes-linux-arm64', + 'toes-linux-x64', ] const buildInFlight = new Map>() -async function buildBinary(target: BuildTarget): Promise { - const existing = buildInFlight.get(target.name) +async function buildBinary(name: string): Promise { + const existing = buildInFlight.get(name) if (existing) return existing const promise = (async () => { - const { existsSync, mkdirSync } = await import('fs') - if (!existsSync(DIST_DIR)) mkdirSync(DIST_DIR, { recursive: true }) - - const proc = Bun.spawn([ - 'bun', 'build', CLI_ENTRY, '--compile', - '--target', `bun-${target.os}-${target.arch}`, - '--minify', '--sourcemap=external', - '--outfile', `${DIST_DIR}/${target.name}`, - ], { stdout: 'inherit', stderr: 'inherit' }) - - const exitCode = await proc.exited - return exitCode === 0 + const proc = Bun.spawn( + ['bun', 'run', BUILD_SCRIPT, `--target=${name}`], + { stdout: 'inherit', stderr: 'inherit' }, + ) + return (await proc.exited) === 0 })() - buildInFlight.set(target.name, promise) - promise.finally(() => buildInFlight.delete(target.name)) + buildInFlight.set(name, promise) + promise.finally(() => buildInFlight.delete(name)) return promise } @@ -117,9 +104,8 @@ app.get('/dist/:file', async c => { } const bunFile = Bun.file(`${DIST_DIR}/${file}`) if (!(await bunFile.exists())) { - const target = BUILD_TARGETS.find(t => t.name === file) - if (!target) return c.text('Not found', 404) - const ok = await buildBinary(target) + if (!BUILD_TARGETS.includes(file)) return c.text('Not found', 404) + const ok = await buildBinary(file) if (!ok) return c.text(`Failed to build "${file}"`, 500) } return new Response(Bun.file(`${DIST_DIR}/${file}`), {