Klient-distribution: självständiga binärer + curl|sh-installer
All checks were successful
build-and-push / build (push) Successful in 26s
release-client / build-release (push) Successful in 1m3s

- daemon: byt node-pty -> @homebridge/node-pty-prebuilt-multiarch (N-API-
  prebuilds för x64+arm64, ingen kompilering); esbuild-bundle av daemonen
- .gitea/workflows/release.yaml: på tag v* bygger pkg båda arkitekturerna på
  Pi-runnern (utan QEMU — prebuilds för båda finns) och publicerar som
  Gitea-release-assets via API
- install.sh: 'curl -fsSL .../install.sh | sh' — detekterar arch, hämtar rätt
  binär från senaste releasen, lägger agent-helm i PATH, skapar config.env +
  valfri systemd-user-service (Arch/Ubuntu)
- deploy/client-build/package.json: pkg-config (assets för prebuilds)
- DEPLOY.md: klient-installationssektion

Verifierat lokalt: pkg-binär (x64, 83 MB) startar, node-pty spawnar pty,
ansluter och input/output funkar end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 17:24:21 +02:00
parent c3972d76df
commit a6e304fb53
8 changed files with 1483 additions and 12 deletions

View File

@@ -0,0 +1,62 @@
name: release-client
# Bygger självständiga klient-binärer (Node + node-pty inbäddat) för
# linux-x64 OCH linux-arm64 på Pi-runnern (prebuilt-multiarch shippar båda
# arkitekturernas prebuilds, så pkg cross-bygger utan QEMU), och publicerar
# dem som assets på en Gitea-release.
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: "Release-tag (t.ex. v0.1.0)"
required: true
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Bestäm tag
id: t
run: |
if [ -n "${{ inputs.tag }}" ]; then echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"; else echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"; fi
- name: Bundla daemonen
run: |
npm install -g pnpm@11.3.0
pnpm install --frozen-lockfile --filter "@agent-helm/daemon..."
pnpm --filter @agent-helm/daemon bundle
- name: Bygg binärer (x64 + arm64) med pkg
run: |
B=/tmp/clientbuild
mkdir -p "$B/out"
cp packages/daemon/dist/daemon.cjs "$B/daemon.cjs"
cp deploy/client-build/package.json "$B/package.json"
cd "$B"
npm install --ignore-scripts --no-audit --no-fund @homebridge/node-pty-prebuilt-multiarch@0.13.1 @yao-pkg/pkg@6.20.0
./node_modules/.bin/pkg daemon.cjs --targets node22-linux-x64 --output out/agent-helm-linux-x64
./node_modules/.bin/pkg daemon.cjs --targets node22-linux-arm64 --output out/agent-helm-linux-arm64
cp "$GITHUB_WORKSPACE/install.sh" out/install.sh
cd out && sha256sum agent-helm-linux-* install.sh > checksums.txt && ls -la
- name: Skapa Gitea-release + ladda upp assets
env:
API: http://gitea-d:3000/api/v1
REPO: ${{ github.repository }}
TAG: ${{ steps.t.outputs.tag }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
B=/tmp/clientbuild/out
BODY="agent-helm klient $TAG — sjalvstandiga binarer (linux x64/arm64). Installera: curl -fsSL https://gitea.brasse-pc.eu/brasse/agent-helm/raw/branch/main/install.sh | sh"
rid=$(curl -s -X POST "$API/repos/$REPO/releases" -H "Authorization: token $TOKEN" -H 'Content-Type: application/json' -d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"body\":\"$BODY\"}" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
if [ -z "$rid" ]; then rid=$(curl -s "$API/repos/$REPO/releases/tags/$TAG" -H "Authorization: token $TOKEN" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2); fi
echo "release id: $rid"
for f in agent-helm-linux-x64 agent-helm-linux-arm64 install.sh checksums.txt; do
echo "laddar upp $f ..."
curl -s -X POST "$API/repos/$REPO/releases/$rid/assets?name=$f" -H "Authorization: token $TOKEN" -F "attachment=@$B/$f" -o /dev/null -w " -> HTTP %{http_code}\n"
done

View File

@@ -136,6 +136,34 @@ Daemonen dyker upp som en session i web-UI:t. (Kräver att NPM:s Websockets är
---
## Klienten (daemon) — installera på en Linux-maskin
Klienten distribueras som **självständiga binärer** (Node + node-pty inbäddat, inga
beroenden på målet) för `linux-x64` och `linux-arm64`, byggda av
`.gitea/workflows/release.yaml` och publicerade som **Release-assets** på Gitea.
**Skapa en release** (bygger båda arkitekturerna på Pi-runnern):
```bash
git tag v0.1.0 && git push origin v0.1.0
# eller: Gitea -> Actions -> release-client -> Run workflow (ange tag)
```
**Installera på valfri Linux-maskin** (Arch, Ubuntu, …) — ett kommando:
```bash
curl -fsSL https://gitea.brasse-pc.eu/brasse/agent-helm/raw/branch/main/install.sh | sh
```
Installern detekterar arch, hämtar rätt binär från senaste releasen, lägger
`agent-helm` i `/usr/local/bin` (eller `~/.local/bin`), skapar
`~/.config/agent-helm/config.env` och en (valfri) systemd-user-service.
Sätt token + kör:
```bash
${EDITOR:-nano} ~/.config/agent-helm/config.env # AGENT_HELM_TOKEN, SERVER_URL, AGENT_CMD
systemctl --user daemon-reload && systemctl --user enable --now agent-helm
# eller direkt: set -a; . ~/.config/agent-helm/config.env; agent-helm
```
Klienten ansluter till `wss://rcai.brasse-pc.eu` och dyker upp som en session i UI:t.
## Uppdatera till senaste
1. `git push master` → runnern bygger + pushar `:latest`.

View File

@@ -0,0 +1,11 @@
{
"name": "agent-helm-client",
"version": "1.0.0",
"bin": "daemon.cjs",
"pkg": {
"assets": [
"node_modules/@homebridge/node-pty-prebuilt-multiarch/prebuilds/**/*",
"node_modules/@homebridge/node-pty-prebuilt-multiarch/lib/**/*"
]
}
}

96
install.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/sh
# agent-helm — klient-installer (självständig binär, Node + node-pty inbäddat).
#
# curl -fsSL https://gitea.brasse-pc.eu/brasse/agent-helm/raw/branch/main/install.sh | sh
#
# Valfria env-vars (annars defaults / fyll i config efteråt):
# AGENT_HELM_TOKEN=... delad token mot servern
# AGENT_HELM_SERVER=wss://... server-URL (default wss://rcai.brasse-pc.eu)
# AGENT_CMD=gemini kommandot som körs i pty:n
# PREFIX=/usr/local install-prefix för binären
set -eu
OWNER=brasse
REPO=agent-helm
BASE=https://gitea.brasse-pc.eu
API="$BASE/api/v1/repos/$OWNER/$REPO"
# --- OS + arkitektur ---
[ "$(uname -s)" = "Linux" ] || { echo "agent-helm: bara Linux stöds just nu"; exit 1; }
case "$(uname -m)" in
x86_64|amd64) ARCH=x64 ;;
aarch64|arm64) ARCH=arm64 ;;
*) echo "agent-helm: arkitektur $(uname -m) stöds inte (endast x64/arm64)"; exit 1 ;;
esac
ASSET="agent-helm-linux-$ARCH"
command -v curl >/dev/null 2>&1 || { echo "agent-helm: curl krävs"; exit 1; }
# --- senaste release-tag ---
echo "agent-helm: slår upp senaste release ..."
TAG=$(curl -fsSL "$API/releases/latest" | tr ',' '\n' | grep -m1 '"tag_name"' | cut -d'"' -f4)
[ -n "${TAG:-}" ] || { echo "agent-helm: hittade ingen release på $BASE"; exit 1; }
URL="$BASE/$OWNER/$REPO/releases/download/$TAG/$ASSET"
# --- bin-katalog (root -> /usr/local/bin, annars sudo, annars ~/.local/bin) ---
PREFIX="${PREFIX:-/usr/local}"
SUDO=""
if [ "$(id -u)" = 0 ] || [ -w "$PREFIX/bin" ]; then
BIN="$PREFIX/bin"
elif command -v sudo >/dev/null 2>&1; then
BIN="$PREFIX/bin"; SUDO=sudo
else
BIN="$HOME/.local/bin"; mkdir -p "$BIN"
fi
echo "agent-helm: hämtar $ASSET ($TAG) -> $BIN/agent-helm"
tmp=$(mktemp)
curl -fSL "$URL" -o "$tmp"
chmod +x "$tmp"
$SUDO install -m 0755 "$tmp" "$BIN/agent-helm"
rm -f "$tmp"
# --- config ---
CFGDIR="$HOME/.config/agent-helm"
CFG="$CFGDIR/config.env"
mkdir -p "$CFGDIR"
if [ ! -f "$CFG" ]; then
cat > "$CFG" <<EOF
# agent-helm klient-config
AGENT_HELM_TOKEN=${AGENT_HELM_TOKEN:-}
SERVER_URL=${AGENT_HELM_SERVER:-wss://rcai.brasse-pc.eu}
AGENT_CMD=${AGENT_CMD:-gemini}
# AGENT_CWD=/sökväg/till/projekt
EOF
chmod 600 "$CFG"
echo "agent-helm: config skapad: $CFG"
else
echo "agent-helm: behåller befintlig config: $CFG"
fi
# --- systemd user-service (valfri) ---
UNITDIR="$HOME/.config/systemd/user"
mkdir -p "$UNITDIR"
cat > "$UNITDIR/agent-helm.service" <<EOF
[Unit]
Description=agent-helm klient (daemon)
After=network-online.target
[Service]
EnvironmentFile=$CFG
ExecStart=$BIN/agent-helm
Restart=on-failure
RestartSec=3
[Install]
WantedBy=default.target
EOF
echo ""
echo " ✓ installerad: $BIN/agent-helm (version $TAG, $ARCH)"
case ":$PATH:" in *":$BIN:"*) ;; *) echo " ⚠ lägg till $BIN i din PATH";; esac
echo ""
echo " Nästa steg:"
echo " 1) sätt token: \${EDITOR:-nano} $CFG"
echo " 2a) kör direkt: set -a; . $CFG; agent-helm"
echo " 2b) eller som tjänst: systemctl --user daemon-reload && systemctl --user enable --now agent-helm"

View File

@@ -3,21 +3,31 @@
"version": "0.0.0",
"private": true,
"type": "module",
"bin": "dist/daemon.cjs",
"scripts": {
"dev": "tsx --env-file-if-exists=../../.env watch src/index.ts",
"start": "tsx --env-file-if-exists=../../.env src/index.ts",
"build": "tsc --noEmit -p tsconfig.json",
"bundle": "esbuild src/index.ts --bundle --platform=node --target=node22 --external:@homebridge/node-pty-prebuilt-multiarch --outfile=dist/daemon.cjs",
"typecheck": "tsc --noEmit -p tsconfig.json"
},
"dependencies": {
"@agent-helm/shared": "workspace:*",
"node-pty": "^1.0.0",
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
"ws": "^8.18.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@types/ws": "^8.5.12",
"@yao-pkg/pkg": "^6.20.0",
"esbuild": "^0.25.0",
"tsx": "^4.19.0",
"typescript": "^5.7.0"
},
"pkg": {
"assets": [
"../../node_modules/.pnpm/**/@homebridge/node-pty-prebuilt-multiarch/prebuilds/**/*",
"../../node_modules/.pnpm/**/@homebridge/node-pty-prebuilt-multiarch/lib/**/*"
]
}
}

View File

@@ -8,7 +8,7 @@
* Persistens (att daemonen själv överlever) är ett yttre lager: kör den i tmux
* eller som en Docker-container med restart-policy. Det hanteras inte här.
*/
import { spawn, type IPty } from "node-pty";
import { spawn, type IPty } from "@homebridge/node-pty-prebuilt-multiarch";
import { WebSocket } from "ws";
import { randomUUID } from "node:crypto";
import os from "node:os";

1275
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,11 @@
packages:
- "packages/*"
# pnpm 11 blockar native build-scripts som standard. node-pty kompilerar sin
# binär och esbuild hämtar sin plattformsbinär (krävs av vite/tsx) — tillåt dem.
# pnpm 11 blockar native build-scripts som standard.
# - esbuild: hämtar sin plattformsbinär (krävs av vite/tsx)
# - prebuilt-multiarch: packar upp färdiga pty-prebuilds (x64 + arm64)
# - node-pty (transitiv) ska INTE kompileras — vi kör prebuilt-multiarchs binärer
allowBuilds:
esbuild: true
node-pty: true
"@homebridge/node-pty-prebuilt-multiarch": true
node-pty: false