Repository navigation
fix(install): install lash, not opencode - #48
Conversation
The install script was upstream's, unmodified. Anyone running `curl -fsSL https://lash.lacy.sh/install | bash` got the opencode binary from github.com/anomalyco/opencode dropped in ~/.opencode/bin. The site proxies this file, so the wrong product was one command away from any visitor. The script itself is good: rosetta detection, musl detection, AVX2 baseline selection, and PATH handling all match our release matrix exactly. Only the identifiers were wrong, so this changes those and leaves the logic alone. APP=opencode -> APP=lash (none) -> ASSET=lashcode $HOME/.opencode/bin -> ${LASH_INSTALL_DIR:-$HOME/.lash/bin} anomalyco/opencode -> lacymorrow/lash mv "$tmp_dir/opencode" -> mv "$tmp_dir/$APP" command -v opencode -> command -v lash APP and ASSET are genuinely two values: the release archives are published as lashcode-<target>, the binary inside them is `lash`. Collapsing them into one name is what makes the filename wrong. Verified end to end on darwin-arm64 with the existing lash hidden from PATH: fetches lashcode-darwin-arm64.zip from v1.7.13, extracts, installs, and the result reports 1.7.13. Also replaced the opencode ASCII art and closing text, and rewrote the README installation section, which still told people to install opencode from opencode.ai. Lash installs alongside opencode rather than over it: different binary name, different install directory. Note for whoever picks this up: main carries a different install script that is lash-branded but broken in other ways. It builds filenames as lash-<target>.tar.gz (wrong prefix, and macOS ships .zip), hardcodes a default version of 0.6.12-fixed that does not exist, and creates its temp directory in the user's cwd. This supersedes it.
The route fetched raw.githubusercontent.com/lacymorrow/lash/dev/install. `dev` is upstream's branch name. `lash` is this repo's default and working branch, and where lacymorrow/lash#48 fixes the script. The two files happen to be identical right now, so this changes nothing today and everything once #48 merges.
|
The two e2e failures here are pre-existing on the branch, not from this change. They are Playwright tests of the desktop app UI: PR #46, the upstream sync, has the same two failures and touches none of the same files. Evidence for the change itself is in the description: ran end to end on darwin-arm64 with the brew-installed lash hidden from |
* feat: strip the site to Lash
lash.lacy.sh was a Shipkit install with a Lash landing page bolted on. The
landing page linked to none of the rest of it, so everything behind the nav was
another product's marketing site: a pricing page for a $0 MIT product, a
features page describing Payload CMS and Auth.js, a blog holding two posts about
Shipkit releases, a download page selling "the premium Next.js boilerplate", and
a dashboard, admin area, 14 demo routes and a SaaS API surface with no product
behind any of it.
Deleted. 426 files, 48k lines. What is left is the landing page, the docs, the
changelog, the contact page, and the /install script route.
Removed:
(kit) faq, features, pricing, bones/cli
(dashboard) dashboard, projects, teams, deployments, api-keys, download, tools
(admin) the whole admin area
(demo) 14 demo and example routes
(integrations) builder.io, google-docs, polar, stripe
(cms) Payload
blog two Shipkit posts, plus rss.xml
settings account, profile, appearance, polar-products
api admin/users, deployments, download, github/*, payments/*,
permissions, projects, setup/*, teams
install the wizard UI, keeping only route.ts, which is the thing
`curl lash.lacy.sh/install` actually hits
Typecheck is clean before and after, which is the tell: none of it was wired to
anything that survived.
Docs. The docs/ directory held Shipkit's documentation, 66 of 78 files
describing a Next.js starter kit. Deleted and replaced with two pages that
document Lash: what the fork adds over OpenCode (the three execution modes and
ctrl+space, how Auto decides between shell and agent, the two prompt bars, cwd
tracking in the footer, Tab for shell completion), and how to install it.
Everything OpenCode already documents links to opencode.ai/docs rather than
being restated here.
With docs/ holding Lash content instead of Shipkit content, it ships again:
docs/** comes back out of .vercelignore.
Sitemap. src/app/sitemap.ts exported generateSitemaps(), which splits output
across /sitemap/0.xml, /sitemap/1.xml and so on. That is a feature for sites
with tens of thousands of URLs, and it is why /sitemap.xml returned 404. Replaced
with a single file listing the landing page, the docs and the changelog. robots.ts
had its sitemap line commented out, so robots.txt named no sitemap either; now it
does, and it disallows /api/ and the auth pages.
Nav is Docs and Changelog. It was Faqs, Features, Pricing on one layout and Blog,
Changelog, Docs on another, pointing at pages that are now gone.
Also removed an em dash from the site description, and the bones/muscles/brains
product tiers from site-config, which are Shipkit's and which nothing read.
Left alone on purpose: the auth routes. The site has no accounts and does not
need sign-in, but removing the auth stack means touching the root layout,
middleware and session providers, which is its own change. robots.txt keeps them
out of the index in the meantime. The contact page and its health check are also
untouched, since another branch is working on them.
* fix(install): proxy the install script from lash, not dev
The route fetched raw.githubusercontent.com/lacymorrow/lash/dev/install. `dev`
is upstream's branch name. `lash` is this repo's default and working branch, and
where lacymorrow/lash#48 fixes the script. The two files happen to be identical
right now, so this changes nothing today and everything once #48 merges.
* fix(types): drop the bones/muscles/brains fields from the branding type
Removing them from the object without removing them from the interface broke
typecheck. They are Shipkit's product tiers, nothing reads them, and the `(kit)`
routes that named them are gone, so the type goes with the values.
…c-2026-09-14 * origin/lash: fix(install): install lash, not opencode (#48)
curl -fsSL https://lash.lacy.sh/install | bashcurrently installs opencode. The site's/installroute proxies this file straight from the repo, so the wrong product is one command away from any visitor.What was wrong
The script is upstream's, unmodified:
/install/betaand/install/nightlyexportLASH_CHANNELand then run this same script, so the channel routes were wrong too.What this changes
Only the identifiers. The logic is good and stays: rosetta detection, musl detection, AVX2 baseline selection, and the shell-config PATH handling all match our release matrix exactly.
APP=opencodeAPP=lashASSET=lashcode$HOME/.opencode/bin${LASH_INSTALL_DIR:-$HOME/.lash/bin}anomalyco/opencodelacymorrow/lashmv "$tmp_dir/opencode"mv "$tmp_dir/$APP"command -v opencodecommand -v lashAPPandASSETare genuinely two values. Release archives publish aslashcode-<target>, the binary inside them islash. Collapsing them into one name is exactly what makes the filename wrong, which is the bug onmain(below).Evidence
Ran end to end on darwin-arm64 with the existing brew-installed lash hidden from
PATH, so the version short-circuit could not skip the download:Fetches
lashcode-darwin-arm64.zipfrom the v1.7.13 release, extracts, installs, runs.shellcheck -S warningreports only the five style warnings that were already there upstream.Also here
The README's installation section still told people to run
curl -fsSL https://opencode.ai/install | bashandbrew install anomalyco/tap/opencode. Rewritten to the real commands, both of which resolve today:brew install lacymorrow/tap/lashandnpm i -g lashcode.One thing to know
maincarries a different install script that is lash-branded but broken in other ways: it builds filenames aslash-<target>.tar.gz(wrong prefix, and macOS ships.zip), hardcodes a default version of0.6.12-fixedwhich does not exist, and doesmkdir -p lashtmp && cd lashtmpin the user's current directory. This supersedes it. Worth deleting that one so it does not get promoted later.