From 2977ab369efa35b1bfc9b12daa59ab09ab8e1158 Mon Sep 17 00:00:00 2001 From: hzhang Date: Fri, 29 May 2026 08:52:14 +0100 Subject: [PATCH] refactor(install): clone HarborForge.Cli to /tmp instead of fixed path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `installCli()` used to look for the CLI source at a fixed path relative to the plugin checkout: either `./HarborForge.Cli` or `../HarborForge.Cli`. That breaks any install layout where the plugin lives on its own — the script just logs "Skipping CLI installation" and returns. Same anti- pattern installManagedMonitor had already fixed for the monitor binary. Mirror the monitor flow: 1. git clone --depth 1 --branch CLI_REPO_URL → /tmp/ 2. go build -ldflags Version=+- -o $openclaw/bin/hf 3. chmod 755 + delete tmp dir on success or failure Adds `--cli-branch ` (default: main) for parity with --monitor-branch. Also stamps the binary with a real version string (was 'dev' before this patch) so `hf version` is informative for debugging. --- scripts/install.mjs | 58 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 25 deletions(-) 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 }); } } -- 2.49.1