moon 0.1.1

universal linux-only tool.
moon-0.1.1 is not a library.

Banner

moon installs a downloaded archive, AppImage or .deb in one command. Zero crates, zero daemons, one binary. ( more features in future )

Install

cargo install moon

No Rust toolchain? The release script does the same thing from the published binaries, into ~/.local/bin:

curl -fsSL https://moonpkg.github.io/cli/scripts/install.sh | bash
moon install app-1.2.3-linux-x64.tar.xz

It will:

  1. extract the archive into ~/.local/share/moon/apps/<name>/
  2. symlink the executable(s) into ~/.local/bin so you can run them from a terminal
  3. write ~/.local/share/applications/<name>.desktop, reusing the package's own .desktop file and icon when present
  4. run update-desktop-database so it shows up in the applications menu
  5. remember everything in a manifest, so moon remove and moon undo can put it all back

Commands

command what it does
moon install <file|url|bundle> install or upgrade an app
moon interactive picker over the current directory
moon inspect <file|url|last> show what installing would do, change nothing
moon list installed apps
moon remove <name>... uninstall: binaries, menu entry, files
moon undo [name] remove the app installed last (asks first)
moon doctor [--fix] find broken entries and repair them
moon export <name> [dir] copy an installed app as a portable bundle
moon bundle <name|folder> [out.moon] pack an app, or a bundle folder, into one .moon file
moon unexport <name> delete a portable bundle
moon history [-n N] [--clear] what was installed, and when
moon config settings
moon help, moon version

Aliases where they feel natural: ls for list, rm for remove, i/add for install, show/what for inspect, log/hist for history, check/verify/repair for doctor.

Install options

option meaning
--name <name> app and command name (default: guessed from the file name)
--bin <rel/path> the main executable inside the archive (default: auto-detected)
--desktop / --no-desktop force or forbid a menu entry
--force overwrite entries that moon does not own
--portable-dir <path> keep the app on another disk instead of ~/.local

Re-running install on an installed app shows what changed and asks whether to upgrade, reinstall, keep or inspect first. In a script it just replaces, and says whether that was an upgrade, a reinstall or a downgrade.

Archives without an icon or .desktop file are treated as CLI tools: no menu entry unless you pass --desktop.

.deb packages

moon install nowly-host.deb --dry-run   # show the plan, write nothing
moon install nowly-host.deb             # install per-user into ~/.local
sudo moon install nowly-host.deb --root # dpkg-style, into the real /usr
option meaning
--root install to the real /usr, /opt, ... (needs root)
--run-scripts run the package's preinst/postinst (never by default)
--no-rewrite don't rewrite absolute paths inside desktop files and wrappers
--dry-run, -n show what would be installed

Packages with files outside /usr (icons, appdata, desktop files) get relocated under ~/.local/share/moon/apps/<name>/system and every absolute path inside the package is rewritten to match, so nothing ends up pointing at paths that don't exist. --root skips the relocation. Conflicts with files moon doesn't own are refused unless you pass --force.

Portable installs

Keep an app on a USB stick instead of in ~/.local:

moon install SomeApp.AppImage --portable-dir /mnt/USB/Apps
USB/
└── Apps/
    └── someapp/
        ├── SomeApp.AppImage
        ├── someapp.desktop
        └── icon.png

Command links in ~/.local/bin and the menu entry still work; they just point into the bundle. Plug the drive into another machine and the app is there.

Exporting a bundle

Turn anything moon already installed into a self-contained folder:

moon export someapp                 # creates ./someapp/
moon export someapp /mnt/USB/Apps   # or somewhere else
moon unexport someapp               # delete the bundle

The bundle carries the app, its menu entry and its icon, with absolute paths pointing inside the bundle. moon doctor flags a portable app whose directory has gone missing, which is what an unplugged USB stick looks like.

.moon bundles

A .moon bundle is one file that holds a whole app: the program, its metadata, its icon and its menu entry. It is a plain tar.gz, so tar xf SomeApp.moon still works, and there is no server involved on either end.

moon bundle someapp        # an installed app  -> ./someapp.moon
moon bundle ytkew-moon     # a bundle folder  -> ./ytkew-moon.moon
moon install someapp.moon  # on any machine, yours included

A bundle folder is a .manifest plus app/, and optionally desktop/ and icon/:

ytkew-moon/
├── ytkew.manifest
├── app/
│   └── ytkew
├── desktop/
│   └── ytkew.desktop
└── icon/
    └── ytkew.svg

The manifest is moon's own key=value format with paths relative to the bundle: dir, main, version, desktop, and link/to pairs for each command. On install moon rewrites the bundled menu entry to the new machine's paths, links the commands into ~/.local/bin, and saves a manifest with the real ones. How to bundle has the whole guide.

doctor

moon doctor
Broken entries:

⚠ someapp 1.2.3
   Application missing: ~/.local/share/moon/apps/someapp
   Menu entry missing: ~/.local/share/applications/someapp.desktop

⚠ btop
   Symlink exists
   Target missing: ~/.local/bin/btop
   Points at: ~/.local/share/moon/apps/btop/bin/btop

moon doctor --fix removes the leftovers and updates the manifests. Add --yes to skip the question. It also finds command links in ~/.local/bin that point at nothing and that moon did not create; those are reported but not touched.

Icons

moon uses Nerd Font glyphs when it detects one and plain text when it does not, so the output stays readable either way:

moon config --icons auto   # default: icons only if a Nerd Font is installed
moon config --icons always
moon config --icons never

All 26 glyphs are single codepoints in the Font Awesome, Octicons and Devicons ranges of Nerd Fonts, so any patched Nerd Font covers them.

Supported inputs

.tar.gz .tar.xz .tar.bz2 .tar.zst .tgz .tar .zip .7z .AppImage .deb .moon, bare executables, and http(s):// URLs.

moon install with no arguments opens a picker over the current directory: arrows or hjkl to move, enter to install, q to quit.

Layout

src/
  main.rs        entry point
  cli.rs         argument parsing and dispatch
  config.rs      settings, Nerd Font detection, the icon set
  install.rs     install/upgrade, conflict prompts, remove, undo, list
  inspect.rs     the dry-run report
  doctor.rs      broken-entry detection and repair
  portable.rs    portable installs and bundles
  bundle.rs      .moon bundles: pack and install one file
  update.rs      self-update through the release install script
  archive/       download and unpack
  deb/           ar, control file, install plan, rollback
  desktop.rs     .desktop and icon handling
  state.rs       manifests and last-install
  history.rs     install log
  tui/           terminal picker
  fsutil.rs      file and tree helpers
  naming.rs      guessing names, versions and architectures
  probe.rs       file sniffing, architecture, library checks
  paths.rs       XDG paths
  util.rs        text and size helpers
docs/
  icons/         one SVG per glyph, plus the generator that cuts them
HOW_TO_BUNDLE.md  the .moon bundle guide, also served at /how-to-bundle

Uninstall moon

moon remove <name>... # the apps first
rm ~/.local/bin/moon