Skip to content

Latest commit

 

History

History
364 lines (294 loc) · 20.8 KB

File metadata and controls

364 lines (294 loc) · 20.8 KB

Installing dira

curl -fsSL https://dirahq.sh/install | sh
irm https://dirahq.sh/install.ps1 | iex

Use install.sh on Linux and macOS (including WSL2), and install.ps1 on native Windows -- see Windows below. Both download from the landing site (vendored, byte-identical copies of the scripts at the root of this repo), do nothing until their very last line, and every download is sha256-verified before anything is installed — there is no --no-verify escape hatch. install.ps1 is a section-for-section port of install.sh: same step order, same environment variables, same guarantees, translated to PowerShell flag syntax (-Version instead of --version, etc.) — see Windows for its flag table.

Flags always beat their matching environment variable. Everything below is read straight out of install.sh's own --help and dira update --help — if the two ever disagree with this file, trust the --help output and file a bug.

Supported targets

Platform Target triple Notes
macOS, Apple Silicon universal-apple-darwin Same download as Intel — a lipo fat binary
macOS, Intel universal-apple-darwin Same download as Apple Silicon
Linux x86_64 x86_64-unknown-linux-musl Static musl — works on Alpine and old-glibc distros alike
Linux arm64 aarch64-unknown-linux-musl Static musl
Windows x86_64 x86_64-pc-windows-msvc Native build. Install with install.ps1, not install.sh — see Windows
Windows arm64 aarch64-pc-windows-msvc Cross-compiled (MSVC links a foreign architecture natively from an x86_64 host)
WSL2 (any arch) x86_64-unknown-linux-musl / aarch64-unknown-linux-musl WSL is Linux to uname — use install.sh from inside the WSL shell, same as bare-metal Linux

There is no x86_64-apple-darwin artifact and no glibc (gnu) Linux artifact — the universal macOS binary and the statically-linked musl binaries make both unnecessary.

Flags

Flag Same as Default
--version <VERSION> DIRA_VERSION latest
--channel <CHANNEL> DIRA_CHANNEL stable (stable | prerelease)
--prerelease shorthand for --channel prerelease
--bin-dir <DIR> DIRA_BIN_DIR ${XDG_BIN_HOME:-$HOME/.local/bin}
--target <TRIPLE> DIRA_TARGET auto-detected (see the table above)
--daemon DIRA_START_DAEMON=1 off — start dirad after installing
--service DIRA_INSTALL_SERVICE=1 off — also run dira daemon install (launchd/systemd-user)
--no-daemon off — never start, restart, or install the daemon, even if one is already running
--no-interactive DIRA_NO_INTERACTIVE=1 off — never prompt, even on a terminal
--force off — overwrite a just install dev symlink; skip the --uninstall confirmation
--uninstall off — remove dira + dirad (never config or data; see Uninstalling)
-h, --help show usage and exit

Environment variables

Variable Purpose Default
DIRA_VERSION Exact version to install instead of resolving one latest
DIRA_CHANNEL stable | prerelease stable
DIRA_BIN_DIR Where dira + dirad are installed ${XDG_BIN_HOME:-$HOME/.local/bin}
DIRA_TARGET Override target-triple detection auto-detected
DIRA_REPO GitHub repo to install from dodi-smart/dirahq-cli
DIRA_API_URL GitHub API base URL https://api.github.com
DIRA_DOWNLOAD_URL Override the release-asset base URL (air-gapped / local installs, also accepts file://) unset — derived from DIRA_REPO + the resolved tag
GITHUB_TOKEN / GH_TOKEN Bearer token for the authenticated-asset path — raises GitHub's 60/hr-per-IP anonymous rate limit; GH_TOKEN wins if both are set unset — unauthenticated public path
DIRA_START_DAEMON Same as --daemon (set to 1) 0
DIRA_INSTALL_SERVICE Same as --service (set to 1) 0
DIRA_NO_INTERACTIVE Same as --no-interactive (set to 1) 0
DIRA_ALLOW_ROOT Silence the "running as root" warning (set to 1) 0
DIRA_DEBUG Verbose debug output on stderr (set to 1) 0

Two more DIRA_* variables are read only by the dira update self-updater, not by install.sh — see dira update semantics below.

Windows

irm https://dirahq.sh/install.ps1 | iex

install.ps1 is a section-for-section PowerShell port of install.sh — same step order, same mandatory sha256 verification, same "does nothing until the very last line" truncation-safety discipline, just PowerShell flag syntax and a .exe extension. PowerShell 5.1 (the default host behind irm | iex) is the compatibility floor; it never calls Set-ExecutionPolicy.

irm | iex has no way to forward flags to the piped script — it just executes the downloaded text. To pass flags, wrap it in a scriptblock and invoke that directly:

& ([scriptblock]::Create((irm https://dirahq.sh/install.ps1))) -Channel prerelease

Or download the script and run it directly — also the only way to use a restricted ExecutionPolicy without a persistent, machine-wide change (irm | iex already bypasses policy for itself; a saved .ps1 file does not):

powershell -ExecutionPolicy Bypass -File install.ps1 [FLAGS]

Flags

Flag Same as Default
-Version <VERSION> DIRA_VERSION latest
-Channel <CHANNEL> DIRA_CHANNEL stable (stable | prerelease)
-Prerelease shorthand for -Channel prerelease
-BinDir <DIR> DIRA_BIN_DIR $env:USERPROFILE\.local\bin
-Target <TRIPLE> DIRA_TARGET auto-detected (x86_64-pc-windows-msvc / aarch64-pc-windows-msvc)
-Daemon DIRA_START_DAEMON=1 off — start dirad after installing
-Service DIRA_INSTALL_SERVICE=1 off — register a DiraDaemon scheduled task (dira daemon install)
-NoDaemon off — never start, restart, or install the daemon, even if one is already running
-Force off — overwrite a dev-build symlink; skip the -Uninstall confirmation
-Uninstall off — remove dira.exe + dirad.exe (never config or data)
-Help show usage and exit

The rest of the environment variables above apply identically — DIRA_REPO, DIRA_API_URL, DIRA_DOWNLOAD_URL (a file:// URL still works, for air-gapped installs), GH_TOKEN/GITHUB_TOKEN, and DIRA_DEBUG. There is no Windows equivalent of DIRA_ALLOW_ROOT — it's a Unix-only concept.

PATH is updated in the user scope via the registry ([Environment]::SetEnvironmentVariable(..., 'User')) — never machine-wide, and never setx, which silently truncates PATH at 1024 characters. It's also prepended to the current session's $env:PATH, so the printed "Next steps" work immediately; open a new terminal for the change to show up elsewhere.

Uninstalling mirrors Uninstalling below: -Uninstall (add -Force to skip the confirmation prompt) asks for confirmation, stops the daemon, best-effort tears down the DiraDaemon scheduled task, then removes dira.exe + dirad.exe. Config and data are never touched.

WSL2

WSL2 is Linux as far as dira is concerned — use install.sh from inside the WSL shell, not install.ps1. install.sh detects WSL and prints a pointer to install.ps1 in case you actually wanted the native build instead; install.ps1 itself refuses outright when run under pwsh on Linux or macOS (including WSL) and points back at install.sh.

Verifying checksums by hand

Every release attaches one dira-<version>-<target>.sha256 per archive, in the same format sha256sum itself produces (<hash> <filename>, two spaces). If the tarball and its .sha256 are in the same directory, verification is a one-liner:

curl -fsSLO "https://github.com/dodi-smart/dirahq-cli/releases/download/v<version>/dira-<version>-<target>.tar.gz"
curl -fsSLO "https://github.com/dodi-smart/dirahq-cli/releases/download/v<version>/dira-<version>-<target>.sha256"
sha256sum -c "dira-<version>-<target>.sha256"        # Linux
shasum -a 256 -c "dira-<version>-<target>.sha256"     # macOS

install.sh does the equivalent internally (_extract_expected_digest in the script), matching the checksum file's filename field rather than trusting line order — a .sha256 file may in principle carry more than one line, one per asset built in that release job.

Each release also carries an aggregate checksums.txt (all legs' .sha256 files concatenated, sorted by filename) purely for human convenience — install.sh never reads it; it always verifies against the per-asset .sha256 for the exact target it downloaded.

Manual / air-gapped install

To install without letting install.sh reach GitHub at all — a machine with no outbound network, or one you'd rather not hand a bearer token to — download the tarball and its checksum through whatever channel you have (another machine, a mirror, a USB stick), put them in one directory, then point the installer at that directory with DIRA_DOWNLOAD_URL using a file:// URL:

mkdir -p /tmp/dira-offline
cp dira-<version>-<target>.tar.gz dira-<version>-<target>.sha256 /tmp/dira-offline/
DIRA_DOWNLOAD_URL="file:///tmp/dira-offline" \
  DIRA_VERSION=<version> \
  DIRA_TARGET=<target> \
  sh install.sh

install.sh still verifies the checksum in this path — a local tarball you sourced yourself is not exempt. This is also exactly the mechanism just install-local uses in this repo to test the installer without cutting a real release (see the justfile).

If you'd rather skip the installer entirely: extract the tarball yourself, chmod 0755 both dira and dirad, and copy them onto $PATH — there is nothing else the installer does to the binaries themselves.

Corporate proxies

install.sh has no proxy handling of its own — it shells out to plain curl or wget, and both honor the standard HTTPS_PROXY/HTTP_PROXY/NO_PROXY (and lowercase) environment variables natively. Export them before running the installer as you would for any other curl/wget invocation:

export HTTPS_PROXY=http://proxy.example.internal:8080
export NO_PROXY=localhost,127.0.0.1,.example.internal
curl -fsSL https://dirahq.sh/install | sh

If your proxy terminates TLS and re-signs with an internal CA, curl/wget need that CA trusted at the OS level (or via CURL_CA_BUNDLE/SSL_CERT_FILE) — this is standard curl/wget behavior, nothing dira-specific.

Adding ~/.local/bin to PATH

install.sh never edits a dotfile for you — under curl | sh, stdin is the script, so there's nothing to read a confirmation from safely. If the install directory isn't already on PATH, it prints one of these hints (exactly matching what the script emits):

fish

fish_add_path ~/.local/bin

zsh — add to ~/.zshrc, then restart your shell:

export PATH="$HOME/.local/bin:$PATH"

bash on Linux — add to ~/.bashrc, then restart your shell:

export PATH="$HOME/.local/bin:$PATH"

bash on macOS — add to ~/.bash_profile instead (macOS bash doesn't source .bashrc for login shells), then restart your shell:

export PATH="$HOME/.local/bin:$PATH"

Any other shell — add to ~/.profile, then restart your shell:

export PATH="$HOME/.local/bin:$PATH"

(Substitute your actual $DIRA_BIN_DIR if you overrode it.)

Uninstalling

curl -fsSL https://dirahq.sh/install | sh -s -- --uninstall
# or, from a checkout:
sh install.sh --uninstall

This asks for confirmation (unless --force), stops the daemon, tears down any launchd agent (~/Library/LaunchAgents/sh.dirahq.dirad.plist) or systemd-user unit (~/.config/systemd/user/dirad.service) it finds — even if the binaries themselves are already gone — then removes dira and dirad from the bin directory. It refuses outright on a just install dev symlink; that's not its install to remove.

What is not removed: config, local capture data, and cache. Uninstalling only ever touches the two binaries and the service unit. To see exactly where your config lives, run dira config path before uninstalling (the uninstaller prints it too, if dira is still runnable at that point). By default (ProjectDirs::from("sh", "dirahq", "dira")):

macOS Linux
Config (config.toml) + local DB (dira.db) ~/Library/Application Support/sh.dirahq.dira/ ${XDG_CONFIG_HOME:-~/.config}/dira/, ${XDG_DATA_HOME:-~/.local/share}/dira/
Cache (update-check cache only) ~/Library/Caches/sh.dirahq.dira/ ${XDG_CACHE_HOME:-~/.cache}/dira/

To remove data too: reinstall dira and run dira nuke (--yes to skip the prompt), or delete those directories by hand. dira nuke deletes every locally-stored event and token row — the full statistics history on this device — but keeps the device identity, signing key, cloud link, and config; it does not touch anything already synced to the cloud, and it does not remove the installed binaries (that's what --uninstall is for).

dira update semantics

dira update is dira's own self-updater — a Rust reimplementation of install.sh's resolve/download/verify steps that also does an in-place atomic swap and restarts the daemon. It reuses install.sh's own environment variables where they overlap (DIRA_REPO, DIRA_API_URL, DIRA_DOWNLOAD_URL, DIRA_TARGET, GITHUB_TOKEN/GH_TOKEN), plus its own flags:

Flag Default Behavior
--check off Resolve only — never downloads, never touches a binary. Exits 0 in every non-error case, including offline, so it's safe to run speculatively. Also refreshes the cache behind the passive "update available" notice (see below).
--version <VERSION> resolve latest Update or downgrade to this exact version — downgrading is allowed.
--channel <CHANNEL> stable stable | prerelease
--force off Skip the dev-install guard — but only for a symlinked (just install) dev install. Never bypasses sha256 verification, and never overrides a build actually running out of target/{release,debug} (there is no "old" binary to overwrite in that case).
--no-restart off Swap the binaries but leave a running daemon on the old version.
--bin-dir <DIR> alongside the running dira (DIRA_BIN_DIR env, or scanned off PATH) Install directory for the new binaries.

Channels and pinning. --channel prerelease opts into the newest …-develop.N build; the default stable channel only ever resolves a clean x.y.z release. --version overrides channel resolution entirely and pins to (or downgrades to) that exact tag.

The dev-install refusal. dira update refuses to run at all against a just install setup: a dira that is a symlink into target/{release,debug} is refused unless --force (the symlink is just a pointer — overwriting it costs nothing real); a dira that is itself a target/{release,debug} build (running via cargo run, or invoking ./target/debug/dira update directly) is refused unconditionally, --force included — there is no old binary to replace, only the build directory cargo is about to rebuild into. Use just install to update a contributor checkout instead.

Atomicity and rollback. Both binaries are staged into .{name}.new.<pid> next to their final path and rename(2)d into place — never opened for writing at the final path, which would fail ETXTBSY against a binary a running dirad has mapped executable. dirad is swapped first, then dira; a .bak hard link of each previous binary is kept until a post-swap dira --version check confirms the new binary actually reports the expected version, at which point the backups are deleted. Any failure before that point best-effort rolls both binaries back to their previous content.

Restart. Unless --no-restart was given, a daemon that was already running is always restarted after a successful swap (see dira daemon restart and the troubleshooting table below for how that's supervised). A daemon that wasn't running beforehand is left stopped.

The passive update notice. Separately from dira update itself, dira status, dira version, and dira daemon status print a rate-limited "update available" notice to stderr (never stdout, so dira status | cat stays byte-identical) when a newer release is cached. The check that populates that cache never blocks the foreground command — it's a detached, fire-and-forget dira update --check spawned in the background, at most once every 24h after a successful check (6h after a failed one). It's suppressed by:

  • a non-TTY stderr
  • CI (any value)
  • NO_UPDATE_NOTIFIER (any value — the npm-ecosystem convention)
  • DIRA_NO_UPDATE_CHECK=1 (or any value other than 0)
  • the update.check config knob set to off (dira config set update.check off, or DIRA_UPDATE__CHECK=false — the config layer's usual __. env mapping)
  • running a target/{release,debug} dev build

The first four only suppress printing; the config knob and a dev build also stop the background refresh itself.

"Newer" means SemVer 2.0 §11 ordering, not simply "a different version string". So a prerelease build is never told to install the older stable head: 0.1.0 is behind 0.1.1-develop.1, and dira update --check says so explicitly (dira is up to date (0.1.1-develop.1 — ahead of the stable channel's 0.1.0)) while the passive notice stays quiet. dira update refuses that downgrade for the same reason — pass --version <v> to move backwards deliberately, or --channel prerelease to keep following prereleases.

What the installer does and does not touch

install.sh and dira update:

  • Do verify a sha256 checksum before installing anything, unconditionally.
  • Do not edit any dotfile — PATH hints are printed, never applied.
  • Do not install a launchd/systemd-user service unless you pass --service, ask dira daemon install directly, or answer yes to the prompt. On a terminal the installer asks whether to register the service; with no terminal (CI, a pipe, --no-interactive) it never asks and never installs one. The question is read from /dev/tty, not stdin — under curl … | sh stdin is the script itself, which is why the installer used to claim it could not ask at all.
  • Do not phone home anywhere beyond GitHub (api.github.com, or your DIRA_API_URL override, plus the release-asset host) to resolve and download a release.
  • Do not touch config, local capture data, or the device's cloud link, ever — only dira nuke (data) or manual deletion (config) do that, and neither removes the binaries.

Troubleshooting

Symptom Likely cause Fix
dira: command not found right after install The bin dir isn't on PATH yet See Adding ~/.local/bin to PATH; start a new shell after editing your rc file
checksum mismatch for dira-<version>-<target>.tar.gz Corrupted download, a captive/corporate proxy rewriting the response, or a genuinely tampered mirror Re-run the install (transient network corruption is common); if it persists behind a proxy, compare against the .sha256 by hand from an unproxied network
dira update/install.sh restart reports could not restart the launchd agent automatically launchctl kickstart and the launchctl stop fallback both failed (agent not loaded, wrong user session) Run the printed command yourself: launchctl kickstart -k gui/$(id -u)/sh.dirahq.dirad
dira update/install.sh restart reports could not restart the systemd-user unit automatically Usually a headless box without loginctl enable-linger, so systemctl --user can't reach the user's systemd instance outside an active login session sudo loginctl enable-linger "$USER", then retry dira daemon restart; or run systemctl --user restart dirad.service yourself once linger is enabled
Install refuses with ... is a 'just install' dev build symlinked at ... refusing to overwrite it You're installing over a contributor checkout's just install symlink Pass --force if you really want a real install there, or just install to update the dev build instead
dira update refuses even with --force The running dira is itself a target/{release,debug} build (e.g. cargo run -p dira -- update) There's no installed binary to replace — use an actual installed dira, or just install
Need jq and don't have it You set GITHUB_TOKEN/GH_TOKEN — the authenticated asset-resolution path requires jq; the normal unauthenticated path never does Unset the token for a normal public install, or install jq