diff --git a/scripts/install.mjs b/scripts/install.mjs index 54c66e7..978adf2 100644 --- a/scripts/install.mjs +++ b/scripts/install.mjs @@ -31,6 +31,7 @@ const OLD_PLUGIN_NAME = 'harborforge-monitor'; const PLUGIN_SRC_DIR = join(__dirname, 'plugin'); const SKILLS_SRC_DIR = join(__dirname, 'skills'); const MONITOR_REPO_URL = 'https://git.hangman-lab.top/zhi/HarborForge.Monitor.git'; +const CLI_REPO_URL = 'https://git.hangman-lab.top/zhi/HarborForge.Cli.git'; const args = process.argv.slice(2); const options = { @@ -43,6 +44,7 @@ const options = { installCli: args.includes('--install-cli'), installMonitor: 'no', monitorBranch: 'main', + cliBranch: 'main', }; const profileIdx = args.indexOf('--openclaw-profile-path'); @@ -60,6 +62,11 @@ if (monitorBranchIdx !== -1 && args[monitorBranchIdx + 1]) { options.monitorBranch = String(args[monitorBranchIdx + 1]); } +const cliBranchIdx = args.indexOf('--cli-branch'); +if (cliBranchIdx !== -1 && args[cliBranchIdx + 1]) { + options.cliBranch = String(args[cliBranchIdx + 1]); +} + function resolveOpenclawPath() { if (options.openclawProfilePath) return options.openclawProfilePath; if (process.env.OPENCLAW_PATH) return resolve(process.env.OPENCLAW_PATH); @@ -316,39 +323,40 @@ async function installCli() { if (!options.installCli) return; const totalSteps = 6; logStep(5, totalSteps, 'Building and installing hf CLI...'); - + const openclawPath = resolveOpenclawPath(); const binDir = join(openclawPath, 'bin'); mkdirSync(binDir, { recursive: true }); - - // Find CLI source — look for HarborForge.Cli relative to project root - const projectRoot = resolve(__dirname, '..'); - const cliDir = join(projectRoot, 'HarborForge.Cli'); - - if (!existsSync(cliDir)) { - // Try parent directory (monorepo layout) - const monoCliDir = resolve(projectRoot, '..', 'HarborForge.Cli'); - if (!existsSync(monoCliDir)) { - logErr(`Cannot find HarborForge.Cli at ${cliDir} or ${monoCliDir}`); - logWarn('Skipping CLI installation'); - return; - } - } - - const effectiveCliDir = existsSync(cliDir) - ? cliDir - : resolve(projectRoot, '..', 'HarborForge.Cli'); - - log(` Building hf from ${effectiveCliDir}...`, 'blue'); - + + // Clone CLI repo to /tmp, build there, copy artifact out. Mirrors + // installManagedMonitor so the install never depends on a checked-out + // sibling repo at a fixed path. + const tmpDir = join('/tmp', `harborforge-cli-${Date.now()}`); + const hfBinary = join(binDir, 'hf'); + try { - const hfBinary = join(binDir, 'hf'); - exec(`go build -o ${hfBinary} ./cmd/hf`, { cwd: effectiveCliDir, silent: !options.verbose }); + log(` Cloning ${CLI_REPO_URL} (branch ${options.cliBranch}) → ${tmpDir}...`, 'blue'); + exec(`git clone --branch ${shellEscape(options.cliBranch)} --depth 1 ${shellEscape(CLI_REPO_URL)} ${shellEscape(tmpDir)}`, { silent: !options.verbose }); + + // Stamp the binary with the version string the prod CLI surfaces in + // `hf version`. Fall back to a date-only label if rev-parse fails for + // any reason (shallow clone shouldn't, but be defensive). + let versionLabel = `${new Date().toISOString().slice(0, 10)}+install`; + try { + const sha = exec(`git rev-parse --short HEAD`, { cwd: tmpDir, silent: true }).trim(); + if (sha) versionLabel = `${new Date().toISOString().slice(0, 10)}+${options.cliBranch}-${sha}`; + } catch { /* keep fallback */ } + + log(` Building hf (version=${versionLabel})...`, 'blue'); + const ldflags = `-X git.hangman-lab.top/zhi/HarborForge.Cli/internal/commands.Version=${versionLabel}`; + exec(`go build -ldflags ${shellEscape(ldflags)} -o ${shellEscape(hfBinary)} ./cmd/hf`, { cwd: tmpDir, silent: !options.verbose }); chmodSync(hfBinary, 0o755); - logOk(`hf binary → ${hfBinary}`); + logOk(`hf binary → ${hfBinary} (branch hint: ${options.cliBranch})`); } catch (err) { logErr(`Failed to build hf CLI: ${err.message}`); logWarn('CLI installation failed, plugin still installed'); + } finally { + rmSync(tmpDir, { recursive: true, force: true }); } }