Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion install/hiclaw-install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ function Wait-MatrixReady {

while ($elapsed -lt $Timeout) {
try {
$result = docker exec $Container curl -sf http://127.0.0.1:6167/_tuwunel/server_version 2>$null
$result = docker exec $Container curl -sf http://127.0.0.1:6167/_matrix/client/versions 2>$null
if ($result) {
Write-Log (Get-Msg "install.wait_matrix.ok")
return $true
Expand Down Expand Up @@ -835,6 +835,15 @@ HICLAW_DEFAULT_WORKER_RUNTIME=$($Config.DEFAULT_WORKER_RUNTIME)
# Matrix E2EE (0=disabled, 1=enabled; default: 0)
HICLAW_MATRIX_E2EE=$($Config.MATRIX_E2EE)

# Matrix provider (tuwunel | synapse; default: tuwunel)
HICLAW_MATRIX_PROVIDER=$($Config.MATRIX_PROVIDER)
HICLAW_SYNAPSE_SHARED_SECRET=$($Config.SYNAPSE_SHARED_SECRET)
HICLAW_PG_HOST=$($Config.PG_HOST)
HICLAW_PG_PORT=$($Config.PG_PORT)
HICLAW_PG_USER=$($Config.PG_USER)
HICLAW_PG_PASSWORD=$($Config.PG_PASSWORD)
HICLAW_PG_DATABASE=$($Config.PG_DATABASE)

# Docker API proxy (0=disabled, 1=enabled; default: 1)
HICLAW_DOCKER_PROXY=$($Config.DOCKER_PROXY)

Expand Down Expand Up @@ -2114,6 +2123,10 @@ function Install-Manager {
$config.MINIO_USER = if ($env:HICLAW_MINIO_USER) { $env:HICLAW_MINIO_USER } else { $config.ADMIN_USER }
$config.MINIO_PASSWORD = if ($env:HICLAW_MINIO_PASSWORD) { $env:HICLAW_MINIO_PASSWORD } else { $config.ADMIN_PASSWORD }
$config.MANAGER_GATEWAY_KEY = if ($env:HICLAW_MANAGER_GATEWAY_KEY) { $env:HICLAW_MANAGER_GATEWAY_KEY } else { New-RandomKey }
if (-not $config.MATRIX_PROVIDER) { $config.MATRIX_PROVIDER = if ($env:HICLAW_MATRIX_PROVIDER) { $env:HICLAW_MATRIX_PROVIDER } else { "tuwunel" } }
if ($config.MATRIX_PROVIDER -eq "synapse") {
$config.SYNAPSE_SHARED_SECRET = if ($env:HICLAW_SYNAPSE_SHARED_SECRET) { $env:HICLAW_SYNAPSE_SHARED_SECRET } else { New-RandomKey }
}

# Store additional config
$config.LANGUAGE = $script:HICLAW_LANGUAGE
Expand Down
15 changes: 14 additions & 1 deletion install/hiclaw-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ wait_matrix_ready() {
log "$(msg install.wait_matrix "${timeout}")"

while [ "${elapsed}" -lt "${timeout}" ]; do
if ${DOCKER_CMD} exec "${container}" curl -sf http://127.0.0.1:6167/_tuwunel/server_version >/dev/null 2>&1; then
if ${DOCKER_CMD} exec "${container}" curl -sf http://127.0.0.1:6167/_matrix/client/versions >/dev/null 2>&1; then
log "$(msg install.wait_matrix.ok)"
return 0
fi
Expand Down Expand Up @@ -2186,6 +2186,10 @@ install_manager() {
HICLAW_MINIO_USER="${HICLAW_MINIO_USER:-${HICLAW_ADMIN_USER}}"
HICLAW_MINIO_PASSWORD="${HICLAW_MINIO_PASSWORD:-${HICLAW_ADMIN_PASSWORD}}"
HICLAW_MANAGER_GATEWAY_KEY="${HICLAW_MANAGER_GATEWAY_KEY:-$(generate_key)}"
HICLAW_MATRIX_PROVIDER="${HICLAW_MATRIX_PROVIDER:-tuwunel}"
if [ "${HICLAW_MATRIX_PROVIDER}" = "synapse" ]; then
HICLAW_SYNAPSE_SHARED_SECRET="${HICLAW_SYNAPSE_SHARED_SECRET:-$(generate_key)}"
fi

# Write .env file
ENV_FILE="${HICLAW_ENV_FILE:-${HOME}/hiclaw-manager.env}"
Expand Down Expand Up @@ -2272,6 +2276,15 @@ HICLAW_DEFAULT_WORKER_RUNTIME=${HICLAW_DEFAULT_WORKER_RUNTIME:-openclaw}
# Matrix E2EE (0=disabled, 1=enabled; default: 0)
HICLAW_MATRIX_E2EE=${HICLAW_MATRIX_E2EE:-0}

# Matrix provider (tuwunel | synapse; default: tuwunel)
HICLAW_MATRIX_PROVIDER=${HICLAW_MATRIX_PROVIDER:-tuwunel}
HICLAW_SYNAPSE_SHARED_SECRET=${HICLAW_SYNAPSE_SHARED_SECRET:-}
HICLAW_PG_HOST=${HICLAW_PG_HOST:-}
HICLAW_PG_PORT=${HICLAW_PG_PORT:-5432}
HICLAW_PG_USER=${HICLAW_PG_USER:-synapse}
HICLAW_PG_PASSWORD=${HICLAW_PG_PASSWORD:-}
HICLAW_PG_DATABASE=${HICLAW_PG_DATABASE:-synapse}

# Docker API proxy (0=disabled, 1=enabled; default: 1)
HICLAW_DOCKER_PROXY=${HICLAW_DOCKER_PROXY:-1}

Expand Down
6 changes: 5 additions & 1 deletion manager/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ COPY --from=hiclaw-controller /usr/local/bin/hiclaw /usr/local/bin/hiclaw
COPY --from=hiclaw-controller /usr/local/bin/kube-apiserver /usr/local/bin/kube-apiserver
COPY --from=hiclaw-controller /opt/hiclaw/config/crd/ /opt/hiclaw/config/crd/

# Synapse Matrix server runtime (installed via pip into base Python 3.10)
# Only active when HICLAW_MATRIX_PROVIDER=synapse; otherwise start-synapse.sh sleeps.
# zip/unzip needed by hiclaw CLI for --zip package handling
RUN apt-get update -qq && apt-get install -y -qq zip unzip > /dev/null 2>&1 && rm -rf /var/lib/apt/lists/*
RUN apt-get update -qq && apt-get install -y -qq libpq5 python3-pip zip unzip > /dev/null 2>&1 \
&& pip3 install --no-cache-dir 'matrix-synapse==1.150.0' psycopg2-binary \
&& rm -rf /var/lib/apt/lists/*

# ---- Built-in observability plugin (bundled unconditionally, enabled at runtime) ----
# Plugin is small; runtime toggles HICLAW_CMS_TRACES_ENABLED / HICLAW_CMS_METRICS_ENABLED
Expand Down
20 changes: 6 additions & 14 deletions manager/agent/skills/human-management/scripts/create-human.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,28 +89,20 @@ fi
log "Step 1: Registering Matrix account..."
HUMAN_PASSWORD=$(openssl rand -hex 16 2>/dev/null || head -c 16 /dev/urandom | xxd -p)

REG_RESP=$(curl -s -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d '{
"username": "'"${HUMAN_USERNAME}"'",
"password": "'"${HUMAN_PASSWORD}"'",
"auth": {
"type": "m.login.registration_token",
"token": "'"${HICLAW_REGISTRATION_TOKEN}"'"
}
}' 2>/dev/null) || true
REG_RESP=$(matrix_register_user_raw "${HUMAN_USERNAME}" "${HUMAN_PASSWORD}" 2>&1) || true

if echo "${REG_RESP}" | jq -e '.access_token' > /dev/null 2>&1; then
HUMAN_TOKEN=$(echo "${REG_RESP}" | jq -r '.access_token')
log " Registered new account: ${MATRIX_ID}"
else
log " Account may already exist (registration response: ${REG_RESP:0:100})"
log " Proceeding with permission configuration..."
_reg_err=$(echo "${REG_RESP}" | jq -r '.error // .errcode // empty' 2>/dev/null)
log " Registration failed: ${_reg_err:-no response} (full: ${REG_RESP:0:200})"
log " Attempting login..."
# Try to login to get a token for auto-joining rooms
HUMAN_TOKEN=$(curl -sf -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/login \
HUMAN_TOKEN=$(curl -s -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/login \
-H 'Content-Type: application/json' \
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"'"${HUMAN_USERNAME}"'"},"password":"'"${HUMAN_PASSWORD}"'"}' \
2>/dev/null | jq -r '.access_token // empty')
| jq -r '.access_token // empty')
fi

# ============================================================
Expand Down
59 changes: 37 additions & 22 deletions manager/agent/skills/worker-management/scripts/create-worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ fi

_fail() {
local err_msg="$1"
echo '{"error": "'"${err_msg}"'"}'
local step="${2:-unknown}"
echo '{"error": "'"${err_msg}"'", "step": "'"${step}"'", "worker": "'"${WORKER_NAME:-unknown}"'"}'

# If a room was already created, notify it about the failure
if [ -n "${ROOM_ID:-}" ] && [ -n "${MANAGER_MATRIX_TOKEN:-}" ]; then
Expand Down Expand Up @@ -217,36 +218,31 @@ else
fi
[ -z "${WORKER_MINIO_PASSWORD}" ] && WORKER_MINIO_PASSWORD=$(generateKey 24)

REG_RESP=$(curl -s -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d '{
"username": "'"${WORKER_NAME}"'",
"password": "'"${WORKER_PASSWORD}"'",
"auth": {
"type": "m.login.registration_token",
"token": "'"${HICLAW_REGISTRATION_TOKEN}"'"
}
}' 2>/dev/null) || true
REG_RESP=$(matrix_register_user_raw "${WORKER_NAME}" "${WORKER_PASSWORD}" 2>&1) || true

if echo "${REG_RESP}" | jq -e '.access_token' > /dev/null 2>&1; then
WORKER_MATRIX_TOKEN=$(echo "${REG_RESP}" | jq -r '.access_token')
log " Registered new account: ${WORKER_USER_ID}"
else
# Log the actual error for diagnostics
_reg_err=$(echo "${REG_RESP}" | jq -r '.error // .errcode // empty' 2>/dev/null)
log " Registration failed: ${_reg_err:-no response} (full: ${REG_RESP:0:200})"
# Account already exists — login with persisted password
log " Account exists, logging in..."
log " Attempting login..."
LOGIN_RESP=$(curl -s -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/login \
-H 'Content-Type: application/json' \
-d '{
"type": "m.login.password",
"identifier": {"type": "m.id.user", "user": "'"${WORKER_NAME}"'"},
"password": "'"${WORKER_PASSWORD}"'"
}' 2>/dev/null) || true
}') || true

if echo "${LOGIN_RESP}" | jq -e '.access_token' > /dev/null 2>&1; then
WORKER_MATRIX_TOKEN=$(echo "${LOGIN_RESP}" | jq -r '.access_token')
log " Logged in: ${WORKER_USER_ID}"
else
_fail "Failed to register or login Matrix account for ${WORKER_NAME}. If re-creating, delete /data/worker-creds/${WORKER_NAME}.env and try again."
_login_err=$(echo "${LOGIN_RESP}" | jq -r '.error // .errcode // "unknown"' 2>/dev/null)
_fail "Failed to register or login Matrix account for ${WORKER_NAME}: ${_login_err}. If re-creating, delete /data/worker-creds/${WORKER_NAME}.env and try again." "step1_matrix_registration"
fi
fi

Expand Down Expand Up @@ -334,17 +330,35 @@ if [ -n "${WORKER_ROOM_ID:-}" ]; then
ROOM_ID="${WORKER_ROOM_ID}"
log " Reusing existing room from persisted state: ${ROOM_ID}"
else
ROOM_RESP=$(curl -sf -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/createRoom \
# Try to recover room_id from registry (previous failed attempt may have created a room)
if [ -z "${WORKER_ROOM_ID:-}" ]; then
_reg_room=$(jq -r --arg w "${WORKER_NAME}" '.workers[$w].room_id // empty' "${HOME}/workers-registry.json" 2>/dev/null)
if [ -n "${_reg_room}" ]; then
WORKER_ROOM_ID="${_reg_room}"
ROOM_ID="${_reg_room}"
log " Recovered room_id from registry: ${_reg_room}"
fi
fi
fi

if [ -z "${ROOM_ID:-}" ]; then
# Build invite list — exclude the room creator (Manager) to avoid Synapse
# rejecting with "already in the room" (Tuwunel silently ignores this).
_invite_list=""
_first=true
for _uid in "${ADMIN_MATRIX_ID}" "${ROOM_AUTHORITY_ID}" "@${WORKER_NAME}:${MATRIX_DOMAIN}"; do
[ "${_uid}" = "${MANAGER_MATRIX_ID}" ] && continue
if [ "${_first}" = true ]; then _first=false; else _invite_list="${_invite_list},"; fi
_invite_list="${_invite_list}\"${_uid}\""
done

ROOM_RESP=$(curl -s -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/createRoom \
-H "Authorization: Bearer ${MANAGER_MATRIX_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{
"name": "'"${ROOM_NAME_PREFIX}: ${WORKER_NAME}"'",
"topic": "Communication channel for '"${WORKER_NAME}"'",
"invite": [
"'"${ADMIN_MATRIX_ID}"'",
"'"${ROOM_AUTHORITY_ID}"'",
"@'"${WORKER_NAME}"':'"${MATRIX_DOMAIN}"'"
],
"invite": ['"${_invite_list}"'],
"preset": "trusted_private_chat",
"power_level_content_override": {
"users": {
Expand All @@ -354,11 +368,12 @@ else
"@'"${WORKER_NAME}"':'"${MATRIX_DOMAIN}"'": 0
}
}'"${ROOM_E2EE_INITIAL_STATE}"'
}' 2>/dev/null) || _fail "Failed to create Matrix room"
}') || true

ROOM_ID=$(echo "${ROOM_RESP}" | jq -r '.room_id // empty')
if [ -z "${ROOM_ID}" ]; then
_fail "Failed to create Matrix room: ${ROOM_RESP}"
_room_err=$(echo "${ROOM_RESP}" | jq -r '.error // .errcode // "unknown"' 2>/dev/null)
_fail "Failed to create Matrix room: ${_room_err}" "step2_room_creation"
fi
log " Room created with all members (Human + Manager + Worker): ${ROOM_ID} — no manual room creation needed"

Expand Down
6 changes: 3 additions & 3 deletions manager/scripts/init/setup-higress.sh
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ if [ ! -f "${SETUP_MARKER}" ]; then
log "First boot: configuring Higress static resources..."

# 0. Local service sources
higress_api POST /v1/service-sources "Registering Tuwunel service source" \
'{"name":"tuwunel","type":"static","domain":"127.0.0.1:6167","port":6167,"properties":{},"authN":{"enabled":false}}'
higress_api POST /v1/service-sources "Registering Matrix service source" \
'{"name":"matrix-server","type":"static","domain":"127.0.0.1:6167","port":6167,"properties":{},"authN":{"enabled":false}}'
higress_api POST /v1/service-sources "Registering Element Web service source" \
'{"name":"element-web","type":"static","domain":"127.0.0.1:8088","port":8088,"properties":{},"authN":{"enabled":false}}'
higress_api POST /v1/service-sources "Registering MinIO service source" \
Expand All @@ -129,7 +129,7 @@ if [ ! -f "${SETUP_MARKER}" ]; then

# 3. Matrix Homeserver Route
higress_api POST /v1/routes "Creating Matrix Homeserver route" \
'{"name":"matrix-homeserver","domains":[],"path":{"matchType":"PRE","matchValue":"/_matrix"},"services":[{"name":"tuwunel.static","port":6167,"weight":100}]}'
'{"name":"matrix-homeserver","domains":[],"path":{"matchType":"PRE","matchValue":"/_matrix"},"services":[{"name":"matrix-server.static","port":6167,"weight":100}]}'

# 4. Element Web Route
higress_api POST /v1/routes "Creating Element Web route" \
Expand Down
56 changes: 24 additions & 32 deletions manager/scripts/init/start-manager-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,24 @@ if [ "${HICLAW_RUNTIME}" != "aliyun" ]; then
# Wait for local infrastructure
waitForService "Higress Gateway" "127.0.0.1" 8080 180
waitForService "Higress Console" "127.0.0.1" 8001 180
waitForService "Tuwunel" "127.0.0.1" 6167 120
waitForHTTP "Tuwunel Matrix API" "${HICLAW_MATRIX_SERVER}/_tuwunel/server_version" 120
waitForService "Matrix Server" "127.0.0.1" 6167 120
waitForHTTP "Matrix API" "${HICLAW_MATRIX_SERVER}/_matrix/client/versions" 120
waitForService "MinIO" "127.0.0.1" 9000 120
else
# Cloud mode: wait for external Tuwunel
log "Waiting for Tuwunel Matrix server at ${HICLAW_MATRIX_SERVER}..."
# Cloud mode: wait for external Matrix server
log "Waiting for Matrix server at ${HICLAW_MATRIX_SERVER}..."
_retry=0
while [ "${_retry}" -lt 30 ]; do
if curl -sf "${HICLAW_MATRIX_SERVER}/_matrix/client/versions" > /dev/null 2>&1; then
log "Tuwunel is ready"
log "Matrix server is ready"
break
fi
_retry=$((_retry + 1))
log " Waiting for Tuwunel (attempt ${_retry}/30)..."
log " Waiting for Matrix server (attempt ${_retry}/30)..."
sleep 5
done
if [ "${_retry}" -ge 30 ]; then
log "ERROR: Tuwunel not reachable at ${HICLAW_MATRIX_SERVER}"
log "ERROR: Matrix server not reachable at ${HICLAW_MATRIX_SERVER}"
exit 1
fi
fi
Expand Down Expand Up @@ -181,31 +181,13 @@ if [ "${HICLAW_RUNTIME}" != "aliyun" ]; then
fi

# ============================================================
# Register Matrix users via Registration API (single-step, no UIAA)
# Register Matrix users via provider-aware registration
# ============================================================
log "Registering human admin Matrix account..."
curl -sf -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d '{
"username": "'"${HICLAW_ADMIN_USER}"'",
"password": "'"${HICLAW_ADMIN_PASSWORD}"'",
"auth": {
"type": "m.login.registration_token",
"token": "'"${HICLAW_REGISTRATION_TOKEN}"'"
}
}' > /dev/null 2>&1 || log "Admin account may already exist"
matrix_register_user "${HICLAW_ADMIN_USER}" "${HICLAW_ADMIN_PASSWORD}"

log "Registering Manager Agent Matrix account..."
curl -sf -X POST ${HICLAW_MATRIX_SERVER}/_matrix/client/v3/register \
-H 'Content-Type: application/json' \
-d '{
"username": "manager",
"password": "'"${HICLAW_MANAGER_PASSWORD}"'",
"auth": {
"type": "m.login.registration_token",
"token": "'"${HICLAW_REGISTRATION_TOKEN}"'"
}
}' > /dev/null 2>&1 || log "Manager account may already exist"
matrix_register_user "manager" "${HICLAW_MANAGER_PASSWORD}"

# Get Manager Agent's Matrix access token
log "Obtaining Manager Matrix access token..."
Expand Down Expand Up @@ -583,14 +565,24 @@ else
log "Matrix token written from template (prefix: ${_written_token:0:10}...)"
fi

# Overlay: ensure openclaw.json homeserver matches the actual Matrix server URL.
# Covers cloud mode (external NLB), Synapse, and any HICLAW_MATRIX_URL override.
# Tuwunel local mode uses the template default (http://127.0.0.1:6167), so no overlay needed.
_current_homeserver=$(jq -r '.channels.matrix.homeserver // ""' /root/manager-workspace/openclaw.json 2>/dev/null)
if [ "${_current_homeserver}" != "${HICLAW_MATRIX_SERVER}" ]; then
log "Updating openclaw.json homeserver: ${_current_homeserver} -> ${HICLAW_MATRIX_SERVER}"
jq --arg homeserver "${HICLAW_MATRIX_SERVER}" \
'.channels.matrix.homeserver = $homeserver' \
/root/manager-workspace/openclaw.json > /tmp/openclaw-homeserver.json && \
mv /tmp/openclaw-homeserver.json /root/manager-workspace/openclaw.json
fi

# Cloud mode: overlay cloud-specific settings onto generated config
if [ "${HICLAW_RUNTIME}" = "aliyun" ]; then
log "Applying cloud overlay to openclaw.json..."
jq --arg homeserver "${HICLAW_MATRIX_SERVER}" \
--arg gateway "${HICLAW_AI_GATEWAY_URL}/v1" \
jq --arg gateway "${HICLAW_AI_GATEWAY_URL}/v1" \
--arg key "${HICLAW_MANAGER_GATEWAY_KEY}" \
'.channels.matrix.homeserver = $homeserver
| .models.providers["hiclaw-gateway"].baseUrl = $gateway
'.models.providers["hiclaw-gateway"].baseUrl = $gateway
| .models.providers["hiclaw-gateway"].apiKey = $key
| ((.hooks.token // "") as $ht | if $ht == $key or $ht == ($key + "-hooks" | @base64) then del(.hooks) else . end)
| .commands.restart = false
Expand Down
Loading
Loading