Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ commands.
## Install

```sh
brew install hotdata-dev/tap/cli # Homebrew
cargo install --path . # from source (requires Rust)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/hotdata-dev/hotdata-cli/releases/latest/download/install.sh | sh
```

The script uses Homebrew (`brew install hotdata-dev/tap/cli`) when `brew` is
present and otherwise drops a prebuilt binary into `~/.hotdata/cli`. It then
installs the agent skill for Claude Code and friends. Set `HOTDATA_NO_BREW=1`
to skip Homebrew, `HOTDATA_NO_SKILLS=1` to skip the skill. To build from
source instead: `cargo install --path .` (requires Rust).

Or grab a binary from [Releases](https://github.com/hotdata-dev/hotdata-cli/releases).
Stay current with `hotdata manage upgrade`; enable tab completion with
`hotdata manage completions bash|zsh|fish`.
Expand Down
4 changes: 4 additions & 0 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ build = ["tar", "-czf", "skills.tar.gz", "skills/"]
[[dist.extra-artifacts]]
artifacts = ["SKILL.md"]
build = ["cp", "skills/hotdata/SKILL.md", "SKILL.md"]

[[dist.extra-artifacts]]
artifacts = ["install.sh"]
build = ["cp", "scripts/install.sh", "install.sh"]
85 changes: 85 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/sh
# install.sh — one installer for Linux and macOS.
#
# If Homebrew is on the machine, install (or upgrade) through the tap so the
# binary is managed by brew and `hotdata manage upgrade` follows suit.
# Otherwise fall back to the cargo-dist shell installer, which drops a
# prebuilt binary into ~/.hotdata/cli.
#
# Usage:
# curl --proto '=https' --tlsv1.2 -LsSf https://github.com/hotdata-dev/hotdata-cli/releases/latest/download/install.sh | sh
#
# After the binary lands, the agent skill is installed too (`hotdata manage
# skills install`): it goes to ~/.agents/skills and is linked into ~/.claude
# when that directory exists, so Claude Code picks it up with no extra step.
#
# Environment:
# HOTDATA_NO_BREW=1 skip Homebrew even when it is installed
# HOTDATA_NO_SKILLS=1 install the binary only, skip the agent skill

set -eu

FORMULA="hotdata-dev/tap/cli"
REPO="https://github.com/hotdata-dev/hotdata-cli"
DIST_INSTALLER="$REPO/releases/latest/download/hotdata-cli-installer.sh"

find_brew() {
if command -v brew >/dev/null 2>&1; then
command -v brew
return 0
fi
for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew /home/linuxbrew/.linuxbrew/bin/brew; do
if [ -x "$candidate" ]; then
echo "$candidate"
return 0
fi
done
return 1
}

# Best-effort: a skill failure must not fail the install.
install_skills() {
bin="$1"
[ "${HOTDATA_NO_SKILLS:-}" = "1" ] && return 0
if [ ! -x "$bin" ]; then
echo "warning: $bin not found; run 'hotdata manage skills install' to add the agent skill" >&2
return 0
fi
echo "Installing the hotdata agent skill" >&2
"$bin" manage skills install --no-input \
|| echo "warning: skill install failed; run 'hotdata manage skills install' later" >&2
}

BREW=""
if [ "${HOTDATA_NO_BREW:-}" != "1" ]; then
BREW="$(find_brew || true)"
fi

if [ -n "$BREW" ]; then
echo "Homebrew found at $BREW; installing $FORMULA" >&2
if "$BREW" list --formula "$FORMULA" >/dev/null 2>&1; then
"$BREW" upgrade "$FORMULA"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Check the fully-qualified formula instead of the short name cli (not blocking).

Suggested change
"$BREW" upgrade "$FORMULA"
if "$BREW" list --formula "$FORMULA" >/dev/null 2>&1; then

The short name cli matches any installed formula named cli from any tap. A user with a different cli formula takes the upgrade branch. brew upgrade hotdata-dev/tap/cli then fails with "not installed", and set -e aborts the script.

else
"$BREW" install "$FORMULA"
fi
HOTDATA_BIN="$("$BREW" --prefix)/bin/hotdata"
echo "Installed $HOTDATA_BIN" >&2
install_skills "$HOTDATA_BIN"
exit 0
fi

echo "Homebrew not found; installing a prebuilt binary to ~/.hotdata/cli" >&2
# Download fully before running: plain sh has no pipefail, so a failed
# download piped into sh would otherwise "succeed" with nothing installed.
TMP="$(mktemp)"
trap 'rm -f "$TMP"' EXIT
if command -v curl >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -LsSf "$DIST_INSTALLER" -o "$TMP"
elif command -v wget >/dev/null 2>&1; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Download the dist installer fully before running it, so a failed download fails the script (not blocking).

POSIX sh has no pipefail. If curl fails here (404 before the next release, or a network error), sh reads empty input and exits 0. The script then reports success with no binary installed. CI jobs that use this installer pass silently. The wget branch on line 56 has the same problem.

Fix: capture the script first, for example script="$(curl --proto '=https' --tlsv1.2 -LsSf "$DIST_INSTALLER")" and then printf '%s\n' "$script" | sh. Under set -e, the failed assignment exits the script with an error.

wget -qO "$TMP" "$DIST_INSTALLER"
else
echo "error: need curl or wget to download the installer" >&2
exit 1
fi
sh "$TMP"
install_skills "$HOME/.hotdata/cli/hotdata"
Loading