#!/usr/bin/env bash # post-install.sh — Install memory-continuity as an OpenClaw lifecycle plugin # # This script: # 1. Copies the plugin to ~/.openclaw/extensions/memory-continuity/ # 2. Adds the plugin entry to openclaw.json (if not present) # 3. Detects OpenClaw agents and installs SKILL.md to selected workspaces # # Usage: # bash scripts/post-install.sh # # Safe to run multiple times (idempotent). set -euo pipefail OPENCLAW_DIR="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}" EXTENSIONS_DIR="$OPENCLAW_DIR/extensions" PLUGIN_DIR="$EXTENSIONS_DIR/memory-continuity" CONFIG_FILE="$OPENCLAW_DIR/openclaw.json" # Resolve the repo root (parent of scripts/) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" echo "=== memory-continuity plugin installer ===" echo "" # Step 1: Copy plugin files to extensions directory echo "[1/3] Installing plugin to $PLUGIN_DIR ..." mkdir -p "$EXTENSIONS_DIR" # Remove old installation if exists if [[ -d "$PLUGIN_DIR" || -L "$PLUGIN_DIR" ]]; then rm -rf "$PLUGIN_DIR" echo " Removed previous installation" fi # Copy essential plugin files (not the entire repo) mkdir -p "$PLUGIN_DIR" for f in index.js openclaw.plugin.json package.json SKILL.md; do if [[ -f "$REPO_DIR/$f" ]]; then cp "$REPO_DIR/$f" "$PLUGIN_DIR/" fi done echo " Copied plugin files" # Step 2: Add plugin entry to openclaw.json echo "[2/3] Configuring openclaw.json ..." if [[ ! -f "$CONFIG_FILE" ]]; then echo " WARNING: $CONFIG_FILE not found. Skipping config update." echo " You'll need to manually add the plugin entry." else python3 -c " import json path = '$CONFIG_FILE' with open(path) as f: data = json.load(f) if 'plugins' not in data: data['plugins'] = {} allow_list = data['plugins'].get('allow', []) if 'memory-continuity' not in allow_list: allow_list.append('memory-continuity') data['plugins']['allow'] = allow_list if 'entries' not in data['plugins']: data['plugins']['entries'] = {} data['plugins']['entries']['memory-continuity'] = { 'enabled': True, 'hooks': { 'allowPromptInjection': True }, 'config': { 'maxStateLines': 50, 'archiveOnNew': True, 'autoExtract': True } } if 'installs' not in data['plugins']: data['plugins']['installs'] = {} data['plugins']['installs']['memory-continuity'] = { 'source': 'path', 'installPath': '~/.openclaw/extensions/memory-continuity', 'sourcePath': '$REPO_DIR' } with open(path, 'w') as f: json.dump(data, f, indent=2) print(' Added plugin entry, trust config, and install record') " 2>/dev/null || echo " WARNING: Could not update config automatically. Add manually." fi # --------------------------------------------------------------------------- # Step 3: Detect agents and install SKILL.md to selected workspaces # --------------------------------------------------------------------------- echo "[3/3] Detecting OpenClaw agents ..." # detect_agents outputs lines of: INDEX|ID|DISPLAY_NAME|WORKSPACE_PATH # Uses python3 to parse openclaw.json; falls back gracefully if unavailable. detect_agents() { if [[ ! -f "$CONFIG_FILE" ]]; then return 1 fi python3 - "$CONFIG_FILE" "$OPENCLAW_DIR" <<'PYEOF' import json, sys, os config_file = sys.argv[1] openclaw_dir = sys.argv[2] with open(config_file) as f: data = json.load(f) default_ws = data.get('defaults', {}).get('workspace', os.path.join(openclaw_dir, 'workspace', 'main')) agents = data.get('list', []) seen = set() idx = 1 for agent in agents: agent_id = agent.get('id', '') if not agent_id or agent_id in seen: continue seen.add(agent_id) name = agent.get('name', agent_id) workspace = agent.get('workspace', default_ws if agent_id == 'main' else None) # Skip agents without a resolvable workspace if not workspace: workspace = os.path.join(openclaw_dir, 'workspaces', agent_id) # Expand ~ in path workspace = os.path.expanduser(workspace) print('{}|{}|{}|{}'.format(idx, agent_id, name, workspace)) idx += 1 PYEOF } # Collect detected agents into arrays AGENT_IDS=() AGENT_NAMES=() AGENT_WORKSPACES=() # Read detection output if command -v python3 &>/dev/null && [[ -f "$CONFIG_FILE" ]]; then while IFS='|' read -r idx agent_id agent_name workspace; do AGENT_IDS+=("$agent_id") AGENT_NAMES+=("$agent_name") AGENT_WORKSPACES+=("$workspace") done < <(detect_agents 2>/dev/null || true) fi install_skill_to_workspace() { local workspace="$1" local skill_dest="${workspace}/skills/memory-continuity" mkdir -p "$skill_dest" cp "$REPO_DIR/SKILL.md" "$skill_dest/SKILL.md" echo " Installed → ${skill_dest}/SKILL.md" } if [[ ${#AGENT_IDS[@]} -eq 0 ]]; then # Fallback: no agents detected — ask user for a workspace path echo " No agents detected in openclaw.json (file missing or parse error)." echo "" printf " Enter workspace path to install SKILL.md (or press Enter to skip): " read -r FALLBACK_WS if [[ -n "$FALLBACK_WS" ]]; then FALLBACK_WS="${FALLBACK_WS/#\~/$HOME}" install_skill_to_workspace "$FALLBACK_WS" else echo " Skipped SKILL.md installation." fi else # Show numbered list echo "" echo " Found ${#AGENT_IDS[@]} agent(s):" for i in "${!AGENT_IDS[@]}"; do num=$((i + 1)) printf " [%d] %s (%s)\n" "$num" "${AGENT_NAMES[$i]}" "${AGENT_WORKSPACES[$i]}" done echo "" echo " Install to: [A]ll agents / [1,2,...] specific (comma-separated) / [Q]uit" printf " > " read -r SELECTION case "${SELECTION^^}" in A|ALL) for i in "${!AGENT_IDS[@]}"; do install_skill_to_workspace "${AGENT_WORKSPACES[$i]}" done ;; Q|QUIT) echo " Skipped SKILL.md installation." ;; *) # Parse comma-separated numbers IFS=',' read -ra PICKS <<< "$SELECTION" INSTALLED=0 for pick in "${PICKS[@]}"; do pick="${pick// /}" # trim spaces if [[ "$pick" =~ ^[0-9]+$ ]]; then idx=$((pick - 1)) if [[ $idx -ge 0 && $idx -lt ${#AGENT_IDS[@]} ]]; then install_skill_to_workspace "${AGENT_WORKSPACES[$idx]}" INSTALLED=$((INSTALLED + 1)) else echo " WARNING: No agent at index $pick — skipped." fi else echo " WARNING: Invalid selection '$pick' — skipped." fi done if [[ $INSTALLED -eq 0 ]]; then echo " No valid selections — SKILL.md not installed." fi ;; esac fi echo "" echo "=== Installation complete ===" echo "" echo "Verify with:" echo " bash scripts/verify.sh" echo " bash scripts/verify.sh --all-agents" echo "" echo "Test with:" echo " 1. Tell your agent something memorable" echo " 2. Send /new" echo " 3. Ask what you told it"