From 424da7e232b82b697abd3d763fea2b46319df66d Mon Sep 17 00:00:00 2001 From: Sandwich Date: Thu, 9 Apr 2026 03:51:39 +0200 Subject: [PATCH 01/13] Add Arch Linux (AUR) install instructions to README Adds "Install Path 3: Arch Linux (AUR)" section covering both AUR helper and manual makepkg installation, linking to the published remoteterm-meshcore AUR package. Closes #171 --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 2512b29..83ab993 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,29 @@ To stop: sudo docker compose down ``` +## Install Path 3: Arch Linux (AUR) + +A [`remoteterm-meshcore`](https://aur.archlinux.org/packages/remoteterm-meshcore) package is available in the AUR. Install it with an AUR helper or build it manually: + +```bash +# with an AUR helper +yay -S remoteterm-meshcore + +# or manually +git clone https://aur.archlinux.org/remoteterm-meshcore.git +cd remoteterm-meshcore +makepkg -si +``` + +Configure your radio connection, then start the service: + +```bash +sudo vi /etc/remoteterm-meshcore/remoteterm.env +sudo systemctl enable --now remoteterm-meshcore +``` + +Access the app at http://localhost:8000. + ## Standard Environment Variables Only one transport may be active at a time. If multiple are set, the server will refuse to start. From 967269ef7d74a33dca5ebfbb6a78bb261b3b2bf6 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Thu, 9 Apr 2026 19:39:57 -0700 Subject: [PATCH 02/13] Initial AUR work --- .github/workflows/publish-aur.yml | 71 +++++++++++++++++ pkg/aur/PKGBUILD | 117 ++++++++++++++++++++++++++++ pkg/aur/remoteterm-meshcore.install | 27 +++++++ pkg/aur/remoteterm-meshcore.service | 29 +++++++ pkg/aur/remoteterm.env | 28 +++++++ 5 files changed, 272 insertions(+) create mode 100644 .github/workflows/publish-aur.yml create mode 100644 pkg/aur/PKGBUILD create mode 100644 pkg/aur/remoteterm-meshcore.install create mode 100644 pkg/aur/remoteterm-meshcore.service create mode 100644 pkg/aur/remoteterm.env diff --git a/.github/workflows/publish-aur.yml b/.github/workflows/publish-aur.yml new file mode 100644 index 0000000..7d0b792 --- /dev/null +++ b/.github/workflows/publish-aur.yml @@ -0,0 +1,71 @@ +name: Publish AUR package + +# Pushes the contents of pkg/aur/ to the remoteterm-meshcore AUR repository +# whenever a GitHub release is published. Can also be triggered manually for +# testing or out-of-band republishes. +# +# Required secrets: +# AUR_SSH_PRIVATE_KEY Private SSH key registered with the AUR maintainer +# account that owns the remoteterm-meshcore package. +# AUR_COMMIT_EMAIL Email used for the AUR git commit identity. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: 'Version to publish (no v prefix, e.g. 3.9.1)' + required: true + +concurrency: + # Serialize publishes so a fast back-to-back release sequence cannot race + # two pushes against the AUR repo. The later one wins by virtue of being + # the final state. + group: publish-aur + cancel-in-progress: false + +jobs: + publish-aur: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Resolve version from event + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ inputs.version }}" + else + VERSION="${{ github.event.release.tag_name }}" + fi + VERSION="${VERSION#v}" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Publishing AUR package for version $VERSION" + + - name: Stamp pkgver into PKGBUILD + run: | + sed -i "s/^pkgver=.*/pkgver=${{ steps.version.outputs.version }}/" pkg/aur/PKGBUILD + sed -i "s/^pkgrel=.*/pkgrel=1/" pkg/aur/PKGBUILD + + - name: Publish to AUR + uses: KSXGitHub/github-actions-deploy-aur@v4.1.2 + with: + pkgname: remoteterm-meshcore + pkgbuild: pkg/aur/PKGBUILD + assets: | + pkg/aur/remoteterm-meshcore.install + pkg/aur/remoteterm-meshcore.service + pkg/aur/remoteterm.env + commit_username: jkingsman + commit_email: ${{ secrets.AUR_COMMIT_EMAIL }} + ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + commit_message: "Update to ${{ steps.version.outputs.version }}" + # Recompute sha256sums from the live release tarball + the bundled + # service/env files. The committed PKGBUILD has SKIP placeholders. + updpkgsums: true + # Validate the PKGBUILD parses and sources download, but skip the + # actual build (which would run uv sync + npm install for several + # minutes of CI time on every release). + test: true + test_flags: --clean --cleanbuild --nodeps --nobuild diff --git a/pkg/aur/PKGBUILD b/pkg/aur/PKGBUILD new file mode 100644 index 0000000..2dd3eb6 --- /dev/null +++ b/pkg/aur/PKGBUILD @@ -0,0 +1,117 @@ +# Maintainer: Jack Kingsman + +pkgname=remoteterm-meshcore +# pkgver is rewritten by .github/workflows/publish-aur.yml on each release. +pkgver=3.9.0 +pkgrel=1 +pkgdesc='Web interface for MeshCore mesh radio networks' +arch=(x86_64 aarch64) +url='https://github.com/jkingsman/Remote-Terminal-for-MeshCore' +license=('MIT') +# No system python dependency — we bundle a standalone interpreter via +# python-build-standalone so the package is immune to Arch python ABI bumps. +depends=(glibc) +makedepends=(uv nodejs npm) +optdepends=('bluez: BLE transport support') +backup=(etc/remoteterm-meshcore/remoteterm.env) +# The bundled python-build-standalone binary ships pre-stripped. makepkg's +# default strip pass corrupts its unusual ELF layout (.dynstr not in segment), +# so we disable stripping for the whole package. +options=(!strip) +install=remoteterm-meshcore.install +source=( + "$pkgname-$pkgver.tar.gz::https://github.com/jkingsman/Remote-Terminal-for-MeshCore/archive/refs/tags/$pkgver.tar.gz" + "remoteterm-meshcore.service" + "remoteterm.env" +) +# sha256sums are recomputed by `updpkgsums` in the publish workflow before +# the PKGBUILD is pushed to AUR. The committed values are intentionally SKIP +# so the file is honest about not tracking real hashes in this repo. +sha256sums=('SKIP' + 'SKIP' + 'SKIP') + +# python-build-standalone: stripped install_only builds (~30 MB each). +# Bump _pyver and _pybuilddate when updating the bundled interpreter. +_pyver=3.13.13 +_pybuilddate=20260408 + +source_x86_64=("python-${_pyver}-x86_64.tar.gz::https://github.com/astral-sh/python-build-standalone/releases/download/${_pybuilddate}/cpython-${_pyver}+${_pybuilddate}-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz") +sha256sums_x86_64=('SKIP') + +source_aarch64=("python-${_pyver}-aarch64.tar.gz::https://github.com/astral-sh/python-build-standalone/releases/download/${_pybuilddate}/cpython-${_pyver}+${_pybuilddate}-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz") +sha256sums_aarch64=('SKIP') + +_srcname="Remote-Terminal-for-MeshCore-$pkgver" + +build() { + cd "$_srcname" + + # Build frontend + cd frontend + npm ci + npm run build + cd .. + + # Create venv using the bundled standalone Python interpreter, then install + # Python dependencies into it. This produces a fully self-contained venv + # that does not reference the system Python at all. + uv venv --python "$srcdir/python/bin/python3" .venv + uv sync --no-dev --frozen +} + +package() { + cd "$_srcname" + + local _optdir=/opt/remoteterm-meshcore + local _instdir="$pkgdir$_optdir" + + # App source + install -d "$_instdir" + cp -r app "$_instdir/" + cp pyproject.toml uv.lock "$_instdir/" + + # Frontend build + install -d "$_instdir/frontend" + cp -r frontend/dist "$_instdir/frontend/" + + # Bundled Python interpreter + cp -a "$srcdir/python" "$_instdir/python" + + # Python venv + cp -a .venv "$_instdir/" + + # Fix shebangs and venv config: replace build-time paths with final + # install paths so the venv works from /opt after installation. + # sed only operates on regular file contents, so symlinks need separate + # fixup below. + find "$_instdir/.venv/bin" -type f -exec \ + sed -i "s|$srcdir/$_srcname/.venv|$_optdir/.venv|g" {} + + find "$_instdir/.venv/bin" -type f -exec \ + sed -i "s|$srcdir/python|$_optdir/python|g" {} + + sed -i \ + -e "s|$srcdir/$_srcname/.venv|$_optdir/.venv|g" \ + -e "s|$srcdir/python|$_optdir/python|g" \ + "$_instdir/.venv/pyvenv.cfg" 2>/dev/null || true + + # Recreate the venv interpreter symlinks — these are symlinks (not files), + # so sed cannot fix them. Point them at the bundled Python. + ln -sf "$_optdir/python/bin/python3" "$_instdir/.venv/bin/python" + ln -sf python "$_instdir/.venv/bin/python3" + ln -sf python "$_instdir/.venv/bin/python3.13" + + # Data directory symlink + ln -s /var/lib/remoteterm-meshcore "$_instdir/data" + + # Systemd service + install -Dm644 "$srcdir/remoteterm-meshcore.service" \ + "$pkgdir/usr/lib/systemd/system/remoteterm-meshcore.service" + + # Environment file + install -Dm640 "$srcdir/remoteterm.env" \ + "$pkgdir/etc/remoteterm-meshcore/remoteterm.env" + + # License + install -Dm644 LICENSE.md \ + "$pkgdir/usr/share/licenses/$pkgname/LICENSE" +} diff --git a/pkg/aur/remoteterm-meshcore.install b/pkg/aur/remoteterm-meshcore.install new file mode 100644 index 0000000..a057022 --- /dev/null +++ b/pkg/aur/remoteterm-meshcore.install @@ -0,0 +1,27 @@ +pre_install() { + getent group remoteterm > /dev/null || groupadd -r remoteterm + getent passwd remoteterm > /dev/null || \ + useradd -r -g remoteterm -d /var/lib/remoteterm-meshcore -s /sbin/nologin \ + -c "RemoteTerm for MeshCore" remoteterm +} + +pre_upgrade() { + pre_install +} + +post_install() { + echo "==> Set your radio connection (serial, TCP, or BLE) in" + echo "==> /etc/remoteterm-meshcore/remoteterm.env" + echo "==> Start the service with: systemctl enable --now remoteterm-meshcore" + echo "==> The web UI will be at http://localhost:8000" +} + +post_upgrade() { + # Clean orphaned __pycache__ dirs left by the previous Python version + find /opt/remoteterm-meshcore -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true + + systemctl daemon-reload + if systemctl is-active --quiet remoteterm-meshcore; then + systemctl restart remoteterm-meshcore + fi +} diff --git a/pkg/aur/remoteterm-meshcore.service b/pkg/aur/remoteterm-meshcore.service new file mode 100644 index 0000000..49e6861 --- /dev/null +++ b/pkg/aur/remoteterm-meshcore.service @@ -0,0 +1,29 @@ +[Unit] +Description=RemoteTerm for MeshCore +Documentation=https://github.com/jkingsman/Remote-Terminal-for-MeshCore +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=remoteterm +Group=remoteterm +WorkingDirectory=/opt/remoteterm-meshcore +EnvironmentFile=/etc/remoteterm-meshcore/remoteterm.env +ExecStart=/opt/remoteterm-meshcore/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000 +Restart=on-failure +RestartSec=5s + +StateDirectory=remoteterm-meshcore + +# Hardening +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=yes +NoNewPrivileges=yes + +# Serial port access (uucp group on Arch) +SupplementaryGroups=uucp + +[Install] +WantedBy=multi-user.target diff --git a/pkg/aur/remoteterm.env b/pkg/aur/remoteterm.env new file mode 100644 index 0000000..2c0efab --- /dev/null +++ b/pkg/aur/remoteterm.env @@ -0,0 +1,28 @@ +# RemoteTerm for MeshCore configuration +# https://github.com/jkingsman/Remote-Terminal-for-MeshCore + +# Transport: uncomment ONE section below + +# Serial auto-detect (default — no config needed) + +# Serial manual port +#MESHCORE_SERIAL_PORT=/dev/ttyUSB0 + +# TCP +#MESHCORE_TCP_HOST=192.168.1.100 +#MESHCORE_TCP_PORT=4000 + +# BLE (also requires the optional `bluez` package) +#MESHCORE_BLE_ADDRESS=AA:BB:CC:DD:EE:FF +#MESHCORE_BLE_PIN=123456 + +# Database +MESHCORE_DATABASE_PATH=/var/lib/remoteterm-meshcore/meshcore.db + +# Bots can run arbitrary Python on the server. Leave this set to 'true' unless +# you trust everyone on your network. +MESHCORE_DISABLE_BOTS=true + +# HTTP Basic Auth (recommended when bots are enabled) +#MESHCORE_BASIC_AUTH_USERNAME= +#MESHCORE_BASIC_AUTH_PASSWORD= From 5c4e04e024b84cf8de9aa77f0d27c978f59aab66 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Thu, 9 Apr 2026 22:46:54 -0700 Subject: [PATCH 03/13] Skip daemon reload if systemctl isn't around --- pkg/aur/remoteterm-meshcore.install | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/aur/remoteterm-meshcore.install b/pkg/aur/remoteterm-meshcore.install index a057022..256972e 100644 --- a/pkg/aur/remoteterm-meshcore.install +++ b/pkg/aur/remoteterm-meshcore.install @@ -20,8 +20,10 @@ post_upgrade() { # Clean orphaned __pycache__ dirs left by the previous Python version find /opt/remoteterm-meshcore -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true - systemctl daemon-reload - if systemctl is-active --quiet remoteterm-meshcore; then - systemctl restart remoteterm-meshcore + if command -v systemctl &>/dev/null && systemctl --version &>/dev/null 2>&1; then + systemctl daemon-reload + if systemctl is-active --quiet remoteterm-meshcore; then + systemctl restart remoteterm-meshcore + fi fi } From 07277935609eec57d490314e039f9fd1a67574b6 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Thu, 9 Apr 2026 23:03:58 -0700 Subject: [PATCH 04/13] Add test script --- scripts/quality/test_aur_package.sh | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 scripts/quality/test_aur_package.sh diff --git a/scripts/quality/test_aur_package.sh b/scripts/quality/test_aur_package.sh new file mode 100644 index 0000000..8ae6da6 --- /dev/null +++ b/scripts/quality/test_aur_package.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +set -euo pipefail + +# test_aur_package.sh — Build the AUR package in one Arch container, then +# install and run it in a clean Arch container with port 8000 exposed. +# +# Usage: +# ./scripts/quality/test_aur_package.sh [--port PORT] +# +# The script streams application logs until you Ctrl-C. + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +PORT=8000 +if [ "${1:-}" = "--port" ]; then PORT="${2:-8000}"; fi + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +ARTIFACT_DIR="$(mktemp -d)" +INSTALL_CONTAINER="remoteterm-aur-test-$$" + +cleanup() { + echo + echo -e "${YELLOW}Cleaning up...${NC}" + docker rm -f "$INSTALL_CONTAINER" 2>/dev/null || true + rm -rf "$ARTIFACT_DIR" + echo -e "${GREEN}Done.${NC}" +} +trap cleanup EXIT + +# ── Phase 1: Build ──────────────────────────────────────────────────────────── + +echo -e "${BOLD}=== Phase 1: Build AUR package ===${NC}" + +docker run --rm \ + -v "$REPO_ROOT/pkg/aur:/pkg:ro" \ + -v "$ARTIFACT_DIR:/out" \ + archlinux:latest bash -c ' +set -euo pipefail + +pacman -Syu --noconfirm base-devel git curl >/dev/null 2>&1 +curl -LsSf https://astral.sh/uv/install.sh | sh >/dev/null 2>&1 +export PATH="$HOME/.local/bin:$PATH" +pacman -S --noconfirm nodejs npm >/dev/null 2>&1 + +useradd -m builder +echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + +BUILD_DIR=/home/builder/build +mkdir -p "$BUILD_DIR" +cp /pkg/PKGBUILD /pkg/remoteterm-meshcore.install \ + /pkg/remoteterm-meshcore.service /pkg/remoteterm.env "$BUILD_DIR/" +chown -R builder:builder "$BUILD_DIR" + +echo "Building package..." +su builder -c "export PATH=\"$HOME/.local/bin:\$PATH\" && cd $BUILD_DIR && makepkg -sf --noconfirm" 2>&1 + +cp "$BUILD_DIR"/remoteterm-meshcore-*.pkg.tar.zst /out/ +echo "Package artifact copied to /out/" +ls -lh /out/*.pkg.tar.zst +' + +PKG_FILE="$(ls "$ARTIFACT_DIR"/*.pkg.tar.zst 2>/dev/null | head -1)" +if [ -z "$PKG_FILE" ]; then + echo -e "${RED}Build failed — no .pkg.tar.zst produced${NC}" + exit 1 +fi + +echo -e "${GREEN}Built: $(basename "$PKG_FILE") ($(du -h "$PKG_FILE" | cut -f1))${NC}" +echo + +# ── Phase 2: Install and run ───────────────────────────────────────────────── + +echo -e "${BOLD}=== Phase 2: Install and run ===${NC}" + +docker run -d \ + --name "$INSTALL_CONTAINER" \ + -p "$PORT:8000" \ + -v "$ARTIFACT_DIR:/pkg:ro" \ + archlinux:latest bash -c ' +set -euo pipefail + +# Install the package (triggers pre_install which creates the remoteterm user) +pacman -Syu --noconfirm >/dev/null 2>&1 +pacman -U --noconfirm /pkg/*.pkg.tar.zst + +# Create the state directory (systemd StateDirectory= would do this on a real host) +mkdir -p /var/lib/remoteterm-meshcore +chown remoteterm:remoteterm /var/lib/remoteterm-meshcore + +echo "============================================" +echo " RemoteTerm installed — starting server" +echo "============================================" + +# Run as the remoteterm service user, matching the systemd unit +exec su -s /bin/bash remoteterm -c "cd /opt/remoteterm-meshcore && exec .venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000" +' >/dev/null + +echo -e "${CYAN}Container:${NC} $INSTALL_CONTAINER" +echo -e "${CYAN}Listening:${NC} http://localhost:$PORT" +echo -e "${CYAN}Health: ${NC} http://localhost:$PORT/api/health" +echo +echo -e "${YELLOW}Streaming logs (Ctrl-C to stop and clean up)...${NC}" +echo + +docker logs -f "$INSTALL_CONTAINER" From e33537018bb4a3bd3b50ca37a87919b889ff66b9 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Thu, 9 Apr 2026 23:11:02 -0700 Subject: [PATCH 05/13] Fix AUR username --- .github/workflows/publish-aur.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-aur.yml b/.github/workflows/publish-aur.yml index 7d0b792..55e2117 100644 --- a/.github/workflows/publish-aur.yml +++ b/.github/workflows/publish-aur.yml @@ -57,7 +57,7 @@ jobs: pkg/aur/remoteterm-meshcore.install pkg/aur/remoteterm-meshcore.service pkg/aur/remoteterm.env - commit_username: jkingsman + commit_username: jackkingsman commit_email: ${{ secrets.AUR_COMMIT_EMAIL }} ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} commit_message: "Update to ${{ steps.version.outputs.version }}" From 5cc0476426e43ee6de01b51419b9ab8f2306e15d Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 00:03:50 -0700 Subject: [PATCH 06/13] Fix port numbering --- docker-compose.example.yml | 2 +- scripts/setup/install_docker.sh | 6 +++--- scripts/setup/install_service.sh | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker-compose.example.yml b/docker-compose.example.yml index 2cfce92..f3101b9 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -31,7 +31,7 @@ services: # TCP # MESHCORE_TCP_HOST: 192.168.1.100 - # MESHCORE_TCP_PORT: 4000 + # MESHCORE_TCP_PORT: 5000 # BLE # BLE in Docker usually needs additional manual compose changes such as diff --git a/scripts/setup/install_docker.sh b/scripts/setup/install_docker.sh index 4f28918..d949b90 100755 --- a/scripts/setup/install_docker.sh +++ b/scripts/setup/install_docker.sh @@ -35,7 +35,7 @@ SERIAL_HOST_PATH="/dev/ttyACM0" SERIAL_COMPOSE_HOST_PATH="/dev/ttyACM0" SERIAL_CONTAINER_PATH="/dev/meshcore-radio" TCP_HOST="" -TCP_PORT="4000" +TCP_PORT="5000" BLE_ADDRESS="" BLE_PIN="" ENABLE_BOTS="N" @@ -311,8 +311,8 @@ case "$TRANSPORT_CHOICE" in echo -e "${RED}TCP host is required.${NC}" read -r -p "TCP host: " TCP_HOST done - read -r -p "TCP port (default: 4000): " TCP_PORT - TCP_PORT="${TCP_PORT:-4000}" + read -r -p "TCP port (default: 5000): " TCP_PORT + TCP_PORT="${TCP_PORT:-5000}" echo -e "${GREEN}TCP: ${TCP_HOST}:${TCP_PORT}${NC}" ;; 3) diff --git a/scripts/setup/install_service.sh b/scripts/setup/install_service.sh index d9a380d..7a140f8 100755 --- a/scripts/setup/install_service.sh +++ b/scripts/setup/install_service.sh @@ -114,8 +114,8 @@ case "$TRANSPORT_CHOICE" in echo -e "${RED}TCP host is required.${NC}" read -rp "TCP host: " TCP_HOST done - read -rp "TCP port (default: 4000): " TCP_PORT - TCP_PORT="${TCP_PORT:-4000}" + read -rp "TCP port (default: 5000): " TCP_PORT + TCP_PORT="${TCP_PORT:-5000}" echo -e "${GREEN}TCP: ${TCP_HOST}:${TCP_PORT}${NC}" ;; 4) From 152a584f355ec920dc6d73eef337fadc70943c8b Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 00:10:41 -0700 Subject: [PATCH 07/13] Fix TCP host --- pkg/aur/remoteterm.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/aur/remoteterm.env b/pkg/aur/remoteterm.env index 2c0efab..ecc80d2 100644 --- a/pkg/aur/remoteterm.env +++ b/pkg/aur/remoteterm.env @@ -10,7 +10,7 @@ # TCP #MESHCORE_TCP_HOST=192.168.1.100 -#MESHCORE_TCP_PORT=4000 +#MESHCORE_TCP_PORT=5000 # BLE (also requires the optional `bluez` package) #MESHCORE_BLE_ADDRESS=AA:BB:CC:DD:EE:FF From 799a7217610e487972091dd10fd8b062f889a06d Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 00:10:53 -0700 Subject: [PATCH 08/13] Be more defensive about systemd detection --- pkg/aur/remoteterm-meshcore.install | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/aur/remoteterm-meshcore.install b/pkg/aur/remoteterm-meshcore.install index 256972e..7161a0b 100644 --- a/pkg/aur/remoteterm-meshcore.install +++ b/pkg/aur/remoteterm-meshcore.install @@ -20,10 +20,12 @@ post_upgrade() { # Clean orphaned __pycache__ dirs left by the previous Python version find /opt/remoteterm-meshcore -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true - if command -v systemctl &>/dev/null && systemctl --version &>/dev/null 2>&1; then - systemctl daemon-reload + # Skip systemd operations in chroots/containers where the binary may exist + # but PID 1 is not systemd. + if [ -d /run/systemd/system ] && command -v systemctl &>/dev/null; then + systemctl daemon-reload || true if systemctl is-active --quiet remoteterm-meshcore; then - systemctl restart remoteterm-meshcore + systemctl restart remoteterm-meshcore || true fi fi } From 7f5dde119f2068b40e840f2c404fbf42d6067ca3 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 00:15:57 -0700 Subject: [PATCH 09/13] Update AGENTS.md --- AGENTS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index f265a75..6fcdca7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -209,6 +209,7 @@ This message-layer echo/path handling is independent of raw-packet storage dedup │ │ ├── MapView.tsx # Leaflet map showing node locations │ │ └── ... │ └── vite.config.ts +├── pkg/aur/ # AUR package files (PKGBUILD, systemd service, env, install hooks) ├── scripts/ # Quality / release helpers (listing below is representative, not exhaustive) │ ├── build/ │ │ ├── collect_licenses.sh # Gather third-party license attributions @@ -216,7 +217,8 @@ This message-layer echo/path handling is independent of raw-packet storage dedup │ ├── quality/ │ │ ├── all_quality.sh # Repo-standard autofix + validate gate │ │ ├── e2e.sh # End-to-end test runner -│ │ └── extended_quality.sh # Quality gate plus e2e and Docker matrix +│ │ ├── extended_quality.sh # Quality gate plus e2e and Docker matrix +│ │ └── test_aur_package.sh # Build + install AUR package in Arch Docker containers │ └── setup/ │ ├── fetch_prebuilt_frontend.py # Download release frontend fallback │ └── install_service.sh # Install/configure Linux systemd service From cb5a76eb5f5f5fb5fe48501993344d6caee53e54 Mon Sep 17 00:00:00 2001 From: Sandwich Date: Fri, 10 Apr 2026 19:23:01 +0200 Subject: [PATCH 10/13] Replace manual user/group creation with sysusers.d and tmpfiles.d --- .github/workflows/publish-aur.yml | 2 ++ pkg/aur/PKGBUILD | 10 ++++++++++ pkg/aur/remoteterm-meshcore.install | 11 ----------- pkg/aur/remoteterm-meshcore.sysusers | 1 + pkg/aur/remoteterm-meshcore.tmpfiles | 1 + scripts/quality/test_aur_package.sh | 12 +++++++----- 6 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 pkg/aur/remoteterm-meshcore.sysusers create mode 100644 pkg/aur/remoteterm-meshcore.tmpfiles diff --git a/.github/workflows/publish-aur.yml b/.github/workflows/publish-aur.yml index 55e2117..979859b 100644 --- a/.github/workflows/publish-aur.yml +++ b/.github/workflows/publish-aur.yml @@ -56,6 +56,8 @@ jobs: assets: | pkg/aur/remoteterm-meshcore.install pkg/aur/remoteterm-meshcore.service + pkg/aur/remoteterm-meshcore.sysusers + pkg/aur/remoteterm-meshcore.tmpfiles pkg/aur/remoteterm.env commit_username: jackkingsman commit_email: ${{ secrets.AUR_COMMIT_EMAIL }} diff --git a/pkg/aur/PKGBUILD b/pkg/aur/PKGBUILD index 2dd3eb6..1b5fc8d 100644 --- a/pkg/aur/PKGBUILD +++ b/pkg/aur/PKGBUILD @@ -23,11 +23,15 @@ source=( "$pkgname-$pkgver.tar.gz::https://github.com/jkingsman/Remote-Terminal-for-MeshCore/archive/refs/tags/$pkgver.tar.gz" "remoteterm-meshcore.service" "remoteterm.env" + "remoteterm-meshcore.sysusers" + "remoteterm-meshcore.tmpfiles" ) # sha256sums are recomputed by `updpkgsums` in the publish workflow before # the PKGBUILD is pushed to AUR. The committed values are intentionally SKIP # so the file is honest about not tracking real hashes in this repo. sha256sums=('SKIP' + 'SKIP' + 'SKIP' 'SKIP' 'SKIP') @@ -111,6 +115,12 @@ package() { install -Dm640 "$srcdir/remoteterm.env" \ "$pkgdir/etc/remoteterm-meshcore/remoteterm.env" + # System user and data directory + install -Dm644 "$srcdir/remoteterm-meshcore.sysusers" \ + "$pkgdir/usr/lib/sysusers.d/remoteterm-meshcore.conf" + install -Dm644 "$srcdir/remoteterm-meshcore.tmpfiles" \ + "$pkgdir/usr/lib/tmpfiles.d/remoteterm-meshcore.conf" + # License install -Dm644 LICENSE.md \ "$pkgdir/usr/share/licenses/$pkgname/LICENSE" diff --git a/pkg/aur/remoteterm-meshcore.install b/pkg/aur/remoteterm-meshcore.install index 7161a0b..2560b69 100644 --- a/pkg/aur/remoteterm-meshcore.install +++ b/pkg/aur/remoteterm-meshcore.install @@ -1,14 +1,3 @@ -pre_install() { - getent group remoteterm > /dev/null || groupadd -r remoteterm - getent passwd remoteterm > /dev/null || \ - useradd -r -g remoteterm -d /var/lib/remoteterm-meshcore -s /sbin/nologin \ - -c "RemoteTerm for MeshCore" remoteterm -} - -pre_upgrade() { - pre_install -} - post_install() { echo "==> Set your radio connection (serial, TCP, or BLE) in" echo "==> /etc/remoteterm-meshcore/remoteterm.env" diff --git a/pkg/aur/remoteterm-meshcore.sysusers b/pkg/aur/remoteterm-meshcore.sysusers new file mode 100644 index 0000000..ccd8b62 --- /dev/null +++ b/pkg/aur/remoteterm-meshcore.sysusers @@ -0,0 +1 @@ +u remoteterm - "RemoteTerm for MeshCore" /var/lib/remoteterm-meshcore diff --git a/pkg/aur/remoteterm-meshcore.tmpfiles b/pkg/aur/remoteterm-meshcore.tmpfiles new file mode 100644 index 0000000..5255da6 --- /dev/null +++ b/pkg/aur/remoteterm-meshcore.tmpfiles @@ -0,0 +1 @@ +d /var/lib/remoteterm-meshcore 0750 remoteterm remoteterm diff --git a/scripts/quality/test_aur_package.sh b/scripts/quality/test_aur_package.sh index 8ae6da6..64421fe 100644 --- a/scripts/quality/test_aur_package.sh +++ b/scripts/quality/test_aur_package.sh @@ -53,7 +53,8 @@ echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers BUILD_DIR=/home/builder/build mkdir -p "$BUILD_DIR" cp /pkg/PKGBUILD /pkg/remoteterm-meshcore.install \ - /pkg/remoteterm-meshcore.service /pkg/remoteterm.env "$BUILD_DIR/" + /pkg/remoteterm-meshcore.service /pkg/remoteterm-meshcore.sysusers \ + /pkg/remoteterm-meshcore.tmpfiles /pkg/remoteterm.env "$BUILD_DIR/" chown -R builder:builder "$BUILD_DIR" echo "Building package..." @@ -84,13 +85,14 @@ docker run -d \ archlinux:latest bash -c ' set -euo pipefail -# Install the package (triggers pre_install which creates the remoteterm user) +# Install the package (sysusers.d creates the remoteterm user, tmpfiles.d creates the data dir) pacman -Syu --noconfirm >/dev/null 2>&1 pacman -U --noconfirm /pkg/*.pkg.tar.zst -# Create the state directory (systemd StateDirectory= would do this on a real host) -mkdir -p /var/lib/remoteterm-meshcore -chown remoteterm:remoteterm /var/lib/remoteterm-meshcore +# In a container there is no systemd to trigger sysusers/tmpfiles automatically, +# so run them manually. +systemd-sysusers +systemd-tmpfiles --create echo "============================================" echo " RemoteTerm installed — starting server" From fd26576e0d29b734be8826b8f78a1c0111559302 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 10:47:21 -0700 Subject: [PATCH 11/13] Use correct email --- pkg/aur/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/aur/PKGBUILD b/pkg/aur/PKGBUILD index 1b5fc8d..44ff3ee 100644 --- a/pkg/aur/PKGBUILD +++ b/pkg/aur/PKGBUILD @@ -1,4 +1,4 @@ -# Maintainer: Jack Kingsman +# Maintainer: Jack Kingsman pkgname=remoteterm-meshcore # pkgver is rewritten by .github/workflows/publish-aur.yml on each release. From 2393dadf1b7d072d6e49a8908078ccc0a40ccd34 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 10:48:38 -0700 Subject: [PATCH 12/13] Unload the service on uninstall --- pkg/aur/remoteterm-meshcore.install | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pkg/aur/remoteterm-meshcore.install b/pkg/aur/remoteterm-meshcore.install index 2560b69..da3c821 100644 --- a/pkg/aur/remoteterm-meshcore.install +++ b/pkg/aur/remoteterm-meshcore.install @@ -18,3 +18,18 @@ post_upgrade() { fi fi } + +pre_remove() { + if [ -d /run/systemd/system ] && command -v systemctl &>/dev/null; then + systemctl disable --now remoteterm-meshcore 2>/dev/null || true + fi +} + +post_remove() { + if [ -d /run/systemd/system ] && command -v systemctl &>/dev/null; then + systemctl daemon-reload + fi + + echo "==> Database and config remain in /var/lib/remoteterm-meshcore/, remoteterm user retained." + echo "==> To fully clean up: sudo rm -rf /var/lib/remoteterm-meshcore" +} From 18db6e4dd802df7ec670579695c62023f4e778bf Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 10 Apr 2026 10:49:49 -0700 Subject: [PATCH 13/13] Make test script executable --- scripts/quality/test_aur_package.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/quality/test_aur_package.sh diff --git a/scripts/quality/test_aur_package.sh b/scripts/quality/test_aur_package.sh old mode 100644 new mode 100755