diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fe6ddc3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +jobs: + go: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - run: go vet ./... + + - run: go test ./... + + - name: Cross-compile + run: | + for os in linux windows darwin; do + CGO_ENABLED=0 GOOS="$os" go build -o /dev/null ./... + done + + nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DeterminateSystems/nix-installer-action@v16 + + - run: nix build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..83ff045 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: release + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Build static binaries + run: | + version="${GITHUB_REF_NAME#v}" + for arch in amd64 arm64; do + out="dist/shared_${version}_linux_${arch}" + mkdir -p "$out" + CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \ + go build -trimpath -ldflags "-s -w" -o "$out/" ./cmd/... + tar -C "$out" -czf "$out.tar.gz" sharedd shared + + # windows is CLI-only; the server ships for linux + out="dist/shared_${version}_windows_${arch}" + mkdir -p "$out" + CGO_ENABLED=0 GOOS=windows GOARCH="$arch" \ + go build -trimpath -ldflags "-s -w" -o "$out/" ./cmd/shared + (cd "$out" && zip -q "../$(basename "$out").zip" shared.exe) + done + + - name: Create release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$GITHUB_REF_NAME" dist/*.tar.gz dist/*.zip \ + --title "$GITHUB_REF_NAME" --generate-notes diff --git a/README.md b/README.md index 8fabbcb..8cc708f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,121 @@ xdg-open http://hello.localhost:8787 ``` The homepage at `http://localhost:8787` lists all deployed sites, each with its -on-disk size and last-updated time. +on-disk size and last-updated time. Each site card also has a `×` button that +deletes the site and all its data (same as `shared rm`). + +## Install + +Two parts: `sharedd`, the server you host on one Linux box on your network, +and `shared`, the CLI you run from any machine to deploy to it. The server +only ships for Linux; the CLI ships for Linux and Windows. + +### Hosting the server + +**NixOS / Nix.** The flake packages both binaries: + +```sh +nix profile install github:sdelcore/shared +``` + +On NixOS, use the bundled module instead — it runs `sharedd` as a hardened +systemd service with state in `/var/lib/shared`: + +```nix +{ + inputs.shared.url = "github:sdelcore/shared"; +} +``` + +```nix +{ inputs, ... }: +{ + imports = [ inputs.shared.nixosModules.default ]; + + services.shared = { + enable = true; + baseHost = "shared.tap"; # sites at .shared.tap + openFirewall = true; + # environmentFile = "/run/secrets/shared.env"; # OPENAI_BASE_URL, OPENAI_API_KEY + }; +} +``` + +**Ubuntu / other Linux.** Download a static binary tarball from the +[releases page](https://github.com/sdelcore/shared/releases) and install it: + +```sh +tar -xzf shared_*_linux_amd64.tar.gz +sudo install -m 0755 sharedd shared /usr/local/bin/ +``` + +Or build from source. This needs Go 1.24+, which is newer than what Ubuntu +24.04's apt ships — install it from [go.dev/dl](https://go.dev/dl/): + +```sh +CGO_ENABLED=0 go install github.com/sdelcore/shared/cmd/...@latest +``` + +The binaries are pure Go and fully static; nothing else is required. To run +the server under systemd, drop this in `/etc/systemd/system/shared.service`: + +```ini +[Unit] +Description=shared site platform +After=network-online.target +Wants=network-online.target + +[Service] +ExecStart=/usr/local/bin/sharedd +Environment=SHARED_ADDR=:8787 +Environment=SHARED_DATA=/var/lib/shared +Environment=SHARED_BASE_HOST=localhost +DynamicUser=yes +StateDirectory=shared +WorkingDirectory=/var/lib/shared +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=multi-user.target +``` + +```sh +sudo systemctl daemon-reload +sudo systemctl enable --now shared +``` + +### Installing the CLI + +Any machine on the network can deploy to the server; point the CLI at it with +`--server` or `$SHARED_SERVER` (default `http://localhost:8787`). + +**Linux / macOS.** The linux release tarball above includes the CLI, or: + +```sh +go install github.com/sdelcore/shared/cmd/shared@latest +``` + +**Windows** (CLI only — the server is not supported on Windows). Download +`shared__windows_amd64.zip` (or `arm64`) from the +[releases page](https://github.com/sdelcore/shared/releases), unzip +`shared.exe` somewhere on `PATH`, and set the server once: + +```powershell +setx SHARED_SERVER http://shared.tap +shared list +``` + +**Or let your agent do it.** The repo ships an +[install-shared-cli](skills/install-shared-cli/SKILL.md) agent skill that +picks the right method for the current OS. Copy it into your agent's skill +directory and ask it to install the CLI: + +```sh +# Claude Code +git clone --depth 1 https://github.com/sdelcore/shared /tmp/shared-skill +cp -r /tmp/shared-skill/skills/install-shared-cli ~/.claude/skills/ +``` ## CLI diff --git a/cmd/shared/main.go b/cmd/shared/main.go index 936a937..58c6810 100644 --- a/cmd/shared/main.go +++ b/cmd/shared/main.go @@ -15,6 +15,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "time" @@ -276,7 +277,14 @@ func cmdOpen(args []string) { } siteURL := u.Scheme + "://" + host + "/" fmt.Println(siteURL) - exec.Command("xdg-open", siteURL).Start() + switch runtime.GOOS { + case "windows": + exec.Command("rundll32", "url.dll,FileProtocolHandler", siteURL).Start() + case "darwin": + exec.Command("open", siteURL).Start() + default: + exec.Command("xdg-open", siteURL).Start() + } } func cmdRm(args []string) { diff --git a/skills/install-shared-cli/SKILL.md b/skills/install-shared-cli/SKILL.md new file mode 100644 index 0000000..c8bb01d --- /dev/null +++ b/skills/install-shared-cli/SKILL.md @@ -0,0 +1,72 @@ +--- +name: install-shared-cli +description: Install or update the `shared` CLI — the deploy tool for the self-hosted shared static-site platform (github.com/sdelcore/shared) — picking the right method for the current OS. Use when the user asks to install, update, or set up the shared CLI, or when a `shared` command fails because the binary is missing. +--- + +# Install the shared CLI + +Installs `shared`, the CLI that talks to a shared server over HTTP +(`shared deploy`, `list`, `open`, `rm`, ...). The server (`sharedd`) runs +elsewhere on the network and is Linux-only — this skill never installs or +starts the server. Installing the CLI requires no privileges beyond writing +to a user-writable `PATH` directory. + +## Steps + +1. **Check if already installed**: if `shared --help` succeeds, skip to + step 3 (or reinstall with the same method if the user asked for an + update). + +2. **Install — first matching method wins**: + + - **Nix** (`nix --version` works): + + ```sh + nix profile install github:sdelcore/shared + ``` + + On NixOS with a flake-managed system config, offer to add it to the + system flake instead if the user prefers declarative installs. + + - **Go 1.24+** (`go version` shows go1.24 or newer): + + ```sh + CGO_ENABLED=0 go install github.com/sdelcore/shared/cmd/shared@latest + ``` + + Verify `$(go env GOPATH)/bin` is on `PATH`; add it to the shell profile + if not. + + - **Release binary** (Linux and Windows only; macOS must use Go or Nix): + find the latest version tag: + + ```sh + curl -s https://api.github.com/repos/sdelcore/shared/releases/latest + ``` + + Download the asset for the OS/arch (note: no `v` prefix in filenames; + `VERSION` is the tag minus `v`): + + | OS | Asset | Contains | + |---------|----------------------------------------|--------------------| + | Linux | `shared_VERSION_linux_{amd64,arm64}.tar.gz` | `sharedd` + `shared` (install only `shared`) | + | Windows | `shared_VERSION_windows_{amd64,arm64}.zip` | `shared.exe` | + + Linux: extract and `install -m 0755 shared ~/.local/bin/` (or + `/usr/local/bin` if the user prefers and has sudo). Windows: unzip + `shared.exe` into a directory on `PATH`, e.g. + `%LOCALAPPDATA%\Programs\shared\`, creating it and appending it to the + user `PATH` if needed. + +3. **Point it at the server**: `shared` defaults to + `http://localhost:8787`, which is almost never right for a CLI-only + machine. Ask the user for their server URL (e.g. `http://shared.tap` or + `http://:8787`) if it isn't already known, then persist it: + + - Unix shells: `export SHARED_SERVER=` in the shell profile + - Windows: `setx SHARED_SERVER ` (takes effect in new terminals) + +4. **Verify end to end**: run `shared list` (in a fresh environment where + `SHARED_SERVER` is set). It should print the deployed sites or an empty + list; a connection error means the URL is wrong or the server is + unreachable — troubleshoot with the user rather than reinstalling.