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
|
## Uppdatera till senaste
|
||||||
|
|
||||||
1. `git push master` → runnern bygger + pushar `:latest`.
|
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",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"bin": "dist/daemon.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "tsx --env-file-if-exists=../../.env watch src/index.ts",
|
"dev": "tsx --env-file-if-exists=../../.env watch src/index.ts",
|
||||||
"start": "tsx --env-file-if-exists=../../.env src/index.ts",
|
"start": "tsx --env-file-if-exists=../../.env src/index.ts",
|
||||||
"build": "tsc --noEmit -p tsconfig.json",
|
"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"
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agent-helm/shared": "workspace:*",
|
"@agent-helm/shared": "workspace:*",
|
||||||
"node-pty": "^1.0.0",
|
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
"@types/ws": "^8.5.12",
|
"@types/ws": "^8.5.12",
|
||||||
|
"@yao-pkg/pkg": "^6.20.0",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.7.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
|
* 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.
|
* 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 { WebSocket } from "ws";
|
||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import os from "node:os";
|
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:
|
||||||
- "packages/*"
|
- "packages/*"
|
||||||
|
|
||||||
# pnpm 11 blockar native build-scripts som standard. node-pty kompilerar sin
|
# pnpm 11 blockar native build-scripts som standard.
|
||||||
# binär och esbuild hämtar sin plattformsbinär (krävs av vite/tsx) — tillåt dem.
|
# - 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:
|
allowBuilds:
|
||||||
esbuild: true
|
esbuild: true
|
||||||
node-pty: true
|
"@homebridge/node-pty-prebuilt-multiarch": true
|
||||||
|
node-pty: false
|
||||||
|
|||||||
Reference in New Issue
Block a user