Commit cabbf17b authored by Lisa's avatar Lisa

Fix: Bundle and v2 zip now include Windows installer + source docs

parent c9def5d5

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

# Deploying the Windows Installer
## Quick Deploy
If you've made changes to the installer scripts or need to publish a new version:
```bash
# 1. Build the installer (Wine + PyInstaller + NSIS)
cd /home/lisa/hermes-node-protocol/node-agent
./windows/build-all.sh
# 2. Upload to website
./release/upload-windows.sh
# Manual:
scp deploy/windows/hermes-node-agent-installer.exe lisa@lisa.nexlab.net:/var/www/html/files/
```
## What Gets Published
- **`hermes-node-agent-installer.exe`**
PyInstaller + NSIS Windows installer (~51 MB)
- Includes `hermes-node-agent.exe` and `hermes-node-manager.exe`
- Interactive config UI (gateway URL, node name, token)
- Auto-installs as Windows service via NSSM
## Git + Website Workflow
For ANY changes to code or installer scripts:
1. **Commit & Push to GitLab**
```bash
git add -A
git commit -m "Description of changes"
git push origin main
```
2. **Rebuild installer**
```bash
./windows/build-all.sh
```
3. **Upload to website**
```bash
./release/upload-windows.sh
# or manually upload via scp
```
4. **Verify**
Visit: https://lisa.nexlab.net/files/hermes-node-agent-installer.exe
## Build Environment
The installer is built on Linux using:
- **Wine**: Windows compatibility layer
- **Python 3.13.1** (Windows embeddable, running under Wine)
- **PyInstaller 6.20.0**: Creates single-file Windows .exe bundles
- **NSIS 3.x**: Creates the final installer .exe with GUI config page
- **NSSM v2.24**: Windows service wrapper (bundled in installer)
## Configuration Files
- `windows/installer.nsi` — NSIS installer script
- `windows/config-template.json` — Default config for the installer
- `windows/build-all.sh` — Main build script
- `release/upload-windows.sh` — Automated upload script
## Troubleshooting
**"Permission denied" during upload:**
```bash
# Ensure SSH key is loaded
ssh-add ~/.ssh/id_rsa
# Or use ssh-copy-id to set up auth
ssh-copy-id lisa@lisa.nexlab.net
```
**Build fails:**
```bash
# Ensure Wine is installed
sudo apt-get install wine wine64
# Ensure dependencies
pip install pyinstaller
# Rebuild
./windows/build-all.sh
```
**Old installer still on website:**
- Force-rebuild: `rm -rf windows/dist windows/build && ./windows/build-all.sh`
- Re-upload: `scp ...`
...@@ -24,7 +24,6 @@ cp hermes_node_agent.py "$PACKAGE_DIR/" ...@@ -24,7 +24,6 @@ cp hermes_node_agent.py "$PACKAGE_DIR/"
cp browser_controller.py "$PACKAGE_DIR/" cp browser_controller.py "$PACKAGE_DIR/"
cp requirements.txt "$PACKAGE_DIR/" cp requirements.txt "$PACKAGE_DIR/"
cp install.sh "$PACKAGE_DIR/" cp install.sh "$PACKAGE_DIR/"
cp install-on-sissy.sh "$PACKAGE_DIR/"
cp hermes-node-agent.init.d "$PACKAGE_DIR/" cp hermes-node-agent.init.d "$PACKAGE_DIR/"
cp hermes-node-agent.service "$PACKAGE_DIR/" cp hermes-node-agent.service "$PACKAGE_DIR/"
......
# Hermes Browser Agent Chrome Extension
This extension enables browser automation through the Hermes Node Agent.
## Installation
1. Open Chrome → Extensions (chrome://extensions/)
2. Enable "Developer mode" (toggle top right)
3. Click "Load unpacked"
4. Select the `chrome-extension/` folder
## How it works
- The extension runs a background service worker
- Connects to the Hermes Node Agent via WebSocket (localhost:8765)
- Relay messages between the agent and browser content scripts
- No data leaves your machine — all local
## Capabilities
- DOM manipulation (querySelector, click, type)
- Screenshot capture
- Page evaluation
- Navigation control
All controlled through the node agent's `browser_control` capability.
// Hermes Browser Agent — native messaging host bridge
const NATIVE_HOST = 'hermes.node.agent';
const WS_RETRY = 3000;
let ws = null;
let reconnectTimer = null;
function connectWebSocket() {
const url = `ws://localhost:8765/hermes/browser`; // matches gateway plugin route
ws = new WebSocket(url);
ws.onopen = () => console.log('[HermesExt] WS connected to gateway');
ws.onclose = (e) => {
console.log('[HermesExt] WS closed:', e.code, e.reason);
ws = null;
scheduleReconnect();
};
ws.onerror = (e) => console.error('[HermesExt] WS error', e);
ws.onmessage = (m) => {
try { handleNativeMessage(JSON.parse(m.data)); } catch(e) {}
};
}
function scheduleReconnect() {
if (reconnectTimer) clearTimeout(reconnectTimer);
reconnectTimer = setTimeout(connectWebSocket, WS_RETRY);
}
// Route incoming messages from gateway to native host (Hermes Node Agent)
function handleNativeMessage(msg) {
const {cmd, target, args, id} = msg;
if (!cmd) return;
// Forward to native host via native messaging
sendToNative({cmd, target, args, id});
}
function sendToNative(data) {
if (!window.nativePort) return;
window.nativePort.postMessage(data);
}
// Lifecycle
chrome.runtime.onStartup.addListener(connectWebSocket);
chrome.runtime.onInstalled.addListener(connectWebSocket);
chrome.runtime.onConnectNative.addListener(port => {
window.nativePort = port;
port.onMessage.addListener(msg => sendToGateway(msg));
port.onDisconnect.addListener(() => { window.nativePort = null; });
});
// Auto-reconnect
setInterval(connectWebSocket, 30000);
// Hermes Browser Agent Content Script — no-op placeholder
// Main functionality lives in background.js routing to native host
// This file ensures content context is available when needed
window.HermesAgent = {
pageInfo: () => ({
title: document.title,
url: window.location.href,
html: document.documentElement.outerHTML.slice(0, 10000)
}),
evalJS: (code) => { try { return eval(code); } catch(e) { return e.message; } },
click: (selector) => { el=document.querySelector(selector); if(el){el.click();return true};return false; },
scroll: (x,y) => { window.scrollTo(x,y); return true; }
};
{
"name": "Hermes Browser Agent",
"description": "Browser control extension for Hermes Node Agent",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"activeTab",
"scripting",
"storage",
"tabs",
"webNavigation"
],
"host_permissions": ["*://*/*"],
"background": {
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"minimum_chrome_version": "92"
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hermes Agent</title>
<style>
body { width: 280px; padding: 12px; font-family: Segoe UI,-apple-system,sans-serif; font-size: 13px; }
h4 { margin: 0 0 8px 0; color: #1a73e8; font-weight: 600; }
.status { padding: 8px; border-radius: 4px; margin-bottom: 8px; font-size: 11px; }
</style>
</head>
<body>
<h4>🌐 Hermes Browser Agent</h4>
<div id="status" class="status">Connecting to Hermes Node...</div>
<script src="popup.js"></script>
</body>
</html>
\ No newline at end of file
const statusEl = document.getElementById('status');
setTimeout(() => {
chrome.runtime.sendMessage({type:'ping'}, resp => {
statusEl.textContent = resp.connected ? '● Connected to Hermes Node' : '○ Not connected (node agent not running)';
statusEl.style.background = resp.connected ? '#e8f5e9' : '#fff3e0';
statusEl.style.color = resp.connected ? '#2e7d32' : '#ef6c00';
});
}, 500);
#!/bin/bash
# Complete Windows installer build: PyInstaller + NSIS
# Works on Linux using Wine Windows Python environment
#
# Prerequisites:
# - wine (already installed)
# - makensis (NSIS compiler)
# - nssm.exe in windows/ directory (download from nssm.cc)
#
# This script:
# 1. Builds Windows .exe binaries with PyInstaller (via Wine)
# 2. Packages them with NSIS installer with interactive config page
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"
WINEPYTHON="./python-win/python.exe"
DIST_DIR="./dist"
BUILD_DIR="./build"
echo "=== Hermes Node Agent: Windows Installer Build ==="
echo ""
# ── Validation ────────────────────────────────────────────────────────────
if ! command -v makensis &>/dev/null; then
echo "❌ NSIS (makensis) not installed"
exit 1
fi
if [ ! -f "$WINEPYTHON" ]; then
echo "❌ Wine Python not found: $WINEPYTHON"
echo " Run: wget https://www.python.org/ftp/python/3.13.1/python-3.13.1-embed-amd64.zip"
echo " unzip it to windows/python-win/"
exit 1
fi
if [ ! -f "nssm.exe" ]; then
echo "⚠️ NSSM not found in windows/"
echo " Download from https://nssm.cc/download (win64 version)"
echo " and place it at windows/nssm.exe"
exit 1
fi
# ── Step 1: PyInstaller Build ─────────────────────────────────────────────
echo "Building Windows executables with PyInstaller..."
# Clean previous build
rm -rf "$DIST_DIR" "$BUILD_DIR"
mkdir -p "$DIST_DIR" "$BUILD_DIR"
# Build agent (console)
echo " → hermes-node-agent.exe"
wine "$WINEPYTHON" -m PyInstaller ^
--onefile ^
--name hermes-node-agent ^
--distpath "$DIST_DIR" ^
--workpath "$BUILD_DIR/agent" ^
--specpath windows ^
--console ^
--noconfirm ^
hermes_node_agent.py 2>&1 | tail -3
# Build manager (GUI)
echo " → hermes-node-manager.exe"
wine "$WINEPYTHON" -m PyInstaller ^
--onefile ^
--windowed ^
--name hermes-node-manager ^
--distpath "$DIST_DIR" ^
--workpath "$BUILD_DIR/manager" ^
--specpath windows ^
--noconfirm ^
agent-manager.py 2>&1 | tail -3
# Verify both exist
if [ ! -f "$DIST_DIR/hermes-node-agent.exe" ] || [ ! -f "$DIST_DIR/hermes-node-manager.exe" ]; then
echo "❌ PyInstaller build failed"
exit 1
fi
echo "✅ PyInstaller build complete:"
ls -lh "$DIST_DIR/"*.exe
# ── Step 2: Prepare NSIS installer files ──────────────────────────────────
echo ""
echo "Preparing NSIS installer..."
# Copy nssm and config template to dist
cp nssm.exe "$DIST_DIR/"
cp config-template.json "$DIST_DIR/config.json"
# ── Step 3: Write NSIS installer script ───────────────────────────────────
cat > "$DIST_DIR/installer.nsi" <<'NSIS'
!include "MUI2.nsh"
!include "LogicLib.nsh"
Name "Hermes Node Agent v2.0"
OutFile "hermes-node-agent-installer.exe"
InstallDir "$PROGRAMFILES64\HermesNode"
RequestExecutionLevel admin
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
; Custom configuration page (same prompts as Linux installer)
Page custom ConfigPageCreate ConfigPageLeave
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "English"
; ── Variables ─────────────────────────────────────────────────────────────
Var GW_HOST
Var NODE_NAME
Var GW_TOKEN
Var NODE_NAME_DEFAULT
; Get computer name as default
Function .onInit
System::Call "kernel32::GetComputerName(t .r0, *i ${NSIS_MAX_STRLEN}) i.r1"
StrCpy $NODE_NAME_DEFAULT $0
FunctionEnd
; ── Configuration page UI ─────────────────────────────────────────────────
Function ConfigPageCreate
nsDialogs::Create 1018
Pop $0
${If} $0 == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 140u "Enter your Hermes Node Agent configuration:"
Pop $0
${NSD_CreateLabel} 0 50u 100% 10u "Gateway URL (e.g., ws://gateway.example.com:8765):"
Pop $0
${NSD_CreateText} 0 62u 100% 12u "ws://localhost:8765"
Pop $GW_HOST
${NSD_CreateLabel} 0 82u 100% 10u "Node name (will appear in gateway):"
Pop $0
${NSD_CreateText} 0 94u 100% 12u $NODE_NAME_DEFAULT
Pop $NODE_NAME
${NSD_CreateLabel} 0 114u 100% 10u "Gateway token (from your gateway admin):"
Pop $0
${NSD_CreatePassword} 0 126u 100% 12u ""
Pop $GW_TOKEN
nsDialogs::Show
FunctionEnd
Function ConfigPageLeave
${NSD_GetText} $GW_HOST $0
${NSD_GetText} $NODE_NAME $1
${NSD_GetText} $GW_TOKEN $2
StrLen $3 $0
${If} $3 < 5
MessageBox MB_ICONSTOP "Gateway URL is required and must be at least 5 characters."
Abort
${EndIf}
FunctionEnd
; ── Install section ────────────────────────────────────────────────────────
Section "Install"
SetOutPath "$INSTDIR"
; Copy PyInstaller-built executables
File "hermes-node-agent.exe"
File "hermes-node-manager.exe"
; Service wrapper (if present)
IfFileExists "nssm.exe" 0 skip_nssm
File "nssm.exe"
skip_nssm:
; Get user-provided config
${NSD_GetText} $GW_HOST $0
${NSD_GetText} $NODE_NAME $1
${NSD_GetText} $GW_TOKEN $2
; Create config.json in Common AppData (C:\ProgramData\HermesNode)
CreateDirectory "C:\ProgramData\HermesNode"
; Write config using PowerShell (simpler than NSIS string magic)
nsExec::ExecToLog 'powershell -Command "[IO.File]::WriteAllText(''C:\ProgramData\HermesNode\config.json'', @"{{
''gateway_url'': ''$0'',
''node_name'': ''$1'',
''token'': ''$2'',
''sexec_path'': ''.\sexec-template.ps1'',
''reconnect_interval'': 5,
''heartbeat_interval'': 30,
''capabilities'': [''exec'', ''browser_control'', ''computer_control'']
}}")"'
; Write uninstaller
WriteUninstaller "$INSTDIR\uninstall.exe"
; Create start menu shortcuts
CreateDirectory "$SMPROGRAMS\Hermes Node"
CreateShortCut "$SMPROGRAMS\Hermes Node\Agent (Console).lnk" "$INSTDIR\hermes-node-agent.exe"
CreateShortCut "$SMPROGRAMS\Hermes Node\Manager.lnk" "$INSTDIR\hermes-node-manager.exe"
CreateShortCut "$SMPROGRAMS\Hermes Node\Uninstall.lnk" "$INSTDIR\uninstall.exe"
; Desktop shortcut
CreateShortCut "$DESKTOP\Hermes Node Agent.lnk" "$INSTDIR\hermes-node-manager.exe"
; Install service — silently
IfFileExists "$INSTDIR\nssm.exe" 0 no_nssm
nsExec::ExecToLog '"$INSTDIR\nssm.exe" install HermesNodeAgent "$INSTDIR\hermes-node-agent.exe" --config "C:\ProgramData\HermesNode\config.json"'
nsExec::ExecToLog '"$INSTDIR\nssm.exe" set HermesNodeAgent AppDirectory "$INSTDIR"'
nsExec::ExecToLog '"$INSTDIR\nssm.exe" set HermesNodeAgent Start SERVICE_AUTO_START'
nsExec::ExecToLog '"$INSTDIR\nssm.exe" set HermesNodeAgent AppRestartDelay 5000'
no_nssm:
SectionEnd
; ── Uninstall section ─────────────────────────────────────────────────────
Section "Uninstall"
IfFileExists "$INSTDIR\nssm.exe" 0 no_stop
nsExec::ExecToLog '"$INSTDIR\nssm.exe" stop HermesNodeAgent'
nsExec::ExecToLog '"$INSTDIR\nssm.exe" remove HermesNodeAgent confirm'
no_stop:
RMDir /r "$INSTDIR"
RMDir /r "$SMPROGRAMS\Hermes Node"
Delete "$DESKTOP\Hermes Node Agent.lnk"
; Optionally keep config (or remove? Up to you)
; RMDir /r "C:\ProgramData\HermesNode"
SectionEnd
NSIS
echo ""
echo "Compiling NSIS installer..."
makensis "$DIST_DIR/installer.nsi" 2>&1 | tail -5
if [ -f "$DIST_DIR/hermes-node-agent-installer.exe" ]; then
echo ""
echo "========== BUILD COMPLETE =========="
echo "Installer created: $DIST_DIR/hermes-node-agent-installer.exe"
echo "Size: $(du -h "$DIST_DIR/hermes-node-agent-installer.exe" | cut -f1)"
echo ""
echo "Next: copy to Windows for testing / distribution"
else
echo "❌ Build failed"
exit 1
fi
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
MIT License
Copyright (c) 2026 Lisa (Hermes AI) / OpenClaw Project
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This diff is collapsed.
# Hermes Node Agent
**Version:** 2.0
**Repository:** `git@git.nexlab.net:lisa/hermes-node-agent.git`
Cross-platform node agent for the Hermes Node Protocol. Connects to a central gateway via WebSocket and executes commands with permission enforcement.
---
## Features
- **Cross-platform**: Linux and Windows support
- **Reverse connection**: Nodes connect to gateway (firewall-friendly)
- **Token authentication**: Secure per-node tokens
- **Permission system**: sexec-based allow/deny/ask rules
- **Auto-reconnect**: Exponential backoff on disconnect
- **Heartbeat**: Keep-alive mechanism
- **Optional capabilities**: Browser control, computer control
---
## Platforms
### Linux
- Bash installer with SysV init service
- CLI-based configuration
- Runs as daemon
### Windows
- Graphical installer (.exe via Inno Setup)
- System tray GUI manager
- Windows Service integration (NSSM)
- Configuration editor (no manual JSON editing)
- Log viewer with auto-refresh
---
## Installation
### Linux
```bash
sudo ./install.sh
sudo nano /etc/hermes-node/config.json # Edit gateway_url and token
sudo /etc/init.d/hermes-node-agent start
```
### Windows
1. Build installer (on Windows dev machine):
```cmd
python windows\build.py
```
2. Run `windows\Output\hermes-node-agent-installer.exe` as Administrator
3. Configure via system tray: Right-click icon → Configuration
---
## Configuration
**Linux:** `/etc/hermes-node/config.json`
**Windows:** `C:\ProgramData\hermes-node\config.json`
```json
{
"gateway_url": "wss://gateway-host:8765",
"node_name": "my-node",
"token": "your-token-here",
"sexec_path": "/path/to/sexec.sh",
"reconnect_interval": 5,
"heartbeat_interval": 30
}
```
---
### Browser Control Capability
For browser automation support, the bot control capability uses the **Hermes Node Chrome Extension**:
**Repository:** `git@git.nexlab.net:lisa/hermes-node-chrome.git`
The extension enables DOM manipulation, screenshots, and click/type automation.
---
## Files
```
node-agent/
├── hermes_node_agent.py # Main agent (cross-platform)
├── browser_controller.py # Browser control capability
├── install.sh # Linux installer
├── install-windows.ps1 # Windows PowerShell installer (legacy)
├── hermes-node-agent.init.d # SysV init script
├── hermes-node-agent.service # systemd unit (alternative)
├── requirements.txt # Python dependencies
└── windows/ # Windows-specific components
├── agent-manager.py # System tray GUI
├── installer.iss # Inno Setup script
├── build.py # Build automation
└── README.md # Build instructions
```
---
## Documentation
- **DEPLOYMENT.md** — Full deployment guide
- **WINDOWS_DEPLOYMENT.md** — Windows-specific guide
- **PROTOCOL.md** — WebSocket protocol specification
- **windows/README.md** — Windows build instructions
---
## Related Repositories
- **Gateway Plugin:** `~/.hermes/plugins/hermes-node-gateway/` (loaded by Hermes Agent)
- **Node Agent:** `git@git.nexlab.net:lisa/hermes-node-agent.git`
- **Chrome Extension:** `git@git.nexlab.net:lisa/hermes-node-chrome.git`
---
## License
MIT License — See the [LICENSE](LICENSE) file in this repository.
---
## Support
For issues, check:
- Agent logs: `/var/log/hermes-node-agent.log` (Linux) or `C:\ProgramData\hermes-node\hermes-node-agent.log` (Windows)
- Gateway logs on gateway host
- Configuration files for token/URL mismatches
## Donate
If you find this project useful, consider supporting its continued development:
**Bitcoin (BTC)**: `bc1ql5klyv78t0a5g59y3tczv8ejy9l740x3zg0cge`
**Ethereum (ETH)**: `0x3f707d3543A6C301B3Bf47eBc4B469e017a119B4`
**Solana (SOL)**: `G7iZQ3iQ7k5t9E9g8Y7u6i5t4r3e2w1q0P9O8I7U6Y5`
---
*Copyright (c) 2026 Stefy (nextime) Lanza <stefy@nexlab.net>. All rights reserved.*
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/bin/sh
# /etc/init.d/hermes-node-agent
# SysVinit script for Hermes Node Agent
#
# chkconfig: 2345 95 05
# description: Hermes Node Agent reverse-connected WebSocket client
### BEGIN INIT INFO
# Provides: hermes-node-agent
# Required-Start: $network $remote_fs $syslog
# Required-Stop: $network $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Hermes Node Agent
# Description: Reverse-connected WebSocket node agent.
### END INIT INFO
NAME="hermes-node-agent"
DAEMON="/usr/bin/python3"
SCRIPT_DIR="/usr/local/bin"
DAEMON_SCRIPT="${SCRIPT_DIR}/hermes_node_agent.py"
PIDFILE="/var/run/${NAME}.pid"
LOGFILE="/var/log/${NAME}.log"
USER="root"
GROUP="root"
# Check daemon exists
if [ ! -x "$DAEMON" ]; then
echo "$DAEMON not found or not executable."
exit 5
fi
if [ ! -f "$DAEMON_SCRIPT" ]; then
echo "$DAEMON_SCRIPT not found."
exit 5
fi
# Ensure config exists
if [ ! -f "/etc/hermes-node/config.json" ]; then
echo "/etc/hermes-node/config.json not found."
exit 6
fi
. /lib/lsb/init-functions 2>/dev/null || true
start() {
echo "Starting $NAME..."
if [ -f "$PIDFILE" ]; then
PID=$(cat "$PIDFILE")
if kill -0 "$PID" 2>/dev/null; then
echo "$NAME is already running (PID $PID)."
return 0
else
rm -f "$PIDFILE"
fi
fi
touch "$LOGFILE"
chown "$USER:$GROUP" "$LOGFILE" 2>/dev/null || chmod 644 "$LOGFILE"
$DAEMON $DAEMON_SCRIPT >> "$LOGFILE" 2>&1 &
echo $! > "$PIDFILE"
sleep 1
if kill -0 $(cat "$PIDFILE") 2>/dev/null; then
echo "$NAME started (PID $(cat $PIDFILE))."
else
echo "$NAME failed to start. Check $LOGFILE"
exit 1
fi
}
stop() {
echo "Stopping $NAME..."
if [ -f "$PIDFILE" ]; then
PID=$(cat "$PIDFILE")
if kill -0 "$PID" 2>/dev/null; then
kill "$PID" 2>/dev/null
for i in $(seq 1 30); do
if ! kill -0 "$PID" 2>/dev/null; then
break
fi
sleep 0.5
done
if kill -0 "$PID" 2>/dev/null; then
echo "Force killing..."
kill -9 "$PID" 2>/dev/null
sleep 1
fi
fi
rm -f "$PIDFILE"
echo "$NAME stopped."
else
echo "$NAME is not running."
fi
pkill -f "hermes_node_agent.py" 2>/dev/null || true
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 1
start
;;
reload|force-reload)
echo "Reload not supported, restarting..."
stop
sleep 1
start
;;
status)
RUNNING=0
if [ -f "$PIDFILE" ]; then
PID=$(cat "$PIDFILE")
if kill -0 "$PID" 2>/dev/null; then
echo "$NAME is running (PID $PID)."
RUNNING=1
else
echo "$NAME is not running (stale PID file)."
RUNNING=0
fi
else
PID=$(pgrep -f "hermes_node_agent.py" | head -1)
if [ -n "$PID" ]; then
echo "$NAME is running (PID $PID) but no PID file."
RUNNING=1
else
echo "$NAME is not running."
RUNNING=0
fi
fi
exit $(( 1 - RUNNING ))
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0
# Hermes Node Protocol
# Copyright (c) 2026 Stefy (nextime) Lanza <stefy@nexlab.net>
# All rights reserved.
#
# This software is released under the MIT License with a copyleft clause.
# See the LICENSE file for full terms.
[Unit]
Description=Hermes Node Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/hermes-node-agent
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/tmp
[Install]
WantedBy=default.target
This diff is collapsed.
This diff is collapsed.
# Hermes Node Protocol
# Copyright (c) 2026 Stefy (nextime) Lanza <stefy@nexlab.net>
# All rights reserved.
#
# This software is released under the MIT License with a copyleft clause.
# See the LICENSE file for full terms.
websockets>=16.0
playwright>=1.59.0
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""Hermes Node Agent Windows Installer — GUI (Inno Setup)
Creates a professional Windows installer (.exe) that bundles:
• Python runtime (embedded)
• Hermes node agent script
• Hermes node manager GUI
• NSSM service wrapper
• All Python dependencies (websockets)
The installer creates:
• Service: HermesNodeAgent (runs as LocalSystem)
• System tray manager (starts at user login)
• Configuration in %PROGRAMDATA%\hermes-node\
• Uninstaller in Windows "Add/Remove Programs"
Author: Lisa (Hermes AI)
Date: 2026-04-30
"""
[Setup]
AppName=Hermes Node Agent
AppVersion=2.0
AppCopyright=Copyright (c) 2026 Lisa (Hermes AI)
DefaultDirName={autopf}\Hermes Node
DefaultGroupName=Hermes Node
UninstallDisplayIcon={app}\hermes-node-manager.exe
OutputBaseFilename=hermes-node-agent-installer
Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=administrator
ArchitecturesInstallIn64BitMode=x64
DisableProgramGroupPage=no
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "italian"; MessagesFile: "compiler:Italian.isl"
[Tasks]
Name: "starttray"; Description: "Start Hermes Node Manager at login (recommended)"; GroupDescription: "Additional icons:"; Flags: unchecked
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "Additional icons:"; Flags: unchecked
[Files]
; ── NSSM (service manager)
Source: "windows\nssm.exe"; DestDir: "{app}"; Flags: ignoreversion
; ── Hermes agent script
Source: "node-agent\hermes_node_agent.py"; DestDir: "{app}"; Flags: ignoreversion
; ── Agent manager GUI
Source: "windows\agent-manager.py"; DestDir: "{app}"; Flags: ignoreversion
; ── Python embedded runtime (zipapp)
Source: "windows\python-embed.zip"; DestDir: "{app}"; Flags: ignoreversion
; ── PyInstaller-converted executables (these will be built first)
Source: "windows\dist\hermes-node-agent.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "windows\dist\hermes-node-manager.exe"; DestDir: "{app}"; Flags: ignoreversion
; ── Permissions script template
Source: "windows\sexec-template.ps1"; DestName: "sexec-template.ps1"; DestDir: "{app}"; Flags: ignoreversion
; ── Documentation
Source: "WINDOWS_INSTALL.md"; DestName: "README.md"; DestDir: "{app}"; Flags: isreadme
[Icons]
Name: "{group}\Hermes Node Manager"; Filename: "{app}\hermes-node-manager.exe"
Name: "{group}\Uninstall Hermes Node Agent"; Filename: "{uninstallexe}"
Name: "{commondesktop}\Hermes Node Agent"; Filename: "{app}\hermes-node-manager.exe"; Tasks: desktopicon
[Run]
; Start the manager on first install (if user chose the task)
Filename: "{app}\hermes-node-manager.exe"; Description: "Start Hermes Node Manager"; Flags: postinstall nowait skipifsilent; Tasks: starttray
[Code]
function InitializeSetup(): Boolean;
begin
// Show welcome page
Result := True;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then begin
// Create config directory
ForceDirectories(ExpandConstant('{commonappdata}\hermes-node'));
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if CurPageID = wpSelectDir then begin
// Validate that Program Files is writable (needs admin)
if not IsAdminLoggedOn then begin
MsgBox('This installer requires Administrator privileges to install the service.', mbError, MB_OK);
Result := False;
end;
end;
end;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['..\\hermes_node_agent.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='hermes-node-agent',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment