Skip to content

Tags: anderix/lux

Tags

v0.19.18

Toggle v0.19.18's commit message
Release 0.19.18

Author: David M. Anderson. Written by David M. Anderson with AI assistance.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

v0.19.17

Toggle v0.19.17's commit message
Release 0.19.17

Author: David M. Anderson. Written by David M. Anderson with AI assistance.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

v0.19.16

Toggle v0.19.16's commit message
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]>

v0.19.15

Toggle v0.19.15's commit message
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]>

v0.19.14

Toggle v0.19.14's commit message
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]>

v0.19.13

Toggle v0.19.13's commit message
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]>

v0.19.12

Toggle v0.19.12's commit message
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]>

v0.19.11

Toggle v0.19.11's commit message
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]>

v0.19.10

Toggle v0.19.10's commit message
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]>

v0.19.9

Toggle v0.19.9's commit message
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]>