Skip to content

Rename binary to lc, fix the Burrito CLI entry point, ship wrapper scripts + local install - #6

Merged
bougyman merged 6 commits into
mainfrom
issue-5
Aug 9, 2026
Merged

Rename binary to lc, fix the Burrito CLI entry point, ship wrapper scripts + local install#6
bougyman merged 6 commits into
mainfrom
issue-5

Conversation

@bougyman

@bougyman bougyman commented Aug 9, 2026

Copy link
Copy Markdown
Member

Summary

Closes #5.

  • Renames the escript/release binary from linear_cli to lc, so the existing bash wrapper scripts (lcreate, lcls, lclose, lcomment, lproj, ported verbatim from vendor/ruby-linear-cli/exe/scripts/) work as-is with no separate aliasing mechanism.
  • Fixes a real bug: the Burrito-wrapped lc binary never actually invoked LinearCli.CLI.main/2 - it boots via -s elixir start_cli, which only recognizes Elixir's own --help/--version flags and otherwise tries to run its first argument as a script file (lc issue list failed with "No file named issue"). Wired CLI.main/2 into Application.start/2 for the standalone-Burrito case, verified against both the native macOS binary and the Linux container image.
  • Fixes two related CLI bugs found along the way: a bare lc invocation crashing with a MatchError (Optimus returns a different shape when no subcommand matches at all), and --help breaking when flags precede it (e.g. lc issue update --close --help, real usage from bin/lclose).
  • Wires the wrapper scripts into the container image (/usr/local/bin/, so exec lc ... resolves via PATH) and adds bash to the Alpine image (bin/lclose needs it).
  • Pins mise.toml to the exact OTP/Elixir version CI uses - Burrito's precompiled-ERTS catalog lags "latest", so floating broke local mix release builds while CI stayed fine.
  • Adds install.sh/uninstall.sh as a local, brew-less install path (builds a native release via mise, installs onto a directory already on $PATH, tracks exactly what it installed via a manifest so uninstall is precise). A Homebrew tap is planned as a follow-up once a real release exists to pin a sha256 against.

Test plan

  • mix test - 175 passed
  • mix format --check-formatted - clean
  • Built the real Linux x86_64 Burrito binary and the container image; verified lc --version, lc whoami --help, and lc issue list (fails cleanly on missing API key, not a boot crash) all reach real CLI logic inside the container
  • Verified all 5 wrapper scripts resolve lc via PATH inside the container
  • Verified the daemon boot path (LINEAR_CLI_DAEMON=true, no args) still boots and stays alive, unaffected by the fix
  • Built the native macOS aarch64 binary directly (no container) and confirmed the same behavior
  • Ran install.sh/uninstall.sh end-to-end in an isolated scratch dir - install, manifest, uninstall all verified

🤖 Generated with Claude Code

`Optimus.parse!/3` returns a bare %Optimus.ParseResult{} (not the usual
{subcommand_path, parse_result} tuple) when no subcommand token is given
at all - a bare `lc` invocation crashed on that with a MatchError. Also
default a bare invocation to `issue list`, matching lc.sh's own behavior,
and fix `--help` breaking when flags come before it (e.g. `lc issue
update --close --help`, real usage from bin/lclose) by only treating the
leading run of non-flag tokens as a help path.
Users never type `linear_cli` - they type `lc`, or one of the bash
wrapper scripts (lcreate, lcls, etc). Naming the escript/release binary
itself `lc` means those wrappers work as-is, with no separate aliasing
mechanism needed.
Ports the bash wrapper scripts verbatim from vendor/ruby-linear-cli/exe/scripts/
(lcreate, lcls, lclose, lcomment, lproj) - they already just `exec lc ...`,
so they work unmodified now that the binary itself is named `lc`.

The container image installs both the binary and the wrappers into
/usr/local/bin/ together so the wrappers' `exec lc ...` actually resolves
via PATH (the old bare `/linear_cli` wasn't on PATH at all), and adds
bash (Alpine's default /bin/sh can't run bin/lclose's `[[ =~ ]]` syntax).
The Burrito-wrapped `lc` binary never actually invoked CLI.main - it
boots via `-s elixir start_cli`, which only recognizes Elixir's own CLI
flags (--help/--version) and otherwise tries to run its first argument
as a script file. `lc issue list` failed with "No file named issue"
instead of reaching the CLI at all; --help/--version only appeared to
work by accident, via Elixir's own flag parsing.

Per Burrito's README, the fix has to live in Application.start/2:
detect the standalone-Burrito case (Burrito.Util.running_standalone?/0,
which checks the __BURRITO env var the Zig wrapper sets) and call
CLI.main/2 directly there, then halt. Verified against both the native
macOS binary and the Linux container image - real subcommands now
reach the actual CLI logic instead of dying at boot.
Copilot AI lite review requested due to automatic review settings August 9, 2026 19:17
Floating on elixir = "latest" drifted local Erlang/Elixir ahead of what
Burrito's precompiled-ERTS catalog actually has cataloged - `mix release`
started 404ing locally (fetching OTP 29.0.5) while CI, pinned via
erlef/setup-beam@v1, stayed fine. Pin both erlang and elixir to match
CI exactly.
Builds a native Burrito release for the current machine (macOS aarch64
or Linux x86_64) via mise, and installs lc plus the bin/ wrapper scripts
onto a directory already on $PATH rather than assuming one. Writes a
manifest of exactly what it installed and where, so uninstall.sh can
remove precisely those files even if $PATH changes in between - a
fallback for machines without Homebrew (rubyists/homebrew-tap to come
once a real release exists to pin against).
@bougyman
bougyman merged commit a637969 into main Aug 9, 2026
2 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the project’s distribution/entrypoint story to consistently ship and run the CLI as lc (including Burrito releases, container image, and wrapper scripts), and fixes CLI boot/help edge cases encountered along that path.

Changes:

  • Renamed the escript/release binary from linear_cli to lc and updated supporting build/CI artifacts accordingly.
  • Fixed the Burrito standalone entrypoint so the real CLI logic runs, and improved CLI parsing behavior for no-subcommand and --help scenarios.
  • Added wrapper scripts plus install.sh/uninstall.sh, and wired wrappers + bash into the container image.

Reviewed changes

Copilot reviewed 10 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
uninstall.sh New uninstaller that removes files listed in an install manifest.
oci/Containerfile Copies lc + wrapper scripts into /usr/local/bin and installs bash in the Alpine image.
mise.toml Pins Erlang/Elixir tool versions to match CI for repeatable local Burrito builds.
install.sh New local install path: builds Burrito release and installs lc + wrapper scripts, writing a manifest for uninstall.
bin/lproj Wrapper script for lc project ….
bin/lcreate Wrapper script for lc issue create ….
bin/lcomment Wrapper script for lc issue update --comment - ….
bin/lcls Wrapper script for lc issue list ….
bin/lclose Wrapper script for lc issue update --close … with custom --help behavior.
app/test/linear_cli/cli_test.exs Updates test expectations/rescue to match the new parse-shape handling.
app/mix.exs Renames escript/release output to lc.
app/lib/linear_cli/cli.ex Normalizes Optimus parse return shapes; adds default lc behavior; improves --help normalization; renames CLI name to lc.
app/lib/linear_cli/application.ex Routes Burrito standalone startup into LinearCli.CLI.main/2 so args are handled.
app/.gitignore Updates ignored escript name to /lc.
.github/workflows/burrito-release.yaml Updates release workflow to build mix release lc.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread uninstall.sh
Comment on lines +37 to +43
if [ "$failed" -ne 0 ]
then
printf '%d file(s) removed, %d failed\n' "$removed" "$failed" >&2
exit 1
fi

printf '%d file(s) removed\n' "$removed"
Comment thread app/lib/linear_cli/cli.ex
Comment on lines +88 to +92
{before, [_ | _]} ->
case Enum.take_while(before, &(not String.starts_with?(&1, "-"))) do
[] -> argv
path -> ["help" | path]
end
@bougyman
bougyman deleted the issue-5 branch August 9, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build a binary and container release

2 participants