Tags: anderix/lux
Tags
Release 0.19.16 Make `lux update --help` describe the command that exists. It said "update lux to the latest release". That is one outcome out of twelve, and on Windows it is never the outcome — a running lux.exe cannot overwrite itself, so the command only ever prints the line to run in a fresh terminal. The help now says that where lux came from decides what happens: a shell installer install is replaced in place, Homebrew, WinGet and cargo are handed their own upgrade commands, and anything else is reported rather than guessed at so no second copy lands further up the PATH. The Windows caveat is stated rather than left to be discovered. The one-line summary in `lux --help` changed to match. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.15 Recognise a cargo install, the one route 0.19.14 left in the dark. `cargo install luxc` writes no receipt, so 0.19.14 put it in the same bucket as a binary someone dropped on their PATH and printed the generic "nothing here says how it got there" message. That route is in lux's own README, and unlike eget its home is knowable, so the message was unhelpful about something lux could work out. A binary under cargo's bin directory with no receipt covering it is now handed `cargo install luxc --force`. CARGO_HOME is honoured, falling back to ~/.cargo/bin, and to %USERPROFILE% on Windows. Order matters here and is tested. The receipt is checked first, because cargo-dist's default layout installs into cargo's own directory — so a receipt naming that prefix means the installer put the binary there, and the installer is what should replace it. Reaching the cargo check means no receipt covers this binary, which leaves cargo as the explanation. The cargo check also sits ahead of the shadowed case, so a machine with an installer copy elsewhere and a cargo build on its PATH is told how to replace the one actually running. To be clear about what 0.19.14 did to this route: it cost it the update, not correctness. A cargo-installed lux never shadowed itself, because the installer writes to the same directory cargo does and overwrote in place. This gives the update back in the form that matches how it was installed. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.14 Stop `lux update` guessing that anything it doesn't recognise came from the installer. 0.19.11 matched Homebrew and WinGet by path and treated everything else as a cargo-dist install. That default is where the bug lives: a lux put in place by eget, built from source, copied into ~/bin, or installed by a distro would get the installer run over the top of it, writing into ~/.cargo/bin and leaving the original at the old version. PATH order then decides which one answers, and nothing on screen says so — the update prints "Done" and `lux --version` reports the old number. eget is what made the default indefensible: it has no canonical install location at all. The binary goes to the working directory by default and anywhere $EGET_BIN points otherwise, so the trick that worked twice cannot work a third time. The installer leaves a receipt — luxc-receipt.json, under $XDG_CONFIG_HOME/luxc or %LOCALAPPDATA%\luxc — recording the prefix it installed into. That is positive evidence of provenance rather than an inference from a path, so the installer now runs only when a receipt names a prefix containing the running binary. A receipt pointing elsewhere names both paths; no receipt reports where lux is and hands back the install command. One change covers every channel not yet anticipated instead of one match string per channel. Package managers are still checked first and win outright: a machine can carry a stale receipt while the lux on its PATH now comes from Homebrew, and the path describes the binary actually running. Paths are compared as normalised text — separators unified, case folded, Windows' verbatim \\?\ prefix stripped, since canonicalize emits one and a receipt records a plain path. That also puts the Windows matching under test on Linux, where a backslash is an ordinary character and a Windows path reads as one component. Verified against the real receipt on this machine: the dev build reports the shadowed case and names both copies. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.13 Publish a Homebrew formula to anderix/homebrew-tap. cargo-dist's homebrew installer was never enabled here, so the formula job had never run for lux despite being wired in other repos. This turns it on: installers gains "homebrew", tap points at anderix/homebrew-tap, and publish-jobs = ["homebrew"] — without that last one the formula is built and attached to the release but never reaches the tap. The formula takes the package name, luxc, because lux in homebrew-core is an unrelated video downloader and core wins the plain name over any tap. The binary is still lux. Cargo.toml gains a homepage. Homebrew formulas carry one and lux had only a repository, so dist warned and the formula would have shipped without a link to the project's own page. Regenerated release.yml with dist 0.31.0, matching cargo-dist-version. The generated job checks out the tap with secrets.HOMEBREW_TAP_TOKEN, which is the secret name now set on this repo. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.12 Correct the two package names 0.19.11 printed: luxc, not lux, on both channels. `lux` is taken on both registries. homebrew-core's `lux` is iawia002's video downloader, so `brew install lux` succeeds and hands you unrelated software — core wins the short name over any tap, permanently. On WinGet the moniker `lux` belongs to JackDevey.Lux, a Govee light-strip CLI, and igoogolx.lux holds the plain package name, so `winget install lux` is ambiguous and errors rather than resolving. `luxc` is free on both, checked rather than assumed: homebrew-core 404s on it, and winget search, --moniker and show all come back empty. So the package is `luxc` on Homebrew and WinGet, matching what crates.io already forced, and `lux update` now prints `brew upgrade anderix/tap/luxc` and `winget upgrade Anderix.luxc`. One rule across three registries beats two rules and a footnote. The binary is still `lux` — the package name is what a person types once, the binary is what they type every day. Nothing is published on either channel yet, so no install is affected. The test fixtures now use real Cellar and WinGet package paths, which is where the formula-versus-binary distinction is visible. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.11 Teach `lux update` where lux came from, before either package channel exists. update_cmd knew one channel: it re-ran the cargo-dist installer, which writes into ~/.cargo/bin. On a machine where lux arrived from Homebrew or WinGet that leaves a second copy the package manager knows nothing about, and PATH order decides which one answers `lux`. The failure is silent — the command prints "Done", and `lux --version` reports the old version. A later `brew upgrade` or `winget upgrade` then reverts only the copy it knows about. On Windows it was worse than silent: the branch printed `irm ... | iex`, so the person who chose WinGet specifically to avoid piping a URL into a shell was told by lux to pipe a URL into a shell. current_exe() classifies the running binary. A Homebrew prefix gets `brew upgrade anderix/tap/lux`, a WinGet path gets `winget upgrade Anderix.lux`, and anything else behaves as before. The command is kept rather than removed on those channels — handing back the right next step is the same stance the diagnostics take. Matching is on the resolved path: Homebrew links bin/lux into its prefix while the file lives under Cellar, and current_exe() follows symlinks on Linux and macOS. /usr/local counts only under Cellar, so a hand-built lux copied to /usr/local/bin is not sent to a package manager that never had it. Both package managers are matched on every platform rather than behind cfg, so the Windows branch is covered by the suite on Linux too. Ordering, not preference: the README, `lux --help`, and the post-update nudge all point at `lux update`, so this has to be released before the first tap or manifest, not alongside them. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.10 Widen two sentences that described outgrowing lux as moving to another language. The README's second sentence cashed outgrowing out as transfer to Rust, Swift, or Go and stopped there; it now also says what a learner takes away — a working model of how a computer holds a value, makes a decision, and admits an answer might not be there — and that it is worth having whether or not they write another line of code. The headline first sentence is untouched. "Beyond lux" spends four paragraphs on what the moves are underneath the syntax and then landed on going somewhere else with them. It now closes on keeping them either way, which is where the rest of the section was already pointing. That text is baked into the binary, so lux learn carries it too. Wording only. No code, no examples, no parity surface changed. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Release 0.19.9 Fix #83: a local named String, Int, or Double breaks the Swift backend. The backend lowers string()/int()/float()/parseInt()/parseFloat() to bare String(...), Int(...), and Double(...) initializer calls. Swift resolves each to the innermost binding, so a lux local of that name shadowed the stdlib type and the emitted call became an attempt to call an integer — the program ran interpreted, built as Go and Rust, and failed only as Swift. These are ordinary names and the conversions are everywhere, so the collision was easy to reach. The initializers are now emitted as Swift.String / Swift.Int / Swift.Double, the same qualification stride got in 0.19.6. An audit of the class across the other backends found them already defended: Go renames a local colliding with a builtin, and Rust emits only method calls and path-qualified constructors a local cannot shadow. Written by David M. Anderson with AI assistance. Co-Authored-By: Claude Opus 4.8 <[email protected]>
PreviousNext