Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
H
hermes-node-agent
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lisa
hermes-node-agent
Commits
aa563f0a
Commit
aa563f0a
authored
May 13, 2026
by
Lisa (AI Assistant)
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: restore integrated exec and installer capability sync
parent
3f9ac2ad
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
626 additions
and
491 deletions
+626
-491
build-linux.sh
build-linux.sh
+3
-3
hermes_node_agent.py
hermes_node_agent.py
+191
-51
install-node.sh
package-hermes-node-agent/deploy/install-node.sh
+34
-339
hermes_node_agent.py
package-hermes-node-agent/hermes_node_agent.py
+201
-73
install.sh
package-hermes-node-agent/install.sh
+197
-25
No files found.
build-linux.sh
View file @
aa563f0a
...
...
@@ -19,11 +19,11 @@ mkdir -p "$PACKAGE_DIR"
echo
"Copying files to
$PACKAGE_DIR
..."
# Copy core files
cp
hermes_node_agent.py
"
$PACKAGE_DIR
/
"
# Copy core files
from the package source of truth
cp
package-hermes-node-agent/hermes_node_agent.py
"
$PACKAGE_DIR
/hermes_node_agent.py
"
cp
browser_controller.py
"
$PACKAGE_DIR
/"
cp
requirements.txt
"
$PACKAGE_DIR
/"
cp
install.sh
"
$PACKAGE_DIR
/
"
cp
package-hermes-node-agent/install.sh
"
$PACKAGE_DIR
/install.sh
"
cp
hermes-node-agent.init.d
"
$PACKAGE_DIR
/"
cp
hermes-node-agent.service
"
$PACKAGE_DIR
/"
...
...
hermes_node_agent.py
View file @
aa563f0a
This diff is collapsed.
Click to expand it.
package-hermes-node-agent/deploy/install-node.sh
View file @
aa563f0a
This diff is collapsed.
Click to expand it.
package-hermes-node-agent/hermes_node_agent.py
View file @
aa563f0a
This diff is collapsed.
Click to expand it.
package-hermes-node-agent/install.sh
View file @
aa563f0a
...
...
@@ -42,14 +42,32 @@ if ! command -v pip3 &> /dev/null; then
exit
1
fi
# Install websockets library
# Install websockets library only if missing
# On modern Debian/Ubuntu with PEP 668, system pip may be externally managed.
echo
"[1/5] Installing Python dependencies..."
pip3
install
--quiet
websockets 2>/dev/null
||
pip
install
--quiet
websockets
if
[
$?
-ne
0
]
;
then
echo
"❌ Failed to install websockets. Try: pip3 install websockets"
exit
1
if
python3
-c
"import websockets"
2>/dev/null
;
then
echo
"✓ websockets library already installed"
else
PIP_OK
=
false
if
command
-v
pip3
>
/dev/null 2>&1
;
then
if
pip3
install
--quiet
--user
websockets 2>/dev/null
;
then
PIP_OK
=
true
fi
fi
if
[
"
$PIP_OK
"
!=
true
]
&&
command
-v
pip
>
/dev/null 2>&1
;
then
if
pip
install
--quiet
--user
websockets 2>/dev/null
;
then
PIP_OK
=
true
fi
fi
if
[
"
$PIP_OK
"
!=
true
]
;
then
echo
"❌ Failed to install websockets in user site-packages."
echo
" Try one of:"
echo
" - apt install python3-websockets"
echo
" - python3 -m venv ~/hermes-node-venv && ~/hermes-node-venv/bin/pip install websockets"
exit
1
fi
echo
"✓ websockets library installed"
fi
echo
"✓ websockets library installed"
# Determine install locations
if
[
"
$RUN_AS_ROOT
"
=
true
]
;
then
...
...
@@ -71,30 +89,184 @@ cp "$(pwd)/node-agent/hermes_node_agent.py" "$AGENT_DIR/hermes-node-agent"
chmod
+x
"
$AGENT_DIR
/hermes-node-agent"
echo
"✓ Installed:
$AGENT_DIR
/hermes-node-agent"
# Create config file if missing
echo
"[3/5] Checking configuration..."
if
[
!
-f
"
$CONFIG_DIR
/config.json"
]
;
then
echo
"[4/5] Creating config file..."
TOKEN
=
$(
python3
-c
"import secrets; print(secrets.token_hex(16))"
)
cat
>
"
$CONFIG_DIR
/config.json"
<<
EOF
# Create or update config interactively, using existing values as defaults
echo
"[3/5] Configuring node..."
EXISTING_GATEWAY_URL
=
"wss://YOUR-GATEWAY-HOST:8765"
EXISTING_NODE_NAME
=
"
$(
hostname
)
"
EXISTING_TOKEN
=
"
$(
python3
-c
"import secrets; print(secrets.token_hex(16))"
)
"
EXISTING_ENABLE_BROWSER
=
"false"
EXISTING_ENABLE_COMPUTER_CONTROL
=
"false"
EXISTING_ENABLE_DESKTOP_OBSERVE
=
"false"
EXISTING_ENABLE_AUDIO_CONTROL
=
"false"
if
[
-f
"
$CONFIG_DIR
/config.json"
]
;
then
EXISTING_GATEWAY_URL
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(data.get('gateway_url', 'wss://YOUR-GATEWAY-HOST:8765'))
PY
)
EXISTING_NODE_NAME
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(data.get('node_name', '
$(
hostname
)
'))
PY
)
EXISTING_TOKEN
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(data.get('token', ''))
PY
)
EXISTING_ENABLE_BROWSER
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_browser', False))).lower())
PY
)
EXISTING_ENABLE_COMPUTER_CONTROL
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_computer_control', False))).lower())
PY
)
EXISTING_ENABLE_DESKTOP_OBSERVE
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_desktop_observe', False))).lower())
PY
)
EXISTING_ENABLE_AUDIO_CONTROL
=
$(
python3 -
<<
PY
import json
from pathlib import Path
p = Path(r'''
$CONFIG_DIR
/config.json''')
data = json.loads(p.read_text())
print(str(bool(data.get('enable_audio_control', False))).lower())
PY
)
echo
" Existing config found:
$CONFIG_DIR
/config.json"
fi
read
-r
-p
"Gateway URL [
$EXISTING_GATEWAY_URL
]: "
GATEWAY_URL
GATEWAY_URL
=
${
GATEWAY_URL
:-
$EXISTING_GATEWAY_URL
}
read
-r
-p
"Node name [
$EXISTING_NODE_NAME
]: "
NODE_NAME
NODE_NAME
=
${
NODE_NAME
:-
$EXISTING_NODE_NAME
}
read
-r
-p
"Token [
$EXISTING_TOKEN
]: "
TOKEN
TOKEN
=
${
TOKEN
:-
$EXISTING_TOKEN
}
DEFAULT_BROWSER_CHOICE
=
"n"
[
"
$EXISTING_ENABLE_BROWSER
"
=
"true"
]
&&
DEFAULT_BROWSER_CHOICE
=
"y"
read
-r
-p
"Enable browser_control? (y/N) [
$DEFAULT_BROWSER_CHOICE
]: "
ENABLE_BROWSER_INPUT
ENABLE_BROWSER_INPUT
=
${
ENABLE_BROWSER_INPUT
:-
$DEFAULT_BROWSER_CHOICE
}
case
"
$ENABLE_BROWSER_INPUT
"
in
y|Y|yes|YES
)
ENABLE_BROWSER
=
true
;;
*
)
ENABLE_BROWSER
=
false
;;
esac
DEFAULT_COMPUTER_CHOICE
=
"n"
[
"
$EXISTING_ENABLE_COMPUTER_CONTROL
"
=
"true"
]
&&
DEFAULT_COMPUTER_CHOICE
=
"y"
read
-r
-p
"Enable computer_control? (y/N) [
$DEFAULT_COMPUTER_CHOICE
]: "
ENABLE_COMPUTER_INPUT
ENABLE_COMPUTER_INPUT
=
${
ENABLE_COMPUTER_INPUT
:-
$DEFAULT_COMPUTER_CHOICE
}
case
"
$ENABLE_COMPUTER_INPUT
"
in
y|Y|yes|YES
)
ENABLE_COMPUTER_CONTROL
=
true
;;
*
)
ENABLE_COMPUTER_CONTROL
=
false
;;
esac
DEFAULT_DESKTOP_CHOICE
=
"n"
[
"
$EXISTING_ENABLE_DESKTOP_OBSERVE
"
=
"true"
]
&&
DEFAULT_DESKTOP_CHOICE
=
"y"
read
-r
-p
"Enable desktop_observe? (y/N) [
$DEFAULT_DESKTOP_CHOICE
]: "
ENABLE_DESKTOP_INPUT
ENABLE_DESKTOP_INPUT
=
${
ENABLE_DESKTOP_INPUT
:-
$DEFAULT_DESKTOP_CHOICE
}
case
"
$ENABLE_DESKTOP_INPUT
"
in
y|Y|yes|YES
)
ENABLE_DESKTOP_OBSERVE
=
true
;;
*
)
ENABLE_DESKTOP_OBSERVE
=
false
;;
esac
DEFAULT_AUDIO_CHOICE
=
"n"
[
"
$EXISTING_ENABLE_AUDIO_CONTROL
"
=
"true"
]
&&
DEFAULT_AUDIO_CHOICE
=
"y"
read
-r
-p
"Enable audio_control? (y/N) [
$DEFAULT_AUDIO_CHOICE
]: "
ENABLE_AUDIO_INPUT
ENABLE_AUDIO_INPUT
=
${
ENABLE_AUDIO_INPUT
:-
$DEFAULT_AUDIO_CHOICE
}
case
"
$ENABLE_AUDIO_INPUT
"
in
y|Y|yes|YES
)
ENABLE_AUDIO_CONTROL
=
true
;;
*
)
ENABLE_AUDIO_CONTROL
=
false
;;
esac
CAPABILITIES
=
'["exec"]'
if
[
"
$ENABLE_BROWSER
"
=
true
]
;
then
CAPABILITIES
=
$(
python3 -
<<
'
PY
' "
$CAPABILITIES
"
import json, sys
caps = json.loads(sys.argv[1])
if 'browser_control' not in caps:
caps.append('browser_control')
print(json.dumps(caps))
PY
)
fi
if
[
"
$ENABLE_COMPUTER_CONTROL
"
=
true
]
;
then
CAPABILITIES
=
$(
python3 -
<<
'
PY
' "
$CAPABILITIES
"
import json, sys
caps = json.loads(sys.argv[1])
if 'computer_control' not in caps:
caps.append('computer_control')
print(json.dumps(caps))
PY
)
fi
if
[
"
$ENABLE_DESKTOP_OBSERVE
"
=
true
]
;
then
CAPABILITIES
=
$(
python3 -
<<
'
PY
' "
$CAPABILITIES
"
import json, sys
caps = json.loads(sys.argv[1])
if 'desktop_observe' not in caps:
caps.append('desktop_observe')
print(json.dumps(caps))
PY
)
fi
if
[
"
$ENABLE_AUDIO_CONTROL
"
=
true
]
;
then
CAPABILITIES
=
$(
python3 -
<<
'
PY
' "
$CAPABILITIES
"
import json, sys
caps = json.loads(sys.argv[1])
if 'audio_control' not in caps:
caps.append('audio_control')
print(json.dumps(caps))
PY
)
fi
cat
>
"
$CONFIG_DIR
/config.json"
<<
EOF
{
"gateway_url": "wss://YOUR-GATEWAY-HOST:8765
",
"node_name": "
$
(
hostname
)
",
"gateway_url": "
$GATEWAY_URL
",
"node_name": "
$
NODE_NAME
",
"token": "
$TOKEN
",
"sexec_path": "
$HOME
/.config/hermes-node-agent/sexec/sexec.sh",
"reconnect_interval": 5,
"heartbeat_interval": 30
"heartbeat_interval": 30,
"capabilities":
$CAPABILITIES
,
"enable_browser":
$ENABLE_BROWSER
,
"enable_computer_control":
$ENABLE_COMPUTER_CONTROL
,
"enable_desktop_observe":
$ENABLE_DESKTOP_OBSERVE
,
"enable_audio_control":
$ENABLE_AUDIO_CONTROL
,
"permissions": {
"deny": ["sudo", "su", "doas", "dd if=", "mkfs", "fdisk", "wipe"],
"ask": ["rm -rf", "dd if=", "> /dev/", "chmod", "chown", "mv /", ":/usr/", ":/etc/", ":/bin/", ":/sbin/"],
"allow": ["cat", "ls", "pwd", "cd", "echo", "head", "tail", "wc", "grep", "find", "stat", "file", "which", "whereis", "df", "du", "free", "uptime", "who", "w", "last", "ps", "top", "htop", "uname", "env", "printenv"]
}
}
EOF
echo
"✓ Config:
$CONFIG_DIR
/config.json"
echo
""
echo
"⚠️ IMPORTANT: Edit
$CONFIG_DIR
/config.json"
echo
" → Set gateway_url to your gateway (e.g., wss://zeiss:8765)"
echo
" → Set token to match gateway's token for this node"
else
echo
"[4/5] Config already exists → skipping"
echo
" Config:
$CONFIG_DIR
/config.json"
fi
echo
"[4/5] Wrote config:
$CONFIG_DIR
/config.json"
# Install SysV init service (root only)
if
[
"
$RUN_AS_ROOT
"
=
true
]
&&
[
-f
"
$SERVICE_FILE
"
]
;
then
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment