feat(installer): add openclaw config-set installer with automatic rollback
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
- Added containerization (`Dockerfile`, `docker-compose.yml`)
|
||||
- Added helper scripts for smoke/dev lifecycle and rule validation
|
||||
- Added no-touch config rendering and integration docs
|
||||
- Added installer script with rollback (`scripts/install-whispergate-openclaw.sh`)
|
||||
- Added discord-control-api with:
|
||||
- `channel-private-create` (create private channel for allowlist)
|
||||
- `channel-private-update` (update allowlist/overwrites for existing channel)
|
||||
|
||||
@@ -27,8 +27,30 @@ The script prints JSON for:
|
||||
|
||||
You can merge this snippet manually into your `openclaw.json`.
|
||||
|
||||
## Installer script (with rollback)
|
||||
|
||||
For production-like install with automatic rollback on error:
|
||||
|
||||
```bash
|
||||
./scripts/install-whispergate-openclaw.sh
|
||||
```
|
||||
|
||||
Environment overrides:
|
||||
|
||||
- `PLUGIN_PATH`
|
||||
- `NO_REPLY_PROVIDER_ID`
|
||||
- `NO_REPLY_MODEL_ID`
|
||||
- `NO_REPLY_BASE_URL`
|
||||
- `NO_REPLY_API_KEY`
|
||||
- `BYPASS_USER_IDS_JSON`
|
||||
- `END_SYMBOLS_JSON`
|
||||
|
||||
The script:
|
||||
- writes via `openclaw config set ... --json`
|
||||
- creates config backup first
|
||||
- restores backup automatically if any step fails
|
||||
|
||||
## Notes
|
||||
|
||||
- This repo does not run config mutation commands.
|
||||
- Keep no-reply API bound to loopback/private network.
|
||||
- If you use API auth, set `AUTH_TOKEN` and align provider apiKey usage.
|
||||
|
||||
140
scripts/install-whispergate-openclaw.sh
Executable file
140
scripts/install-whispergate-openclaw.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Install WhisperGate config into OpenClaw safely.
|
||||
# - uses `openclaw config set ... --json` for writes
|
||||
# - creates full config backup
|
||||
# - rolls back automatically on failure
|
||||
|
||||
OPENCLAW_CONFIG_PATH="${OPENCLAW_CONFIG_PATH:-$HOME/.openclaw/openclaw.json}"
|
||||
PLUGIN_PATH="${PLUGIN_PATH:-/root/.openclaw/workspace-operator/WhisperGate/dist/plugin}"
|
||||
NO_REPLY_PROVIDER_ID="${NO_REPLY_PROVIDER_ID:-custom-127-0-0-1-8787}"
|
||||
NO_REPLY_MODEL_ID="${NO_REPLY_MODEL_ID:-whispergate-no-reply-v1}"
|
||||
NO_REPLY_BASE_URL="${NO_REPLY_BASE_URL:-http://127.0.0.1:8787/v1}"
|
||||
NO_REPLY_API_KEY="${NO_REPLY_API_KEY:-wg-local-test-token}"
|
||||
BYPASS_USER_IDS_JSON="${BYPASS_USER_IDS_JSON:-["561921120408698910","1474088632750047324"]}"
|
||||
END_SYMBOLS_JSON="${END_SYMBOLS_JSON:-["🔚"]}"
|
||||
|
||||
BACKUP_PATH="${OPENCLAW_CONFIG_PATH}.bak-whispergate-install-$(date +%Y%m%d%H%M%S)"
|
||||
INSTALLED_OK=0
|
||||
|
||||
rollback() {
|
||||
local ec=$?
|
||||
if [[ $INSTALLED_OK -eq 1 ]]; then
|
||||
return
|
||||
fi
|
||||
echo "[whispergate-install] ERROR (exit=$ec). Rolling back config from backup..."
|
||||
if [[ -f "$BACKUP_PATH" ]]; then
|
||||
cp -f "$BACKUP_PATH" "$OPENCLAW_CONFIG_PATH"
|
||||
echo "[whispergate-install] rollback complete: $OPENCLAW_CONFIG_PATH restored"
|
||||
else
|
||||
echo "[whispergate-install] WARNING: backup file not found, cannot auto-rollback"
|
||||
fi
|
||||
exit "$ec"
|
||||
}
|
||||
|
||||
trap rollback ERR
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "[whispergate-install] missing command: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
oc_set_json() {
|
||||
local path="$1"
|
||||
local json="$2"
|
||||
openclaw config set "$path" "$json" --json >/dev/null
|
||||
}
|
||||
|
||||
echo "[whispergate-install] checking prerequisites..."
|
||||
require_cmd openclaw
|
||||
require_cmd python3
|
||||
|
||||
if [[ ! -f "$OPENCLAW_CONFIG_PATH" ]]; then
|
||||
echo "[whispergate-install] config not found: $OPENCLAW_CONFIG_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp -f "$OPENCLAW_CONFIG_PATH" "$BACKUP_PATH"
|
||||
echo "[whispergate-install] backup created: $BACKUP_PATH"
|
||||
|
||||
# 1) plugins.load.paths append plugin path (dedupe)
|
||||
CURRENT_PATHS_JSON="[]"
|
||||
if openclaw config get plugins.load.paths --json >/tmp/wg_paths.json 2>/dev/null; then
|
||||
CURRENT_PATHS_JSON="$(cat /tmp/wg_paths.json)"
|
||||
fi
|
||||
|
||||
NEW_PATHS_JSON="$(python3 - <<'PY'
|
||||
import json, os
|
||||
cur=json.loads(os.environ['CURRENT_PATHS_JSON'])
|
||||
pp=os.environ['PLUGIN_PATH']
|
||||
if not isinstance(cur,list):
|
||||
cur=[]
|
||||
if pp not in cur:
|
||||
cur.append(pp)
|
||||
print(json.dumps(cur, ensure_ascii=False))
|
||||
PY
|
||||
)"
|
||||
|
||||
oc_set_json "plugins.load.paths" "$NEW_PATHS_JSON"
|
||||
echo "[whispergate-install] set plugins.load.paths"
|
||||
|
||||
# 2) plugin entry
|
||||
PLUGIN_ENTRY_JSON="$(python3 - <<'PY'
|
||||
import json, os
|
||||
entry={
|
||||
'enabled': True,
|
||||
'config': {
|
||||
'enabled': True,
|
||||
'discordOnly': True,
|
||||
'bypassUserIds': json.loads(os.environ['BYPASS_USER_IDS_JSON']),
|
||||
'endSymbols': json.loads(os.environ['END_SYMBOLS_JSON']),
|
||||
'noReplyProvider': os.environ['NO_REPLY_PROVIDER_ID'],
|
||||
'noReplyModel': os.environ['NO_REPLY_MODEL_ID'],
|
||||
}
|
||||
}
|
||||
print(json.dumps(entry, ensure_ascii=False))
|
||||
PY
|
||||
)"
|
||||
|
||||
oc_set_json "plugins.entries.whispergate" "$PLUGIN_ENTRY_JSON"
|
||||
echo "[whispergate-install] set plugins.entries.whispergate"
|
||||
|
||||
# 3) no-reply model provider (under models.providers)
|
||||
PROVIDER_JSON="$(python3 - <<'PY'
|
||||
import json, os
|
||||
provider={
|
||||
'baseUrl': os.environ['NO_REPLY_BASE_URL'],
|
||||
'apiKey': os.environ['NO_REPLY_API_KEY'],
|
||||
'api': 'openai-completions',
|
||||
'models': [{
|
||||
'id': os.environ['NO_REPLY_MODEL_ID'],
|
||||
'name': 'whispergate-no-reply-v1 (Custom Provider)',
|
||||
'reasoning': False,
|
||||
'input': ['text'],
|
||||
'cost': {'input': 0, 'output': 0, 'cacheRead': 0, 'cacheWrite': 0},
|
||||
'contextWindow': 4096,
|
||||
'maxTokens': 4096,
|
||||
}]
|
||||
}
|
||||
print(json.dumps(provider, ensure_ascii=False))
|
||||
PY
|
||||
)"
|
||||
|
||||
PROVIDER_PATH="models.providers[\"${NO_REPLY_PROVIDER_ID}\"]"
|
||||
oc_set_json "$PROVIDER_PATH" "$PROVIDER_JSON"
|
||||
echo "[whispergate-install] set ${PROVIDER_PATH}"
|
||||
|
||||
# 4) quick validation reads
|
||||
openclaw config get plugins.entries.whispergate --json >/dev/null
|
||||
openclaw config get "$PROVIDER_PATH" --json >/dev/null
|
||||
|
||||
INSTALLED_OK=1
|
||||
trap - ERR
|
||||
|
||||
echo "[whispergate-install] install completed successfully"
|
||||
echo "[whispergate-install] next steps:"
|
||||
echo " 1) start no-reply api (port 8787)"
|
||||
echo " 2) restart gateway: openclaw gateway restart"
|
||||
Reference in New Issue
Block a user