File size: 5,078 Bytes
a861001 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | import { spawnSync } from "node:child_process";
import {
chmodSync,
copyFileSync,
cpSync,
mkdirSync,
rmSync,
symlinkSync,
writeFileSync,
} from "node:fs";
import { homedir } from "node:os";
import { basename, dirname, join, resolve } from "node:path";
const executableName = process.platform === "win32" ? "rsih.exe" : "rsih";
const outputDirectory = resolve("dist");
const outputPath = join(outputDirectory, executableName);
mkdirSync(outputDirectory, { recursive: true });
const build = spawnSync(
"bun",
["build", "src/cli.ts", "--compile", "--outfile", outputPath],
{
cwd: process.cwd(),
stdio: "inherit",
},
);
if (build.error?.code === "ENOENT") {
throw new Error(
"Bun is required to build the standalone binary. Install Bun or use the npm-linked CLI.",
);
}
if (build.status !== 0) {
process.exitCode = build.status ?? 1;
} else {
if (process.platform !== "win32") chmodSync(outputPath, 0o755);
copyFileSync(resolve("package.json"), join(outputDirectory, "package.json"));
copyFileSync(resolve("README.md"), join(outputDirectory, "README.md"));
// No CHANGELOG.md ships with the binary. Pi resolves the changelog next to
// the package.json it reads, so pairing Pi's release notes with RSIH's
// version makes every Pi release look unseen and replays "What's New" on
// every start; a missing file reads as no entries, which is what we want.
// Built-in Genomes. `resolveHarnessGenome` looks for `<PI_PACKAGE_DIR>/genomes`
// after the project and user directories, so `--genome paperlab` and
// `--genome harness-rsi` work from any cwd without an install step.
// Clear the target first so a Genome removed from config/genomes does not
// keep shipping from earlier builds.
rmSync(join(outputDirectory, "genomes"), { recursive: true, force: true });
cpSync(resolve("config", "genomes"), join(outputDirectory, "genomes"), {
recursive: true,
});
cpSync(
resolve(
"node_modules",
"@earendil-works",
"pi-coding-agent",
"docs",
),
join(outputDirectory, "docs"),
{ recursive: true },
);
cpSync(
resolve(
"node_modules",
"@earendil-works",
"pi-coding-agent",
"examples",
),
join(outputDirectory, "examples"),
{ recursive: true },
);
cpSync(
resolve(
"node_modules",
"@earendil-works",
"pi-coding-agent",
"dist",
"modes",
"interactive",
"theme",
),
join(outputDirectory, "theme"),
{ recursive: true },
);
cpSync(
resolve(
"node_modules",
"@earendil-works",
"pi-coding-agent",
"dist",
"modes",
"interactive",
"assets",
),
join(outputDirectory, "assets"),
{ recursive: true },
);
cpSync(
resolve(
"node_modules",
"@earendil-works",
"pi-coding-agent",
"dist",
"core",
"export-html",
),
join(outputDirectory, "export-html"),
{ recursive: true },
);
console.log(`Built ${outputPath}`);
if (process.argv.includes("--install")) install(outputPath);
}
/**
* Install the built binary together with everything it resolves relative to
* itself.
*
* The binary is not self-sufficient: `PI_PACKAGE_DIR` is the directory the
* executable sits in, and that is where it looks for package.json (the version),
* the built-in Genome seeds, themes and Pi's own assets. Copying just the
* executable onto the PATH produces an rsih that reports version 0.0.0 and
* cannot find `paperlab` or `harness-rsi` at all. So the whole payload goes to a
* library directory and only a link goes on the PATH.
*/
function install(outputPath) {
const binDirectory = resolve(
process.env.RSIH_INSTALL_DIR ?? join(homedir(), ".local", "bin"),
);
const libDirectory = resolve(
process.env.RSIH_LIB_DIR ?? join(homedir(), ".local", "lib", "rsih"),
);
const executable = basename(outputPath);
mkdirSync(libDirectory, { recursive: true });
cpSync(dirname(outputPath), libDirectory, { recursive: true, force: true });
const target = join(libDirectory, executable);
if (process.platform !== "win32") chmodSync(target, 0o755);
console.log(`Installed payload to ${libDirectory}`);
if (process.platform === "win32") {
// Symlinks need elevation on Windows, so the payload directory itself goes
// on the PATH.
console.log(`Add ${libDirectory} to your PATH.`);
return;
}
mkdirSync(binDirectory, { recursive: true });
const link = join(binDirectory, executable);
rmSync(link, { force: true });
symlinkSync(target, link);
console.log(`Linked ${link}`);
// `gee` is `rsih --genome harness-rsi`. It cannot be a link, because the
// binary would have no way to know which name invoked it.
const gee = join(binDirectory, "gee");
rmSync(gee, { force: true });
writeFileSync(
gee,
`#!/bin/sh\n# Generated by rsih. Equivalent to: rsih --genome harness-rsi\nexec ${JSON.stringify(link)} --genome harness-rsi "$@"\n`,
"utf8",
);
chmodSync(gee, 0o755);
console.log(`Wrote ${gee}`);
}
|