openvibers/openvibe.link Commits
Every system: Windows ARM64, Linux .deb/.rpm/tarballs and macOS tarballs on each release (#134)
Changes
@@@ -82,9 +82,41 @@ jobs:- uses: actions/setup-go@v5with:go-version-file: go.mod++ # The packages are built on every run so a broken .deb/.rpm is caught before a tag: dpkg-deb ships with Ubuntu,++ # rpm (rpmbuild) does not.++ - run: sudo apt-get update -qq && sudo apt-get install -y -qq rpm- run: scripts/dist.sh ci# OpenVibe.Bot's /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this exact release asset.- run: test -s dist/install.sh && cmp -s install/install.sh dist/install.sh++ - name: every OS, architecture and package the release promises is in dist++ run: |++ for f in \++ dist/openvibe-link-linux-amd64 dist/openvibe-link-linux-arm64 \++ dist/openvibe-link-darwin-amd64 dist/openvibe-link-darwin-arm64 \++ dist/openvibe-link-windows-amd64.exe dist/openvibe-link-windows-arm64.exe \++ dist/openvibe-link_*_amd64.deb dist/openvibe-link_*_arm64.deb \++ dist/openvibe-link-*-1.x86_64.rpm dist/openvibe-link-*-1.aarch64.rpm \++ dist/openvibe-link_*_linux_amd64.tar.gz dist/openvibe-link_*_linux_arm64.tar.gz \++ dist/openvibe-link_*_darwin_amd64.tar.gz dist/openvibe-link_*_darwin_arm64.tar.gz; do++ test -s "$f" || { echo "missing $f"; exit 1; }++ done++ - name: the packages carry the program and the alias, not just a file++ run: |++ for f in dist/*.deb; do++ dpkg-deb -c "$f" > /tmp/pkg.txt++ grep -q 'usr/local/bin/openvibe-link$' /tmp/pkg.txt++ grep -q 'usr/local/bin/openvibe-node -> openvibe-link$' /tmp/pkg.txt++ done++ for f in dist/*.rpm; do++ rpm -qpl "$f" > /tmp/pkg.txt++ grep -qx '/usr/local/bin/openvibe-link' /tmp/pkg.txt++ grep -qx '/usr/local/bin/openvibe-node' /tmp/pkg.txt++ done++ for f in dist/openvibe-link_*.tar.gz; do++ tar -tzf "$f" > /tmp/pkg.txt++ grep -q '/install.sh$' /tmp/pkg.txt++ grep -q '/README.md$' /tmp/pkg.txt++ done- run: ls -l dist && cat dist/SHA256SUMSgo-other-os:@@@ -24,21 +24,34 @@ jobs:- run: go vet ./... && go test -count=1 ./...- run: |for p in sdk dryrun adeept_adr036 cozmo relay ros2 computer voice; do python -m pytest -q plugins/$p/tests; done++ # The packages are built on every tag, and CI already built them on the PR that made this commit: rpm is the++ # only tool Ubuntu does not ship.++ - run: sudo apt-get update -qq && sudo apt-get install -y -qq rpm- run: scripts/dist.sh "${GITHUB_REF_NAME}"# Every release must carry the installer OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are-- # documented to serve (releases/latest/download/install.sh), the plugin bundle the installer downloads, and the-- # checksums it verifies them against.-- - name: the release carries the assets the installer and OpenVibe.Bot depend on++ # documented to serve (releases/latest/download/install.sh), the plugin bundle the installer downloads, every++ # OS/architecture the site offers, and the checksums they are verified against.++ - name: the release carries every OS, architecture and package the site offersrun: |test -s dist/install.shtest -s dist/openvibe-node-plugins.tar.gztest -s dist/SHA256SUMS-- # The new name and the alias it replaces are both in every release for a year (plan 2026-11-07 §5).-- test -s dist/openvibe-link-linux-amd64-- test -s dist/openvibe-node-linux-amd64-- test -s dist/openvibe-link-windows-amd64.exe-- test -s dist/openvibe-node-windows-amd64.exe++ for f in \++ dist/openvibe-link-linux-amd64 dist/openvibe-link-linux-arm64 \++ dist/openvibe-link-darwin-amd64 dist/openvibe-link-darwin-arm64 \++ dist/openvibe-link-windows-amd64.exe dist/openvibe-link-windows-arm64.exe \++ dist/openvibe-link_*_amd64.deb dist/openvibe-link_*_arm64.deb \++ dist/openvibe-link-*-1.x86_64.rpm dist/openvibe-link-*-1.aarch64.rpm \++ dist/openvibe-link_*_linux_amd64.tar.gz dist/openvibe-link_*_linux_arm64.tar.gz \++ dist/openvibe-link_*_darwin_amd64.tar.gz dist/openvibe-link_*_darwin_arm64.tar.gz \++ dist/openvibe-node-linux-amd64 dist/openvibe-node-windows-amd64.exe; do++ test -s "$f" || { echo "missing $f"; exit 1; }++ done- name: publish the releaseenv:GH_TOKEN: ${{ github.token }}-- run: gh release create "${GITHUB_REF_NAME}" dist/* --title "OpenVibe Link ${GITHUB_REF_NAME}" --generate-notes++ # The Android workflow also attaches its APK on a tag, and either job may reach the release first: create it++ # only when it is absent, then upload (clobber) so both workflows can publish to the same tag.++ run: |++ gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1 || gh release create "${GITHUB_REF_NAME}" --title "OpenVibe Link ${GITHUB_REF_NAME}" --generate-notes++ gh release upload "${GITHUB_REF_NAME}" dist/* --clobber@@@ -8,6 +8,11 @@ One service for your computers, servers, Raspberry Pis, phones and robots: pairlike **OpenVibe.Bot** (robots: drive, cameras, sensors, with safety) and **OpenVibe.Actor** (computer control for AIagents, at the level you set on the machine) can use the device. It connects out, needs no open ports, and keeps a local kill switch.++Every release is built by CI for every system: **Windows x64 and ARM64**, **macOS Apple silicon and Intel**, **Linux++x64 and ARM64** (`.deb`, `.rpm`, a tarball, and the `curl | sh` script), and the **Android APK**. The++[openvibe.link install page](https://openvibe.link/#install) picks the visitor's OS and offers the others; the++[install guide](docs/install.md) has the exact steps, including the home-screen web app for iPhone and iPad.++On a robot's Raspberry Pi (or other Linux computer), the one command:```sh@@@ -3,16 +3,101 @@OpenVibe Link is one program, `openvibe-link` (`openvibe-node` is kept as an alias), plus Python plugins for robots. It connects **out** to OpenVibe (no openports, works behind any home router), and a local kill switch stops everything it drives.++++## Install on your OS++++Every release is built by CI on the tag and carries the same program for each system: Windows x64 and ARM64, macOS++Apple silicon and Intel, Linux x64 and ARM64 (.deb, .rpm, tarball and the `curl | sh` script), and the Android APK.++Links for every file are on [openvibe.link](https://openvibe.link/#install); the release page has the same files and++`SHA256SUMS`.++++### Windows (x64 and ARM64)++++1. Download `openvibe-link-windows-amd64.exe` (x64) or `openvibe-link-windows-arm64.exe` (ARM64) from++ [openvibe.link](https://openvibe.link/#install) or the latest release.++2. Windows may show SmartScreen the first time: **More info** → **Run anyway**.++3. In an **Administrator** PowerShell, from the folder you saved it in:++++ ```powershell++ .\openvibe-link pair <CODE>++ .\openvibe-link install++ ```++++ The code comes from [openvibe.bot/machines](https://openvibe.bot/machines) (**Add a machine**).++4. `openvibe-link status` shows the link; the machine appears in your account's machines.++++`openvibe-node.exe` is the same program under its old name, so an existing shortcut or script keeps working.++++### macOS (Apple silicon and Intel)++++The one command installs the right build and the launchd service:++++```sh++curl -fsSL https://openvibe.link/install | sh++```++++Or download the program: `openvibe-link-darwin-arm64` (Apple silicon) or `openvibe-link-darwin-amd64` (Intel), or the++tarball `openvibe-link_<version>_darwin_arm64.tar.gz` / `..._darwin_amd64.tar.gz` with `install.sh` and the plugins++beside it. Gatekeeper: right-click the file and choose **Open** the first time. Then:++++```sh++sudo ./openvibe-link pair <CODE>++sudo ./openvibe-link install++```++++The same command works on a Raspberry Pi or another Linux robot and also finds the kit and its driver.++++### Linux (x64 and ARM64: .deb, .rpm, tarball, script)++++The one command, on any distribution, finds the CPU and installs the systemd service:++++```sh++curl -fsSL https://openvibe.link/install | sh++```++++Or use the package for your distribution:++++```sh++sudo apt install ./openvibe-link_<version>_amd64.deb # Debian, Ubuntu (x64; _arm64.deb on ARM64)++sudo dnf install ./openvibe-link-<version>-1.x86_64.rpm # Fedora, RHEL (aarch64 on ARM64)++```++++The packages put `openvibe-link` in `/usr/local/bin` and make `openvibe-node` a symlink to it; they do not start or++pair anything by themselves. Then:++++```sh++openvibe-link pair <CODE>++sudo openvibe-link install++```++++The tarballs (`openvibe-link_<version>_linux_amd64.tar.gz` and `..._linux_arm64.tar.gz`) carry the program, the++plugin bundle and `install.sh`; unpack one and run `sudo ./install.sh --local .`.++++### Android (the existing APK)++++Download `openvibe-link-<tag>.apk` on the phone, allow installing from that source when Android asks, and open++**OpenVibe Link**. Pair with a code from [openvibe.bot/link/phone](https://openvibe.bot/link/phone). This is the direct++APK, not Google Play; it has approvals, Activity, pairing and **Send to OpenVibe**, and no phone automation. Details:++[android.md](android.md).++++### iPhone and iPad (what works today)++++There is no native iOS app yet. The home-screen web app works now: open [openvibe.my](https://openvibe.my/) in Safari,++sign in, then **Share** → **Add to Home Screen**. It gives you **Approvals**, **Activity**, your **machines** and++pairing from the phone.++++A native iOS app, push notifications and a background Link connection wait on an Apple Developer account and the App++Store review that follows it; nothing here pretends they already work.++## The one command (Raspberry Pi and other Linux robots)On the robot's computer, with nothing set up on openvibe.bot first:```sh--curl -fsSL https://node.openvibe.network/install | sh++curl -fsSL https://openvibe.link/install | sh```--The same installer is also at <https://openvibe.bot/install>, which keeps working; `node.openvibe.network` is the--Node's own address and has a page that says what it is and how to install it.++The same installer is also at <https://openvibe.bot/install>, which keeps working; `node.openvibe.network/install` keeps working and sends you to openvibe.link.On a Raspberry Pi it turns on I2C and SPI (now and after a reboot, through `raspi-config`), installs what is missing of`i2c-tools`, the camera tools (`rpicam-apps`), `python3-venv`, `python3-lgpio` and `qrencode`, and looks at the I2C bus:@@@ -48,7 +133,7 @@ write Raspberry Pi OS Lite (64-bit) with Raspberry Pi Imager, copy the page's `ucard's `bootfs` drive, and switch the robot on. On first boot the Pi joins your Wi-Fi, turns on SSH, and runs```sh--curl -fsSL https://node.openvibe.network/install | sh -s -- --setup osk_…++curl -fsSL https://openvibe.link/install | sh -s -- --setup osk_…```with the card's setup key (`OPENVIBE_SETUP_KEY` works too). openvibe.bot approves that claim at once for the person who@@@ -63,7 +148,7 @@ Its output is in `journalctl -u openvibe-setup` on the Pi.2. On the device, run that command, adding `--driver` for your robot:```sh-- curl -fsSL https://node.openvibe.network/install | sh -s -- --robot rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X --code ABCD-1234 --driver adeept++ curl -fsSL https://openvibe.link/install | sh -s -- --robot rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X --code ABCD-1234 --driver adeept```The shape is `--robot rob_… --code CODE [--driver adeept|adeept-mecanum|cozmo|looi|ros2|ros2-holonomic|none]`. `--robot` is the robot's@@@ -94,7 +179,7 @@ has the details.- **Network pairing**: `--network <URL> --pairing pair_… --code CODE`, e.g.```sh-- curl -fsSL https://node.openvibe.network/install | sh -s -- --network https://openvibe.network --pairing pair_01J8Z4M2Q0R7T9YV3K6N8P1W2Y --code ABCD-1234 --driver adeept++ curl -fsSL https://openvibe.link/install | sh -s -- --network https://openvibe.network --pairing pair_01J8Z4M2Q0R7T9YV3K6N8P1W2Y --code ABCD-1234 --driver adeept```The Node redeems the code on OpenVibe.Network (`POST <network>/api/v1/node-pairing`) and stores the machine's node@@@ -6,7 +6,7 @@ VERSION="${1:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}"cd "$(dirname "$0")/.."rm -rf distmkdir -p dist--for target in linux/amd64 linux/arm64 linux/arm/7 darwin/amd64 darwin/arm64 windows/amd64; do++for target in linux/amd64 linux/arm64 linux/arm/7 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; doos="${target%%/*}"rest="${target#*/}"arch="${rest%%/*}"@@@ -32,5 +32,7 @@ tar -czf dist/openvibe-node-plugins.tar.gz -C plugins \# OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this asset name:# https://github.com/OpenVibers/OpenVibe.Node/releases/latest/download/install.sh — do not rename it.cp install/install.sh dist/install.sh++# Friendly Linux and macOS artifacts: .deb, .rpm and a tarball per architecture, from the binaries above.++scripts/package.sh "$VERSION"(cd dist && if command -v sha256sum >/dev/null 2>&1; then sha256sum -- * >SHA256SUMS; else shasum -a 256 -- * >SHA256SUMS; fi)echo "dist/ ready for $VERSION"nnew file mode 100755@@@ -0,0 +1,140 @@++#!/bin/sh++# Build the friendly Linux and macOS artifacts from the binaries dist.sh just built:++# .deb, .rpm and a .tar.gz for Linux amd64 and arm64, and a .tar.gz for macOS arm64 and amd64.++# The binaries themselves stay in dist/ for the curl | sh installer and for direct download.++# scripts/package.sh VERSION++set -eu++VERSION="${1:?usage: scripts/package.sh VERSION}"++cd "$(dirname "$0")/.."++++# Package versions cannot carry a leading v or arbitrary git describe text: keep RPM and dpkg happy, and keep the++# version visible to a person. v0.45.0 -> 0.45.0; v0.0.0-dev -> 0.0.0.dev.++pkgver="${VERSION#v}"++pkgver="$(printf '%s' "$pkgver" | sed 's/[^A-Za-z0-9.+~]/./g')"++[ -n "$pkgver" ] || pkgver=0.0.0++# dpkg refuses a version that does not start with a digit; the CI build is version "ci".++case "$pkgver" in [0-9]*) ;; *) pkgver="0.$pkgver" ;; esac++++work="$(mktemp -d)"++trap 'rm -rf "$work"' EXIT++++# docs every package and tarball carries next to the program++docs() {++ dir="$1"++ mkdir -p "$dir"++ cp README.md "$dir/README.md"++ cp docs/install.md "$dir/install.md"++}++++# ---- tarballs: Linux and macOS, one per architecture ----++for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do++ os="${target%%/*}"++ arch="${target##*/}"++ case "$os/$arch" in++ linux/amd64|linux/arm64) bin="dist/openvibe-link-linux-$arch" ;;++ darwin/amd64|darwin/arm64) bin="dist/openvibe-link-darwin-$arch" ;;++ *) echo "package: no tarball rule for $target" >&2; exit 1 ;;++ esac++ test -s "$bin" || { echo "package: $bin is missing (run scripts/dist.sh first)" >&2; exit 1; }++++ root="$work/openvibe-link-$pkgver-$os-$arch"++ mkdir -p "$root"++ # The installer's --local layout: the OS-specific binary name and the plugin bundle beside install.sh.++ cp "$bin" "$root/openvibe-link-$os-$arch"++ cp "$bin" "$root/openvibe-node-$os-$arch"++ cp dist/openvibe-node-plugins.tar.gz "$root/"++ cp install/install.sh "$root/install.sh"++ docs "$root"++ tar -czf "dist/openvibe-link_${pkgver}_${os}_${arch}.tar.gz" -C "$work" "openvibe-link-$pkgver-$os-$arch"++ echo "built dist/openvibe-link_${pkgver}_${os}_${arch}.tar.gz"++done++++# ---- .deb: the program and the old-name alias, plus docs; no scripts, no network in postinst ----++for arch in amd64 arm64; do++ bin="dist/openvibe-link-linux-$arch"++ test -s "$bin" || { echo "package: $bin is missing" >&2; exit 1; }++ root="$work/deb-$arch"++ mkdir -p "$root/DEBIAN" "$root/usr/local/bin" "$root/usr/share/doc/openvibe-link"++ install -m 0755 "$bin" "$root/usr/local/bin/openvibe-link"++ ln -s openvibe-link "$root/usr/local/bin/openvibe-node"++ cp README.md "$root/usr/share/doc/openvibe-link/README.md"++ cp docs/install.md "$root/usr/share/doc/openvibe-link/install.md"++ size="$(du -sk "$root/usr" | cut -f1)"++ cat >"$root/DEBIAN/control" <<EOF++Package: openvibe-link++Version: $pkgver++Section: net++Priority: optional++Architecture: $arch++Maintainer: OpenVibe <[email protected]>++Installed-Size: $size++Depends: ca-certificates++Homepage: https://openvibe.link++Description: OpenVibe Link: your machines, connected++ OpenVibe Link runs on your computer or server and connects out to OpenVibe: your agents can use it only as far as++ you allow, and you choose what it offers the network. The openvibe-node command is kept as an alias.++EOF++ ( cd "$root" && find . -type f -exec md5sum {} + | sed 's| \./| |' | sort -k2 >DEBIAN/md5sums )++ dpkg-deb --build --root-owner-group "$root" "dist/openvibe-link_${pkgver}_${arch}.deb" >/dev/null++ echo "built dist/openvibe-link_${pkgver}_${arch}.deb"++done++++# ---- .rpm: the same contents, built with rpmbuild; CI installs rpm, a local run skips it with a warning ----++if command -v rpmbuild >/dev/null 2>&1; then++ for pair in amd64:x86_64 arm64:aarch64; do++ arch="${pair%%:*}"++ rpmarch="${pair##*:}"++ bin="dist/openvibe-link-linux-$arch"++ test -s "$bin" || { echo "package: $bin is missing" >&2; exit 1; }++ top="$work/rpm-$rpmarch"++ mkdir -p "$top/SOURCES" "$top/SPECS" "$top/BUILD" "$top/BUILDROOT" "$top/RPMS" "$top/SRPMS"++ cp "$bin" "$top/SOURCES/openvibe-link"++ cp README.md "$top/SOURCES/README.md"++ cp docs/install.md "$top/SOURCES/install.md"++ cat >"$top/SPECS/openvibe-link.spec" <<EOF++Name: openvibe-link++Version: $pkgver++Release: 1++Summary: OpenVibe Link: your machines, connected++License: AGPL-3.0++URL: https://openvibe.link++Source0: openvibe-link++Source1: README.md++Source2: install.md++AutoReqProv: no++%global debug_package %{nil}++%global _build_id_links none++++%description++OpenVibe Link runs on your computer or server and connects out to OpenVibe: your agents++can use it only as far as you allow, and you choose what it offers the network. The++openvibe-node command is kept as an alias.++++%prep++++%build++++%install++mkdir -p %{buildroot}/usr/local/bin %{buildroot}/usr/share/doc/openvibe-link++install -m 0755 %{SOURCE0} %{buildroot}/usr/local/bin/openvibe-link++ln -s openvibe-link %{buildroot}/usr/local/bin/openvibe-node++install -m 0644 %{SOURCE1} %{buildroot}/usr/share/doc/openvibe-link/README.md++install -m 0644 %{SOURCE2} %{buildroot}/usr/share/doc/openvibe-link/install.md++++%files++/usr/local/bin/openvibe-link++/usr/local/bin/openvibe-node++/usr/share/doc/openvibe-link/README.md++/usr/share/doc/openvibe-link/install.md++EOF++ rpmbuild -bb --quiet --define "_topdir $top" --define "_arch $rpmarch" --define "_build_arch $rpmarch" \++ --define "_target_cpu $rpmarch" --define "_target_os linux" "$top/SPECS/openvibe-link.spec" \++ >/dev/null 2>"$work/rpm-$rpmarch.err" || { cat "$work/rpm-$rpmarch.err" >&2; exit 1; }++ cp "$top"/RPMS/"$rpmarch"/*.rpm "dist/openvibe-link-${pkgver}-1.${rpmarch}.rpm"++ echo "built dist/openvibe-link-${pkgver}-1.${rpmarch}.rpm"++ done++else++ echo "package: rpmbuild is not installed here; skipped the .rpm (CI installs rpm and builds it)" >&2++fi++++echo "packages ready for $VERSION"
@@ -82,9 +82,41 @@ jobs:
@@ -82,9 +82,41 @@ jobs:
- uses: actions/setup-go@v5
- uses: actions/setup-go@v5
with:
with:
go-version-file: go.mod
go-version-file: go.mod
+ # The packages are built on every run so a broken .deb/.rpm is caught before a tag: dpkg-deb ships with Ubuntu,
+ # rpm (rpmbuild) does not.
+ - run: sudo apt-get update -qq && sudo apt-get install -y -qq rpm
- run: scripts/dist.sh ci
- run: scripts/dist.sh ci
# OpenVibe.Bot's /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this exact release asset.
# OpenVibe.Bot's /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this exact release asset.
- run: test -s dist/install.sh && cmp -s install/install.sh dist/install.sh
- run: test -s dist/install.sh && cmp -s install/install.sh dist/install.sh
+ - name: every OS, architecture and package the release promises is in dist
+ run: |
+ for f in \
+ dist/openvibe-link-linux-amd64 dist/openvibe-link-linux-arm64 \
+ dist/openvibe-link-darwin-amd64 dist/openvibe-link-darwin-arm64 \
+ dist/openvibe-link-windows-amd64.exe dist/openvibe-link-windows-arm64.exe \
+ dist/openvibe-link_*_amd64.deb dist/openvibe-link_*_arm64.deb \
+ dist/openvibe-link-*-1.x86_64.rpm dist/openvibe-link-*-1.aarch64.rpm \
+ dist/openvibe-link_*_linux_amd64.tar.gz dist/openvibe-link_*_linux_arm64.tar.gz \
+ dist/openvibe-link_*_darwin_amd64.tar.gz dist/openvibe-link_*_darwin_arm64.tar.gz; do
+ test -s "$f" || { echo "missing $f"; exit 1; }
+ done
+ - name: the packages carry the program and the alias, not just a file
+ run: |
+ for f in dist/*.deb; do
+ dpkg-deb -c "$f" > /tmp/pkg.txt
+ grep -q 'usr/local/bin/openvibe-link$' /tmp/pkg.txt
+ grep -q 'usr/local/bin/openvibe-node -> openvibe-link$' /tmp/pkg.txt
+ done
+ for f in dist/*.rpm; do
+ rpm -qpl "$f" > /tmp/pkg.txt
+ grep -qx '/usr/local/bin/openvibe-link' /tmp/pkg.txt
+ grep -qx '/usr/local/bin/openvibe-node' /tmp/pkg.txt
+ done
+ for f in dist/openvibe-link_*.tar.gz; do
+ tar -tzf "$f" > /tmp/pkg.txt
+ grep -q '/install.sh$' /tmp/pkg.txt
+ grep -q '/README.md$' /tmp/pkg.txt
+ done
- run: ls -l dist && cat dist/SHA256SUMS
- run: ls -l dist && cat dist/SHA256SUMS
go-other-os:
go-other-os:
@@ -24,21 +24,34 @@ jobs:
@@ -24,21 +24,34 @@ jobs:
- run: go vet ./... && go test -count=1 ./...
- run: go vet ./... && go test -count=1 ./...
- run: |
- run: |
for p in sdk dryrun adeept_adr036 cozmo relay ros2 computer voice; do python -m pytest -q plugins/$p/tests; done
for p in sdk dryrun adeept_adr036 cozmo relay ros2 computer voice; do python -m pytest -q plugins/$p/tests; done
+ # The packages are built on every tag, and CI already built them on the PR that made this commit: rpm is the
+ # only tool Ubuntu does not ship.
+ - run: sudo apt-get update -qq && sudo apt-get install -y -qq rpm
- run: scripts/dist.sh "${GITHUB_REF_NAME}"
- run: scripts/dist.sh "${GITHUB_REF_NAME}"
# Every release must carry the installer OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are
# Every release must carry the installer OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are
- # documented to serve (releases/latest/download/install.sh), the plugin bundle the installer downloads, and the
- # checksums it verifies them against.
- - name: the release carries the assets the installer and OpenVibe.Bot depend on
+ # documented to serve (releases/latest/download/install.sh), the plugin bundle the installer downloads, every
+ # OS/architecture the site offers, and the checksums they are verified against.
+ - name: the release carries every OS, architecture and package the site offers
run: |
run: |
test -s dist/install.sh
test -s dist/install.sh
test -s dist/openvibe-node-plugins.tar.gz
test -s dist/openvibe-node-plugins.tar.gz
test -s dist/SHA256SUMS
test -s dist/SHA256SUMS
- # The new name and the alias it replaces are both in every release for a year (plan 2026-11-07 §5).
- test -s dist/openvibe-link-linux-amd64
- test -s dist/openvibe-node-linux-amd64
- test -s dist/openvibe-link-windows-amd64.exe
- test -s dist/openvibe-node-windows-amd64.exe
+ for f in \
+ dist/openvibe-link-linux-amd64 dist/openvibe-link-linux-arm64 \
+ dist/openvibe-link-darwin-amd64 dist/openvibe-link-darwin-arm64 \
+ dist/openvibe-link-windows-amd64.exe dist/openvibe-link-windows-arm64.exe \
+ dist/openvibe-link_*_amd64.deb dist/openvibe-link_*_arm64.deb \
+ dist/openvibe-link-*-1.x86_64.rpm dist/openvibe-link-*-1.aarch64.rpm \
+ dist/openvibe-link_*_linux_amd64.tar.gz dist/openvibe-link_*_linux_arm64.tar.gz \
+ dist/openvibe-link_*_darwin_amd64.tar.gz dist/openvibe-link_*_darwin_arm64.tar.gz \
+ dist/openvibe-node-linux-amd64 dist/openvibe-node-windows-amd64.exe; do
+ test -s "$f" || { echo "missing $f"; exit 1; }
+ done
- name: publish the release
- name: publish the release
env:
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ github.token }}
- run: gh release create "${GITHUB_REF_NAME}" dist/* --title "OpenVibe Link ${GITHUB_REF_NAME}" --generate-notes
+ # The Android workflow also attaches its APK on a tag, and either job may reach the release first: create it
+ # only when it is absent, then upload (clobber) so both workflows can publish to the same tag.
+ run: |
+ gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1 || gh release create "${GITHUB_REF_NAME}" --title "OpenVibe Link ${GITHUB_REF_NAME}" --generate-notes
+ gh release upload "${GITHUB_REF_NAME}" dist/* --clobber
@@ -8,6 +8,11 @@ One service for your computers, servers, Raspberry Pis, phones and robots: pair
@@ -8,6 +8,11 @@ One service for your computers, servers, Raspberry Pis, phones and robots: pair
like **OpenVibe.Bot** (robots: drive, cameras, sensors, with safety) and **OpenVibe.Actor** (computer control for AI
like **OpenVibe.Bot** (robots: drive, cameras, sensors, with safety) and **OpenVibe.Actor** (computer control for AI
agents, at the level you set on the machine) can use the device. It connects out, needs no open ports, and keeps a local kill switch.
agents, at the level you set on the machine) can use the device. It connects out, needs no open ports, and keeps a local kill switch.
+Every release is built by CI for every system: **Windows x64 and ARM64**, **macOS Apple silicon and Intel**, **Linux
+x64 and ARM64** (`.deb`, `.rpm`, a tarball, and the `curl | sh` script), and the **Android APK**. The
+[openvibe.link install page](https://openvibe.link/#install) picks the visitor's OS and offers the others; the
+[install guide](docs/install.md) has the exact steps, including the home-screen web app for iPhone and iPad.
+
On a robot's Raspberry Pi (or other Linux computer), the one command:
On a robot's Raspberry Pi (or other Linux computer), the one command:
```sh
```sh
@@ -3,16 +3,101 @@
@@ -3,16 +3,101 @@
OpenVibe Link is one program, `openvibe-link` (`openvibe-node` is kept as an alias), plus Python plugins for robots. It connects **out** to OpenVibe (no open
OpenVibe Link is one program, `openvibe-link` (`openvibe-node` is kept as an alias), plus Python plugins for robots. It connects **out** to OpenVibe (no open
ports, works behind any home router), and a local kill switch stops everything it drives.
ports, works behind any home router), and a local kill switch stops everything it drives.
+
+## Install on your OS
+
+Every release is built by CI on the tag and carries the same program for each system: Windows x64 and ARM64, macOS
+Apple silicon and Intel, Linux x64 and ARM64 (.deb, .rpm, tarball and the `curl | sh` script), and the Android APK.
+Links for every file are on [openvibe.link](https://openvibe.link/#install); the release page has the same files and
+`SHA256SUMS`.
+
+### Windows (x64 and ARM64)
+
+1. Download `openvibe-link-windows-amd64.exe` (x64) or `openvibe-link-windows-arm64.exe` (ARM64) from
+ [openvibe.link](https://openvibe.link/#install) or the latest release.
+2. Windows may show SmartScreen the first time: **More info** → **Run anyway**.
+3. In an **Administrator** PowerShell, from the folder you saved it in:
+
+ ```powershell
+ .\openvibe-link pair <CODE>
+ .\openvibe-link install
+ ```
+
+ The code comes from [openvibe.bot/machines](https://openvibe.bot/machines) (**Add a machine**).
+4. `openvibe-link status` shows the link; the machine appears in your account's machines.
+
+`openvibe-node.exe` is the same program under its old name, so an existing shortcut or script keeps working.
+
+### macOS (Apple silicon and Intel)
+
+The one command installs the right build and the launchd service:
+
+```sh
+curl -fsSL https://openvibe.link/install | sh
+```
+
+Or download the program: `openvibe-link-darwin-arm64` (Apple silicon) or `openvibe-link-darwin-amd64` (Intel), or the
+tarball `openvibe-link_<version>_darwin_arm64.tar.gz` / `..._darwin_amd64.tar.gz` with `install.sh` and the plugins
+beside it. Gatekeeper: right-click the file and choose **Open** the first time. Then:
+
+```sh
+sudo ./openvibe-link pair <CODE>
+sudo ./openvibe-link install
+```
+
+The same command works on a Raspberry Pi or another Linux robot and also finds the kit and its driver.
+
+### Linux (x64 and ARM64: .deb, .rpm, tarball, script)
+
+The one command, on any distribution, finds the CPU and installs the systemd service:
+
+```sh
+curl -fsSL https://openvibe.link/install | sh
+```
+
+Or use the package for your distribution:
+
+```sh
+sudo apt install ./openvibe-link_<version>_amd64.deb # Debian, Ubuntu (x64; _arm64.deb on ARM64)
+sudo dnf install ./openvibe-link-<version>-1.x86_64.rpm # Fedora, RHEL (aarch64 on ARM64)
+```
+
+The packages put `openvibe-link` in `/usr/local/bin` and make `openvibe-node` a symlink to it; they do not start or
+pair anything by themselves. Then:
+
+```sh
+openvibe-link pair <CODE>
+sudo openvibe-link install
+```
+
+The tarballs (`openvibe-link_<version>_linux_amd64.tar.gz` and `..._linux_arm64.tar.gz`) carry the program, the
+plugin bundle and `install.sh`; unpack one and run `sudo ./install.sh --local .`.
+
+### Android (the existing APK)
+
+Download `openvibe-link-<tag>.apk` on the phone, allow installing from that source when Android asks, and open
+**OpenVibe Link**. Pair with a code from [openvibe.bot/link/phone](https://openvibe.bot/link/phone). This is the direct
+APK, not Google Play; it has approvals, Activity, pairing and **Send to OpenVibe**, and no phone automation. Details:
+[android.md](android.md).
+
+### iPhone and iPad (what works today)
+
+There is no native iOS app yet. The home-screen web app works now: open [openvibe.my](https://openvibe.my/) in Safari,
+sign in, then **Share** → **Add to Home Screen**. It gives you **Approvals**, **Activity**, your **machines** and
+pairing from the phone.
+
+A native iOS app, push notifications and a background Link connection wait on an Apple Developer account and the App
+Store review that follows it; nothing here pretends they already work.
+
## The one command (Raspberry Pi and other Linux robots)
## The one command (Raspberry Pi and other Linux robots)
On the robot's computer, with nothing set up on openvibe.bot first:
On the robot's computer, with nothing set up on openvibe.bot first:
```sh
```sh
-curl -fsSL https://node.openvibe.network/install | sh
+curl -fsSL https://openvibe.link/install | sh
```
```
-The same installer is also at <https://openvibe.bot/install>, which keeps working; `node.openvibe.network` is the
-Node's own address and has a page that says what it is and how to install it.
+The same installer is also at <https://openvibe.bot/install>, which keeps working; `node.openvibe.network/install` keeps working and sends you to openvibe.link.
On a Raspberry Pi it turns on I2C and SPI (now and after a reboot, through `raspi-config`), installs what is missing of
On a Raspberry Pi it turns on I2C and SPI (now and after a reboot, through `raspi-config`), installs what is missing of
`i2c-tools`, the camera tools (`rpicam-apps`), `python3-venv`, `python3-lgpio` and `qrencode`, and looks at the I2C bus:
`i2c-tools`, the camera tools (`rpicam-apps`), `python3-venv`, `python3-lgpio` and `qrencode`, and looks at the I2C bus:
@@ -48,7 +133,7 @@ write Raspberry Pi OS Lite (64-bit) with Raspberry Pi Imager, copy the page's `u
@@ -48,7 +133,7 @@ write Raspberry Pi OS Lite (64-bit) with Raspberry Pi Imager, copy the page's `u
card's `bootfs` drive, and switch the robot on. On first boot the Pi joins your Wi-Fi, turns on SSH, and runs
card's `bootfs` drive, and switch the robot on. On first boot the Pi joins your Wi-Fi, turns on SSH, and runs
```sh
```sh
-curl -fsSL https://node.openvibe.network/install | sh -s -- --setup osk_…
+curl -fsSL https://openvibe.link/install | sh -s -- --setup osk_…
```
```
with the card's setup key (`OPENVIBE_SETUP_KEY` works too). openvibe.bot approves that claim at once for the person who
with the card's setup key (`OPENVIBE_SETUP_KEY` works too). openvibe.bot approves that claim at once for the person who
@@ -63,7 +148,7 @@ Its output is in `journalctl -u openvibe-setup` on the Pi.
@@ -63,7 +148,7 @@ Its output is in `journalctl -u openvibe-setup` on the Pi.
2. On the device, run that command, adding `--driver` for your robot:
2. On the device, run that command, adding `--driver` for your robot:
```sh
```sh
- curl -fsSL https://node.openvibe.network/install | sh -s -- --robot rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X --code ABCD-1234 --driver adeept
+ curl -fsSL https://openvibe.link/install | sh -s -- --robot rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X --code ABCD-1234 --driver adeept
```
```
The shape is `--robot rob_… --code CODE [--driver adeept|adeept-mecanum|cozmo|looi|ros2|ros2-holonomic|none]`. `--robot` is the robot's
The shape is `--robot rob_… --code CODE [--driver adeept|adeept-mecanum|cozmo|looi|ros2|ros2-holonomic|none]`. `--robot` is the robot's
@@ -94,7 +179,7 @@ has the details.
@@ -94,7 +179,7 @@ has the details.
- **Network pairing**: `--network <URL> --pairing pair_… --code CODE`, e.g.
- **Network pairing**: `--network <URL> --pairing pair_… --code CODE`, e.g.
```sh
```sh
- curl -fsSL https://node.openvibe.network/install | sh -s -- --network https://openvibe.network --pairing pair_01J8Z4M2Q0R7T9YV3K6N8P1W2Y --code ABCD-1234 --driver adeept
+ curl -fsSL https://openvibe.link/install | sh -s -- --network https://openvibe.network --pairing pair_01J8Z4M2Q0R7T9YV3K6N8P1W2Y --code ABCD-1234 --driver adeept
```
```
The Node redeems the code on OpenVibe.Network (`POST <network>/api/v1/node-pairing`) and stores the machine's node
The Node redeems the code on OpenVibe.Network (`POST <network>/api/v1/node-pairing`) and stores the machine's node
@@ -6,7 +6,7 @@ VERSION="${1:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}"
@@ -6,7 +6,7 @@ VERSION="${1:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}"
cd "$(dirname "$0")/.."
cd "$(dirname "$0")/.."
rm -rf dist
rm -rf dist
mkdir -p dist
mkdir -p dist
-for target in linux/amd64 linux/arm64 linux/arm/7 darwin/amd64 darwin/arm64 windows/amd64; do
+for target in linux/amd64 linux/arm64 linux/arm/7 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do
os="${target%%/*}"
os="${target%%/*}"
rest="${target#*/}"
rest="${target#*/}"
arch="${rest%%/*}"
arch="${rest%%/*}"
@@ -32,5 +32,7 @@ tar -czf dist/openvibe-node-plugins.tar.gz -C plugins \
@@ -32,5 +32,7 @@ tar -czf dist/openvibe-node-plugins.tar.gz -C plugins \
# OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this asset name:
# OpenVibe.Bot's GET /install route and BOT_INSTALLER_SOURCE_URL are documented to serve this asset name:
# https://github.com/OpenVibers/OpenVibe.Node/releases/latest/download/install.sh — do not rename it.
# https://github.com/OpenVibers/OpenVibe.Node/releases/latest/download/install.sh — do not rename it.
cp install/install.sh dist/install.sh
cp install/install.sh dist/install.sh
+# Friendly Linux and macOS artifacts: .deb, .rpm and a tarball per architecture, from the binaries above.
+scripts/package.sh "$VERSION"
(cd dist && if command -v sha256sum >/dev/null 2>&1; then sha256sum -- * >SHA256SUMS; else shasum -a 256 -- * >SHA256SUMS; fi)
(cd dist && if command -v sha256sum >/dev/null 2>&1; then sha256sum -- * >SHA256SUMS; else shasum -a 256 -- * >SHA256SUMS; fi)
echo "dist/ ready for $VERSION"
echo "dist/ ready for $VERSION"
new file mode 100755
new file mode 100755
@@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
+#!/bin/sh
+# Build the friendly Linux and macOS artifacts from the binaries dist.sh just built:
+# .deb, .rpm and a .tar.gz for Linux amd64 and arm64, and a .tar.gz for macOS arm64 and amd64.
+# The binaries themselves stay in dist/ for the curl | sh installer and for direct download.
+# scripts/package.sh VERSION
+set -eu
+VERSION="${1:?usage: scripts/package.sh VERSION}"
+cd "$(dirname "$0")/.."
+
+# Package versions cannot carry a leading v or arbitrary git describe text: keep RPM and dpkg happy, and keep the
+# version visible to a person. v0.45.0 -> 0.45.0; v0.0.0-dev -> 0.0.0.dev.
+pkgver="${VERSION#v}"
+pkgver="$(printf '%s' "$pkgver" | sed 's/[^A-Za-z0-9.+~]/./g')"
+[ -n "$pkgver" ] || pkgver=0.0.0
+# dpkg refuses a version that does not start with a digit; the CI build is version "ci".
+case "$pkgver" in [0-9]*) ;; *) pkgver="0.$pkgver" ;; esac
+
+work="$(mktemp -d)"
+trap 'rm -rf "$work"' EXIT
+
+# docs every package and tarball carries next to the program
+docs() {
+ dir="$1"
+ mkdir -p "$dir"
+ cp README.md "$dir/README.md"
+ cp docs/install.md "$dir/install.md"
+}
+
+# ---- tarballs: Linux and macOS, one per architecture ----
+for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do
+ os="${target%%/*}"
+ arch="${target##*/}"
+ case "$os/$arch" in
+ linux/amd64|linux/arm64) bin="dist/openvibe-link-linux-$arch" ;;
+ darwin/amd64|darwin/arm64) bin="dist/openvibe-link-darwin-$arch" ;;
+ *) echo "package: no tarball rule for $target" >&2; exit 1 ;;
+ esac
+ test -s "$bin" || { echo "package: $bin is missing (run scripts/dist.sh first)" >&2; exit 1; }
+
+ root="$work/openvibe-link-$pkgver-$os-$arch"
+ mkdir -p "$root"
+ # The installer's --local layout: the OS-specific binary name and the plugin bundle beside install.sh.
+ cp "$bin" "$root/openvibe-link-$os-$arch"
+ cp "$bin" "$root/openvibe-node-$os-$arch"
+ cp dist/openvibe-node-plugins.tar.gz "$root/"
+ cp install/install.sh "$root/install.sh"
+ docs "$root"
+ tar -czf "dist/openvibe-link_${pkgver}_${os}_${arch}.tar.gz" -C "$work" "openvibe-link-$pkgver-$os-$arch"
+ echo "built dist/openvibe-link_${pkgver}_${os}_${arch}.tar.gz"
+done
+
+# ---- .deb: the program and the old-name alias, plus docs; no scripts, no network in postinst ----
+for arch in amd64 arm64; do
+ bin="dist/openvibe-link-linux-$arch"
+ test -s "$bin" || { echo "package: $bin is missing" >&2; exit 1; }
+ root="$work/deb-$arch"
+ mkdir -p "$root/DEBIAN" "$root/usr/local/bin" "$root/usr/share/doc/openvibe-link"
+ install -m 0755 "$bin" "$root/usr/local/bin/openvibe-link"
+ ln -s openvibe-link "$root/usr/local/bin/openvibe-node"
+ cp README.md "$root/usr/share/doc/openvibe-link/README.md"
+ cp docs/install.md "$root/usr/share/doc/openvibe-link/install.md"
+ size="$(du -sk "$root/usr" | cut -f1)"
+ cat >"$root/DEBIAN/control" <<EOF
+Package: openvibe-link
+Version: $pkgver
+Section: net
+Priority: optional
+Architecture: $arch
+Maintainer: OpenVibe <[email protected]>
+Installed-Size: $size
+Depends: ca-certificates
+Homepage: https://openvibe.link
+Description: OpenVibe Link: your machines, connected
+ OpenVibe Link runs on your computer or server and connects out to OpenVibe: your agents can use it only as far as
+ you allow, and you choose what it offers the network. The openvibe-node command is kept as an alias.
+EOF
+ ( cd "$root" && find . -type f -exec md5sum {} + | sed 's| \./| |' | sort -k2 >DEBIAN/md5sums )
+ dpkg-deb --build --root-owner-group "$root" "dist/openvibe-link_${pkgver}_${arch}.deb" >/dev/null
+ echo "built dist/openvibe-link_${pkgver}_${arch}.deb"
+done
+
+# ---- .rpm: the same contents, built with rpmbuild; CI installs rpm, a local run skips it with a warning ----
+if command -v rpmbuild >/dev/null 2>&1; then
+ for pair in amd64:x86_64 arm64:aarch64; do
+ arch="${pair%%:*}"
+ rpmarch="${pair##*:}"
+ bin="dist/openvibe-link-linux-$arch"
+ test -s "$bin" || { echo "package: $bin is missing" >&2; exit 1; }
+ top="$work/rpm-$rpmarch"
+ mkdir -p "$top/SOURCES" "$top/SPECS" "$top/BUILD" "$top/BUILDROOT" "$top/RPMS" "$top/SRPMS"
+ cp "$bin" "$top/SOURCES/openvibe-link"
+ cp README.md "$top/SOURCES/README.md"
+ cp docs/install.md "$top/SOURCES/install.md"
+ cat >"$top/SPECS/openvibe-link.spec" <<EOF
+Name: openvibe-link
+Version: $pkgver
+Release: 1
+Summary: OpenVibe Link: your machines, connected
+License: AGPL-3.0
+URL: https://openvibe.link
+Source0: openvibe-link
+Source1: README.md
+Source2: install.md
+AutoReqProv: no
+%global debug_package %{nil}
+%global _build_id_links none
+
+%description
+OpenVibe Link runs on your computer or server and connects out to OpenVibe: your agents
+can use it only as far as you allow, and you choose what it offers the network. The
+openvibe-node command is kept as an alias.
+
+%prep
+
+%build
+
+%install
+mkdir -p %{buildroot}/usr/local/bin %{buildroot}/usr/share/doc/openvibe-link
+install -m 0755 %{SOURCE0} %{buildroot}/usr/local/bin/openvibe-link
+ln -s openvibe-link %{buildroot}/usr/local/bin/openvibe-node
+install -m 0644 %{SOURCE1} %{buildroot}/usr/share/doc/openvibe-link/README.md
+install -m 0644 %{SOURCE2} %{buildroot}/usr/share/doc/openvibe-link/install.md
+
+%files
+/usr/local/bin/openvibe-link
+/usr/local/bin/openvibe-node
+/usr/share/doc/openvibe-link/README.md
+/usr/share/doc/openvibe-link/install.md
+EOF
+ rpmbuild -bb --quiet --define "_topdir $top" --define "_arch $rpmarch" --define "_build_arch $rpmarch" \
+ --define "_target_cpu $rpmarch" --define "_target_os linux" "$top/SPECS/openvibe-link.spec" \
+ >/dev/null 2>"$work/rpm-$rpmarch.err" || { cat "$work/rpm-$rpmarch.err" >&2; exit 1; }
+ cp "$top"/RPMS/"$rpmarch"/*.rpm "dist/openvibe-link-${pkgver}-1.${rpmarch}.rpm"
+ echo "built dist/openvibe-link-${pkgver}-1.${rpmarch}.rpm"
+ done
+else
+ echo "package: rpmbuild is not installed here; skipped the .rpm (CI installs rpm and builds it)" >&2
+fi
+
+echo "packages ready for $VERSION"