Files
infrapuzzle/k8s/openclaw/scripts/bootstrap-deps.sh
T

206 lines
9.2 KiB
Bash

#!/bin/sh
set -e
echo "=== OpenClaw Dependency & Runtime Bootstrap ==="
export PATH="/home/node/.openclaw/bin:/home/node/.openclaw/.local/bin:$PATH"
SCRIPTS_DIR="/home/node/.openclaw/scripts"
mkdir -p /home/node/.openclaw/bin "$SCRIPTS_DIR" /home/node/.openclaw/.config
touch /home/node/.openclaw/.config/keep
# 1. Sanitize legacy config keys in openclaw.json
node -e '
const fs = require("fs");
for (const file of ["/home/node/.openclaw/openclaw.json", "/home/openclaw/.openclaw/openclaw.json"]) {
if (fs.existsSync(file)) {
try {
const cfg = JSON.parse(fs.readFileSync(file, "utf8"));
if (cfg.browser) {
delete cfg.browser.remoteCdpTimeoutMs;
if (cfg.browser.profiles) {
if (cfg.browser.profiles.default) delete cfg.browser.profiles.default.color;
if (cfg.browser.profiles.chrome) delete cfg.browser.profiles.chrome;
}
}
if (cfg.gateway && cfg.gateway.controlUi) {
delete cfg.gateway.controlUi.dangerouslyDisableDeviceAuth;
}
if (!cfg.agents) cfg.agents = {};
cfg.agents.ownership = "explicit";
if (cfg.agents.entries && cfg.agents.entries.main) {
delete cfg.agents.entries.main.default;
}
fs.writeFileSync(file, JSON.stringify(cfg, null, 2));
console.log("Sanitized config file:", file);
} catch (e) {
console.error("Failed to sanitize", file, e.message);
}
}
}
' || true
# 2. Run pre-flight session recovery
echo "Running pre-flight self-healing..."
python3 "$SCRIPTS_DIR/recover_sessions.py" || true
# 3. Doctor fix
echo "Running openclaw doctor --fix to migrate runtime config on PVC..."
openclaw doctor --fix || true
# 4. Garmin OAuth tokens bootstrap / preserve
if [ ! -s /home/node/.openclaw/garmin_tokens/garmin_tokens.json ] && [ -n "$GARMIN_TOKENS_BASE64" ]; then
echo "Bootstrapping initial Garmin OAuth tokens from secret..."
mkdir -p /home/node/.openclaw/garmin_tokens
echo "$GARMIN_TOKENS_BASE64" | base64 -d > /home/node/.openclaw/garmin_tokens/garmin_tokens.json
chmod 700 /home/node/.openclaw/garmin_tokens
chmod 600 /home/node/.openclaw/garmin_tokens/garmin_tokens.json
elif [ -s /home/node/.openclaw/garmin_tokens/garmin_tokens.json ]; then
echo "Preserving live Garmin OAuth tokens on PVC..."
chmod 700 /home/node/.openclaw/garmin_tokens
chmod 600 /home/node/.openclaw/garmin_tokens/garmin_tokens.json
fi
# 5. Cleanup legacy binaries and superseded local skills
rm -rf /home/node/.openclaw/bin/whisper* /home/node/.openclaw/bin/.whisper* /home/node/.openclaw/scripts/whisper* /home/node/.openclaw/models/whisper || true
rm -rf /home/node/.openclaw/skills/memobird /home/node/.openclaw/skills/nerd-report /home/node/.openclaw/skills/rvv-regensburg /home/node/.openclaw/skills/skill-creator || true
rm -rf /home/node/.openclaw/workspace/skills /home/node/.openclaw/workspace-koch/skills /home/node/.openclaw/workspace-recherche/skills || true
# 6. Ensure tools.allow and models.providers.openrouter.apiKey unset
openclaw config unset tools.allow || true
openclaw config unset models.providers.openrouter.apiKey || true
openclaw config unset agents.entries.mila_tracker.tools.profile || true
openclaw config unset agents.entries.nutrition_tracker.tools.profile || true
# 7. Decouple hardlinked bootstrap files
for dir in /home/node/.openclaw/workspace-*; do
if [ -d "$dir" ]; then
for file in USER.md MEMORY.md; do
if [ -f "/home/node/.openclaw/workspace/$file" ]; then
cp --remove-destination "/home/node/.openclaw/workspace/$file" "$dir/$file"
chown node:node "$dir/$file" 2>/dev/null || true
chmod 664 "$dir/$file" 2>/dev/null || true
fi
done
fi
done
# 8. Install CLI binaries
if [ ! -f "/home/node/.openclaw/bin/openhue.real" ]; then
echo "Installing openhue CLI binary..."
curl -sL https://github.com/openhue/openhue-cli/releases/download/0.24/openhue_Linux_x86_64.tar.gz | tar -xz -C /home/node/.openclaw/bin openhue
mv /home/node/.openclaw/bin/openhue /home/node/.openclaw/bin/openhue.real
printf '#!/bin/sh\nexport HOME=/home/node/.openclaw\nexec /home/node/.openclaw/bin/openhue.real "$@"\n' > /home/node/.openclaw/bin/openhue
chmod +x /home/node/.openclaw/bin/openhue /home/node/.openclaw/bin/openhue.real
fi
if [ ! -f "/home/node/.openclaw/bin/summarize" ]; then
echo "Installing summarize CLI via npm..."
npm install -g --prefix /home/node/.openclaw @steipete/summarize || true
fi
if [ ! -f "/home/node/.openclaw/bin/mcp-server-github" ]; then
echo "Installing @modelcontextprotocol/server-github via npm..."
npm install -g --prefix /home/node/.openclaw @modelcontextprotocol/server-github || true
fi
if [ ! -f "/home/node/.openclaw/bin/kubectl" ]; then
echo "Installing kubectl CLI binary..."
curl -fsSL https://dl.k8s.io/release/v1.31.0/bin/linux/amd64/kubectl -o /home/node/.openclaw/bin/kubectl
chmod +x /home/node/.openclaw/bin/kubectl
fi
if [ ! -f "/home/node/.openclaw/bin/jq" ]; then
echo "Installing jq CLI binary..."
curl -fsSL https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64 -o /home/node/.openclaw/bin/jq
chmod +x /home/node/.openclaw/bin/jq
fi
if [ ! -f "/home/node/.openclaw/bin/file" ]; then
echo "Setting up file CLI helper..."
cp "$SCRIPTS_DIR/file_cli.py" /home/node/.openclaw/bin/file
chmod +x /home/node/.openclaw/bin/file
fi
if [ -x "/home/node/.openclaw/.local/bin/python3" ]; then
/home/node/.openclaw/bin/uv pip install --break-system-packages --python /home/node/.openclaw/.local/bin/python3 pillow google-api-python-client pypdf || true
fi
# 9. Clone or pull infrapuzzle repository to PVC
mkdir -p /home/node/.openclaw/repos
if [ ! -d "/home/node/.openclaw/repos/infrapuzzle/.git" ]; then
echo "Cloning infrapuzzle repository to PVC..."
git clone --depth 1 "https://${GIT_SYNC_USERNAME}:${GIT_SYNC_PASSWORD}@git.moritzgraf.de/moritz/infrapuzzle.git" /home/node/.openclaw/repos/infrapuzzle || true
else
echo "Pulling latest infrapuzzle commits on PVC..."
git -C /home/node/.openclaw/repos/infrapuzzle pull origin master || git -C /home/node/.openclaw/repos/infrapuzzle pull origin main || true
fi
# 10. Seed and maintain persistent mcp-venv
if [ ! -d "/home/node/.openclaw/mcp-venv" ]; then
echo "Seeding persistent mcp-venv..."
uv venv --python 3.12 /home/node/.openclaw/mcp-venv
uv pip install --python /home/node/.openclaw/mcp-venv \
prometheus-mcp-server \
ha-mcp \
chuk-mcp-open-meteo \
gitea-mcp \
git+https://github.com/Taxuspt/garmin_mcp \
"mcp>=2.0" \
filetype \
google-api-python-client \
google-auth \
bring-api \
requests \
beautifulsoup4 \
youtube-transcript-api
fi
if [ -d "/home/node/.openclaw/mcp-venv" ]; then
python3 -c 'import os; p="/home/node/.openclaw/mcp-venv/lib/python3.12/site-packages/mcp/server/fastmcp.py"; open(p, "w").write("import os\nfrom fastmcp import FastMCP as _FastMCP, Context\n\nclass FastMCP(_FastMCP):\n def __init__(self, name=\"MCP Server\", host=None, port=None, **kwargs):\n if host is not None: os.environ[\"FASTMCP_HOST\"] = str(host)\n if port is not None: os.environ[\"FASTMCP_PORT\"] = str(port)\n super().__init__(name=name, **kwargs)\n")' || true
python3 "$SCRIPTS_DIR/patch_garmin_mcp.py" || true
fi
# 11. Extensions & Plugins
if [ ! -d "/home/node/.openclaw/extensions/perplexity" ]; then
echo "Installing perplexity plugin..."
openclaw plugins install clawhub:@openclaw/perplexity-plugin --accept-capabilities || true
fi
echo "Enabling memory-wiki plugin..."
openclaw plugins enable memory-wiki || true
echo "Patching perplexity web search runtime for chat completions compatibility..."
node "$SCRIPTS_DIR/patch_perplexity.mjs" || true
# 12. Ensure OpenRouter auth profile in state DB
echo "Ensuring OpenRouter auth profile in state DB..."
node --input-type=module -e '
import { DatabaseSync } from "node:sqlite";
const key = process.env.OPENROUTER_API_KEY;
if (key) {
try {
const dbPath = "/home/node/.openclaw/state/openclaw.sqlite";
const db = new DatabaseSync(dbPath);
db.prepare("CREATE TABLE IF NOT EXISTS config_machine_state (state_key TEXT PRIMARY KEY, value_json TEXT NOT NULL, updated_at_ms INTEGER NOT NULL)").run();
const row = db.prepare("SELECT value_json FROM config_machine_state WHERE state_key = \x27authProfiles.store\x27").get();
let store = row?.value_json ? JSON.parse(row.value_json) : { version: 1, profiles: {} };
if (!store.profiles) store.profiles = {};
store.profiles["openrouter:default"] = {
type: "api_key",
provider: "openrouter",
key: key
};
db.prepare("INSERT INTO config_machine_state (state_key, value_json, updated_at_ms) VALUES (\x27authProfiles.store\x27, ?, ?) ON CONFLICT(state_key) DO UPDATE SET value_json = excluded.value_json, updated_at_ms = excluded.updated_at_ms")
.run(JSON.stringify(store), Date.now());
console.log("Synchronized openrouter auth profile in state DB.");
} catch (e) {
console.error("Could not sync auth profile:", e.message);
}
}
' || true
# 13. Pre-warm SQLite page cache
echo "Pre-warming SQLite database files into OS page cache for instant cold start..."
cat /home/node/.openclaw/state/openclaw.sqlite /home/node/.openclaw/agents/*/agent/openclaw-agent.sqlite > /dev/null 2>&1 || true
echo "=== Bootstrap Complete ==="