Skip to content

moshcode: uninstall an engine or tool - #150

Merged
ralyodio merged 1 commit into
mainfrom
feat/uninstall
Jul 31, 2026
Merged

moshcode: uninstall an engine or tool#150
ralyodio merged 1 commit into
mainfrom
feat/uninstall

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

moshcode install had no inverse. Removing opencode meant knowing which installer put it where — the thing the wrapper exists to spare you.

moshcode uninstall <engine|tool> [--dry-run] [--yes]

Two installer shapes, one inverse

npm install -g <pkg> is undone by npm, which knows what it put where. The package name is read out of the install spec rather than duplicated, so it can't drift.

A curl … | sh installer drops a binary and leaves no record. Removing it means finding and deleting that binary — a different kind of operation, treated like one:

  • Only offered inside an allow-list of places a per-user installer would plausibly write (~/.local/bin, ~/.bun/bin, /usr/local/bin, …). The question isn't "is this dangerous" but "did something we ran create this" — and only an allow-list answers that. /usr/bin/opencode came from a package manager and isn't ours to remove.
  • Needs --yes. Deleting a file because a flag was left off isn't a thing this should do. npm removals don't ask, since one command puts it back.
  • Says config and credentials stay. "Uninstalled" reads as "gone" and it isn't.

Verified live

uninstall claude --dry-run    run     npm uninstall -g @anthropic-ai/claude-code
uninstall opencode            opencode is not on your PATH — nothing to remove
uninstall ugig  (in /tmp)     /tmp/fakebin/ugig is not in a directory moshcode installs into.
uninstall c0mpute             this deletes ~/.local/bin/c0mpute. re-run with --yes to do it.
uninstall c0mpute --yes       ✓ removed /home/anthony/.local/bin/c0mpute

Tests

Plans are data, so every branch is tested without deleting anything. 7 tests, most about when it refuses — including that an npm entry ignores a /usr/bin path that the binary branch would reject.

Also exports resolveExecutable from engines.mjs, which was module-private.

🤖 Generated with Claude Code

`moshcode install` had no inverse. Removing opencode meant knowing which
installer had put it where, which is the thing the wrapper exists to spare you.

  moshcode uninstall <engine|tool> [--dry-run] [--yes]

Installers come in two shapes and only one has an inverse anyone wrote down.
`npm install -g <pkg>` is undone by npm, which knows what it put where — the
package name is read out of the install spec rather than duplicated. A
`curl … | sh` installer drops a binary and leaves no record, so removing it
means finding that binary and deleting it, which is a different kind of
operation and is treated like one:

  - it is only offered when the binary sits somewhere a per-user installer
    would plausibly have put it. An allow-list, not a deny-list: the question
    is not "is this dangerous" but "did something we ran create this", and
    /usr/bin/opencode came from a package manager and is not ours to remove
  - it needs --yes. Deleting a file because a flag was left off is not a thing
    this should do
  - it says out loud that config, caches and credentials in your home
    directory stay, because "uninstalled" reads as "gone" and it is not

npm removals do not ask, since one command puts it back.

Plans are data, so every branch is tested without deleting anything, and
--dry-run shows exactly what would go. 7 tests, most of them about when it
refuses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit af572d5 into main Jul 31, 2026
1 of 3 checks passed
@ralyodio
ralyodio deleted the feat/uninstall branch July 31, 2026 12:51
ralyodio pushed a commit that referenced this pull request Jul 31, 2026
`moshcode uninstall <engine|tool>` shipped in #150 and is documented in
`moshcode help`, but it was never added to CORE_CLI_COMMANDS. Shell
completion is generated from that roster, so tab completion did not know
the command existed: `moshcode un<TAB>` offered nothing, and
`moshcode uninstall <TAB>` offered no targets. The `remove` alias was
missing for the same reason.

completion.test.mjs already guards this ("completion schema covers every
explicitly dispatched CLI command") and has been failing on main since
#150 landed.

Add uninstall and remove to the roster, and give uninstall a target
bucket wired into the bash, zsh and fish generators. The bucket is the
same ENGINES + TOOLS roster the dispatch resolves against, so every
offered target is one uninstall can actually accept. Flags --yes,
-y and --dry-run complete after a target.

Co-authored-by: clawedassistant26 <307253840+clawedassistant26@users.noreply.github.com>
ralyodio added a commit that referenced this pull request Jul 31, 2026
* chore(release): v0.13.3

install.sh resolves releases/latest, so everything merged since v0.13.2 has
been sitting on main unreachable — `moshcode dns enable` exists in the source
and not in anyone's binary.

The headline is the DNS bridge (#141). Moshpit names now resolve for every
program on the machine, not just inside TronBrowser: each OS gets the mechanism
that routes ONE SUFFIX rather than the one that replaces the resolver —
/etc/resolver on macOS, systemd-resolved routing-only domains or dnsmasq on
Linux, an NRPT rule per namespace on Windows.

  moshcode dns enable / disable / status
  moshcode uninstall <engine|tool>          (#150, completion in #151)

The pit gained most of a namespace registry in between: key pins per name
(#137), pasted bulk claiming with per-line price and target (#138, #142, #143,
#146), all-numeric endings (#147), /n/<name> serving a name or a directory
(#145, #149), and Buy Now on an unclaimed name (#148).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: restore the em-dash the version bump escaped

The bump rewrote package.json through a JSON serialiser that defaults to ASCII,
turning the em-dash in `description` into —. Valid JSON and the same string
once parsed, but a gratuitous diff in a commit that should touch one line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant