Klient-distribution: självständiga binärer + curl|sh-installer
- 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:
62
.gitea/workflows/release.yaml
Normal file
62
.gitea/workflows/release.yaml
Normal 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
|
||||
@@ -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`.
|
||||
|
||||
11
deploy/client-build/package.json
Normal file
11
deploy/client-build/package.json
Normal 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
96
install.sh
Executable 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"
|
||||
@@ -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/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
1275
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user