Files
TencentDB-Agent-Memory/scripts/install-openclaw-plugin-v2.sh
T

185 lines
8.2 KiB
Bash
Raw Normal View History

2026-05-29 17:33:12 +08:00
#!/usr/bin/env bash
set -euo pipefail
log() { printf '[install-openclaw-plugin-v2] %s\n' "$*" >&2; }
fail() { printf '[install-openclaw-plugin-v2][ERROR] %s\n' "$*" >&2; exit 1; }
need_cmd() { command -v "$1" >/dev/null 2>&1 || fail "missing command: $1"; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PLUGIN_DIR="${OPENCLAW_PLUGIN_DIR:-$REPO_ROOT/openclaw-plugin}"
INSTALL_OPENCLAW="${INSTALL_OPENCLAW:-1}"
OPENCLAW_INSTALL_FLAGS="${OPENCLAW_INSTALL_FLAGS:-}"
WRITE_OPENCLAW_CONFIG="${WRITE_OPENCLAW_CONFIG:-1}"
OPENCLAW_CONFIG_FILE="${OPENCLAW_CONFIG_FILE:-$HOME/.openclaw/openclaw.json}"
MEMORY_PLUGIN_ID="memory-tencentdb-client"
TDAI_MEMORY_ENDPOINT="${TDAI_MEMORY_ENDPOINT:-http://127.0.0.1:8420}"
TDAI_MEMORY_API_KEY="${TDAI_MEMORY_API_KEY:-local}"
TDAI_MEMORY_INSTANCE_ID="${TDAI_MEMORY_INSTANCE_ID:-${TDAI_MEMORY_SERVICE_ID:-default}}"
TDAI_MEMORY_RECALL_MAX_RESULTS="${TDAI_MEMORY_RECALL_MAX_RESULTS:-5}"
TDAI_MEMORY_INCLUDE_PERSONA="${TDAI_MEMORY_INCLUDE_PERSONA:-true}"
TDAI_MEMORY_INCLUDE_SCENE_NAV="${TDAI_MEMORY_INCLUDE_SCENE_NAV:-true}"
TDAI_MEMORY_CAPTURE_ENABLED="${TDAI_MEMORY_CAPTURE_ENABLED:-true}"
TDAI_MEMORY_ALLOW_PROMPT_INJECTION="${TDAI_MEMORY_ALLOW_PROMPT_INJECTION:-true}"
TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS="${TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS:-true}"
need_cmd npm
need_cmd node
need_cmd curl
if [[ ! -d "$PLUGIN_DIR" ]]; then
fail "OpenClaw plugin directory not found: $PLUGIN_DIR"
fi
if ! command -v openclaw >/dev/null 2>&1; then
if [[ "$INSTALL_OPENCLAW" == "1" ]]; then
log "OpenClaw CLI not found; installing from https://get.openclaw.dev"
curl -fsSL https://get.openclaw.dev | bash
export PATH="$HOME/.local/bin:$HOME/bin:/usr/local/bin:$PATH"
else
fail "OpenClaw CLI not found. Install it first or run with INSTALL_OPENCLAW=1."
fi
fi
command -v openclaw >/dev/null 2>&1 || fail "OpenClaw CLI still not found after install; please check PATH"
OPENCLAW_VERSION_RAW="$(openclaw --version 2>/dev/null || printf 'unknown')"
log "OpenClaw version: $OPENCLAW_VERSION_RAW"
# Hook policy fields (allowPromptInjection / allowConversationAccess) were
# accepted by the gateway zod schema starting at 2026.4.24 (PR #71221).
# 2026.4.23 and earlier use `.strict()` and will REFUSE to start the gateway
# if these fields are present. We therefore version-gate the config write to
# match `src/utils/ensure-hook-policy.ts::HOOK_POLICY_MIN_VERSION`.
HOOK_POLICY_MIN="2026.4.24"
WRITE_HOOK_POLICY=0
if [[ "$OPENCLAW_VERSION_RAW" =~ ([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
v_major="${BASH_REMATCH[1]}"
v_minor="${BASH_REMATCH[2]}"
v_patch="${BASH_REMATCH[3]}"
IFS=. read -r m_major m_minor m_patch <<<"$HOOK_POLICY_MIN"
if (( v_major > m_major )) \
|| { (( v_major == m_major )) && (( v_minor > m_minor )); } \
|| { (( v_major == m_major )) && (( v_minor == m_minor )) && (( v_patch >= m_patch )); }; then
WRITE_HOOK_POLICY=1
fi
fi
if [[ "$WRITE_HOOK_POLICY" == "1" ]]; then
log "Detected OpenClaw >= $HOOK_POLICY_MIN — will write hooks.allowPromptInjection / allowConversationAccess"
else
log "Detected OpenClaw < $HOOK_POLICY_MIN (or version unparseable) — will SKIP hooks.* policy fields (older gateway schemas reject them)"
fi
log "Installing plugin dependencies"
(cd "$PLUGIN_DIR" && npm install)
log "Building plugin"
(cd "$PLUGIN_DIR" && npm run build)
log "Installing linked plugin into OpenClaw: $PLUGIN_DIR"
# shellcheck disable=SC2086
openclaw plugins install -l "$PLUGIN_DIR" $OPENCLAW_INSTALL_FLAGS
if [[ "$WRITE_OPENCLAW_CONFIG" == "1" ]]; then
log "Updating OpenClaw config: $OPENCLAW_CONFIG_FILE"
mkdir -p "$(dirname "$OPENCLAW_CONFIG_FILE")"
if [[ -f "$OPENCLAW_CONFIG_FILE" ]]; then
cp "$OPENCLAW_CONFIG_FILE" "$OPENCLAW_CONFIG_FILE.bak.$(date +%Y%m%d%H%M%S)"
fi
OPENCLAW_CONFIG_FILE="$OPENCLAW_CONFIG_FILE" \
MEMORY_PLUGIN_ID="$MEMORY_PLUGIN_ID" \
TDAI_MEMORY_ENDPOINT="$TDAI_MEMORY_ENDPOINT" \
TDAI_MEMORY_API_KEY="$TDAI_MEMORY_API_KEY" \
TDAI_MEMORY_INSTANCE_ID="$TDAI_MEMORY_INSTANCE_ID" \
TDAI_MEMORY_RECALL_MAX_RESULTS="$TDAI_MEMORY_RECALL_MAX_RESULTS" \
TDAI_MEMORY_INCLUDE_PERSONA="$TDAI_MEMORY_INCLUDE_PERSONA" \
TDAI_MEMORY_INCLUDE_SCENE_NAV="$TDAI_MEMORY_INCLUDE_SCENE_NAV" \
TDAI_MEMORY_CAPTURE_ENABLED="$TDAI_MEMORY_CAPTURE_ENABLED" \
TDAI_MEMORY_ALLOW_PROMPT_INJECTION="$TDAI_MEMORY_ALLOW_PROMPT_INJECTION" \
TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS="$TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS" \
WRITE_HOOK_POLICY="$WRITE_HOOK_POLICY" \
node <<'NODE'
const fs = require('node:fs');
const file = process.env.OPENCLAW_CONFIG_FILE;
const pluginId = process.env.MEMORY_PLUGIN_ID;
function parseBool(value, fallback) {
if (value === undefined || value === '') return fallback;
return !['0', 'false', 'no', 'off'].includes(String(value).toLowerCase());
}
function parsePositiveInt(value, fallback) {
const parsed = Number.parseInt(String(value ?? ''), 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
let config = {};
if (fs.existsSync(file)) {
const raw = fs.readFileSync(file, 'utf8').trim();
if (raw) config = JSON.parse(raw);
}
config.plugins ??= {};
config.plugins.entries ??= {};
const entry = config.plugins.entries[pluginId] ?? {};
entry.enabled = true;
// Hook policy fields (allowPromptInjection / allowConversationAccess) are
// only safe to write on OpenClaw >= 2026.4.24. The shell wrapper sets
// WRITE_HOOK_POLICY=1 after parsing `openclaw --version`; on older gateways
// it stays 0 and we *remove* any stale fields to keep the gateway bootable.
const writeHookPolicy = process.env.WRITE_HOOK_POLICY === '1';
if (writeHookPolicy) {
entry.hooks ??= {};
entry.hooks.allowPromptInjection = parseBool(process.env.TDAI_MEMORY_ALLOW_PROMPT_INJECTION, entry.hooks.allowPromptInjection ?? true);
entry.hooks.allowConversationAccess = parseBool(process.env.TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS, entry.hooks.allowConversationAccess ?? true);
} else if (entry.hooks && (entry.hooks.allowPromptInjection !== undefined || entry.hooks.allowConversationAccess !== undefined)) {
// Older gateways (zod .strict()) reject these fields; strip them defensively.
delete entry.hooks.allowPromptInjection;
delete entry.hooks.allowConversationAccess;
if (Object.keys(entry.hooks).length === 0) delete entry.hooks;
}
entry.config ??= {};
entry.config.server ??= {};
entry.config.recall ??= {};
entry.config.capture ??= {};
entry.config.server.url = process.env.TDAI_MEMORY_ENDPOINT || entry.config.server.url || 'http://127.0.0.1:8420';
entry.config.server.apiKey = process.env.TDAI_MEMORY_API_KEY || entry.config.server.apiKey || 'local';
entry.config.server.instanceId = process.env.TDAI_MEMORY_INSTANCE_ID || entry.config.server.instanceId || 'default';
entry.config.recall.maxResults = parsePositiveInt(process.env.TDAI_MEMORY_RECALL_MAX_RESULTS, entry.config.recall.maxResults ?? 5);
entry.config.recall.includePersona = parseBool(process.env.TDAI_MEMORY_INCLUDE_PERSONA, entry.config.recall.includePersona ?? true);
entry.config.recall.includeSceneNav = parseBool(process.env.TDAI_MEMORY_INCLUDE_SCENE_NAV, entry.config.recall.includeSceneNav ?? true);
entry.config.capture.enabled = parseBool(process.env.TDAI_MEMORY_CAPTURE_ENABLED, entry.config.capture.enabled ?? true);
config.plugins.entries[pluginId] = entry;
fs.writeFileSync(file, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
NODE
else
log "Skipping OpenClaw config update because WRITE_OPENCLAW_CONFIG=$WRITE_OPENCLAW_CONFIG"
fi
if [[ "$WRITE_HOOK_POLICY" == "1" ]]; then
HOOK_SUMMARY=" plugins.entries[\"$MEMORY_PLUGIN_ID\"].hooks.allowPromptInjection = $TDAI_MEMORY_ALLOW_PROMPT_INJECTION
plugins.entries[\"$MEMORY_PLUGIN_ID\"].hooks.allowConversationAccess = $TDAI_MEMORY_ALLOW_CONVERSATION_ACCESS"
else
HOOK_SUMMARY=" plugins.entries[\"$MEMORY_PLUGIN_ID\"].hooks.* = (skipped — OpenClaw < $HOOK_POLICY_MIN does not accept these fields)"
fi
cat >&2 <<EOF
[install-openclaw-plugin-v2] Done.
Memory plugin configured:
plugins.entries["$MEMORY_PLUGIN_ID"].enabled = true
$HOOK_SUMMARY
server.url = "$TDAI_MEMORY_ENDPOINT"
server.apiKey = "$TDAI_MEMORY_API_KEY"
server.instanceId = "$TDAI_MEMORY_INSTANCE_ID"
Next steps:
1. Ensure Memory Gateway is running at $TDAI_MEMORY_ENDPOINT.
2. Restart OpenClaw Gateway if needed:
openclaw gateway restart
EOF