Files
LLeMbas-CLI/scripts/build.ts
T
HomerandClaude Fable 5.1 837f38c744 Harness spec 1.1.0: one plan, prototypes and the library shared; the CLI implements it
The spec: plan_write and plan_update (new, shared, offered in every mode) and
plan_submit (now shared) keep one structured plan — findings, objectives,
phases of tasks — in place of the todo list, which lives on as a former name
of plan_write. The shared system text is one text for both projects, with
variables for what differs; the mode texts, a prototypes block and a library
block are shared. acp.md: the client hands the device what only it knows
(context, library, prototypes), the plan travels as a structure (plan_state),
library calls carry the chat's scope, and a client may rewind a session.
loop.json says its numbers as numbers. Four conformance areas: plan,
prototype, library_scope, toolcall_index.

The CLI: the plan is kept per session in the store and drawn above the prompt
and on the approval card; the prompt is assembled from the spec's texts with
their variables filled; the link reads the instance's instructions,
personalization, knowledge scope and prototype offer, sends the plan as a
structure and answers rewind; library calls to the instance carry the session
as scope; a prototype written in the terminal is saved as a file and named in
the transcript; a tool-call fragment without an index continues the last call;
the default theme is Moria; dead exports and Hermes leftovers removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-18 04:02:12 +02:00

69 lines
3.3 KiB
TypeScript

#!/usr/bin/env bun
// Builds the single-file `lembas` binary — for the host, or for another platform:
// bun run scripts/build.ts [outfile] [--target linux-arm64]
// Targets: linux-x64, linux-x64-baseline (x86-64 CPUs without AVX2), linux-arm64, and the -musl
// variants; Bun also knows darwin-* and windows-*, which LLeMbas CLI does not support yet.
// Another platform needs OpenTUI's native package for it in node_modules: Bun skips the ones for
// other machines, so fetch them with `bun install --frozen-lockfile --os=linux --cpu=arm64` (the
// lockfile already lists them; nothing in the repository changes).
import type { BunPlugin } from "bun"
import solidPlugin from "@opentui/solid/bun-plugin"
import pkg from "../package.json"
const args = process.argv.slice(2)
const at = args.indexOf("--target")
const target = at >= 0 ? args.splice(at, 2)[1] : undefined
if (target !== undefined && !/^(linux|darwin|windows)-(x64|arm64)(-musl)?(-baseline)?$/.test(target)) {
console.error(`--target ${target}: expected e.g. linux-arm64, linux-x64, linux-x64-baseline, linux-x64-musl`)
process.exit(2)
}
const outfile = args[0] ?? "dist/lembas"
// -baseline is the CPU level of Bun itself; OpenTUI's library is the same one.
const [os, arch, libc] = (target ?? `${process.platform}-${process.arch}`).replace(/-baseline$/, "").split("-")
// OpenTUI imports the native library of whichever platform it runs on, so the bundle would carry
// every variant found in node_modules. Only the target's goes in; the others stay out.
const nativeOnly: BunPlugin = {
name: "opentui-native-for-target",
setup(build) {
const want = `@opentui/core-${os === "windows" ? "win32" : os}-${arch}${libc ? `-${libc}` : ""}`
build.onResolve({ filter: /^@opentui\/core-(linux|darwin|win32)-/ }, (a) => (a.path === want || a.path === `${want}-musl` ? undefined : { path: a.path, external: true }))
void Bun.resolveSync(want, process.cwd()) // fail here, by name, when it is not installed
},
}
// A release build (HEAD exactly at the tag vX.Y.Z) reports X.Y.Z; anything else reports
// X.Y.Z+<commit>, so a tester can tell which build they have. An export without .git (a deploy
// script may build one) passes the commit in LEMBAS_BUILD.
function buildId(): string {
const given = process.env.LEMBAS_BUILD
if (given !== undefined) return given
const r = Bun.spawnSync(["git", "describe", "--tags", "--always", "--dirty"], { stdout: "pipe", stderr: "ignore" })
return r.exitCode === 0 ? r.stdout.toString().trim() : ""
}
const id = buildId()
const version = id === `v${pkg.version}` || id === "" ? pkg.version : `${pkg.version}+${id.replace(/^v[\d.]+-\d+-/, "")}`
const result = await Bun.build({
entrypoints: ["./src/cli.ts"],
tsconfig: "./tsconfig.json",
plugins: [solidPlugin, nativeOnly],
format: "esm",
minify: true,
compile: {
outfile,
...(target ? { target: `bun-${target}` as Bun.Build.CompileTarget } : {}),
autoloadBunfig: false,
autoloadDotenv: false,
// --use-system-ca: a root installed in the OS store (a private CA) is trusted, as OpenCode does.
execArgv: [`--user-agent=lembas-cli/${version}`, "--use-system-ca", "--"],
},
define: {
LEMBAS_VERSION: JSON.stringify(version),
},
})
for (const log of result.logs) console.error(log)
if (!result.success) process.exit(1)
console.log(`built ${outfile} (${version}${target ? `, ${target}` : ""})`)