Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ jobs:
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="$GITHUB_REF_NAME"; else VERSION="dev-${GITHUB_SHA:0:12}"; fi
mkdir -p bin
go build -trimpath -ldflags "-X main.version=${VERSION}" -o "bin/lem${EXE}" ./cli
# main.backend is "cpu" for every cell this job builds (the other backends —
# metal, amd, cuda — are built by their own dedicated jobs/CI); lem's
# self-update asset-selection reads it to pick its own release asset.
go build -trimpath -ldflags "-X main.version=${VERSION} -X main.backend=cpu" -o "bin/lem${EXE}" ./cli
test -s "bin/lem${EXE}"

- uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -110,7 +113,12 @@ jobs:
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="$GITHUB_REF_NAME"; else VERSION="dev-${GITHUB_SHA:0:12}"; fi
task metallib
task build:embed VERSION="${VERSION}"
# GO_VERSION_LDFLAGS is Taskfile.yml's own var, threaded into build:embed's
# -ldflags; overriding it here on the CLI (Task's documented per-invocation
# override, e.g. the Taskfile's own "task build VERSION=1.2.3" example) folds
# in main.backend=metal without touching Taskfile.yml, whose ldflags string
# otherwise only knows about main.version.
task build:embed VERSION="${VERSION}" GO_VERSION_LDFLAGS="-X main.version=${VERSION} -X main.backend=metal"
test -s bin/lem

- uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -161,7 +169,16 @@ jobs:
echo "version=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
echo "tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
echo "name=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
echo "prerelease=false" >> "$GITHUB_OUTPUT"
# A tag containing '-' (v1.2.3-beta.1, v1.2.3-alpha.2, even a bare
# v2.0.0-rc.1) is a semver prerelease — publish it as a GitHub
# prerelease so go-update's channel filter (alpha/beta substring,
# else the prerelease flag) classifies it correctly instead of
# every tag looking "stable".
if [[ "$GITHUB_REF_NAME" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi
else
echo "version=dev-${GITHUB_SHA:0:12}" >> "$GITHUB_OUTPUT"
echo "tag=dev" >> "$GITHUB_OUTPUT"
Expand Down
1 change: 1 addition & 0 deletions cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ require (
dappco.re/go/i18n v0.12.1 // indirect
dappco.re/go/log v0.13.1 // indirect
dappco.re/go/ratelimit v0.12.1 // indirect
dappco.re/go/update v0.13.0
forge.lthn.ai/Snider/Enchantrix v0.0.5 // indirect
github.com/99designs/gqlgen v0.17.88 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions cli/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ dappco.re/go/ratelimit v0.12.1 h1:3NTFrsNGfuyZYWsKXTOyJbKSZiN2f6/9abeAbvaRV7w=
dappco.re/go/ratelimit v0.12.1/go.mod h1:5Vdbbyyh99N3tMMqYVbTj8/Bg/jg3f31fscWsAKonuk=
dappco.re/go/store v0.14.1 h1:om6d865punooegHQFZ6tnZoFOp/Ec0xh0iW/kKx/pWc=
dappco.re/go/store v0.14.1/go.mod h1:ys8oTbYaB5wgxWQXcI48b0Mjm0aOld9PGJnqlU7vNs0=
dappco.re/go/update v0.13.0 h1:vIDjSCeLXC8EFmYFnOa7JURrrebet0GAz0rbfXoyLz0=
dappco.re/go/update v0.13.0/go.mod h1:nXfDo7mOC+FgqI3QIPjGhq7IRktc9X5FBVOlgOXdQUg=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
forge.lthn.ai/Snider/Borg v0.3.1 h1:gfC1ZTpLoZai07oOWJiVeQ8+qJYK8A795tgVGJHbVL8=
Expand Down
11 changes: 11 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ var commandName = "lem"
// an unstamped build reports "dev".
var version = "dev"

// backend is stamped by the build (-ldflags "-X main.backend=<cpu|metal|amd|cuda>"),
// naming the GPU backend this binary was compiled for (docs/release-artifacts.md's
// {os}-{arch}-lem-{backend}-... grid). It has no locally meaningful default: `lem
// update`'s asset-selection needs the real value to find this platform's release
// asset, so an unstamped build reports "" and fails loudly there rather than
// silently guessing a backend.
var backend = ""

func cliName() string {
name := core.Trim(commandName)
if name == "" {
Expand Down Expand Up @@ -92,6 +100,8 @@ func runCommand(ctx context.Context, args []string, stdout, stderr io.Writer) in
return runSpecCommand(ctx, args[1:], stdout, stderr)
case "ebook":
return runEbookCommand(ctx, args[1:], stdout, stderr)
case "update":
return runUpdateCommand(ctx, args[1:], stdout, stderr)
case "tui":
return tui.Run(ctx, args[1:], stdout, stderr)
case "version", "-v", "--version":
Expand Down Expand Up @@ -127,6 +137,7 @@ func printUsage(w io.Writer) {
core.WriteString(w, " pack build/inspect/list/extract .model containers (no weights loaded)\n")
core.WriteString(w, " ebook render a model directory as a valid EPUB3 (weights as base64 plates)\n")
core.WriteString(w, " version print the binary name and stamped version\n")
core.WriteString(w, " update self-update from GitHub releases (channel derived from the stamped version)\n")
core.WriteString(w, "\n")
core.WriteString(w, "Convert\n")
core.WriteString(w, " quant quantise a dense model dir (MLX, GPTQ, FP8, NF4, or GGUF)\n")
Expand Down
4 changes: 3 additions & 1 deletion cli/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestRunCommand_Dispatch(t *testing.T) {
{"data route", []string{"data"}, 2, false},
{"ebook route", []string{"ebook"}, 2, false},
{"spec route", []string{"spec", "--output", specOut}, 0, false},
{"update route", []string{"update", "--help"}, 0, false},
{"version route", []string{"version"}, 0, false},
{"version flag", []string{"--version"}, 0, false},
} {
Expand Down Expand Up @@ -91,6 +92,7 @@ func TestHelpPresentsLongFlagsOnly(t *testing.T) {
{"data", "review", "--help"},
{"spec", "--help"},
{"ebook", "--help"},
{"update", "--help"},
{"tui", "--help"},
} {
t.Run(strings.Join(argv, "_"), func(t *testing.T) {
Expand All @@ -115,7 +117,7 @@ func TestPrintUsage(t *testing.T) {
var buf bytes.Buffer
printUsage(&buf)
out := buf.String()
for _, verb := range []string{"serve", "generate", "ssd", "sft", "tune", "pack", "ebook", "quant", "data", "spec"} {
for _, verb := range []string{"serve", "generate", "ssd", "sft", "tune", "pack", "ebook", "quant", "data", "spec", "update"} {
if !core.Contains(out, verb) {
t.Errorf("usage missing verb %q", verb)
}
Expand Down
Loading
Loading