feat(cli): add Bun single executable binary support

Enables building hapi as standalone Bun-compiled executables for macOS,
Linux, and Windows (x64/arm64). Adds build script, bootstrap entry point,
runtime asset management, and automatic deployment of bundled tools
(ripgrep, difftastic). Includes MCP stdio bridge support and proper
environment handling for compiled binaries. Updates documentation with
build and installation instructions for single executable distribution.
This commit is contained in:
weishu
2025-12-20 21:41:11 +08:00
parent bf18224d05
commit 17eeba10d6
28 changed files with 605 additions and 238 deletions
+3 -1
View File
@@ -21,10 +21,12 @@ export async function findAllHappyProcesses(): Promise<Array<{ pid: number, comm
const name = proc.name || '';
// Check if it's a Happy process
const isHappyBinary = name === 'hapi' || name === 'hapi.exe' || /\bhapi(\.exe)?\b/.test(cmd);
const isHappy = name.includes('happy') ||
name === 'node' && (cmd.includes('happy-cli') || cmd.includes('dist/index.mjs')) ||
cmd.includes('happy.mjs') ||
cmd.includes('happy-coder') ||
isHappyBinary ||
(cmd.includes('tsx') && cmd.includes('src/index.ts') && cmd.includes('happy-cli'));
if (!isHappy) continue;
@@ -120,4 +122,4 @@ export async function killRunawayHappyProcesses(): Promise<{ killed: number, err
}
return { killed, errors };
}
}
+3 -4
View File
@@ -1,6 +1,5 @@
import fs from 'fs/promises';
import os from 'os';
import * as tmp from 'tmp';
import { ApiClient } from '@/api/api';
import { TrackedSession } from './types';
@@ -233,14 +232,14 @@ export async function startDaemon(): Promise<void> {
if (options.agent === 'codex') {
// Create a temporary directory for Codex
const codexHomeDir = tmp.dirSync();
const codexHomeDir = await fs.mkdtemp(join(os.tmpdir(), 'hapi-codex-'));
// Write the token to the temporary directory
fs.writeFile(join(codexHomeDir.name, 'auth.json'), options.token);
await fs.writeFile(join(codexHomeDir, 'auth.json'), options.token);
// Set the environment variable for Codex
extraEnv = {
CODEX_HOME: codexHomeDir.name
CODEX_HOME: codexHomeDir
};
} else { // Assuming claude
extraEnv = {